Compare commits
107 Commits
v3.0.0
...
7c7e64311e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c7e64311e | ||
|
|
46714df604 | ||
|
|
197dc40510 | ||
|
|
8e3b286190 | ||
|
|
91ca91571b | ||
|
|
ce9228c5bb | ||
|
|
6f19c86fe6 | ||
|
|
422d935b26 | ||
|
|
cca3090577 | ||
|
|
4766d2e628 | ||
|
|
c9ca55b45b | ||
|
|
bcff4fd9e3 | ||
|
|
d4ed2b8672 | ||
|
|
ee838aa488 | ||
|
|
b27fa844e6 | ||
|
|
7f728c7a92 | ||
|
|
15ffb4ec2e | ||
|
|
f92e510665 | ||
|
|
997548dd4b | ||
|
|
25ab33c79c | ||
|
|
9d439d1dcf | ||
|
|
0a08c489be | ||
|
|
038e7725f9 | ||
|
|
4ccf249663 | ||
|
|
1d5b01f77f | ||
|
|
538dac3a46 | ||
|
|
6c383dd9f5 | ||
|
|
9ae49f8797 | ||
|
|
3c175ba28d | ||
|
|
e34592c3d4 | ||
|
|
fd044a4752 | ||
|
|
6e264ad500 | ||
|
|
83fd1ee983 | ||
|
|
7640de34e5 | ||
|
|
77846601ee | ||
|
|
b80dc6e23f | ||
|
|
176cc67a5c | ||
|
|
afaa86ef6e | ||
|
|
d1a820728f | ||
|
|
11bb1dba0f | ||
|
|
345d2819d8 | ||
|
|
36e3cf8c52 | ||
|
|
06ff95cdc3 | ||
|
|
9adeee6c83 | ||
|
|
e42d35f3bf | ||
|
|
a69d1f51b9 | ||
|
|
911ae6cb1f | ||
|
|
9a2f326e42 | ||
|
|
46a8d6b552 | ||
|
|
cf5423f69f | ||
|
|
177375a7b7 | ||
|
|
016bdbdd94 | ||
|
|
41e0dcb528 | ||
|
|
787e447d09 | ||
|
|
9c092ae3bb | ||
|
|
42bc8fea95 | ||
|
|
c4fc1e6fcf | ||
|
|
6f6d0893ec | ||
|
|
a6a55202a3 | ||
|
|
24bee53f9e | ||
|
|
afc9d3d17d | ||
|
|
97ce15d116 | ||
|
|
879fe48945 | ||
|
|
5d834d924a | ||
|
|
fece90b307 | ||
|
|
06d110ed16 | ||
|
|
dfcadda2bb | ||
|
|
3c9546ded9 | ||
|
|
a3d82e092e | ||
|
|
96a1b741df | ||
|
|
e7b7d1d084 | ||
|
|
efc30c3ac8 | ||
|
|
2ae13aafd4 | ||
|
|
e925050207 | ||
|
|
7aa67cfc2f | ||
|
|
6d38e2bf25 | ||
|
|
8ed5e61f63 | ||
|
|
c3c89f8cc8 | ||
|
|
a3a6bdbc55 | ||
|
|
07d9fc1f45 | ||
|
|
73a60e3591 | ||
|
|
c79848c654 | ||
|
|
ec092a11c3 | ||
|
|
9a7b727413 | ||
|
|
b8d16b7669 | ||
|
|
058a4aee2a | ||
|
|
1b50c7f9f1 | ||
|
|
e7f53fd55f | ||
|
|
07bdc5e585 | ||
|
|
e1b8a5f011 | ||
|
|
80ca76ea37 | ||
|
|
2c6ff66830 | ||
|
|
4f79a66559 | ||
|
|
22883b4334 | ||
|
|
081da6d18d | ||
|
|
74eb5b2530 | ||
|
|
b0328fe0ef | ||
|
|
2ee0aae57e | ||
|
|
d9c3de660a | ||
|
|
ccbf5c9520 | ||
|
|
c4f7c1f5d0 | ||
|
|
1208c46cca | ||
|
|
06a63c377e | ||
|
|
0fa25032a3 | ||
|
|
28ad29d6ed | ||
|
|
b9097b4989 | ||
|
|
5d14eb20af |
133
.github/workflows/publish-images.yml
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
name: Publish Docker Images
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: Release tag to rebuild
|
||||
required: true
|
||||
type: string
|
||||
|
||||
concurrency:
|
||||
group: publish-images-${{ inputs.release_tag || github.ref_name }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_OWNER: ${{ github.repository_owner }}
|
||||
RELEASE_TAG: ${{ inputs.release_tag || github.ref_name }}
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish ${{ matrix.image }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
attestations: write
|
||||
id-token: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- image: ruoyi-ai-backend
|
||||
source: local
|
||||
context: .
|
||||
dockerfile: docs/docker/ruoyi-ai/Dockerfile.backend
|
||||
- image: ruoyi-ai-mysql
|
||||
source: local
|
||||
context: .
|
||||
dockerfile: docs/docker/ruoyi-ai/Dockerfile.mysql
|
||||
- image: ruoyi-ai-admin
|
||||
source: admin
|
||||
context: build/ruoyi-admin
|
||||
dockerfile: build/ruoyi-admin/apps/web-antd/Dockerfile
|
||||
- image: ruoyi-ai-web
|
||||
source: web
|
||||
context: build/ruoyi-web
|
||||
dockerfile: build/ruoyi-web/Dockerfile.frontend
|
||||
|
||||
steps:
|
||||
- name: Checkout backend repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ env.RELEASE_TAG }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Checkout admin repository
|
||||
if: matrix.source == 'admin'
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: ${{ github.repository_owner }}/ruoyi-admin
|
||||
ref: ${{ env.RELEASE_TAG }}
|
||||
path: build/ruoyi-admin
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Checkout web repository
|
||||
if: matrix.source == 'web'
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: ${{ github.repository_owner }}/ruoyi-web
|
||||
ref: ${{ env.RELEASE_TAG }}
|
||||
path: build/ruoyi-web
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Configure frontend dependency builds
|
||||
if: matrix.source == 'admin' || matrix.source == 'web'
|
||||
shell: bash
|
||||
run: |
|
||||
python3 - "${{ matrix.dockerfile }}" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
dockerfile = Path(sys.argv[1])
|
||||
content = dockerfile.read_text()
|
||||
marker = "pnpm install --frozen-lockfile"
|
||||
replacement = (
|
||||
"pnpm install --frozen-lockfile "
|
||||
"--config.dangerously-allow-all-builds=true"
|
||||
)
|
||||
if marker not in content:
|
||||
raise SystemExit(f"pnpm install command not found in {dockerfile}")
|
||||
dockerfile.write_text(content.replace(marker, replacement, 1))
|
||||
PY
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_OWNER }}/${{ matrix.image }}
|
||||
tags: |
|
||||
type=raw,value=${{ env.RELEASE_TAG }}
|
||||
type=raw,value=latest
|
||||
labels: |
|
||||
org.opencontainers.image.source=https://github.com/${{ github.repository }}
|
||||
org.opencontainers.image.version=${{ env.RELEASE_TAG }}
|
||||
|
||||
- name: Build and push image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ${{ matrix.context }}
|
||||
file: ${{ matrix.dockerfile }}
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha,scope=${{ matrix.image }}
|
||||
cache-to: type=gha,mode=max,scope=${{ matrix.image }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
5
.gitignore
vendored
@@ -23,6 +23,9 @@ target/
|
||||
.idea
|
||||
.claude
|
||||
.github
|
||||
!.github/
|
||||
!.github/workflows/
|
||||
!.github/workflows/**
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
@@ -45,6 +48,7 @@ nbdist/
|
||||
*.xml.versionsBackup
|
||||
*.swp
|
||||
data/
|
||||
logs/
|
||||
|
||||
!*/build/*.java
|
||||
!*/build/*.html
|
||||
@@ -52,3 +56,4 @@ data/
|
||||
|
||||
.flattened-pom.xml
|
||||
/.claude/settings.local.json
|
||||
/docs/docker/milvus/volumes/
|
||||
|
||||
327
README.md
@@ -2,11 +2,7 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||
[![Contributors][contributors-shield]][contributors-url]
|
||||
[![Forks][forks-shield]][forks-url]
|
||||
[![Stargazers][stars-shield]][stars-url]
|
||||
[![Issues][issues-shield]][issues-url]
|
||||
[![MIT License][license-shield]][license-url]
|
||||
[![Contributors][contributors-shield]][contributors-url] [![Forks][forks-shield]][forks-url] [![Stargazers][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url] [![MIT License][license-shield]][license-url]
|
||||
|
||||
|
||||
<p align="center">
|
||||
@@ -17,226 +13,268 @@
|
||||
|
||||
<img src="docs/image/logo.png" alt="RuoYi AI Logo" width="120" height="120">
|
||||
|
||||
### 企业级AI助手平台
|
||||
### Enterprise-Grade AI Assistant Platform
|
||||
|
||||
*开箱即用的全栈AI平台,支持多智能体协同、Supervisor模式编排、多种决策模式、RAG技术和流程编排能力*
|
||||
*An out-of-the-box full-stack AI platform supporting multi-agent collaboration, Supervisor mode orchestration, and multiple decision models, with advanced RAG technology and visual workflow orchestration capabilities*
|
||||
|
||||
**[English](README_EN.md)** | **[📖 使用文档](https://doc.pandarobot.chat)** |
|
||||
**[🚀 在线体验](https://web.pandarobot.chat)** | **[🐛 问题反馈](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 功能建议](https://github.com/ageerle/ruoyi-ai/issues)**
|
||||
**[中文](README_ZH.md)** | **[📖 Documentation](https://doc.ruoyiai.chat/)** |
|
||||
**[🚀 Live Demo](https://web.ruoyiai.chat/)** | **[🐛 Report Issues](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 Feature Requests](https://github.com/ageerle/ruoyi-ai/issues)**
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## ✨ 核心亮点
|
||||
## 🚀 Live Demo
|
||||
|
||||
| 模块 | 现有能力
|
||||
|:----------:|---
|
||||
| **模型管理** | 多模型接入(OpenAI/DeepSeek/通义/智谱)、多模态理解、Coze/DIFY/FastGPT平台集成
|
||||
| **知识管理** | 本地RAG + 向量库(Milvus/Weaviate/Qdrant) + 文档解析
|
||||
| **工具管理** | Mcp协议集成、Skills能力 + 可扩展工具生态
|
||||
| **流程编排** | 可视化工作流设计器、节点拖拽编排、SSE流式执行,目前已经支持模型调用,邮件发送,人工审核等节点
|
||||
| **多智能体** | 基于Langchain4j的Agent框架、Supervisor模式编排,支持多种决策模型
|
||||
| Service | URL | Default Account |
|
||||
|---|---|---|
|
||||
| Admin Panel | http://129.226.199.247:25666 | admin / admin123 |
|
||||
| User Frontend | http://129.226.199.247:25137 | admin / admin123 |
|
||||
| Commercial Edition | https://web.ruoyiai.chat | WeChat QR code login |
|
||||
|
||||
## 🚀 快速体验
|
||||
## ✨ Core Features
|
||||
|
||||
### 在线演示
|
||||
| Module | Current Capabilities |
|
||||
|:---:|---|
|
||||
| **Model Management** | Multi-model integration (DeepSeek/Zhipu/MIMO/Bailian/OpenAI), multi-modal understanding, Coze/DIFY/FastGPT/RAGFlow platform integration |
|
||||
| **Knowledge Management** | Local RAG + Vector DB (Milvus/Weaviate/Qdrant) + Document parsing |
|
||||
| **Tool Management** | MCP protocol integration, Skills capability + Extensible tool ecosystem |
|
||||
| **Workflow Orchestration** | Visual workflow designer, drag-and-drop node orchestration, SSE streaming execution, currently supports model calls, email sending, manual review, and other nodes |
|
||||
| **Multi-Agent** | Agent framework based on Langchain4j, Supervisor mode orchestration, supports multiple decision models, can flexibly combine tools and skills |
|
||||
|
||||
| 平台 | 地址 | 账号 |
|
||||
|:------:|---|---|
|
||||
| 用户端 | [web.pandarobot.chat](https://web.pandarobot.chat) | admin / admin123 |
|
||||
| 管理后台 | [admin.pandarobot.chat](https://admin.pandarobot.chat) | admin / admin123 |
|
||||
### Project Repositories
|
||||
|
||||
### 项目源码
|
||||
|
||||
| 项目模块 | GitHub 仓库 | Gitee 仓库 | GitCode 仓库 |
|
||||
| Module | GitHub Repository | Gitee Repository | GitCode Repository |
|
||||
|----------|-------------------------------------------------------|------------------------------------------------------|--------------------------------------------------------|
|
||||
| 🔧 后端服务 | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) |
|
||||
| 🎨 用户前端 | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) |
|
||||
| 🛠️ 管理后台 | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
|
||||
| 🔧 Backend | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) |
|
||||
| 🎨 User Frontend | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) |
|
||||
| 🛠️ Admin Panel | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
|
||||
| 🎬 Drama | [ruoyi-drama](https://github.com/ageerle/ruoyi-drama) | [ruoyi-drama](https://gitee.com/ageerle/ruoyi-drama) | [ruoyi-drama](https://gitcode.com/ageerle/ruoyi-drama) |
|
||||
| 🤖 Copilot | [ruoyi-copilot](https://github.com/ageerle/ruoyi-copilot) | [ruoyi-copilot](https://gitee.com/ageerle/ruoyi-copilot) | [ruoyi-copilot](https://gitcode.com/ageerle/ruoyi-copilot) |
|
||||
| 📱 Mini-App | [ruoyi-uniapp](https://github.com/ageerle/ruoyi-uniapp) | [ruoyi-uniapp](https://gitee.com/ageerle/ruoyi-uniapp) | [ruoyi-uniapp](https://gitcode.com/ageerle/ruoyi-uniapp) |
|
||||
|
||||
### 合作项目
|
||||
| 项目名称 | GitHub 仓库 | Gitee 仓库
|
||||
### Partner Projects
|
||||
| Project Name | GitHub Repository | Gitee Repository |
|
||||
|----------------|-------------------------------------------------------|------------------------------------------------------|
|
||||
| element-plus-x | [element-plus-x](https://github.com/element-plus-x/Element-Plus-X) | [element-plus-x](https://gitee.com/he-jiayue/element-plus-x) |
|
||||
| element-plus-x | [element-plus-x](https://github.com/element-plus-x/Element-Plus-X) | [element-plus-x](https://gitee.com/he-jiayue/element-plus-x) |
|
||||
|
||||
## 🛠️ 技术架构
|
||||
## 🛠️ Technical Architecture
|
||||
|
||||
### 核心框架
|
||||
- **后端架构**:Spring Boot 3.5.8 + Langchain4j
|
||||
- **数据存储**:MySQL 8.0 + Redis + 向量数据库(Milvus/Weaviate/Qdrant)
|
||||
- **前端技术**:Vue 3 + Vben Admin + element-plus-x
|
||||
- **安全认证**:Sa-Token + JWT 双重保障
|
||||
### Core Framework
|
||||
- **Backend**: Spring Boot 3.5.8 + Langchain4j
|
||||
- **Data Storage**: MySQL 8.0 + Redis + Vector Databases (Milvus/Weaviate/Qdrant)
|
||||
- **Frontend**: Vue 3 + Vben Admin + element-plus-x
|
||||
- **Security**: Sa-Token + JWT dual-layer security
|
||||
- **Document Processing**: PDF, Word, Excel parsing, intelligent image analysis
|
||||
- **Real-time Communication**: WebSocket real-time communication, SSE streaming response
|
||||
- **System Monitoring**: Comprehensive logging system, performance monitoring, service health checks
|
||||
|
||||
## 🐳 Docker Deployment
|
||||
|
||||
- **文档处理**:PDF、Word、Excel 解析,图像智能分析
|
||||
- **实时通信**:WebSocket 实时通信,SSE 流式响应
|
||||
- **系统监控**:完善的日志体系、性能监控、服务健康检查
|
||||
This project provides two Docker deployment methods:
|
||||
|
||||
## 🐳 Docker 部署
|
||||
### Method 1: One-click Start All Services (Recommended)
|
||||
|
||||
本项目提供两种 Docker 部署方式:
|
||||
|
||||
### 方式一:一键启动所有服务(推荐)
|
||||
|
||||
使用 `docker-compose-all.yaml` 可以一键启动所有服务(包括后端、管理端、用户端及依赖服务):
|
||||
Use `docker-compose-all.yaml` to start all services at once (including backend, admin panel, user frontend, and dependencies):
|
||||
#### Requirements
|
||||
- Docker Engine(Linux/macOS)或 Docker Desktop(Windows)
|
||||
- Docker Compose V2
|
||||
|
||||
#### Linux / macOS
|
||||
```bash
|
||||
# 克隆仓库
|
||||
git clone https://github.com/ageerle/ruoyi-ai.git
|
||||
|
||||
# Clone the v3.1.0 release
|
||||
git clone --depth 1 --branch v3.1.0 https://github.com/ageerle/ruoyi-ai.git
|
||||
cd ruoyi-ai
|
||||
|
||||
# 启动所有服务(从镜像仓库拉取预构建镜像)
|
||||
docker-compose -f docker-compose-all.yaml up -d
|
||||
# Pin the image version. Public GHCR images do not require docker login.
|
||||
cp docs/docker/ruoyi-ai/.env.example docs/docker/ruoyi-ai/.env
|
||||
sed -i 's/^RUIYI_VERSION=.*/RUIYI_VERSION=v3.1.0/' docs/docker/ruoyi-ai/.env
|
||||
|
||||
# 查看服务状态
|
||||
docker-compose -f docker-compose-all.yaml ps
|
||||
# Pull pre-built images from GHCR and start all services
|
||||
docker compose --env-file docs/docker/ruoyi-ai/.env \
|
||||
-f docs/docker/ruoyi-ai/docker-compose-all.yaml pull
|
||||
docker compose --env-file docs/docker/ruoyi-ai/.env \
|
||||
-f docs/docker/ruoyi-ai/docker-compose-all.yaml up -d
|
||||
|
||||
# 访问服务
|
||||
# 管理端: http://localhost:25666 (admin / admin123)
|
||||
# 用户端: http://localhost:25137
|
||||
# 后端API: http://localhost:26039
|
||||
# Check service status
|
||||
docker compose --env-file docs/docker/ruoyi-ai/.env \
|
||||
-f docs/docker/ruoyi-ai/docker-compose-all.yaml ps
|
||||
|
||||
# Access services (replace SERVER_IP with the server address)
|
||||
# Admin Panel: http://SERVER_IP:25666 (admin / admin123)
|
||||
# User Frontend: http://SERVER_IP:25137
|
||||
# Backend API: http://SERVER_IP:26039
|
||||
```
|
||||
|
||||
### 方式二:分步部署(源码编译)
|
||||
#### Windows PowerShell
|
||||
If you are using Windows with Docker Desktop, you can use PowerShell to execute the following commands:
|
||||
|
||||
如果您需要从源码构建后端服务,请按照以下步骤操作:
|
||||
```PowerShell
|
||||
|
||||
#### 第一步:部署后端服务
|
||||
|
||||
```bash
|
||||
# 进入后端项目目录
|
||||
# Clone the v3.1.0 release
|
||||
git clone --depth 1 --branch v3.1.0 https://github.com/ageerle/ruoyi-ai.git
|
||||
cd ruoyi-ai
|
||||
|
||||
# 启动后端服务(源码编译构建)
|
||||
# Create the environment configuration file
|
||||
Copy-Item docs\docker\ruoyi-ai\.env.example docs\docker\ruoyi-ai\.env
|
||||
|
||||
# Pin the image version
|
||||
(Get-Content docs\docker\ruoyi-ai\.env) `
|
||||
-replace '^RUIYI_VERSION=.*', 'RUIYI_VERSION=v3.1.0' |
|
||||
Set-Content docs\docker\ruoyi-ai\.env
|
||||
|
||||
# Check the environment configuration
|
||||
Get-Content docs\docker\ruoyi-ai\.env
|
||||
|
||||
# Pull pre-built images from GHCR and start all services
|
||||
docker compose --env-file docs\docker\ruoyi-ai\.env `
|
||||
-f docs\docker\ruoyi-ai\docker-compose-all.yaml pull
|
||||
docker compose --env-file docs\docker\ruoyi-ai\.env `
|
||||
-f docs\docker\ruoyi-ai\docker-compose-all.yaml up -d
|
||||
|
||||
# Check service status
|
||||
docker compose --env-file docs\docker\ruoyi-ai\.env `
|
||||
-f docs\docker\ruoyi-ai\docker-compose-all.yaml ps
|
||||
```
|
||||
|
||||
The default Compose file also publishes MySQL (`23306`), Redis (`26379`),
|
||||
Weaviate (`28080`), and MinIO (`29000`/`29090`). For production deployments,
|
||||
change the default MySQL and MinIO passwords and expose only the application
|
||||
ports through the firewall or a reverse proxy.
|
||||
|
||||
To upgrade to another published release, update `RUIYI_VERSION` in
|
||||
`docs/docker/ruoyi-ai/.env`, then run `docker compose pull` and
|
||||
`docker compose up -d` with the same `--env-file` and `-f` options. Do not use
|
||||
`docker compose down -v` unless you intend to delete persistent data volumes.
|
||||
|
||||
### Method 2: Step-by-step Deployment (Source Build)
|
||||
|
||||
If you need to build backend services from source, follow these steps:
|
||||
|
||||
#### Step 1: Deploy Backend Service
|
||||
|
||||
```bash
|
||||
# Enter backend project directory
|
||||
cd ruoyi-ai
|
||||
|
||||
# Start backend service (build from source)
|
||||
docker-compose up -d --build
|
||||
|
||||
# 等待后端服务启动完成
|
||||
# Wait for backend service to start
|
||||
docker-compose logs -f backend
|
||||
```
|
||||
|
||||
#### 第二步:部署管理端
|
||||
#### Step 2: Deploy Admin Panel
|
||||
|
||||
```bash
|
||||
# 进入管理端项目目录
|
||||
# Enter admin panel project directory
|
||||
cd ruoyi-admin
|
||||
|
||||
# 构建并启动管理端
|
||||
# Build and start admin panel
|
||||
docker-compose up -d --build
|
||||
|
||||
# 访问管理端
|
||||
# 地址: http://localhost:5666
|
||||
# Access admin panel
|
||||
# URL: http://localhost:5666
|
||||
```
|
||||
|
||||
#### 第三步:部署用户端(可选)
|
||||
#### Step 3: Deploy User Frontend (Optional)
|
||||
|
||||
```bash
|
||||
# 进入用户端项目目录
|
||||
# Enter user frontend project directory
|
||||
cd ruoyi-web
|
||||
|
||||
# 构建并启动用户端
|
||||
# Build and start user frontend
|
||||
docker-compose up -d --build
|
||||
|
||||
# 访问用户端
|
||||
# 地址: http://localhost:5137
|
||||
# Access user frontend
|
||||
# URL: http://localhost:5137
|
||||
```
|
||||
|
||||
### 服务端口说明
|
||||
### Service Ports
|
||||
|
||||
| 服务 | 一键启动端口 | 分步部署端口 | 说明 |
|
||||
| Service | One-click Port | Step-by-step Port | Description |
|
||||
|------|-------------|-------------|------|
|
||||
| 管理端 | 25666 | 5666 | 管理后台访问地址 |
|
||||
| 用户端 | 25137 | 5137 | 用户前端访问地址 |
|
||||
| 后端服务 | 26039 | 6039 | 后端 API 服务 |
|
||||
| MySQL | 23306 | 23306 | 数据库服务 |
|
||||
| Redis | 26379 | 6379 | 缓存服务 |
|
||||
| Weaviate | 28080 | 28080 | 向量数据库 |
|
||||
| MinIO API | 29000 | 9000 | 对象存储 API |
|
||||
| MinIO Console | 29090 | 9090 | 对象存储控制台 |
|
||||
| Admin Panel | 25666 | 5666 | Admin backend access |
|
||||
| User Frontend | 25137 | 5137 | User frontend access |
|
||||
| Backend Service | 26039 | 6039 | Backend API service |
|
||||
| MySQL | 23306 | 23306 | Database service |
|
||||
| Redis | 26379 | 6379 | Cache service |
|
||||
| Weaviate | 28080 | 28080 | Vector database |
|
||||
| MinIO API | 29000 | 9000 | Object storage API |
|
||||
| MinIO Console | 29090 | 9090 | Object storage console |
|
||||
|
||||
### 镜像仓库
|
||||
## 📚 Documentation
|
||||
|
||||
所有镜像托管在阿里云容器镜像服务:
|
||||
Want to learn more about installation, deployment, configuration, and secondary development?
|
||||
|
||||
```
|
||||
crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai
|
||||
```
|
||||
**👉 [Complete Documentation](https://doc.ruoyiai.chat/)**
|
||||
|
||||
可用镜像:
|
||||
- `mysql:v3` - MySQL 数据库(包含初始化 SQL)
|
||||
- `redis:6.2` - Redis 缓存
|
||||
- `weaviate:1.30.0` - 向量数据库
|
||||
- `minio:latest` - 对象存储
|
||||
- `ruoyi-ai-backend:latest` - 后端服务
|
||||
- `ruoyi-ai-admin:latest` - 管理端前端
|
||||
- `ruoyi-ai-web:latest` - 用户端前端
|
||||
- [Model and API Key configuration in ruoyi-admin (Chinese)](docs/model-configuration.md)
|
||||
- [Dify Cloud setup for local development (Chinese)](docs/dify-cloud.md)
|
||||
|
||||
### 常用命令
|
||||
## 🤝 Contributing
|
||||
|
||||
```bash
|
||||
# 停止所有服务
|
||||
docker-compose -f docker-compose-all.yaml down
|
||||
We warmly welcome community contributions! Whether you are a seasoned developer or just getting started, you can contribute to the project 💪
|
||||
|
||||
# 查看服务日志
|
||||
docker-compose -f docker-compose-all.yaml logs -f [服务名]
|
||||
### How to Contribute
|
||||
|
||||
# 重启某个服务
|
||||
docker-compose -f docker-compose-all.yaml restart [服务名]
|
||||
```
|
||||
1. **Fork** the project to your account
|
||||
2. **Create a branch** (`git checkout -b feature/new-feature-name`)
|
||||
3. **Commit your changes** (`git commit -m 'Add new feature'`)
|
||||
4. **Push to the branch** (`git push origin feature/new-feature-name`)
|
||||
5. **Create a Pull Request**
|
||||
|
||||
## 📚 使用文档
|
||||
> 💡 **Tip**: We recommend submitting PRs to GitHub, we will automatically sync to other code hosting platforms
|
||||
|
||||
想要深入了解安装部署、功能配置和二次开发?
|
||||
## 📄 License
|
||||
|
||||
**👉 [完整使用文档](https://doc.pandarobot.chat)**
|
||||
This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## 🤝 参与贡献
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
我们热烈欢迎社区贡献!无论您是资深开发者还是初学者,都可以为项目贡献力量 💪
|
||||
Thanks to the following excellent open-source projects for their support:
|
||||
- [Langchain4j](https://github.com/langchain4j/langchain4j) - Powerful Java LLM development framework
|
||||
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - Mature enterprise-level rapid development framework
|
||||
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - Modern Vue admin template
|
||||
|
||||
### 贡献方式
|
||||
## 💎 Sponsors
|
||||
|
||||
1. **Fork** 项目到您的账户
|
||||
2. **创建分支** (`git checkout -b feature/新功能名称`)
|
||||
3. **提交代码** (`git commit -m '添加某某功能'`)
|
||||
4. **推送分支** (`git push origin feature/新功能名称`)
|
||||
5. **发起 Pull Request**
|
||||
**Thanks to the following sponsors for supporting this project:**
|
||||
|
||||
> 💡 **小贴士**:建议将 PR 提交到 GitHub,我们会自动同步到其他代码托管平台
|
||||
<a href="https://www.atlascloud.ai?ref=89F97E">
|
||||
<img src="docs/image/sponsor/atlascloud_banner.png" alt="Atlas Cloud" width="160" height="80">
|
||||
</a>
|
||||
|
||||
## 📄 开源协议
|
||||
[Visit Atlas Cloud](https://www.atlascloud.ai?ref=89F97E&utm_source=github&utm_campaign=ruoyi-drama) · [Coding Plan Promotion](https://www.atlascloud.ai/console/coding-plan)
|
||||
A full-modal AI inference platform that gives developers a unified AI API, supporting video generation, image generation, and LLMs. Connect once to access **300+ curated models**.
|
||||
|
||||
本项目采用 **MIT 开源协议**,详情请查看 [LICENSE](LICENSE) 文件。
|
||||
<a href="https://www.volcengine.com/activity/codingplan?utm_campaign=hw&utm_content=hw&utm_medium=devrel_tool_web&utm_source=OWO&utm_term=ageerle-ruoyi-ai">
|
||||
<img src="docs/image/sponsor/huoshan.png" alt="Volcengine CodingPlan" width="160" height="80">
|
||||
</a>
|
||||
|
||||
## 🙏 特别鸣谢
|
||||
[Sign up to claim 25 million tokens — go now](https://www.volcengine.com/activity/ai618?utm_campaign=hw&utm_content=hw&utm_medium=devrel_tool_web&utm_source=OWO&utm_term=ageerle-ruoyi-ai)
|
||||
Enjoy ByteDance's in-house Doubao models plus full-power open-source SOTA models, covering text, VLM, and image generation — all modalities in one stop: Seed-2.1, Seedream-5.0, GLM-5.2, DeepSeek, and more. Not just for coding — it can also tackle complex long-horizon Agent tasks!
|
||||
|
||||
感谢以下优秀的开源项目为本项目提供支持:
|
||||
- [Spring AI Alibaba Copilot](https://github.com/spring-ai-alibaba/copilot) - 基于spring-ai-alibaba
|
||||
的智能编码助手
|
||||
- [Langchain4j](https://github.com/langchain4j/langchain4j) - 强大的 Java LLM 开发框架
|
||||
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - 成熟的企业级快速开发框架
|
||||
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - 现代化的 Vue 后台管理模板
|
||||
|
||||
## 🌐 生态伙伴
|
||||
|
||||
- [PPIO 派欧云](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - 提供高性价比的 GPU
|
||||
算力和模型 API 服务
|
||||
- [优云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_ruoyi) - 万卡RTX40系GPU+海内外主流模型API服务,秒级响应,按量计费,新客免费用。
|
||||
|
||||
## 💬 社区交流
|
||||
## 💬 Community Chat
|
||||
|
||||
<div align="center">
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="docs/image/wx.png" alt="微信二维码" width="200" height="200"><br>
|
||||
<strong>扫码添加作者微信</strong><br>
|
||||
<em>邀请进群学习</em>
|
||||
<img src="docs/image/wx.png" alt="WeChat QR Code" width="200" height="200"><br>
|
||||
<strong>Scan to add author on WeChat</strong><br>
|
||||
<em>Join group for learning</em>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/image/qq.png" alt="QQ群二维码" width="200" height="200"><br>
|
||||
<strong>QQ技术交流群</strong><br>
|
||||
<em>技术讨论</em>
|
||||
<img src="docs/image/douyin.png" alt="Douyin QR Code" width="200" height="200"><br>
|
||||
<strong>Douyin Video Tutorials</strong><br>
|
||||
<em>Open Douyin, scan & follow to watch video tutorials</em>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/image/qq.png" alt="QQ Group QR Code" width="200" height="200"><br>
|
||||
<strong>QQ Tech Exchange Group</strong><br>
|
||||
<em>Technical discussion</em>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
@@ -245,11 +283,12 @@ docker-compose -f docker-compose-all.yaml restart [服务名]
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**[⭐ 点个Star支持一下](https://github.com/ageerle/ruoyi-ai)** • **[ Fork 开始贡献](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 English](README_EN.md)** • **[📖 查看完整文档](https://doc.pandarobot.chat)**
|
||||
**[⭐ Star to Support](https://github.com/ageerle/ruoyi-ai)** • **[Fork to Contribute](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 中文](README_ZH.md)** • **[📖 Complete Documentation](https://doc.ruoyiai.chat/)**
|
||||
|
||||
*用 ❤️ 打造,由 RuoYi AI 开源社区维护*
|
||||
*Built with ❤️, maintained by the RuoYi AI open-source community*
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
266
README_EN.md
@@ -1,266 +0,0 @@
|
||||
|
||||
# RuoYi AI
|
||||
|
||||
<div align="center">
|
||||
|
||||
[![Contributors][contributors-shield]][contributors-url]
|
||||
[![Forks][forks-shield]][forks-url]
|
||||
[![Stargazers][stars-shield]][stars-url]
|
||||
[![Issues][issues-shield]][issues-url]
|
||||
[![MIT License][license-shield]][license-url]
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/13209">
|
||||
<img src="https://trendshift.io/api/badge/repositories/13209" alt="GitHub Trending">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<img src="docs/image/logo.png" alt="RuoYi AI Logo" width="120" height="120">
|
||||
|
||||
### Enterprise-Grade AI Assistant Platform
|
||||
|
||||
*An out-of-the-box full-stack AI platform supporting multi-agent collaboration, Supervisor mode orchestration, and multiple decision models, with advanced RAG technology and visual workflow orchestration capabilities*
|
||||
|
||||
**[中文](README.md)** | **[📖 Documentation](https://doc.pandarobot.chat)** |
|
||||
**[🚀 Live Demo](https://web.pandarobot.chat)** | **[🐛 Report Issues](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 Feature Requests](https://github.com/ageerle/ruoyi-ai/issues)**
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
## ✨ Core Features
|
||||
|
||||
| Module | Current Capabilities |
|
||||
|:---:|---|
|
||||
| **Model Management** | Multi-model integration (OpenAI/DeepSeek/Tongyi/Zhipu), multi-modal understanding, Coze/DIFY/FastGPT platform integration |
|
||||
| **Knowledge Base** | Local RAG + Vector DB (Milvus/Weaviate/Qdrant) + Document parsing |
|
||||
| **Tool Management** | MCP protocol integration, Skills capability + Extensible tool ecosystem |
|
||||
| **Workflow Orchestration** | Visual workflow designer, drag-and-drop node orchestration, SSE streaming execution, currently supports model calls, email sending, manual review nodes |
|
||||
| **Multi-Agent** | Agent framework based on Langchain4j, Supervisor mode orchestration, supports multiple decision models |
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Live Demo
|
||||
|
||||
| Platform | URL | Account |
|
||||
|:------:|---|---|
|
||||
| User Frontend | [web.pandarobot.chat](https://web.pandarobot.chat) | admin / admin123 |
|
||||
| Admin Panel | [admin.pandarobot.chat](https://admin.pandarobot.chat) | admin / admin123 |
|
||||
|
||||
### Project Repositories
|
||||
|
||||
| Module | GitHub Repository | Gitee Repository | GitCode Repository |
|
||||
|----------|-------------------------------------------------------|------------------------------------------------------|--------------------------------------------------------|
|
||||
| 🔧 Backend | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) |
|
||||
| 🎨 User Frontend | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) |
|
||||
| 🛠️ Admin Panel | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
|
||||
|
||||
### Partner Projects
|
||||
| Project Name | GitHub Repository | Gitee Repository |
|
||||
|----------------|-------------------------------------------------------|------------------------------------------------------|
|
||||
| element-plus-x | [element-plus-x](https://github.com/element-plus-x/Element-Plus-X) | [element-plus-x](https://gitee.com/he-jiayue/element-plus-x) |
|
||||
|
||||
## 🛠️ Technical Architecture
|
||||
|
||||
### Core Framework
|
||||
- **Backend**: Spring Boot 3.5.8 + Langchain4j
|
||||
- **Data Storage**: MySQL 8.0 + Redis + Vector Databases (Milvus/Weaviate/Qdrant)
|
||||
- **Frontend**: Vue 3 + Vben Admin + element-plus-x
|
||||
- **Security**: Sa-Token + JWT dual-layer security
|
||||
|
||||
|
||||
- **Document Processing**: PDF, Word, Excel parsing, intelligent image analysis
|
||||
- **Real-time Communication**: WebSocket real-time communication, SSE streaming response
|
||||
- **System Monitoring**: Comprehensive logging system, performance monitoring, service health checks
|
||||
|
||||
## 🐳 Docker Deployment
|
||||
|
||||
This project provides two Docker deployment methods:
|
||||
|
||||
### Method 1: One-click Start All Services (Recommended)
|
||||
|
||||
Use `docker-compose-all.yaml` to start all services at once (including backend, admin panel, user frontend, and dependencies):
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/ageerle/ruoyi-ai.git
|
||||
cd ruoyi-ai
|
||||
|
||||
# Start all services (pull pre-built images from registry)
|
||||
docker-compose -f docker-compose-all.yaml up -d
|
||||
|
||||
# Check service status
|
||||
docker-compose -f docker-compose-all.yaml ps
|
||||
|
||||
# Access services
|
||||
# Admin Panel: http://localhost:25666 (admin / admin123)
|
||||
# User Frontend: http://localhost:25137
|
||||
# Backend API: http://localhost:26039
|
||||
```
|
||||
|
||||
### Method 2: Step-by-step Deployment (Source Build)
|
||||
|
||||
If you need to build backend services from source, follow these steps:
|
||||
|
||||
#### Step 1: Deploy Backend Service
|
||||
|
||||
```bash
|
||||
# Enter backend project directory
|
||||
cd ruoyi-ai
|
||||
|
||||
# Start backend service (build from source)
|
||||
docker-compose up -d --build
|
||||
|
||||
# Wait for backend service to start
|
||||
docker-compose logs -f backend
|
||||
```
|
||||
|
||||
#### Step 2: Deploy Admin Panel
|
||||
|
||||
```bash
|
||||
# Enter admin panel project directory
|
||||
cd ruoyi-admin
|
||||
|
||||
# Build and start admin panel
|
||||
docker-compose up -d --build
|
||||
|
||||
# Access admin panel
|
||||
# URL: http://localhost:5666
|
||||
```
|
||||
|
||||
#### Step 3: Deploy User Frontend (Optional)
|
||||
|
||||
```bash
|
||||
# Enter user frontend project directory
|
||||
cd ruoyi-web
|
||||
|
||||
# Build and start user frontend
|
||||
docker-compose up -d --build
|
||||
|
||||
# Access user frontend
|
||||
# URL: http://localhost:5137
|
||||
```
|
||||
|
||||
### Service Ports
|
||||
|
||||
| Service | One-click Port | Step-by-step Port | Description |
|
||||
|------|-------------|-------------|------|
|
||||
| Admin Panel | 25666 | 5666 | Admin backend access |
|
||||
| User Frontend | 25137 | 5137 | User frontend access |
|
||||
| Backend Service | 26039 | 6039 | Backend API service |
|
||||
| MySQL | 23306 | 23306 | Database service |
|
||||
| Redis | 26379 | 6379 | Cache service |
|
||||
| Weaviate | 28080 | 28080 | Vector database |
|
||||
| MinIO API | 29000 | 9000 | Object storage API |
|
||||
| MinIO Console | 29090 | 9090 | Object storage console |
|
||||
|
||||
### Image Registry
|
||||
|
||||
All images are hosted on Alibaba Cloud Container Registry:
|
||||
|
||||
```
|
||||
crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai
|
||||
```
|
||||
|
||||
Available images:
|
||||
- `mysql:v3` - MySQL database (includes initialization SQL)
|
||||
- `redis:6.2` - Redis cache
|
||||
- `weaviate:1.30.0` - Vector database
|
||||
- `minio:latest` - Object storage
|
||||
- `ruoyi-ai-backend:latest` - Backend service
|
||||
- `ruoyi-ai-admin:latest` - Admin frontend
|
||||
- `ruoyi-ai-web:latest` - User frontend
|
||||
|
||||
### Common Commands
|
||||
|
||||
```bash
|
||||
# Stop all services
|
||||
docker-compose -f docker-compose-all.yaml down
|
||||
|
||||
# View service logs
|
||||
docker-compose -f docker-compose-all.yaml logs -f [service-name]
|
||||
|
||||
# Restart a service
|
||||
docker-compose -f docker-compose-all.yaml restart [service-name]
|
||||
```
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
Want to learn more about installation, deployment, configuration, and secondary development?
|
||||
|
||||
**👉 [Complete Documentation](https://doc.pandarobot.chat)**
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We warmly welcome community contributions! Whether you are a seasoned developer or just getting started, you can contribute to the project 💪
|
||||
|
||||
### How to Contribute
|
||||
|
||||
1. **Fork** the project to your account
|
||||
2. **Create a branch** (`git checkout -b feature/new-feature-name`)
|
||||
3. **Commit your changes** (`git commit -m 'Add new feature'`)
|
||||
4. **Push to the branch** (`git push origin feature/new-feature-name`)
|
||||
5. **Create a Pull Request**
|
||||
|
||||
> 💡 **Tip**: We recommend submitting PRs to GitHub, we will automatically sync to other code hosting platforms
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
Thanks to the following excellent open-source projects for their support:
|
||||
- [Spring AI Alibaba Copilot](https://github.com/spring-ai-alibaba/copilot) - Intelligent coding assistant based on spring-ai-alibaba
|
||||
- [Langchain4j](https://github.com/langchain4j/langchain4j) - Powerful Java LLM development framework
|
||||
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - Mature enterprise-level rapid development framework
|
||||
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - Modern Vue admin template
|
||||
|
||||
## 🌐 Ecosystem Partners
|
||||
|
||||
- [PPIO Cloud](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - Provides cost-effective GPU computing and model API services
|
||||
- [Youyun Intelligent Computing](https://www.compshare.cn/?ytag=GPU_YY-gh_ruoyi) - Thousands of RTX40 series GPUs + mainstream models API services, second-level response, pay-per-use, free for new customers.
|
||||
|
||||
|
||||
## 💬 Community Chat
|
||||
|
||||
<div align="center">
|
||||
|
||||
**[📱 Join Telegram Group](
|
||||
https://t.me/+LqooQAc5HxRmYmE1)**
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**[⭐ Star to Support](https://github.com/ageerle/ruoyi-ai)** • **[Fork to Contribute](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 中文](README.md)** • **[📖 Complete Documentation](https://doc.pandarobot.chat)**
|
||||
|
||||
*Built with ❤️, maintained by the RuoYi AI open-source community*
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Badge Links -->
|
||||
|
||||
[contributors-shield]: https://img.shields.io/github/contributors/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
|
||||
[contributors-url]: https://github.com/ageerle/ruoyi-ai/graphs/contributors
|
||||
|
||||
[forks-shield]: https://img.shields.io/github/forks/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
|
||||
[forks-url]: https://github.com/ageerle/ruoyi-ai/network/members
|
||||
|
||||
[stars-shield]: https://img.shields.io/github/stars/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
|
||||
[stars-url]: https://github.com/ageerle/ruoyi-ai/stargazers
|
||||
|
||||
[issues-shield]: https://img.shields.io/github/issues/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
|
||||
[issues-url]: https://github.com/ageerle/ruoyi-ai/issues
|
||||
|
||||
[license-shield]: https://img.shields.io/github/license/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
|
||||
[license-url]: https://github.com/ageerle/ruoyi-ai/blob/main/LICENSE
|
||||
312
README_ZH.md
Normal file
@@ -0,0 +1,312 @@
|
||||
# RuoYi AI
|
||||
|
||||
<div align="center">
|
||||
|
||||
[![Contributors][contributors-shield]][contributors-url] [![Forks][forks-shield]][forks-url] [![Stargazers][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url] [![MIT License][license-shield]][license-url]
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/13209">
|
||||
<img src="https://trendshift.io/api/badge/repositories/13209" alt="GitHub Trending">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<img src="docs/image/logo.png" alt="RuoYi AI Logo" width="120" height="120">
|
||||
|
||||
### 企业级AI助手平台
|
||||
|
||||
*开箱即用的全栈AI平台,支持多智能体协同、Supervisor模式编排、多种决策模式、RAG技术和流程编排能力*
|
||||
|
||||
**[English](README.md)** | **[📖 使用文档](https://doc.ruoyiai.chat/)** |
|
||||
**[🚀 在线体验](https://web.ruoyiai.chat/)** | **[🐛 问题反馈](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 功能建议](https://github.com/ageerle/ruoyi-ai/issues)**
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## 🚀 演示地址
|
||||
|
||||
| 服务 | 访问地址 | 默认账号 |
|
||||
|---|---|---|
|
||||
| 管理端 | http://129.226.199.247:25666 | admin / admin123 |
|
||||
| 用户端 | http://129.226.199.247:25137 | admin / admin123 |
|
||||
| 商业版 | https://web.ruoyiai.chat | 微信扫码登录 |
|
||||
|
||||
## ✨ 核心亮点
|
||||
|
||||
| 模块 | 现有能力
|
||||
|:---------:|---
|
||||
| **模型管理** | 多模型接入(DeepSeek/智谱/MIMO/百炼/OpenAI)、多模态理解、Coze/DIFY/FastGPT/RAGFlow平台集成
|
||||
| **知识管理** | 本地RAG + 向量库(Milvus/Weaviate/Qdrant) + 文档解析
|
||||
| **工具管理** | Mcp协议集成、Skills能力 + 可扩展工具生态
|
||||
| **流程编排** | 可视化工作流设计器、节点拖拽编排、SSE流式执行,目前已经支持模型调用,邮件发送,人工审核等节点
|
||||
| **智能体管理** | 基于Langchain4j的Agent框架、Supervisor模式编排,支持多种决策模型,可以灵活搭配工具,skills
|
||||
|
||||
|
||||
### 项目源码
|
||||
|
||||
| 项目模块 | GitHub 仓库 | Gitee 仓库 | GitCode 仓库 |
|
||||
|----------|-------------------------------------------------------|------------------------------------------------------|--------------------------------------------------------|
|
||||
| 🔧 后端服务 | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) |
|
||||
| 🎨 用户前端 | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) |
|
||||
| 🛠️ 管理后台 | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
|
||||
| 🎬 短剧平台 | [ruoyi-drama](https://github.com/ageerle/ruoyi-drama) | [ruoyi-drama](https://gitee.com/ageerle/ruoyi-drama) | [ruoyi-drama](https://gitcode.com/ageerle/ruoyi-drama) |
|
||||
| 🤖 编程助手 | [ruoyi-copilot](https://github.com/ageerle/ruoyi-copilot) | [ruoyi-copilot](https://gitee.com/ageerle/ruoyi-copilot) | [ruoyi-copilot](https://gitcode.com/ageerle/ruoyi-copilot) |
|
||||
| 📱 小程序端 | [ruoyi-uniapp](https://github.com/ageerle/ruoyi-uniapp) | [ruoyi-uniapp](https://gitee.com/ageerle/ruoyi-uniapp) | [ruoyi-uniapp](https://gitcode.com/ageerle/ruoyi-uniapp) |
|
||||
|
||||
### 合作项目
|
||||
| 项目名称 | GitHub 仓库 | Gitee 仓库
|
||||
|----------------|-------------------------------------------------------|------------------------------------------------------|
|
||||
| element-plus-x | [element-plus-x](https://github.com/element-plus-x/Element-Plus-X) | [element-plus-x](https://gitee.com/he-jiayue/element-plus-x) |
|
||||
|
||||
## 🛠️ 技术架构
|
||||
|
||||
### 核心框架
|
||||
- **后端架构**:Spring Boot 3.5.8 + Langchain4j
|
||||
- **数据存储**:MySQL 8.0 + Redis + 向量数据库(Milvus/Weaviate/Qdrant)
|
||||
- **前端技术**:Vue 3 + Vben Admin + element-plus-x
|
||||
- **安全认证**:Sa-Token + JWT 双重保障
|
||||
- **文档处理**:PDF、Word、Excel 解析,图像智能分析
|
||||
- **实时通信**:WebSocket 实时通信,SSE 流式响应
|
||||
- **系统监控**:完善的日志体系、性能监控、服务健康检查
|
||||
|
||||
## 🐳 Docker 部署
|
||||
|
||||
本项目提供两种 Docker 部署方式:
|
||||
|
||||
### 方式一:一键启动所有服务(推荐)
|
||||
|
||||
使用 `docker-compose-all.yaml` 可以一键启动所有服务(包括后端、管理端、用户端及依赖服务):
|
||||
#### 环境要求
|
||||
|
||||
- Docker Engine(Linux/macOS)或 Docker Desktop(Windows)
|
||||
- Docker Compose V2
|
||||
|
||||
#### Linux / macOS
|
||||
```bash
|
||||
# 克隆 v3.1.0 版本
|
||||
git clone --depth 1 --branch v3.1.0 https://github.com/ageerle/ruoyi-ai.git
|
||||
cd ruoyi-ai
|
||||
|
||||
# 固定镜像版本。GHCR 镜像已公开,无需 docker login
|
||||
cp docs/docker/ruoyi-ai/.env.example docs/docker/ruoyi-ai/.env
|
||||
sed -i 's/^RUIYI_VERSION=.*/RUIYI_VERSION=v3.1.0/' docs/docker/ruoyi-ai/.env
|
||||
|
||||
# 从 GHCR 拉取预构建镜像并启动全部服务
|
||||
docker compose --env-file docs/docker/ruoyi-ai/.env \
|
||||
-f docs/docker/ruoyi-ai/docker-compose-all.yaml pull
|
||||
docker compose --env-file docs/docker/ruoyi-ai/.env \
|
||||
-f docs/docker/ruoyi-ai/docker-compose-all.yaml up -d
|
||||
|
||||
# 查看服务状态
|
||||
docker compose --env-file docs/docker/ruoyi-ai/.env \
|
||||
-f docs/docker/ruoyi-ai/docker-compose-all.yaml ps
|
||||
|
||||
# 访问服务(将 SERVER_IP 替换为服务器地址)
|
||||
# 管理端: http://SERVER_IP:25666 (admin / admin123)
|
||||
# 用户端: http://SERVER_IP:25137
|
||||
# 后端API: http://SERVER_IP:26039
|
||||
```
|
||||
|
||||
#### Windows PowerShell
|
||||
如果您使用 Windows + Docker Desktop,可以使用 PowerShell 执行以下命令:
|
||||
```PowerShell
|
||||
# 克隆 v3.1.0 版本
|
||||
git clone --depth 1 --branch v3.1.0 https://github.com/ageerle/ruoyi-ai.git
|
||||
cd ruoyi-ai
|
||||
|
||||
# 创建环境配置文件
|
||||
Copy-Item docs\docker\ruoyi-ai\.env.example docs\docker\ruoyi-ai\.env
|
||||
|
||||
# 固定镜像版本
|
||||
(Get-Content docs\docker\ruoyi-ai\.env) `
|
||||
-replace '^RUIYI_VERSION=.*', 'RUIYI_VERSION=v3.1.0' |
|
||||
Set-Content docs\docker\ruoyi-ai\.env
|
||||
|
||||
# 查看环境配置
|
||||
Get-Content docs\docker\ruoyi-ai\.env
|
||||
|
||||
# 从 GHCR 拉取预构建镜像并启动全部服务
|
||||
docker compose --env-file docs\docker\ruoyi-ai\.env `
|
||||
-f docs\docker\ruoyi-ai\docker-compose-all.yaml pull
|
||||
docker compose --env-file docs\docker\ruoyi-ai\.env `
|
||||
-f docs\docker\ruoyi-ai\docker-compose-all.yaml up -d
|
||||
|
||||
# 查看服务状态
|
||||
docker compose --env-file docs\docker\ruoyi-ai\.env `
|
||||
-f docs\docker\ruoyi-ai\docker-compose-all.yaml ps
|
||||
```
|
||||
|
||||
默认 Compose 还会发布 MySQL(`23306`)、Redis(`26379`)、Weaviate(`28080`)和
|
||||
MinIO(`29000`/`29090`)端口。生产环境请修改 MySQL 和 MinIO 默认密码,并通过防火墙或反向代理只开放应用端口。
|
||||
|
||||
升级到其他已发布版本时,修改 `docs/docker/ruoyi-ai/.env` 中的 `RUIYI_VERSION`,然后使用相同的
|
||||
`--env-file` 和 `-f` 参数执行 `docker compose pull`、`docker compose up -d`。除非确定要删除持久化数据卷,
|
||||
不要执行 `docker compose down -v`。
|
||||
|
||||
### 方式二:分步部署(源码编译)
|
||||
|
||||
如果您需要从源码构建后端服务,请按照以下步骤操作:
|
||||
|
||||
#### 第一步:部署后端服务
|
||||
|
||||
```bash
|
||||
# 进入后端项目目录
|
||||
cd ruoyi-ai
|
||||
|
||||
# 启动后端服务(源码编译构建)
|
||||
docker-compose up -d --build
|
||||
|
||||
# 等待后端服务启动完成
|
||||
docker-compose logs -f backend
|
||||
```
|
||||
|
||||
#### 第二步:部署管理端
|
||||
|
||||
```bash
|
||||
# 进入管理端项目目录
|
||||
cd ruoyi-admin
|
||||
|
||||
# 构建并启动管理端
|
||||
docker-compose up -d --build
|
||||
|
||||
# 访问管理端
|
||||
# 地址: http://localhost:5666
|
||||
```
|
||||
|
||||
#### 第三步:部署用户端(可选)
|
||||
|
||||
```bash
|
||||
# 进入用户端项目目录
|
||||
cd ruoyi-web
|
||||
|
||||
# 构建并启动用户端
|
||||
docker-compose up -d --build
|
||||
|
||||
# 访问用户端
|
||||
# 地址: http://localhost:5137
|
||||
```
|
||||
|
||||
### 服务端口说明
|
||||
|
||||
| 服务 | 一键启动端口 | 分步部署端口 | 说明 |
|
||||
|------|-------------|-------------|------|
|
||||
| 管理端 | 25666 | 5666 | 管理后台访问地址 |
|
||||
| 用户端 | 25137 | 5137 | 用户前端访问地址 |
|
||||
| 后端服务 | 26039 | 6039 | 后端 API 服务 |
|
||||
| MySQL | 23306 | 23306 | 数据库服务 |
|
||||
| Redis | 26379 | 6379 | 缓存服务 |
|
||||
| Weaviate | 28080 | 28080 | 向量数据库 |
|
||||
| MinIO API | 29000 | 9000 | 对象存储 API |
|
||||
| MinIO Console | 29090 | 9090 | 对象存储控制台 |
|
||||
|
||||
## 📚 使用文档
|
||||
|
||||
想要深入了解安装部署、功能配置和二次开发?
|
||||
|
||||
**👉 [完整使用文档](https://doc.ruoyiai.chat/)**
|
||||
|
||||
- [在 ruoyi-admin 中配置模型和 API Key](docs/model-configuration.md)
|
||||
- [本地开发接入 Dify 官方云服务](docs/dify-cloud.md)
|
||||
|
||||
## 🤝 参与贡献
|
||||
|
||||
我们热烈欢迎社区贡献!无论您是资深开发者还是初学者,都可以为项目贡献力量 💪
|
||||
|
||||
### 贡献方式
|
||||
|
||||
1. **Fork** 项目到您的账户
|
||||
2. **创建分支** (`git checkout -b feature/新功能名称`)
|
||||
3. **提交代码** (`git commit -m '添加某某功能'`)
|
||||
4. **推送分支** (`git push origin feature/新功能名称`)
|
||||
5. **发起 Pull Request**
|
||||
|
||||
> 💡 **小贴士**:建议将 PR 提交到 GitHub,我们会自动同步到其他代码托管平台
|
||||
|
||||
## 📄 开源协议
|
||||
|
||||
本项目采用 **MIT 开源协议**,详情请查看 [LICENSE](LICENSE) 文件。
|
||||
|
||||
## 🙏 特别鸣谢
|
||||
|
||||
感谢以下优秀的开源项目为本项目提供支持:
|
||||
- [Langchain4j](https://github.com/langchain4j/langchain4j) - 强大的 Java LLM 开发框架
|
||||
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - 成熟的企业级快速开发框架
|
||||
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - 现代化的 Vue 后台管理模板
|
||||
|
||||
|
||||
## 💎 赞助商
|
||||
|
||||
**感谢以下赞助商对本项目的支持:**
|
||||
|
||||
<a href="https://www.atlascloud.ai?ref=89F97E">
|
||||
<img src="docs/image/sponsor/atlascloud_banner.png" alt="Atlas Cloud" width="160" height="80">
|
||||
</a>
|
||||
|
||||
[访问Atlas Cloud官网](https://www.atlascloud.ai?ref=89F97E&utm_source=github&utm_campaign=ruoyi-drama) · [编程计划优惠](https://www.atlascloud.ai/console/coding-plan)
|
||||
全模态 AI 推理平台,为开发者提供统一的 AI API,支持视频生成、图像生成和大语言模型。一次接入,即可访问 **300+ 精选模型**。
|
||||
|
||||
<a href="https://www.volcengine.com/activity/codingplan?utm_campaign=hw&utm_content=hw&utm_medium=devrel_tool_web&utm_source=OWO&utm_term=ageerle-ruoyi-ai">
|
||||
<img src="docs/image/sponsor/huoshan.png" alt="火山引擎 CodingPlan" width="160" height="80">
|
||||
</a>
|
||||
|
||||
[注册即领2500万Tokens,立即前往](https://www.volcengine.com/activity/ai618?utm_campaign=hw&utm_content=hw&utm_medium=devrel_tool_web&utm_source=OWO&utm_term=ageerle-ruoyi-ai)
|
||||
享字节自研豆包模型+满血版开源 SOTA模型,覆盖文本、VLM、图像生成,全模态一站配齐:Seed-2.1、Seedream-5.0、GLM-5.2、DeepSeek等。不止编程、更能解决 Agent 复杂长程任务!
|
||||
|
||||
|
||||
## 💬 社区交流
|
||||
|
||||
<div align="center">
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="docs/image/wx.png" alt="微信二维码" width="200" height="200"><br>
|
||||
<strong>扫码添加作者微信</strong><br>
|
||||
<em>邀请进群学习</em>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/image/douyin.png" alt="抖音二维码" width="200" height="200"><br>
|
||||
<strong>抖音视频教程</strong><br>
|
||||
<em>打开抖音扫一扫,关注查看视频教程</em>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="docs/image/qq.png" alt="QQ群二维码" width="200" height="200"><br>
|
||||
<strong>QQ技术交流群</strong><br>
|
||||
<em>技术讨论</em>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
<div align="center">
|
||||
|
||||
**[⭐ 点个Star支持一下](https://github.com/ageerle/ruoyi-ai)** • **[ Fork 开始贡献](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 English](README.md)** • **[📖 查看完整文档](https://doc.ruoyiai.chat/)**
|
||||
|
||||
*用 ❤️ 打造,由 RuoYi AI 开源社区维护*
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Badge Links -->
|
||||
|
||||
[contributors-shield]: https://img.shields.io/github/contributors/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
|
||||
[contributors-url]: https://github.com/ageerle/ruoyi-ai/graphs/contributors
|
||||
|
||||
[forks-shield]: https://img.shields.io/github/forks/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
|
||||
[forks-url]: https://github.com/ageerle/ruoyi-ai/network/members
|
||||
|
||||
[stars-shield]: https://img.shields.io/github/stars/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
|
||||
[stars-url]: https://github.com/ageerle/ruoyi-ai/stargazers
|
||||
|
||||
[issues-shield]: https://img.shields.io/github/issues/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
|
||||
[issues-url]: https://github.com/ageerle/ruoyi-ai/issues
|
||||
|
||||
[license-shield]: https://img.shields.io/github/license/ageerle/ruoyi-ai.svg?style=flat-square
|
||||
|
||||
[license-url]: https://github.com/ageerle/ruoyi-ai/blob/main/LICENSE
|
||||
50
docs/dify-cloud.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Dify 官方云服务配置
|
||||
|
||||
本指南适用于本地运行 RuoYi-AI Java 后端、连接 Dify 官方云服务的场景。
|
||||
|
||||
## 准备 Dify 应用
|
||||
|
||||
在 Dify 中创建并发布聊天应用,先在 Dify 自己的调试页面确认可以正常回答。首次接入可以使用 Chatbot(聊天助手)。在该应用的 API 访问页面创建应用 API Key。
|
||||
|
||||
应用 Key 对应具体的 Dify 应用;知识库 Key 不能用于聊天。Dify 官方云服务的 API 基础地址为 `https://api.dify.ai/v1`。参见 [Dify API 入门](https://docs.dify.ai/en/api-reference/guides/get-started) 和 [聊天应用 API](https://docs.dify.ai/en/api-reference/guides/chat)。
|
||||
|
||||
## 在后台配置 Key
|
||||
|
||||
API Key 统一在 **ruoyi-admin → 对话管理 → 模型管理** 中直接填写并保存,无需配置后端环境变量。
|
||||
|
||||
## 模型管理填写示例
|
||||
|
||||
先确认厂商管理中的 `Dify` 已启用,再在模型管理中修改 Dify 模型:
|
||||
|
||||
| 字段 | 填写内容 |
|
||||
| --- | --- |
|
||||
| 模型分类 | 聊天(`chat`) |
|
||||
| 模型供应商 | Dify(编码 `dify`) |
|
||||
| 模型名称 | `dify-chat` |
|
||||
| 模型描述 | Dify 聊天助手 |
|
||||
| 请求地址 | `https://api.dify.ai/v1` |
|
||||
| 密钥 | 从 Dify 应用复制的真实 API Key,如 `app-...` |
|
||||
| 是否显示 | 是 |
|
||||
|
||||
直接填写真实应用 Key,不需要 `env:` 或 `Bearer ` 前缀。编辑时回显已保存的 Key,默认隐藏,点击眼睛可查看原文。输入内容原样保存,清空后保存会清除原 Key。保存后新的调用读取最新配置,无需重启后端。
|
||||
|
||||
请求地址填写到 `/v1`,不要追加 `/chat-messages`,也不要填写 Dify 应用的网页分享链接。模型名称是本系统的选择标识,可以取一个不重复的应用名称;实际调用哪个 Dify 应用由应用 Key 决定。
|
||||
|
||||
已有数据库直接在模型管理中按上述内容保存即可,无需重新导入全量 SQL。保存后在聊天页面选择该模型,发送一条简单消息验证。
|
||||
|
||||
## 适用范围
|
||||
|
||||
- 官方云服务使用 `https://api.dify.ai/v1`;自建 Dify 填写后端可以访问的服务 API 地址。
|
||||
- 不同模型可以填写不同的应用 Key,分别连接对应的 Dify 应用。
|
||||
- 当前适配器使用聊天消息接口,普通 Workflow 应用不能通过此模型配置调用。
|
||||
- 当前请求的自定义 `inputs` 为空。接入的聊天应用应能在不提供额外必填输入变量的情况下运行。
|
||||
- 当前聊天适配器没有实现 Dify 的 Human Input 表单交互和文件上传流程;首次验证请使用简单文本聊天应用。
|
||||
|
||||
## 常见情况
|
||||
|
||||
| 现象 | 检查方法 |
|
||||
| --- | --- |
|
||||
| 后台无法保存 | 检查厂商是否启用,以及模型分类、名称等必填项是否齐全。 |
|
||||
| 查看已保存的密钥 | 编辑时默认隐藏,点击密钥框右侧的眼睛查看原文;清空后保存会清除密钥。 |
|
||||
| Dify 返回鉴权失败 | 在模型管理中填写当前应用的有效 API Key,检查复制时是否带入空格或 `Bearer ` 前缀。 |
|
||||
| Dify 返回应用类型或输入参数错误 | 检查是否使用聊天应用,以及应用是否要求额外输入变量;先在 Dify 中验证应用可以回答。 |
|
||||
@@ -1,8 +1,6 @@
|
||||
version: '3.5'
|
||||
|
||||
services:
|
||||
etcd:
|
||||
container_name: milvus-etcd
|
||||
container_name: ruoyi-rag-milvus-etcd
|
||||
image: quay.io/coreos/etcd:v3.5.18
|
||||
environment:
|
||||
- ETCD_AUTO_COMPACTION_MODE=revision
|
||||
@@ -19,14 +17,11 @@ services:
|
||||
retries: 3
|
||||
|
||||
minio:
|
||||
container_name: milvus-minio
|
||||
container_name: ruoyi-rag-milvus-minio
|
||||
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
|
||||
environment:
|
||||
MINIO_ACCESS_KEY: minioadmin
|
||||
MINIO_SECRET_KEY: minioadmin
|
||||
ports:
|
||||
- "9001:9001"
|
||||
- "9000:9000"
|
||||
volumes:
|
||||
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data
|
||||
command: minio server /minio_data --console-address ":9001"
|
||||
@@ -37,7 +32,7 @@ services:
|
||||
retries: 3
|
||||
|
||||
standalone:
|
||||
container_name: milvus-standalone
|
||||
container_name: ruoyi-rag-milvus
|
||||
image: milvusdb/milvus:v2.5.7
|
||||
command: ["milvus", "run", "standalone"]
|
||||
security_opt:
|
||||
@@ -61,7 +56,7 @@ services:
|
||||
- "minio"
|
||||
|
||||
attu:
|
||||
container_name: attu
|
||||
container_name: ruoyi-rag-attu
|
||||
image: zilliz/attu:v2.5.7
|
||||
environment:
|
||||
MILVUS_URL: milvus-standalone:19530
|
||||
@@ -72,4 +67,4 @@ services:
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: milvus
|
||||
name: ruoyi-rag-milvus
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
---
|
||||
services:
|
||||
qdrant:
|
||||
image: qdrant/qdrant:latest
|
||||
container_name: ruoyi-rag-qdrant
|
||||
image: qdrant/qdrant:v1.17.0
|
||||
ports:
|
||||
- 6333:6333
|
||||
- 6334:6334
|
||||
volumes:
|
||||
- qdrant_data:/qdrant/storage
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "bash -c 'exec 3<>/dev/tcp/127.0.0.1/6333 && printf \"GET /healthz HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n\" >&3 && grep -q \"200 OK\" <&3'"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 10s
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
qdrant_data:
|
||||
...
|
||||
|
||||
6
docs/docker/ruoyi-ai/.env.example
Normal file
@@ -0,0 +1,6 @@
|
||||
# GitHub Container Registry namespace owner.
|
||||
# For the upstream project this is ageerle; change it when using a fork.
|
||||
IMAGE_OWNER=ageerle
|
||||
|
||||
# Use latest for convenience, or pin a release such as v3.1.0.
|
||||
RUIYI_VERSION=latest
|
||||
@@ -20,6 +20,22 @@ RUN mvn clean package -Pprod -DskipTests
|
||||
# 最终运行镜像
|
||||
FROM eclipse-temurin:17-jre-alpine
|
||||
|
||||
RUN set -eux; \
|
||||
apk add --no-cache ffmpeg; \
|
||||
for filter in scale pad fps setsar format tpad trim settb setpts xfade \
|
||||
aresample aformat apad atrim asetpts anullsrc concat acrossfade; do \
|
||||
ffmpeg -hide_banner -filters 2>/dev/null | grep -Eq "[[:space:]]${filter}[[:space:]]"; \
|
||||
done; \
|
||||
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q dissolve; \
|
||||
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q fadeblack; \
|
||||
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q slideleft; \
|
||||
ffmpeg -hide_banner -encoders 2>/dev/null | grep -Eq '[[:space:]]libx264[[:space:]]'; \
|
||||
ffmpeg -hide_banner -encoders 2>/dev/null | grep -Eq '[[:space:]]aac[[:space:]]'; \
|
||||
ffprobe -hide_banner -version >/dev/null
|
||||
|
||||
ENV FFMPEG_PATH=/usr/bin/ffmpeg \
|
||||
FFPROBE_PATH=/usr/bin/ffprobe
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
@@ -27,10 +43,10 @@ WORKDIR /app
|
||||
COPY --from=builder /build/ruoyi-admin/target/ruoyi-admin.jar ./ruoyi-admin.jar
|
||||
|
||||
# 创建日志目录
|
||||
RUN mkdir -p /ruoyi/server/logs
|
||||
RUN mkdir -p /ruoyi/server/logs /ruoyi/server/temp
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 6039
|
||||
|
||||
# 启动命令
|
||||
ENTRYPOINT ["java", "-jar", "ruoyi-admin.jar", "--spring.profiles.active=prod"]
|
||||
ENTRYPOINT ["java", "-Djava.io.tmpdir=/ruoyi/server/temp", "-jar", "ruoyi-admin.jar", "--spring.profiles.active=prod"]
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
# 基于官方MySQL 8.0镜像构建自定义镜像
|
||||
# 构建命令: docker build -t registry.cn-hangzhou.aliyuncs.com/ruoyi-ai/mysql:v3 -f Dockerfile.mysql .
|
||||
FROM mysql:8.0.33
|
||||
FROM mysql:8.0
|
||||
|
||||
# 设置时区
|
||||
ENV TZ=Asia/Shanghai
|
||||
|
||||
# 复制初始化脚本和SQL文件到镜像中
|
||||
COPY docs/script/docker/mysql/init/init-db.sh /docker-entrypoint-initdb.d/init-db.sh
|
||||
COPY docs/script/sql/ruoyi-ai-v3_mysql8.sql /docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql
|
||||
|
||||
# 设置脚本可执行权限
|
||||
RUN chmod +x /docker-entrypoint-initdb.d/init-db.sh
|
||||
# MySQL 官方入口会按文件名顺序执行初始化目录中的 SQL。
|
||||
# 主库统一为 ruoyi-ai,与初始化 SQL 和 Compose 中的数据库配置保持一致。
|
||||
COPY docs/script/sql/ruoyi-ai.sql /docker-entrypoint-initdb.d/01-ruoyi-ai.sql
|
||||
COPY docs/script/sql/snail_job_mysql.sql /docker-entrypoint-initdb.d/02-snail-job.sql
|
||||
|
||||
# MySQL启动参数
|
||||
CMD ["--default-authentication-plugin=mysql_native_password", \
|
||||
@@ -18,4 +16,4 @@ CMD ["--default-authentication-plugin=mysql_native_password", \
|
||||
"--collation-server=utf8mb4_general_ci", \
|
||||
"--explicit_defaults_for_timestamp=true", \
|
||||
"--lower_case_table_names=1", \
|
||||
"--skip-ssl"]
|
||||
"--skip-ssl"]
|
||||
|
||||
@@ -10,27 +10,28 @@
|
||||
# - RuoYi-Admin (管理端前端)
|
||||
# - RuoYi-Web (用户端前端)
|
||||
#
|
||||
# 镜像仓库地址: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai
|
||||
|
||||
version: '3.8'
|
||||
# 镜像仓库地址: ghcr.io/ageerle
|
||||
|
||||
services:
|
||||
# ==================== MySQL 数据库 ====================
|
||||
mysql:
|
||||
# 阿里云镜像地址(包含初始化SQL)
|
||||
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/mysql:v3
|
||||
# GHCR 镜像(包含初始化SQL)
|
||||
image: ghcr.io/${IMAGE_OWNER:-ageerle}/ruoyi-ai-mysql:${RUIYI_VERSION:-latest}
|
||||
container_name: ruoyi-ai-mysql
|
||||
restart: always
|
||||
ports:
|
||||
- "23306:3306"
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: ruoyi-ai-agent
|
||||
MYSQL_DATABASE: ruoyi-ai
|
||||
TZ: Asia/Shanghai
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"]
|
||||
# Force TCP: during first-time initialization MySQL exposes a temporary
|
||||
# socket-only server. A socket ping would mark the service healthy before
|
||||
# the real network listener (used by the backend) is ready.
|
||||
test: ["CMD", "mysqladmin", "ping", "--protocol=tcp", "-h", "127.0.0.1", "-u", "root", "-proot"]
|
||||
interval: 15s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
@@ -40,7 +41,7 @@ services:
|
||||
|
||||
# ==================== Redis 缓存 ====================
|
||||
redis:
|
||||
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/redis:6.2
|
||||
image: redis:6.2
|
||||
container_name: ruoyi-ai-redis
|
||||
restart: always
|
||||
ports:
|
||||
@@ -58,14 +59,14 @@ services:
|
||||
|
||||
# ==================== Weaviate 向量数据库 ====================
|
||||
weaviate:
|
||||
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/weaviate:1.30.0
|
||||
image: semitechnologies/weaviate:1.30.0
|
||||
container_name: ruoyi-ai-weaviate
|
||||
restart: always
|
||||
ports:
|
||||
- "28080:8080"
|
||||
environment:
|
||||
QUERY_DEFAULTS_LIMIT: 25
|
||||
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: true
|
||||
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: "true"
|
||||
PERSISTENCE_DATA_PATH: /var/lib/weaviate
|
||||
DEFAULT_VECTORIZER_MODULE: none
|
||||
ENABLE_MODULES: text2vec-cohere,text2vec-huggingface,text2vec-palm,text2vec-openai,generative-openai,generative-cohere,generative-palm,ref2vec-centroid,reranker-cohere,qna-openai
|
||||
@@ -77,7 +78,7 @@ services:
|
||||
|
||||
# ==================== MinIO 对象存储 ====================
|
||||
minio:
|
||||
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/minio:latest
|
||||
image: minio/minio:latest
|
||||
container_name: ruoyi-ai-minio
|
||||
restart: always
|
||||
ports:
|
||||
@@ -94,7 +95,7 @@ services:
|
||||
|
||||
# ==================== RuoYi-AI 后端服务 ====================
|
||||
backend:
|
||||
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-backend:latest
|
||||
image: ghcr.io/${IMAGE_OWNER:-ageerle}/ruoyi-ai-backend:${RUIYI_VERSION:-latest}
|
||||
container_name: ruoyi-ai-backend
|
||||
restart: always
|
||||
ports:
|
||||
@@ -104,13 +105,19 @@ services:
|
||||
# MySQL 配置
|
||||
SPRING_DATASOURCE_DYNAMIC_PRIMARY: master
|
||||
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_DRIVERCLASSNAME: com.mysql.cj.jdbc.Driver
|
||||
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://mysql:3306/ruoyi-ai-agent?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://mysql:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: root
|
||||
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: root
|
||||
# Redis 配置
|
||||
SPRING_DATA_REDIS_HOST: redis
|
||||
SPRING_DATA_REDIS_PORT: 6379
|
||||
SPRING_DATA_REDIS_DATABASE: 0
|
||||
# Allow large presentation files for knowledge-base ingestion.
|
||||
SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE: 600MB
|
||||
SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE: 620MB
|
||||
VECTOR_STORE_TYPE: weaviate
|
||||
VECTOR_STORE_WEAVIATE_PROTOCOL: http
|
||||
VECTOR_STORE_WEAVIATE_HOST: weaviate:8080
|
||||
# 日志配置
|
||||
LOGGING_LEVEL_ORG_RUOYI: info
|
||||
LOGGING_LEVEL_ORG_SPRINGFRAMEWORK: warn
|
||||
@@ -128,7 +135,7 @@ services:
|
||||
|
||||
# ==================== RuoYi-AI 管理端前端 ====================
|
||||
admin-frontend:
|
||||
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-admin:latest
|
||||
image: ghcr.io/${IMAGE_OWNER:-ageerle}/ruoyi-ai-admin:${RUIYI_VERSION:-latest}
|
||||
container_name: ruoyi-ai-admin
|
||||
restart: always
|
||||
ports:
|
||||
@@ -153,7 +160,7 @@ services:
|
||||
|
||||
# ==================== RuoYi-AI 用户端前端 ====================
|
||||
web-frontend:
|
||||
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-web:latest
|
||||
image: ghcr.io/${IMAGE_OWNER:-ageerle}/ruoyi-ai-web:${RUIYI_VERSION:-latest}
|
||||
container_name: ruoyi-ai-web
|
||||
restart: always
|
||||
ports:
|
||||
@@ -177,4 +184,4 @@ volumes:
|
||||
weaviate-data:
|
||||
minio-data:
|
||||
logs-data:
|
||||
upload-data:
|
||||
upload-data:
|
||||
|
||||
@@ -18,11 +18,11 @@ services:
|
||||
- "23306:3306"
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: ruoyi-ai-agent
|
||||
MYSQL_DATABASE: ruoyi-ai
|
||||
TZ: Asia/Shanghai
|
||||
volumes:
|
||||
- ./docs/script/docker/mysql/init/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh:ro
|
||||
- ./docs/script/sql/ruoyi-ai-v3_mysql8.sql:/docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql:ro
|
||||
- ../../script/sql/ruoyi-ai.sql:/docker-entrypoint-initdb.d/01-ruoyi-ai.sql:ro
|
||||
- ../../script/sql/snail_job_mysql.sql:/docker-entrypoint-initdb.d/02-snail-job.sql:ro
|
||||
- mysql-data:/var/lib/mysql
|
||||
command:
|
||||
--default-authentication-plugin=mysql_native_password
|
||||
@@ -32,7 +32,9 @@ services:
|
||||
--lower_case_table_names=1
|
||||
--skip-ssl
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"]
|
||||
# Do not let the socket-only initialization server satisfy the check.
|
||||
# The backend connects over TCP and must wait for that listener.
|
||||
test: ["CMD", "mysqladmin", "ping", "--protocol=tcp", "-h", "127.0.0.1", "-u", "root", "-proot"]
|
||||
interval: 15s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
@@ -108,7 +110,7 @@ services:
|
||||
# MySQL 配置
|
||||
SPRING_DATASOURCE_DYNAMIC_PRIMARY: master
|
||||
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_DRIVERCLASSNAME: com.mysql.cj.jdbc.Driver
|
||||
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://mysql:3306/ruoyi-ai-agent?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://mysql:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: root
|
||||
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: root
|
||||
# Redis 配置
|
||||
|
||||
@@ -5,12 +5,12 @@ services:
|
||||
- --host
|
||||
- 0.0.0.0
|
||||
- --port
|
||||
- '6038'
|
||||
- '8080'
|
||||
- --scheme
|
||||
- http
|
||||
image: semitechnologies/weaviate:1.19.7
|
||||
image: semitechnologies/weaviate:1.30.0
|
||||
ports:
|
||||
- 6038:6038
|
||||
- 28080:8080
|
||||
- 50051:50051
|
||||
volumes:
|
||||
- weaviate_data:/var/lib/weaviate
|
||||
|
||||
BIN
docs/image/01.png
Normal file
|
After Width: | Height: | Size: 298 KiB |
BIN
docs/image/02.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
docs/image/03.png
Normal file
|
After Width: | Height: | Size: 316 KiB |
BIN
docs/image/douyin.png
Normal file
|
After Width: | Height: | Size: 276 KiB |
|
Before Width: | Height: | Size: 156 KiB |
BIN
docs/image/sponsor/atlascloud_banner.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/image/sponsor/huoshan.png
Normal file
|
After Width: | Height: | Size: 105 KiB |
34
docs/model-configuration.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# 模型与 API Key 配置
|
||||
|
||||
模型的 API Key 统一在 **ruoyi-admin → 对话管理 → 模型管理** 中配置。
|
||||
|
||||
1. 在“厂商管理”中选择并启用对应厂商,填写服务 API 地址。
|
||||
2. 在“模型管理”中新建或编辑模型,选择厂商、分类,填写服务商提供的模型 ID。
|
||||
3. 在“密钥”框直接粘贴真实 API Key,保存模型。
|
||||
4. 在 `ruoyi-web` 中选择模型使用;向量和重排模型则在对应知识库配置中选择。
|
||||
|
||||
需要 API Key 的厂商适配器使用该模型保存的 Key,不要求固定的 Key 前缀或环境变量名称。自定义 OpenAI、Anthropic 服务的地址与 Key 也在模型管理中配置,无需设置配对环境变量。无需鉴权的本地模型可以不填 Key。
|
||||
|
||||
## 修改与批量更新
|
||||
|
||||
- 编辑模型时回显已保存的 Key,默认以密码形式隐藏,点击眼睛可查看原文;每次重新打开编辑框都会恢复隐藏。
|
||||
- 密钥按输入内容原样保存,不限制前缀或格式,也不去除首尾空格。清空后保存会清除原 Key。
|
||||
- 按厂商批量更新接口会将提交的 Key 保存到该厂商的模型中。
|
||||
- 保存后新的模型调用会读取最新配置,无需重启后端。正在进行的请求继续使用开始时的配置。
|
||||
- 模型列表、聊天用户端和导出文件不返回 Key。
|
||||
|
||||
## 已有模型
|
||||
|
||||
如果模型中原来保存的是 `env:ATLAS_API_KEY` 等文本,请在后台将其替换为真实 Key。密钥字段按填写内容直接使用,不解析 `env:` 引用。无需重新导入数据库。
|
||||
|
||||
## 示例
|
||||
|
||||
| 场景 | 厂商编码 | 密钥框填写内容 |
|
||||
| --- | --- | --- |
|
||||
| 千问聊天、向量或重排 | `qianwen` | 阿里云百炼的 API Key |
|
||||
| DeepSeek | `deepseek` | DeepSeek 控制台创建的 API Key |
|
||||
| Atlas 多媒体 | `atlas` | Atlas 控制台创建的 API Key |
|
||||
| Dify 聊天应用 | `dify` | 对应应用的 `app-...` Key |
|
||||
| 自定义 OpenAI / Anthropic | `custom_api` / `custom_anthropic` | 对应服务的 API Key |
|
||||
|
||||
填写的地址、模型 ID 和 Key 应对应同一个服务账号。模型是否可用、支持哪些能力以及额度限制,以服务商实际响应为准。
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
# 数据库初始化脚本
|
||||
# 使用 --force 参数确保即使出错也继续执行
|
||||
|
||||
echo "开始初始化数据库..."
|
||||
|
||||
# 使用 --force 参数忽略错误继续执行
|
||||
mysql -uroot -proot ruoyi-ai-agent --force < /docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql
|
||||
|
||||
echo "数据库初始化完成"
|
||||
86
docs/script/install-ffmpeg-windows.ps1
Normal file
@@ -0,0 +1,86 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$Force
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Find-Executable([string]$Name) {
|
||||
$command = Get-Command $Name -ErrorAction SilentlyContinue
|
||||
if ($command) {
|
||||
return $command.Source
|
||||
}
|
||||
|
||||
$roots = @(
|
||||
(Join-Path $env:LOCALAPPDATA 'Microsoft\WinGet\Packages'),
|
||||
(Join-Path $env:USERPROFILE 'scoop\apps\ffmpeg'),
|
||||
'C:\ProgramData\chocolatey\bin',
|
||||
'C:\ffmpeg'
|
||||
)
|
||||
foreach ($root in $roots) {
|
||||
if (-not (Test-Path $root)) { continue }
|
||||
$match = Get-ChildItem -Path $root -Filter "$Name.exe" -Recurse -ErrorAction SilentlyContinue |
|
||||
Select-Object -First 1 -ExpandProperty FullName
|
||||
if ($match) { return $match }
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
$ffmpeg = Find-Executable 'ffmpeg'
|
||||
$ffprobe = Find-Executable 'ffprobe'
|
||||
|
||||
if ($Force -or -not $ffmpeg -or -not $ffprobe) {
|
||||
$winget = Get-Command winget -ErrorAction SilentlyContinue
|
||||
if (-not $winget) {
|
||||
throw '未找到 winget。请先从 Microsoft Store 安装“应用安装程序”,或使用项目 Dockerfile 运行后端。'
|
||||
}
|
||||
|
||||
Write-Host '正在通过 winget 安装 FFmpeg...' -ForegroundColor Cyan
|
||||
& winget install --id Gyan.FFmpeg --exact --source winget `
|
||||
--accept-package-agreements --accept-source-agreements
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "winget 安装失败,退出码: $LASTEXITCODE"
|
||||
}
|
||||
|
||||
$ffmpeg = Find-Executable 'ffmpeg'
|
||||
$ffprobe = Find-Executable 'ffprobe'
|
||||
}
|
||||
|
||||
if (-not $ffmpeg -or -not $ffprobe) {
|
||||
throw 'FFmpeg 已安装但未能定位 ffmpeg.exe 或 ffprobe.exe。请重新打开 PowerShell 后再次运行脚本。'
|
||||
}
|
||||
|
||||
$binDirectory = Split-Path -Parent $ffmpeg
|
||||
[Environment]::SetEnvironmentVariable('FFMPEG_PATH', $ffmpeg, 'User')
|
||||
[Environment]::SetEnvironmentVariable('FFPROBE_PATH', $ffprobe, 'User')
|
||||
|
||||
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
|
||||
$pathParts = @($userPath -split ';' | Where-Object { $_ })
|
||||
if ($pathParts -notcontains $binDirectory) {
|
||||
$newPath = (@($pathParts) + $binDirectory) -join ';'
|
||||
[Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
|
||||
}
|
||||
|
||||
$env:FFMPEG_PATH = $ffmpeg
|
||||
$env:FFPROBE_PATH = $ffprobe
|
||||
if (($env:Path -split ';') -notcontains $binDirectory) {
|
||||
$env:Path = "$binDirectory;$env:Path"
|
||||
}
|
||||
|
||||
Write-Host "ffmpeg: $ffmpeg" -ForegroundColor Green
|
||||
Write-Host "ffprobe: $ffprobe" -ForegroundColor Green
|
||||
|
||||
& $ffmpeg -hide_banner -version | Select-Object -First 1
|
||||
& $ffprobe -hide_banner -version | Select-Object -First 1
|
||||
|
||||
$encoders = & $ffmpeg -hide_banner -encoders 2>&1 | Out-String
|
||||
if ($encoders -notmatch '\blibx264\b') {
|
||||
throw '当前 FFmpeg 不包含 libx264 编码器,无法满足短剧合成配置。'
|
||||
}
|
||||
if ($encoders -notmatch '\baac\b') {
|
||||
throw '当前 FFmpeg 不包含 AAC 编码器,无法满足短剧合成配置。'
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '安装与配置完成。请完全重启 IntelliJ IDEA 和 ruoyi-ai 后端服务。' -ForegroundColor Yellow
|
||||
Write-Host '重启后,Spring 将从 FFMPEG_PATH 和 FFPROBE_PATH 读取绝对路径。'
|
||||
45
docs/script/sql/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# SQL 脚本说明
|
||||
|
||||
## 全新安装
|
||||
|
||||
执行 [ruoyi-ai.sql](ruoyi-ai.sql) 即可创建 `ruoyi-ai` 主库和 `snail_job` 调度库,并导入初始化数据。
|
||||
|
||||
```sh
|
||||
mysql -uroot -p < ruoyi-ai.sql
|
||||
```
|
||||
|
||||
主 SQL 已合并下表中的全部更新,无需再次执行 `update` 目录中的脚本。[snail_job_mysql.sql](snail_job_mysql.sql) 仅用于单独初始化调度库,执行主 SQL 后无需再执行它。
|
||||
|
||||
全量初始化包含 `DROP TABLE` 和调度库的 `DROP DATABASE`,已有数据库升级应使用对应的增量脚本。
|
||||
|
||||
## 已有数据库升级
|
||||
|
||||
连接目标主库后,按文件名升序执行尚未应用的更新脚本;不要根据文件重命名重复执行已应用的更新。
|
||||
|
||||
- `2026-06-15-trace.sql` 原名为 `update-0615-trace.sql`,内容未变;其中菜单插入没有判重,不应重复执行。
|
||||
- `2026-08-30-mcp-market-tool-tenant.sql` 是一次性迁移,执行前检查脚本内的预检要求;部分执行失败后应按实际表结构续跑。
|
||||
- 其余脚本包含重复执行保护,具体适用条件见各脚本注释。
|
||||
|
||||
## 命名约定
|
||||
|
||||
更新脚本统一采用 `YYYY-MM-DD-功能描述.sql`,功能描述使用小写英文和连字符,例如 `2026-09-01-sys-url.sql`。保留已有更新日期,同日脚本按文件名升序执行,并确保依赖顺序一致。
|
||||
|
||||
全量入口保留 `ruoyi-ai.sql`,独立调度库入口保留 `snail_job_mysql.sql`。
|
||||
|
||||
## 主 SQL 合并清单
|
||||
|
||||
截至 2026-09-01,`update` 目录的 9 个脚本均已体现在主 SQL 的最终表结构和初始化数据中。结构变更直接并入建表语句,重复配置按最终值保留一份;旧库回填及兼容逻辑保留在增量脚本中。
|
||||
|
||||
| 更新脚本 | 主 SQL 中对应内容 |
|
||||
| --- | --- |
|
||||
| [2026-06-15-trace.sql](update/2026-06-15-trace.sql) | `trace_run`、`trace_node` 表、租户字段和索引,以及链路追踪菜单 |
|
||||
| [2026-07-20-knowledge-fragment-fid.sql](update/2026-07-20-knowledge-fragment-fid.sql) | 附件 `file_hash`、片段 `fid`、可空的 `doc_id` 和知识库租户索引 |
|
||||
| [2026-07-21-chat-provider-icon-length.sql](update/2026-07-21-chat-provider-icon-length.sql) | `chat_provider.provider_icon` 扩展为 `varchar(1000)` |
|
||||
| [2026-07-21-sys-config-node-template.sql](update/2026-07-21-sys-config-node-template.sql) | 7 个工作流节点消息模板配置 |
|
||||
| [2026-07-24-register-default-role-and-missing-menus.sql](update/2026-07-24-register-default-role-and-missing-menus.sql) | 默认注册角色、角色菜单关联、默认角色配置,以及会话、附件和片段权限 |
|
||||
| [2026-07-29-sys-config-node-template-all.sql](update/2026-07-29-sys-config-node-template-all.sql) | 工作流全部 8 个模板,前 7 个配置与上一批模板合并去重 |
|
||||
| [2026-07-29-zhipu-web-search-node.sql](update/2026-07-29-zhipu-web-search-node.sql) | 智谱网络搜索节点及其消息模板;内部组件名保留 `Google` 以兼容已有流程 |
|
||||
| [2026-08-30-mcp-market-tool-tenant.sql](update/2026-08-30-mcp-market-tool-tenant.sql) | `mcp_market_tool` 租户、审计字段和 `idx_tenant_market` 索引 |
|
||||
| [2026-09-01-sys-url.sql](update/2026-09-01-sys-url.sql) | `sys_url` 表、5 个菜单权限和 2 条公开链接 |
|
||||
|
||||
后续增加更新脚本时,同步修改主 SQL 中对应的表结构或初始化数据,并更新本清单及主 SQL 文件头。
|
||||
545
docs/script/sql/snail_job_mysql.sql
Normal file
128
docs/script/sql/update/2026-06-15-trace.sql
Normal file
@@ -0,0 +1,128 @@
|
||||
-- 链路追踪运行记录表
|
||||
CREATE TABLE IF NOT EXISTS `trace_run` (
|
||||
`id` bigint NOT NULL COMMENT '主键',
|
||||
`trace_id` varchar(64) NOT NULL COMMENT '链路ID',
|
||||
`trace_name` varchar(128) NOT NULL COMMENT '链路名称',
|
||||
`business_type` varchar(64) NOT NULL COMMENT '业务类型',
|
||||
`business_id` varchar(128) DEFAULT NULL COMMENT '业务ID',
|
||||
`user_id` bigint DEFAULT NULL COMMENT '用户ID',
|
||||
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
|
||||
`status` varchar(32) NOT NULL COMMENT '状态',
|
||||
`start_time` datetime NOT NULL COMMENT '开始时间',
|
||||
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
|
||||
`duration_ms` bigint DEFAULT NULL COMMENT '耗时毫秒',
|
||||
`error_message` varchar(1000) DEFAULT NULL COMMENT '错误摘要',
|
||||
`metadata` text DEFAULT NULL COMMENT '元数据JSON',
|
||||
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
|
||||
`create_by` bigint DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_trace_run_trace_id` (`trace_id`) USING BTREE,
|
||||
KEY `idx_trace_run_business` (`business_type`, `business_id`) USING BTREE,
|
||||
KEY `idx_trace_run_status_time` (`status`, `start_time`) USING BTREE,
|
||||
KEY `idx_trace_run_tenant_time` (`tenant_id`, `start_time`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='链路追踪运行记录表' ROW_FORMAT=DYNAMIC;
|
||||
|
||||
-- 链路追踪节点记录表
|
||||
CREATE TABLE IF NOT EXISTS `trace_node` (
|
||||
`id` bigint NOT NULL COMMENT '主键',
|
||||
`trace_id` varchar(64) NOT NULL COMMENT '链路ID',
|
||||
`node_id` varchar(64) NOT NULL COMMENT '节点ID',
|
||||
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
|
||||
`parent_node_id` varchar(64) DEFAULT NULL COMMENT '父节点ID',
|
||||
`node_name` varchar(128) NOT NULL COMMENT '节点名称',
|
||||
`node_type` varchar(64) NOT NULL COMMENT '节点类型',
|
||||
`depth` int DEFAULT 0 COMMENT '节点深度',
|
||||
`sort_order` int DEFAULT 0 COMMENT '排序',
|
||||
`class_name` varchar(255) DEFAULT NULL COMMENT '类名',
|
||||
`method_name` varchar(128) DEFAULT NULL COMMENT '方法名',
|
||||
`status` varchar(32) NOT NULL COMMENT '状态',
|
||||
`start_time` datetime NOT NULL COMMENT '开始时间',
|
||||
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
|
||||
`duration_ms` bigint DEFAULT NULL COMMENT '耗时毫秒',
|
||||
`error_message` varchar(1000) DEFAULT NULL COMMENT '错误摘要',
|
||||
`input_payload` text DEFAULT NULL COMMENT '输入JSON',
|
||||
`output_payload` text DEFAULT NULL COMMENT '输出JSON',
|
||||
`metadata` text DEFAULT NULL COMMENT '元数据JSON',
|
||||
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
|
||||
`create_by` bigint DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_trace_node_trace_id` (`trace_id`) USING BTREE,
|
||||
KEY `idx_trace_node_parent` (`trace_id`, `parent_node_id`) USING BTREE,
|
||||
KEY `idx_trace_node_time` (`trace_id`, `start_time`) USING BTREE,
|
||||
KEY `idx_trace_node_tenant_time` (`tenant_id`, `start_time`) USING BTREE,
|
||||
KEY `idx_trace_node_type_status` (`node_type`, `status`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='链路追踪节点记录表' ROW_FORMAT=DYNAMIC;
|
||||
|
||||
-- 兼容已存在的旧 trace 表:CREATE TABLE IF NOT EXISTS 不会给旧表补新字段
|
||||
SET @trace_run_add_tenant_sql = (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE `trace_run` ADD COLUMN `tenant_id` varchar(20) DEFAULT ''000000'' COMMENT ''租户编号'' AFTER `user_id`',
|
||||
'SELECT 1'
|
||||
)
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'trace_run'
|
||||
AND COLUMN_NAME = 'tenant_id'
|
||||
);
|
||||
PREPARE trace_run_add_tenant_stmt FROM @trace_run_add_tenant_sql;
|
||||
EXECUTE trace_run_add_tenant_stmt;
|
||||
DEALLOCATE PREPARE trace_run_add_tenant_stmt;
|
||||
|
||||
SET @trace_run_add_tenant_idx_sql = (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE `trace_run` ADD INDEX `idx_trace_run_tenant_time` (`tenant_id`, `start_time`) USING BTREE',
|
||||
'SELECT 1'
|
||||
)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'trace_run'
|
||||
AND INDEX_NAME = 'idx_trace_run_tenant_time'
|
||||
);
|
||||
PREPARE trace_run_add_tenant_idx_stmt FROM @trace_run_add_tenant_idx_sql;
|
||||
EXECUTE trace_run_add_tenant_idx_stmt;
|
||||
DEALLOCATE PREPARE trace_run_add_tenant_idx_stmt;
|
||||
|
||||
SET @trace_node_add_tenant_sql = (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE `trace_node` ADD COLUMN `tenant_id` varchar(20) DEFAULT ''000000'' COMMENT ''租户编号'' AFTER `node_id`',
|
||||
'SELECT 1'
|
||||
)
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'trace_node'
|
||||
AND COLUMN_NAME = 'tenant_id'
|
||||
);
|
||||
PREPARE trace_node_add_tenant_stmt FROM @trace_node_add_tenant_sql;
|
||||
EXECUTE trace_node_add_tenant_stmt;
|
||||
DEALLOCATE PREPARE trace_node_add_tenant_stmt;
|
||||
|
||||
SET @trace_node_add_tenant_idx_sql = (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE `trace_node` ADD INDEX `idx_trace_node_tenant_time` (`tenant_id`, `start_time`) USING BTREE',
|
||||
'SELECT 1'
|
||||
)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'trace_node'
|
||||
AND INDEX_NAME = 'idx_trace_node_tenant_time'
|
||||
);
|
||||
PREPARE trace_node_add_tenant_idx_stmt FROM @trace_node_add_tenant_idx_sql;
|
||||
EXECUTE trace_node_add_tenant_idx_stmt;
|
||||
DEALLOCATE PREPARE trace_node_add_tenant_idx_stmt;
|
||||
|
||||
-- 链路追踪监控菜单 & 按钮权限
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `remark`)
|
||||
SELECT (SELECT COALESCE(MAX(`menu_id`), 0) + 1 FROM (SELECT `menu_id` FROM `sys_menu`) t), '链路追踪', 2, 7, 'trace', 'monitor/trace/index', '', 1, 0, 'C', '0', '0', 'monitor:trace:list', 'tabler:route', 103, 1, NOW(), '链路追踪监控菜单';
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `remark`)
|
||||
SELECT (SELECT COALESCE(MAX(`menu_id`), 0) + 1 FROM (SELECT `menu_id` FROM `sys_menu`) t), '链路追踪查询', (SELECT `menu_id` FROM `sys_menu` WHERE `perms` = 'monitor:trace:list' AND `menu_type` = 'C' LIMIT 1), 1, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:trace:query', '#', 103, 1, NOW(), '';
|
||||
58
docs/script/sql/update/2026-07-20-knowledge-fragment-fid.sql
Normal file
@@ -0,0 +1,58 @@
|
||||
-- RAG metadata migration (MySQL 8). Safe to execute repeatedly.
|
||||
-- 注意:MySQL 8 不支持 ALTER TABLE ... ADD COLUMN IF NOT EXISTS(仅 MariaDB 支持),
|
||||
-- 因此列的增量添加统一用 information_schema 守卫 + PREPARE 实现幂等。
|
||||
SET @add_file_hash_col = IF(EXISTS(
|
||||
SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
|
||||
AND table_name = 'knowledge_attach' AND column_name = 'file_hash'),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE `knowledge_attach` ADD COLUMN `file_hash` varchar(64) NULL DEFAULT NULL COMMENT ''文件SHA-256摘要'' AFTER `doc_id`');
|
||||
PREPARE stmt FROM @add_file_hash_col; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
ALTER TABLE `knowledge_attach`
|
||||
MODIFY COLUMN `doc_id` varchar(32) NULL DEFAULT NULL COMMENT '文档ID';
|
||||
|
||||
SET @add_file_hash = IF(EXISTS(
|
||||
SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
|
||||
AND table_name = 'knowledge_attach' AND index_name = 'uk_knowledge_file_hash'),
|
||||
'SELECT 1', 'ALTER TABLE `knowledge_attach` ADD UNIQUE INDEX `uk_knowledge_file_hash` (`knowledge_id`, `file_hash`)');
|
||||
PREPARE stmt FROM @add_file_hash; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @add_fid_col = IF(EXISTS(
|
||||
SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE()
|
||||
AND table_name = 'knowledge_fragment' AND column_name = 'fid'),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE `knowledge_fragment` ADD COLUMN `fid` varchar(32) NULL DEFAULT NULL COMMENT ''向量库片段ID'' AFTER `id`');
|
||||
PREPARE stmt FROM @add_fid_col; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
ALTER TABLE `knowledge_fragment`
|
||||
MODIFY COLUMN `doc_id` varchar(32) NULL DEFAULT NULL COMMENT '文档ID';
|
||||
|
||||
UPDATE `knowledge_fragment`
|
||||
SET `fid` = LOWER(MD5(CONCAT('knowledge_fragment:', `id`)))
|
||||
WHERE `fid` IS NULL OR `fid` = '';
|
||||
|
||||
SET @drop_idx_fid = IF(EXISTS(
|
||||
SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
|
||||
AND table_name = 'knowledge_fragment' AND index_name = 'idx_fid'),
|
||||
'ALTER TABLE `knowledge_fragment` DROP INDEX `idx_fid`', 'SELECT 1');
|
||||
PREPARE stmt FROM @drop_idx_fid; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @add_uk_fid = IF(EXISTS(
|
||||
SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
|
||||
AND table_name = 'knowledge_fragment' AND index_name = 'uk_fid'),
|
||||
'SELECT 1', 'ALTER TABLE `knowledge_fragment` ADD UNIQUE INDEX `uk_fid` (`fid`)');
|
||||
PREPARE stmt FROM @add_uk_fid; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
ALTER TABLE `knowledge_fragment` MODIFY COLUMN `fid` varchar(32) NOT NULL COMMENT '向量库片段ID';
|
||||
|
||||
SET @add_tenant_user = IF(EXISTS(
|
||||
SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
|
||||
AND table_name = 'knowledge_info' AND index_name = 'idx_tenant_user'),
|
||||
'SELECT 1', 'ALTER TABLE `knowledge_info` ADD INDEX `idx_tenant_user` (`tenant_id`, `user_id`)');
|
||||
PREPARE stmt FROM @add_tenant_user; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @add_tenant_share = IF(EXISTS(
|
||||
SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
|
||||
AND table_name = 'knowledge_info' AND index_name = 'idx_tenant_share'),
|
||||
'SELECT 1', 'ALTER TABLE `knowledge_info` ADD INDEX `idx_tenant_share` (`tenant_id`, `share`)');
|
||||
PREPARE stmt FROM @add_tenant_share; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
@@ -0,0 +1,7 @@
|
||||
-- 加宽 chat_provider.provider_icon 字段 (对应 issue IHPUDA)
|
||||
-- 背景:文件系统使用 minio 私有桶时,厂商图标存的是带签名的临时访问 URL,
|
||||
-- 长度常超过 255,导致「Data too long for column 'provider_icon'」。
|
||||
-- MODIFY COLUMN 可重复执行。
|
||||
|
||||
ALTER TABLE `chat_provider`
|
||||
MODIFY COLUMN `provider_icon` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '厂商图标';
|
||||
@@ -0,0 +1,33 @@
|
||||
-- 补充工作流节点消息模板配置 (对应 issue IJX5VV)
|
||||
-- 背景:NodeMessageTemplateEnum 依赖以下 7 个 sys_config 键,缺失时
|
||||
-- WorkflowMessageUtil.getNodeMessageTemplate 会抛出「请先配置该节点的响应模板」。
|
||||
-- 这批配置在历史提交 20d531c0 中存在,SQL 脚本合并重命名时遗失,此处恢复。
|
||||
-- 幂等:按 config_key + tenant_id 判重,可重复执行。
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027192921483309058, '000000', 'HTTP请求节点响应模板', 'node.httpRequest.template', '✅ HTTP请求节点:结束响应 - ', 'Y', 103, 1, '2026-02-27 09:23:51', 1, '2026-02-27 09:31:41', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.httpRequest.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027193296990957569, '000000', '文生图节点响应模板', 'node.image.template', '🎨 文生图节点:结束响应 - 图片URL: ', 'Y', 103, 1, '2026-02-27 09:25:20', 1, '2026-02-27 09:31:52', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.image.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027193820393959425, '000000', '发送邮箱节点响应模板', 'node.mailsend.template', '📧 发送邮箱节点:结束响应 - ', 'Y', 103, 1, '2026-02-27 09:27:25', 1, '2026-02-27 09:32:05', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.mailsend.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027194134438277122, '000000', '结束节点响应模板', 'node.end.template', '🔚 流程已执行完毕,如果您有其他需求,请随时重新发起请求。', 'Y', 103, 1, '2026-02-27 09:28:40', 1, '2026-02-27 09:32:53', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.end.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027208880369647617, '000000', '条件分支节点响应模板', 'node.switch.template', '🔀 条件分支节点:触发 -> 跳转到节点 ', 'Y', 103, 1, '2026-02-27 10:27:15', 1, '2026-02-27 10:35:54', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.switch.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027213914603995137, '000000', '大模型回答节点响应模板', 'node.llmAnswer.template', '🤖 LLM 节点 生成回答:', 'Y', 103, 1, '2026-02-27 10:47:16', 1, '2026-02-27 10:52:40', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.llmAnswer.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027217577397391361, '000000', '工作流异常响应模板', 'node.exception.template', '🛑 工作流发生异常:', 'N', 103, 1, '2026-02-27 11:01:49', 1, '2026-02-27 11:02:01', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.exception.template' AND `tenant_id` = '000000');
|
||||
@@ -0,0 +1,119 @@
|
||||
-- 注册链路修复:补齐缺失的菜单权限标识 + 新建注册默认角色
|
||||
-- 关联问题:
|
||||
-- #3 注册用户无默认角色 -> 无权限访问 AI 对话界面
|
||||
-- #4 sys_menu 缺 system:session:* / system:attach:* / system:fragment:*,
|
||||
-- 且 知识管理 父菜单 perms 为 knowledge:info:list,与控制器
|
||||
-- KnowledgeInfoController 用的 system:info:list 对不上,:list 无法授权。
|
||||
-- 本脚本幂等,可重复执行(INSERT IGNORE + UPDATE 天然幂等)。
|
||||
-- 新增 menu_id / role_id / config_id 统一使用 2099010100000000xxx 段,
|
||||
-- 与现有 snowflake id(2xxxxxxxxxxxxxxxxx)不冲突。
|
||||
|
||||
-- ============================================================
|
||||
-- 1. 修正 知识管理 父菜单权限标识:knowledge:info:list -> system:info:list
|
||||
-- ============================================================
|
||||
UPDATE `sys_menu`
|
||||
SET `perms` = 'system:info:list'
|
||||
WHERE `menu_id` = 2006681261898813441 AND `perms` = 'knowledge:info:list';
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 新增 会话管理 菜单组(system:session:*)
|
||||
-- 父菜单=对话管理(2000209300188356609)。
|
||||
-- 管理端暂无 chat/session 页面,故 C 菜单设为隐藏(visible=1),
|
||||
-- 权限标识仍可在角色管理中授权给用户端使用。
|
||||
-- ============================================================
|
||||
INSERT IGNORE INTO `sys_menu` VALUES
|
||||
(2099010100000000001, '会话管理', 2000209300188356609, 6, 'session', NULL, NULL, 1, 0, 'C', '1', '0', 'system:session:list', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '会话管理菜单'),
|
||||
(2099010100000000002, '会话管理查询', 2099010100000000001, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:session:query', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000003, '会话管理新增', 2099010100000000001, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:session:add', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000004, '会话管理修改', 2099010100000000001, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:session:edit', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000005, '会话管理删除', 2099010100000000001, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:session:remove', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000006, '会话管理导出', 2099010100000000001, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:session:export', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '');
|
||||
|
||||
-- ============================================================
|
||||
-- 3. 新增 知识附件 菜单组(system:attach:*)
|
||||
-- 父菜单=对话管理(2000209300188356609),组件对应管理端 knowledge/attach/index。
|
||||
-- ============================================================
|
||||
INSERT IGNORE INTO `sys_menu` VALUES
|
||||
(2099010100000000010, '知识附件', 2000209300188356609, 7, 'attach', 'knowledge/attach/index', NULL, 1, 0, 'C', '0', '0', 'system:attach:list', 'ant-design:paper-clip-outlined', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '知识附件菜单'),
|
||||
(2099010100000000011, '知识附件查询', 2099010100000000010, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:attach:query', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000012, '知识附件新增', 2099010100000000010, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:attach:add', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000013, '知识附件修改', 2099010100000000010, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:attach:edit', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000014, '知识附件删除', 2099010100000000010, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:attach:remove', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000015, '知识附件导出', 2099010100000000010, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:attach:export', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '');
|
||||
|
||||
-- ============================================================
|
||||
-- 4. 新增 知识片段 菜单组(system:fragment:*)
|
||||
-- 父菜单=对话管理(2000209300188356609),组件对应管理端 knowledge/fragment/index。
|
||||
-- ============================================================
|
||||
INSERT IGNORE INTO `sys_menu` VALUES
|
||||
(2099010100000000020, '知识片段', 2000209300188356609, 8, 'fragment', 'knowledge/fragment/index', NULL, 1, 0, 'C', '0', '0', 'system:fragment:list', 'ant-design:file-text-outlined', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '知识片段菜单'),
|
||||
(2099010100000000021, '知识片段查询', 2099010100000000020, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:fragment:query', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000022, '知识片段新增', 2099010100000000020, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:fragment:add', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000023, '知识片段修改', 2099010100000000020, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:fragment:edit', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000024, '知识片段删除', 2099010100000000020, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:fragment:remove', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, ''),
|
||||
(2099010100000000025, '知识片段导出', 2099010100000000020, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:fragment:export', '#', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '');
|
||||
|
||||
-- ============================================================
|
||||
-- 5. 新建 普通用户 角色(租户 000000,data_scope=5 仅本人)
|
||||
-- ============================================================
|
||||
INSERT IGNORE INTO `sys_role` VALUES
|
||||
(2099010100000000030, '000000', '普通用户', 'user', 2, '5', 1, 1, '0', '0', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '注册用户默认角色');
|
||||
|
||||
-- ============================================================
|
||||
-- 6. 角色-菜单关联:普通用户 拥有用户端 AI 对话所需权限
|
||||
-- 会话管理(001-006) + 聊天消息(2000210914680823809 及 810-814)
|
||||
-- + 知识管理(2006681261898813441 及 442-446)
|
||||
-- + 知识附件(010-015) + 知识片段(020-025)
|
||||
-- ============================================================
|
||||
INSERT IGNORE INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES
|
||||
-- 会话管理
|
||||
(2099010100000000030, 2099010100000000001),
|
||||
(2099010100000000030, 2099010100000000002),
|
||||
(2099010100000000030, 2099010100000000003),
|
||||
(2099010100000000030, 2099010100000000004),
|
||||
(2099010100000000030, 2099010100000000005),
|
||||
(2099010100000000030, 2099010100000000006),
|
||||
-- 聊天消息
|
||||
(2099010100000000030, 2000210914680823809),
|
||||
(2099010100000000030, 2000210914680823810),
|
||||
(2099010100000000030, 2000210914680823811),
|
||||
(2099010100000000030, 2000210914680823812),
|
||||
(2099010100000000030, 2000210914680823813),
|
||||
(2099010100000000030, 2000210914680823814),
|
||||
-- 知识管理
|
||||
(2099010100000000030, 2006681261898813441),
|
||||
(2099010100000000030, 2006681261898813442),
|
||||
(2099010100000000030, 2006681261898813443),
|
||||
(2099010100000000030, 2006681261898813444),
|
||||
(2099010100000000030, 2006681261898813445),
|
||||
(2099010100000000030, 2006681261898813446),
|
||||
-- 知识附件
|
||||
(2099010100000000030, 2099010100000000010),
|
||||
(2099010100000000030, 2099010100000000011),
|
||||
(2099010100000000030, 2099010100000000012),
|
||||
(2099010100000000030, 2099010100000000013),
|
||||
(2099010100000000030, 2099010100000000014),
|
||||
(2099010100000000030, 2099010100000000015),
|
||||
-- 知识片段
|
||||
(2099010100000000030, 2099010100000000020),
|
||||
(2099010100000000030, 2099010100000000021),
|
||||
(2099010100000000030, 2099010100000000022),
|
||||
(2099010100000000030, 2099010100000000023),
|
||||
(2099010100000000030, 2099010100000000024),
|
||||
(2099010100000000030, 2099010100000000025);
|
||||
|
||||
-- ============================================================
|
||||
-- 7. 注册默认角色配置项 sys.register.defaultRoleId
|
||||
-- 后端 SysRegisterService 注册成功后读取此配置为新用户绑定角色;
|
||||
-- 值为空字符串时不绑定(保留旧行为)。
|
||||
-- ============================================================
|
||||
INSERT IGNORE INTO `sys_config` VALUES
|
||||
(2099010100000000031, '000000', '注册-默认角色ID', 'sys.register.defaultRoleId', '2099010100000000030', 'Y', 103, 1, '2026-07-24 00:00:00', NULL, NULL, '新注册用户绑定的默认角色ID,留空则不绑定');
|
||||
|
||||
-- ============================================================
|
||||
-- 8. 前置条件(运营项,默认不执行):开启用户注册
|
||||
-- sys.account.registerUser 默认 false,后端 AuthController.register
|
||||
-- 会据此返回「当前系统没有开启注册功能」。若要开放注册,取消注释执行。
|
||||
-- ============================================================
|
||||
-- UPDATE `sys_config` SET `config_value` = 'true'
|
||||
-- WHERE `config_key` = 'sys.account.registerUser' AND `tenant_id` = '000000';
|
||||
@@ -0,0 +1,39 @@
|
||||
-- 一次性补全工作流节点消息模板配置 (NodeMessageTemplateEnum 全部 8 个键)
|
||||
-- 背景:节点执行时 WorkflowMessageUtil.getNodeMessageTemplate 从 sys_config 读取展示模板,
|
||||
-- 历史库中这批配置缺失, 导致运行工作流抛「请先配置该节点的响应模板」。
|
||||
-- 其中前 7 个见 2026-07-21-sys-config-node-template.sql,
|
||||
-- Google Search 为此前从未入库的节点模板。
|
||||
-- 说明:代码已增加内置默认模板兜底, 本脚本为可选, 执行后模板可在 系统管理-配置管理 中自定义。
|
||||
-- 幂等:按 config_key + tenant_id 判重, 可重复执行。
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027192921483309058, '000000', 'HTTP请求节点响应模板', 'node.httpRequest.template', '✅ HTTP请求节点:结束响应 - ', 'Y', 103, 1, '2026-02-27 09:23:51', 1, '2026-02-27 09:31:41', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.httpRequest.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027193296990957569, '000000', '文生图节点响应模板', 'node.image.template', '🎨 文生图节点:结束响应 - 图片URL: ', 'Y', 103, 1, '2026-02-27 09:25:20', 1, '2026-02-27 09:31:52', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.image.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027193820393959425, '000000', '发送邮箱节点响应模板', 'node.mailsend.template', '📧 发送邮箱节点:结束响应 - ', 'Y', 103, 1, '2026-02-27 09:27:25', 1, '2026-02-27 09:32:05', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.mailsend.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027194134438277122, '000000', '结束节点响应模板', 'node.end.template', '🔚 流程已执行完毕,如果您有其他需求,请随时重新发起请求。', 'Y', 103, 1, '2026-02-27 09:28:40', 1, '2026-02-27 09:32:53', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.end.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027208880369647617, '000000', '条件分支节点响应模板', 'node.switch.template', '🔀 条件分支节点:触发 -> 跳转到节点 ', 'Y', 103, 1, '2026-02-27 10:27:15', 1, '2026-02-27 10:35:54', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.switch.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027213914603995137, '000000', '大模型回答节点响应模板', 'node.llmAnswer.template', '🤖 LLM 节点 生成回答:', 'Y', 103, 1, '2026-02-27 10:47:16', 1, '2026-02-27 10:52:40', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.llmAnswer.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2027217577397391361, '000000', '工作流异常响应模板', 'node.exception.template', '🛑 工作流发生异常:', 'N', 103, 1, '2026-02-27 11:01:49', 1, '2026-02-27 11:02:01', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.exception.template' AND `tenant_id` = '000000');
|
||||
|
||||
INSERT INTO `sys_config` (`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
SELECT 2084157200000000003, '000000', '网络搜索节点响应模板', 'node.googleSearch.template', '🔍 网络搜索节点处理完成:', 'Y', 103, 1, '2026-07-29 19:40:00', 1, '2026-07-29 19:40:00', NULL
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `config_key` = 'node.googleSearch.template' AND `tenant_id` = '000000');
|
||||
66
docs/script/sql/update/2026-07-29-zhipu-web-search-node.sql
Normal file
@@ -0,0 +1,66 @@
|
||||
-- 智谱 Web Search 工作流扩展节点
|
||||
-- 内部组件名继续使用 Google,以兼容现有前端组件和已保存流程。
|
||||
|
||||
UPDATE `t_workflow_component`
|
||||
SET `title` = '网络搜索',
|
||||
`remark` = '调用智谱 Web Search 检索互联网信息',
|
||||
`display_order` = 40,
|
||||
`is_enable` = 1,
|
||||
`is_deleted` = 0,
|
||||
`update_time` = NOW()
|
||||
WHERE `name` = 'Google'
|
||||
AND `tenant_id` = '000000';
|
||||
|
||||
INSERT INTO `t_workflow_component`
|
||||
(`uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`,
|
||||
`create_time`, `update_time`, `is_deleted`, `tenant_id`)
|
||||
SELECT
|
||||
'a7f8c2d44e5b4c83a9d6f103c2b47e18',
|
||||
'Google',
|
||||
'网络搜索',
|
||||
'调用智谱 Web Search 检索互联网信息',
|
||||
40,
|
||||
1,
|
||||
NOW(),
|
||||
NOW(),
|
||||
0,
|
||||
'000000'
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM `t_workflow_component`
|
||||
WHERE `name` = 'Google'
|
||||
AND `tenant_id` = '000000'
|
||||
);
|
||||
|
||||
UPDATE `sys_config`
|
||||
SET `config_name` = '网络搜索节点响应模板',
|
||||
`config_value` = '🔍 网络搜索节点处理完成:',
|
||||
`update_time` = NOW()
|
||||
WHERE `config_key` = 'node.googleSearch.template'
|
||||
AND `tenant_id` = '000000';
|
||||
|
||||
INSERT INTO `sys_config`
|
||||
(`config_id`, `tenant_id`, `config_name`, `config_key`, `config_value`,
|
||||
`config_type`, `create_dept`, `create_by`, `create_time`, `update_by`,
|
||||
`update_time`, `remark`)
|
||||
SELECT
|
||||
2084157200000000003,
|
||||
'000000',
|
||||
'网络搜索节点响应模板',
|
||||
'node.googleSearch.template',
|
||||
'🔍 网络搜索节点处理完成:',
|
||||
'Y',
|
||||
103,
|
||||
1,
|
||||
NOW(),
|
||||
1,
|
||||
NOW(),
|
||||
'智谱 Web Search 工作流扩展节点'
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM `sys_config`
|
||||
WHERE `config_key` = 'node.googleSearch.template'
|
||||
AND `tenant_id` = '000000'
|
||||
);
|
||||
41
docs/script/sql/update/2026-08-30-mcp-market-tool-tenant.sql
Normal file
@@ -0,0 +1,41 @@
|
||||
-- ----------------------------
|
||||
-- MCP 市场工具租户与审计列补齐
|
||||
-- 2026-08-30
|
||||
-- ----------------------------
|
||||
-- 本脚本只迁移结构和归属信息,不删除无法关联到市场的孤儿记录。
|
||||
-- 孤儿记录的 tenant_id 保持 NULL,因此租户归属查询会 fail closed。
|
||||
-- 这是一次性迁移脚本:两个 ALTER TABLE 都会隐式提交。若执行中断或仅完成部分 DDL,
|
||||
-- 必须先核对实际表结构后逐句续跑,禁止直接重跑整个文件。
|
||||
-- 本机受控执行入口为 scripts/apply-live-migrations.ps1;先使用 -PreflightOnly,
|
||||
-- 再以同一个显式 DPAPI 备份路径执行正式迁移。生产环境仍需按自身发布流程审计后执行。
|
||||
|
||||
-- 首次 DDL 前预检;上线前应确认结果为 0,避免新增列后留下无法可信回填的归属。
|
||||
SELECT COUNT(*) AS `preflight_invalid_market_owner_count`
|
||||
FROM `mcp_market_tool` AS `tool`
|
||||
LEFT JOIN `mcp_market_info` AS `market` ON `market`.`id` = `tool`.`market_id`
|
||||
WHERE `market`.`id` IS NULL
|
||||
OR `market`.`tenant_id` IS NULL;
|
||||
|
||||
ALTER TABLE `mcp_market_tool`
|
||||
ADD COLUMN `tenant_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '租户编号' AFTER `local_tool_id`,
|
||||
ADD COLUMN `create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门' AFTER `tenant_id`,
|
||||
ADD COLUMN `create_by` bigint NULL DEFAULT NULL COMMENT '创建者' AFTER `create_dept`,
|
||||
ADD COLUMN `update_by` bigint NULL DEFAULT NULL COMMENT '更新者' AFTER `create_time`,
|
||||
ADD COLUMN `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间' AFTER `update_by`;
|
||||
|
||||
UPDATE `mcp_market_tool` AS `tool`
|
||||
INNER JOIN `mcp_market_info` AS `market` ON `market`.`id` = `tool`.`market_id`
|
||||
SET `tool`.`tenant_id` = `market`.`tenant_id`;
|
||||
|
||||
ALTER TABLE `mcp_market_tool`
|
||||
MODIFY COLUMN `tenant_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '000000' COMMENT '租户编号',
|
||||
ADD INDEX `idx_tenant_market` (`tenant_id`, `market_id`);
|
||||
|
||||
-- 上线前应确认结果为 0;统计覆盖父市场缺失、子表租户为空、父子租户为空或不一致。
|
||||
SELECT COUNT(*) AS `invalid_market_tool_tenant_count`
|
||||
FROM `mcp_market_tool` AS `tool`
|
||||
LEFT JOIN `mcp_market_info` AS `market` ON `market`.`id` = `tool`.`market_id`
|
||||
WHERE `market`.`id` IS NULL
|
||||
OR `tool`.`tenant_id` IS NULL
|
||||
OR `market`.`tenant_id` IS NULL
|
||||
OR NOT (BINARY `tool`.`tenant_id` <=> BINARY `market`.`tenant_id`);
|
||||
76
docs/script/sql/update/2026-09-01-sys-url.sql
Normal file
@@ -0,0 +1,76 @@
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- URL 管理模块增量脚本(可重复执行)
|
||||
-- 1) 创建 sys_url 表
|
||||
-- 2) 新增「系统管理 -> URL管理」菜单及 4 个按钮权限(按 perms 去重,幂等)
|
||||
-- 3) 插入两条初始公开网站链接(按 name + url 去重,幂等)
|
||||
-- 适用于已存在数据库的升级;全新安装请直接使用 ruoyi-ai.sql
|
||||
-- ----------------------------------------------------------------------------
|
||||
|
||||
-- ----------------------------
|
||||
-- 1. URL 管理表 sys_url
|
||||
-- ----------------------------
|
||||
CREATE TABLE IF NOT EXISTS `sys_url` (
|
||||
`url_id` bigint NOT NULL AUTO_INCREMENT COMMENT '链接ID',
|
||||
`tenant_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '000000' COMMENT '租户编号',
|
||||
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '链接名称',
|
||||
`url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'HTTP(S) 地址',
|
||||
`description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '链接说明',
|
||||
`sort_order` int NULL DEFAULT 0 COMMENT '显示顺序',
|
||||
`status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
|
||||
`create_by` bigint NULL DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint NULL DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`url_id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'URL 管理表' ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- 2. 菜单 & 按钮权限(幂等:perms 不存在时才插入)
|
||||
-- 父菜单 1 = 系统管理目录
|
||||
-- ----------------------------
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `remark`)
|
||||
SELECT (SELECT COALESCE(MAX(`menu_id`), 0) + 1 FROM (SELECT `menu_id` FROM `sys_menu`) t), 'URL管理', 1, 12, 'url', 'system/url/index', '', 1, 0, 'C', '0', '0', 'system:url:list', 'mdi:link-variant', 103, 1, NOW(), 'URL管理菜单'
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'system:url:list' AND `menu_type` = 'C');
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `remark`)
|
||||
SELECT (SELECT COALESCE(MAX(`menu_id`), 0) + 1 FROM (SELECT `menu_id` FROM `sys_menu`) t), 'URL查询', (SELECT `menu_id` FROM `sys_menu` WHERE `perms` = 'system:url:list' AND `menu_type` = 'C' LIMIT 1), 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:url:query', '#', 103, 1, NOW(), ''
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'system:url:query' AND `menu_type` = 'F');
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `remark`)
|
||||
SELECT (SELECT COALESCE(MAX(`menu_id`), 0) + 1 FROM (SELECT `menu_id` FROM `sys_menu`) t), 'URL新增', (SELECT `menu_id` FROM `sys_menu` WHERE `perms` = 'system:url:list' AND `menu_type` = 'C' LIMIT 1), 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:url:add', '#', 103, 1, NOW(), ''
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'system:url:add' AND `menu_type` = 'F');
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `remark`)
|
||||
SELECT (SELECT COALESCE(MAX(`menu_id`), 0) + 1 FROM (SELECT `menu_id` FROM `sys_menu`) t), 'URL修改', (SELECT `menu_id` FROM `sys_menu` WHERE `perms` = 'system:url:list' AND `menu_type` = 'C' LIMIT 1), 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:url:edit', '#', 103, 1, NOW(), ''
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'system:url:edit' AND `menu_type` = 'F');
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `remark`)
|
||||
SELECT (SELECT COALESCE(MAX(`menu_id`), 0) + 1 FROM (SELECT `menu_id` FROM `sys_menu`) t), 'URL删除', (SELECT `menu_id` FROM `sys_menu` WHERE `perms` = 'system:url:list' AND `menu_type` = 'C' LIMIT 1), 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:url:remove', '#', 103, 1, NOW(), ''
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'system:url:remove' AND `menu_type` = 'F');
|
||||
|
||||
-- ----------------------------
|
||||
-- 3. 初始公开网站链接(幂等:name + url 均不存在时才插入)
|
||||
-- ----------------------------
|
||||
INSERT INTO `sys_url`
|
||||
(`tenant_id`, `name`, `url`, `description`, `sort_order`, `status`, `create_dept`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '000000', '若依官网', 'https://ruoyi.vip', 'RuoYi 官方网站,提供文档、源码与社区支持', 1, '0', 103, 1, NOW(), '初始公开链接'
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_url` WHERE `name` = '若依官网' AND `url` = 'https://ruoyi.vip');
|
||||
|
||||
INSERT INTO `sys_url`
|
||||
(`tenant_id`, `name`, `url`, `description`, `sort_order`, `status`, `create_dept`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '000000', 'RuoYi-AI 开源仓库', 'https://github.com/ageerle/ruoyi-ai', 'RuoYi-AI 项目 GitHub 仓库', 2, '0', 103, 1, NOW(), '初始公开链接'
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_url` WHERE `name` = 'RuoYi-AI 开源仓库' AND `url` = 'https://github.com/ageerle/ruoyi-ai');
|
||||
@@ -0,0 +1,24 @@
|
||||
-- 知识库检索工作流节点注册
|
||||
-- 为新安装和已有环境提供幂等的节点注册
|
||||
|
||||
INSERT INTO `t_workflow_component`
|
||||
(`uuid`, `name`, `title`, `remark`, `display_order`, `is_enable`,
|
||||
`create_time`, `update_time`, `is_deleted`, `tenant_id`)
|
||||
SELECT
|
||||
'b8e3c1d55f6a4d92b0e7f214d3c58a29',
|
||||
'KnowledgeRetrieval',
|
||||
'知识库检索',
|
||||
'从知识库中检索相关内容,支持向量检索和混合检索',
|
||||
30,
|
||||
1,
|
||||
NOW(),
|
||||
NOW(),
|
||||
0,
|
||||
'000000'
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM `t_workflow_component`
|
||||
WHERE `name` = 'KnowledgeRetrieval'
|
||||
AND `tenant_id` = '000000'
|
||||
);
|
||||
47
docs/tenant-management.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# 新增租户接口
|
||||
|
||||
开启 `tenant.enable: true` 后,超级管理员可通过 `POST /system/tenant` 创建租户。请求需要登录凭证和 `system:tenant:add` 权限;使用反向代理时,请按部署配置添加接口前缀。
|
||||
|
||||
## 请求参数
|
||||
|
||||
请求使用 `Content-Type: application/json`。
|
||||
|
||||
| 参数 | 说明 |
|
||||
| --- | --- |
|
||||
| `companyName` | 企业名称,必填且不能与已有租户重复。 |
|
||||
| `contactUserName` | 联系人,必填。 |
|
||||
| `contactPhone` | 联系电话,必填。 |
|
||||
| `username` | 租户初始管理员用户名,必填。 |
|
||||
| `password` | 租户初始管理员密码,必填。 |
|
||||
| `packageId` | 已存在的租户套餐 ID,必填。建议使用字符串传输,避免浏览器对大整数的精度损失。 |
|
||||
| `expireTime` | 过期时间,使用 `yyyy-MM-dd HH:mm:ss`,例如 `2027-09-11 00:00:00`;不传或传 `null` 表示不限制有效期。未带时区的时间按后端运行时区解释。 |
|
||||
| `accountCount` | 可创建的用户数量,`-1` 表示不限制。 |
|
||||
|
||||
## 请求示例
|
||||
|
||||
请将套餐 ID 替换为当前系统中的有效套餐,并设置实际使用的管理员账号和密码。
|
||||
|
||||
```json
|
||||
{
|
||||
"companyName": "示例企业",
|
||||
"contactUserName": "联系人",
|
||||
"contactPhone": "13800000000",
|
||||
"username": "tenant_admin",
|
||||
"password": "ChangeMe_123456!",
|
||||
"packageId": "2018611998196109314",
|
||||
"expireTime": "2027-09-11 00:00:00",
|
||||
"accountCount": -1
|
||||
}
|
||||
```
|
||||
|
||||
## 日期配置
|
||||
|
||||
后端默认日期格式配置位于 `ruoyi-admin/src/main/resources/application.yml`:
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
jackson:
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
```
|
||||
|
||||
扩展应用的 `ObjectMapper` 时,使用 Spring 注入的 `Jackson2ObjectMapperBuilder`,以保留全局日期格式、自定义 Jackson 模块和构建器配置。
|
||||
35
docs/url-management.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# URL 管理
|
||||
|
||||
URL 管理用于维护 Copilot 新建编程任务页的常用链接。管理端入口为“系统管理 → URL管理”(`/system/url`),支持新增、编辑、批量删除、名称和状态筛选及分页。
|
||||
|
||||
## 安装与权限
|
||||
|
||||
已有数据库执行 [增量脚本](script/sql/update/2026-09-01-sys-url.sql),可重复执行。新安装使用包含 URL 表、菜单及初始链接的全量 `docs/script/sql/ruoyi-ai.sql`。脚本创建 `sys_url` 表和菜单;普通管理角色需分配对应菜单及按钮权限。
|
||||
|
||||
| 接口 | 权限 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| `GET /system/url/list` | `system:url:list` | 名称、状态筛选和分页 |
|
||||
| `GET /system/url/{urlId}` | `system:url:query` | 编辑回填 |
|
||||
| `POST /system/url` | `system:url:add` | 新增 |
|
||||
| `PUT /system/url` | `system:url:edit` | 编辑 |
|
||||
| `DELETE /system/url/{urlIds}` | `system:url:remove` | 删除,多个 ID 以逗号分隔 |
|
||||
| `GET /system/url/shortcuts` | `coding:harness:use` 或 `system:url:list` | 当前租户的已启用链接 |
|
||||
|
||||
链接地址仅允许带有效主机名的 HTTP(S) 地址。状态 `0` 表示启用,`1` 表示停用;列表和快捷入口按 `sortOrder`、`urlId` 升序排列。数据查询和修改遵循当前租户隔离。
|
||||
|
||||
## 使用
|
||||
|
||||
在管理端填写名称、地址、说明、顺序和状态后保存。Copilot 点击“新建编程任务”会刷新快捷入口;停用的链接不显示。卡片显示名称、说明和外链标识,并以 `noopener,noreferrer` 在新标签页打开。加载中、空列表和请求失败均有提示,失败时可重试。
|
||||
|
||||
后端实现位于 `ruoyi-modules/ruoyi-system` 的 `SysUrlController`、`SysUrlServiceImpl`;管理端位于 `ruoyi-admin/apps/web-antd/src/views/system/url`;Copilot 使用 `UrlShortcutCards.vue` 和 `useUrlShortcuts.ts`。
|
||||
|
||||
## 2026-09-08 最终验收
|
||||
|
||||
- 后端打包、管理端构建和 Copilot 构建通过;Copilot 构建包含类型检查。
|
||||
- URL 接口 14/14,覆盖 CRUD、分页、排序、输入校验、权限和租户隔离。
|
||||
- Copilot 单元测试 18/18,卡片状态与点击检查 7/7,EXTERNAL 计划工具回归 2/2。
|
||||
- 增量 SQL 连续执行两次通过,全量 SQL 的 URL 模块在临时隔离库通过。
|
||||
- 浏览器完成新增、编辑、筛选、停用隐藏、重新启用刷新和卡片说明检查;临时数据已清理。
|
||||
- 管理端全项目仍有 103 项既有类型诊断,URL 模块为 0 项。
|
||||
|
||||
本轮还修复了 EXTERNAL 模式隐藏 `plan_step` 的框架问题,使模型能在证据校验后完成计划。原生运行和计划均已到达 `COMPLETED`。本轮为本地验收;未包含远程部署。新标签页打开参数通过组件测试确认,本轮未新增真实弹窗或手机尺寸实测结论。
|
||||
47
pom.xml
@@ -13,7 +13,7 @@
|
||||
<description>全栈式AI开发平台</description>
|
||||
|
||||
<properties>
|
||||
<revision>3.0.0</revision>
|
||||
<revision>3.1.0</revision>
|
||||
<spring-boot.version>3.5.8</spring-boot.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
@@ -43,8 +43,6 @@
|
||||
<aws.sdk.version>2.28.22</aws.sdk.version>
|
||||
<!-- SMS 配置 -->
|
||||
<sms4j.version>3.3.5</sms4j.version>
|
||||
<!-- 限制框架中的fastjson版本 -->
|
||||
<fastjson.version>1.2.83</fastjson.version>
|
||||
<!-- 面向运行时的D-ORM依赖 -->
|
||||
<anyline.version>8.7.2-20250603</anyline.version>
|
||||
<!-- 工作流配置 -->
|
||||
@@ -54,18 +52,25 @@
|
||||
<!-- Jackson XML -->
|
||||
<jackson-dataformat-xml.version>2.18.2</jackson-dataformat-xml.version>
|
||||
<!-- AI 相关依赖 -->
|
||||
<langchain4j.version>1.13.0</langchain4j.version>
|
||||
<langchain4j.community.version>1.13.0-beta23</langchain4j.community.version>
|
||||
<langgraph4j.version>1.5.3</langgraph4j.version>
|
||||
|
||||
<langchain4j.version>1.17.2</langchain4j.version>
|
||||
<langchain4j.beta.version>1.17.2-beta27</langchain4j.beta.version>
|
||||
<langchain4j.community.version>1.17.0-beta27</langchain4j.community.version>
|
||||
<langgraph4j.version>1.8.20</langgraph4j.version>
|
||||
|
||||
<weaviate.version>1.19.6</weaviate.version>
|
||||
<dify.version>1.0.7</dify.version>
|
||||
<dify.version>1.2.7</dify.version>
|
||||
<coze.version>0.4.2</coze.version>
|
||||
<!-- 智谱官方 Java SDK -->
|
||||
<zai-sdk.version>0.3.5</zai-sdk.version>
|
||||
|
||||
<!-- gRPC 版本 - 解决 Milvus SDK 依赖冲突 -->
|
||||
<grpc.version>1.62.2</grpc.version>
|
||||
<!-- Apache Commons Compress - 用于POI处理ZIP格式 -->
|
||||
<commons-compress.version>1.27.1</commons-compress.version>
|
||||
|
||||
|
||||
<avatar-generator.version>1.1.0</avatar-generator.version>
|
||||
<javassist.version>3.30.2-GA</javassist.version>
|
||||
<jsoup.version>1.21.2</jsoup.version>
|
||||
<knife4j.version>4.4.0</knife4j.version>
|
||||
<swagger-annotations.version>2.2.8</swagger-annotations.version>
|
||||
@@ -79,7 +84,7 @@
|
||||
<maven-surefire-plugin.version>3.5.3</maven-surefire-plugin.version>
|
||||
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
|
||||
<!-- 打包默认跳过测试 -->
|
||||
<skipTests>true</skipTests>
|
||||
<skipTests>false</skipTests>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
@@ -342,6 +347,12 @@
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>${justauth.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- 离线IP地址定位库 ip2region -->
|
||||
@@ -351,12 +362,6 @@
|
||||
<version>${ip2region.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
@@ -499,20 +504,8 @@
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<!-- 关闭过滤 -->
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<!-- 引入所有 匹配文件进行过滤 -->
|
||||
<includes>
|
||||
<include>application*</include>
|
||||
<include>bootstrap*</include>
|
||||
<include>banner*</include>
|
||||
</includes>
|
||||
<!-- 启用过滤 即该资源中的变量将会被过滤器中的值替换 -->
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
|
||||
@@ -1,31 +1,59 @@
|
||||
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
|
||||
# FFmpeg-enabled variant of ruoyi-admin/Dockerfile.
|
||||
FROM bellsoft/liberica-openjdk-rocky:17.0.16-cds
|
||||
#FROM bellsoft/liberica-openjdk-rocky:21.0.8-cds
|
||||
#FROM findepi/graalvm:java17-native
|
||||
|
||||
LABEL maintainer="Lion Li"
|
||||
|
||||
# Rocky base repositories do not provide the full codec build. RPM Fusion Free
|
||||
# supplies ffmpeg with libx264, while the checks below prevent a reduced build
|
||||
# from reaching production unnoticed.
|
||||
RUN set -eux; \
|
||||
dnf -y install dnf-plugins-core epel-release; \
|
||||
. /etc/os-release; \
|
||||
rocky_major="${VERSION_ID%%.*}"; \
|
||||
if [ "${rocky_major}" -ge 9 ]; then \
|
||||
dnf config-manager --set-enabled crb; \
|
||||
else \
|
||||
dnf config-manager --set-enabled powertools; \
|
||||
fi; \
|
||||
dnf -y install "https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-${rocky_major}.noarch.rpm"; \
|
||||
dnf -y install ffmpeg; \
|
||||
for filter in scale pad fps setsar format tpad trim settb setpts xfade \
|
||||
aresample aformat apad atrim asetpts anullsrc concat acrossfade; do \
|
||||
ffmpeg -hide_banner -filters 2>/dev/null | grep -Eq "[[:space:]]${filter}[[:space:]]"; \
|
||||
done; \
|
||||
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q dissolve; \
|
||||
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q fadeblack; \
|
||||
ffmpeg -hide_banner -h filter=xfade 2>&1 | grep -q slideleft; \
|
||||
ffmpeg -hide_banner -encoders 2>/dev/null | grep -Eq '[[:space:]]libx264[[:space:]]'; \
|
||||
ffmpeg -hide_banner -encoders 2>/dev/null | grep -Eq '[[:space:]]aac[[:space:]]'; \
|
||||
ffprobe -hide_banner -version >/dev/null; \
|
||||
dnf clean all; \
|
||||
rm -rf /var/cache/dnf
|
||||
|
||||
RUN mkdir -p /ruoyi/server/logs \
|
||||
/ruoyi/server/temp \
|
||||
/ruoyi/skywalking/agent
|
||||
|
||||
WORKDIR /ruoyi/server
|
||||
|
||||
ENV SERVER_PORT=8080 SNAIL_PORT=28080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
|
||||
ENV SERVER_PORT=8080 \
|
||||
SNAIL_PORT=28080 \
|
||||
LANG=C.UTF-8 \
|
||||
LC_ALL=C.UTF-8 \
|
||||
JAVA_OPTS="" \
|
||||
FFMPEG_PATH=/usr/bin/ffmpeg \
|
||||
FFPROBE_PATH=/usr/bin/ffprobe
|
||||
|
||||
EXPOSE ${SERVER_PORT}
|
||||
# 暴露 snail job 客户端端口 用于定时任务调度中心通信
|
||||
EXPOSE ${SNAIL_PORT}
|
||||
|
||||
ADD ./target/ruoyi-admin.jar ./app.jar
|
||||
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
|
||||
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
|
||||
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom \
|
||||
-Djava.io.tmpdir=/ruoyi/server/temp \
|
||||
-Dserver.port=${SERVER_PORT} \
|
||||
-Dsnail-job.port=${SNAIL_PORT} \
|
||||
# 应用名称 如果想区分集群节点监控 改成不同的名称即可
|
||||
#-Dskywalking.agent.service_name=ruoyi-server \
|
||||
#-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
|
||||
-XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
|
||||
-jar app.jar
|
||||
|
||||
|
||||
@@ -4,9 +4,6 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
|
||||
/**
|
||||
* 启动程序
|
||||
*
|
||||
@@ -16,66 +13,10 @@ import java.net.ServerSocket;
|
||||
public class RuoYiAIApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
killPortProcess(6039);
|
||||
SpringApplication application = new SpringApplication(RuoYiAIApplication.class);
|
||||
application.setApplicationStartup(new BufferingApplicationStartup(2048));
|
||||
application.run(args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ RuoYi-AI启动成功 ლ(´ڡ`ლ)");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查并终止占用指定端口的进程
|
||||
*
|
||||
* @param port 端口号
|
||||
*/
|
||||
private static void killPortProcess(int port) {
|
||||
try {
|
||||
if (!isPortInUse(port)) {
|
||||
return;
|
||||
}
|
||||
System.out.println("端口 " + port + " 已被占用,正在查找并终止进程...");
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder("netstat", "-ano");
|
||||
Process process = pb.start();
|
||||
java.io.BufferedReader reader = new java.io.BufferedReader(
|
||||
new java.io.InputStreamReader(process.getInputStream()));
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.contains(":" + port + " ") && line.contains("LISTENING")) {
|
||||
String[] parts = line.trim().split("\\s+");
|
||||
String pid = parts[parts.length - 1];
|
||||
System.out.println("找到占用端口 " + port + " 的进程 PID: " + pid + ",正在终止...");
|
||||
|
||||
ProcessBuilder killPb = new ProcessBuilder("taskkill", "/F", "/PID", pid);
|
||||
Process killProcess = killPb.start();
|
||||
int exitCode = killProcess.waitFor();
|
||||
if (exitCode == 0) {
|
||||
System.out.println("进程 " + pid + " 已成功终止");
|
||||
} else {
|
||||
System.out.println("终止进程 " + pid + " 失败,exitCode: " + exitCode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 等待一小段时间确保端口释放
|
||||
Thread.sleep(500);
|
||||
} catch (Exception e) {
|
||||
System.out.println("检查/终止端口进程时发生异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查端口是否被占用
|
||||
*/
|
||||
private static boolean isPortInUse(int port) {
|
||||
try (ServerSocket socket = new ServerSocket()) {
|
||||
socket.bind(new InetSocketAddress(port));
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ spring.boot.admin.client:
|
||||
metadata:
|
||||
username: ${spring.boot.admin.client.username}
|
||||
userpassword: ${spring.boot.admin.client.password}
|
||||
username: @monitor.username@
|
||||
password: @monitor.password@
|
||||
username: ${MONITOR_USERNAME:ruoyi}
|
||||
password: ${MONITOR_PASSWORD:123456}
|
||||
|
||||
--- # mcp配置信息
|
||||
mcp:
|
||||
@@ -17,6 +17,26 @@ mcp:
|
||||
enabled: false
|
||||
url: http://localhost:8085/sse
|
||||
|
||||
--- # Local Harness workspace boundary. Override the environment variable to narrow it further.
|
||||
coding:
|
||||
harness:
|
||||
workspace:
|
||||
shared-root: ${CODING_HARNESS_WORKSPACE_SHARED_ROOT:D:/Project}
|
||||
journal:
|
||||
# Keep local projection disabled unless an operator explicitly chooses a destination.
|
||||
enabled: ${CODING_HARNESS_JOURNAL_ENABLED:false}
|
||||
output-directory: ${CODING_HARNESS_JOURNAL_OUTPUT_DIRECTORY:./data/coding-harness-journal}
|
||||
# 本地实战也必须显式提供 Docker CLI 绝对路径与不可变镜像;默认保持关闭。
|
||||
tools:
|
||||
execute-process:
|
||||
enabled: ${CODING_HARNESS_EXECUTE_PROCESS_ENABLED:false}
|
||||
sandbox:
|
||||
docker-executable: ${CODING_HARNESS_DOCKER_EXECUTABLE:}
|
||||
docker-executable-sha256: ${CODING_HARNESS_DOCKER_EXECUTABLE_SHA256:}
|
||||
docker-config-directory: ${CODING_HARNESS_DOCKER_CONFIG_DIRECTORY:}
|
||||
docker-host: ${CODING_HARNESS_DOCKER_HOST:}
|
||||
image: ${CODING_HARNESS_SANDBOX_IMAGE:}
|
||||
|
||||
--- # 上传文件地址
|
||||
sys:
|
||||
upload:
|
||||
@@ -27,12 +47,12 @@ snail-job:
|
||||
enabled: false
|
||||
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
|
||||
group: "ruoyi_group"
|
||||
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表
|
||||
# SnailJob 接入验证令牌 详见 docs/script/sql/ruoyi-ai-v3_mysql8.sql `sj_group_config` 表
|
||||
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
|
||||
server:
|
||||
host: 127.0.0.1
|
||||
port: 17888
|
||||
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
|
||||
# 命名空间UUID 详见 docs/script/sql/ruoyi-ai-v3_mysql8.sql `sj_namespace`表`unique_id`字段
|
||||
namespace: ${spring.profiles.active}
|
||||
# 随主应用端口漂移
|
||||
port: 2${server.port}
|
||||
@@ -46,7 +66,7 @@ spring:
|
||||
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
|
||||
dynamic:
|
||||
# 性能分析插件(有性能损耗 不建议生产环境使用)
|
||||
p6spy: true
|
||||
p6spy: false
|
||||
# 设置默认的数据源或者数据源组,默认值即为 master
|
||||
primary: master
|
||||
# 严格模式 匹配不到数据源则报错
|
||||
|
||||
@@ -9,8 +9,8 @@ spring.boot.admin.client:
|
||||
metadata:
|
||||
username: ${spring.boot.admin.client.username}
|
||||
userpassword: ${spring.boot.admin.client.password}
|
||||
username: @monitor.username@
|
||||
password: @monitor.password@
|
||||
username: ${MONITOR_USERNAME:ruoyi}
|
||||
password: ${MONITOR_PASSWORD:123456}
|
||||
|
||||
--- # mcp配置信息
|
||||
mcp:
|
||||
@@ -28,12 +28,12 @@ snail-job:
|
||||
enabled: false
|
||||
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
|
||||
group: "ruoyi_group"
|
||||
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表
|
||||
# SnailJob 接入验证令牌 详见 docs/script/sql/ruoyi-ai-v3_mysql8.sql `sj_group_config` 表
|
||||
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
|
||||
server:
|
||||
host: 127.0.0.1
|
||||
port: 17888
|
||||
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
|
||||
# 命名空间UUID 详见 docs/script/sql/ruoyi-ai-v3_mysql8.sql `sj_namespace`表`unique_id`字段
|
||||
namespace: ${spring.profiles.active}
|
||||
# 随主应用端口漂移
|
||||
port: 2${server.port}
|
||||
@@ -47,7 +47,7 @@ spring:
|
||||
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
|
||||
dynamic:
|
||||
# 性能分析插件(有性能损耗 不建议生产环境使用)
|
||||
p6spy: true
|
||||
p6spy: false
|
||||
# 设置默认的数据源或者数据源组,默认值即为 master
|
||||
primary: master
|
||||
# 严格模式 匹配不到数据源则报错
|
||||
|
||||
@@ -20,6 +20,39 @@ server:
|
||||
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
|
||||
worker: 256
|
||||
|
||||
# execute_process 只能经由固定镜像的 Docker OS sandbox;缺任一配置均 fail closed。
|
||||
coding:
|
||||
harness:
|
||||
journal:
|
||||
# Operator HTML projection is opt-in; production paths must be chosen by deployment config.
|
||||
enabled: ${CODING_HARNESS_JOURNAL_ENABLED:false}
|
||||
output-directory: ${CODING_HARNESS_JOURNAL_OUTPUT_DIRECTORY:./data/coding-harness-journal}
|
||||
budget:
|
||||
# 模型回合上限;工具额度按每回合最多 3 次保持同比例,避免工具预算先于回合耗尽。
|
||||
# No task iteration or wall-time cutoff; context compaction supports continued work.
|
||||
# Optional cumulative spending ceilings (0 = disabled).
|
||||
max-tool-calls: 0
|
||||
max-input-tokens: 0
|
||||
max-output-tokens: 0
|
||||
tools:
|
||||
execute-process:
|
||||
enabled: ${CODING_HARNESS_EXECUTE_PROCESS_ENABLED:false}
|
||||
sandbox:
|
||||
# 必须是宿主 Docker CLI 的绝对路径;不会搜索或继承宿主 PATH/HOME。
|
||||
docker-executable: ${CODING_HARNESS_DOCKER_EXECUTABLE:}
|
||||
# 对 CLI 文件内容做每次控制调用前复核,不能只信文件名或绝对路径。
|
||||
docker-executable-sha256: ${CODING_HARNESS_DOCKER_EXECUTABLE_SHA256:}
|
||||
# 必须是绝对、无链接且始终为空的专用目录,阻断宿主 config.json/proxy/credential helper。
|
||||
docker-config-directory: ${CODING_HARNESS_DOCKER_CONFIG_DIRECTORY:}
|
||||
# 只接受平台本地 Docker Engine(Windows named pipe / Unix socket),拒绝远端 context。
|
||||
docker-host: ${CODING_HARNESS_DOCKER_HOST:}
|
||||
# 仅接受 evaluator 批准的本地 sha256:<64 hex> image ID,永不 pull/build。
|
||||
image: ${CODING_HARNESS_SANDBOX_IMAGE:}
|
||||
|
||||
--- # 小程序对话 WebSocket 兜底默认模型(前端未传 model 且无智能体绑定时使用)
|
||||
chat:
|
||||
default-model: deepseek-v4-flash
|
||||
|
||||
captcha:
|
||||
# 是否启用验证码校验
|
||||
enable: false
|
||||
@@ -35,10 +68,19 @@ captcha:
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
org.ruoyi: @logging.level@
|
||||
org.ruoyi: ${LOGGING_LEVEL_ORG_RUOYI:info}
|
||||
org.springframework: warn
|
||||
org.mybatis.spring.mapper: error
|
||||
org.apache.fury: warn
|
||||
# MCP traffic/stdout may contain tool arguments, results or credentials.
|
||||
MCP: "OFF"
|
||||
dev.langchain4j.mcp: "OFF"
|
||||
dev.langchain4j.mcp.McpToolProvider: "OFF"
|
||||
dev.langchain4j.mcp.client.logging.DefaultMcpLogMessageHandler: "OFF"
|
||||
dev.langchain4j.mcp.client.transport.stdio.StdioMcpTransport: "OFF"
|
||||
dev.langchain4j.mcp.client.transport.stdio.ProcessStderrHandler: "OFF"
|
||||
dev.langchain4j.mcp.transport.stdio.JsonRpcIoHandler: "ERROR"
|
||||
dev.langchain4j.mcp.client.transport.http.StreamableHttpMcpTransport: "OFF"
|
||||
config: classpath:logback-plus.xml
|
||||
|
||||
# 用户配置
|
||||
@@ -75,7 +117,7 @@ spring:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
profiles:
|
||||
active: @profiles.active@
|
||||
active: ${SPRING_PROFILES_ACTIVE:dev}
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
@@ -141,6 +183,9 @@ tenant:
|
||||
- sys_client
|
||||
- sys_oss_config
|
||||
- flow_spel
|
||||
# 链路追踪监控表:运维需跨租户全局查看,且 trace_node 在异步线程写入、租户上下文不传播,故排除租户过滤
|
||||
- trace_run
|
||||
- trace_node
|
||||
|
||||
# MyBatisPlus配置
|
||||
# https://baomidou.com/config/
|
||||
@@ -226,6 +271,18 @@ xss:
|
||||
# 排除链接
|
||||
excludeUrls:
|
||||
- /system/notice
|
||||
# Coding prompts contain source text (for example TypeScript <T>), rendered as escaped Markdown.
|
||||
- /coding/harness/sessions/*/runs
|
||||
- /coding/harness/sessions/*/runs/*/inputs
|
||||
|
||||
--- # 链路追踪配置
|
||||
trace:
|
||||
# 是否启用链路追踪,默认 true
|
||||
# 关闭后所有埋点代码会直接透传业务逻辑,不写库、不创建上下文,零性能开销
|
||||
enabled: true
|
||||
payload:
|
||||
# 错误信息最大字符长度(格式: "异常类名: 异常消息"),超过部分会被截断丢弃
|
||||
max-error-length: 1000
|
||||
|
||||
--- # 分布式锁 lock4j 全局配置
|
||||
lock4j:
|
||||
@@ -263,9 +320,9 @@ websocket:
|
||||
--- # 演示模式配置
|
||||
demo:
|
||||
# 是否开启演示模式(开启后所有写操作将被拦截)
|
||||
enabled: false
|
||||
enabled: ${DEMO_ENABLED:false}
|
||||
# 提示消息
|
||||
message: "演示模式,不允许进行写操作"
|
||||
message: "演示模式,不允许操作"
|
||||
# 排除的路径(这些路径不受演示模式限制)
|
||||
excludes:
|
||||
- /login
|
||||
@@ -276,7 +333,9 @@ demo:
|
||||
- /chat/send
|
||||
- /system/session/**
|
||||
- /system/message/**
|
||||
|
||||
- /system/attach/**
|
||||
- /system/fragment/**
|
||||
- /system/info/**
|
||||
--- # warm-flow工作流配置
|
||||
warm-flow:
|
||||
# 是否开启工作流,默认true
|
||||
@@ -294,11 +353,12 @@ warm-flow:
|
||||
vector-store:
|
||||
# 向量存储类型 可选(weaviate/milvus/qdrant)
|
||||
# 如需修改向量库类型,请修改此配置值!
|
||||
type: milvus
|
||||
# 注意:需与 docker-compose 实际部署的向量库保持一致(当前 compose 内置 weaviate,映射端口 28080)
|
||||
type: weaviate
|
||||
# Weaviate配置
|
||||
weaviate:
|
||||
protocol: http
|
||||
host: 127.0.0.1:6038
|
||||
host: 127.0.0.1:28080
|
||||
classname: LocalKnowledge
|
||||
# Milvus配置
|
||||
milvus:
|
||||
@@ -311,3 +371,48 @@ vector-store:
|
||||
collectionname: LocalKnowledge
|
||||
api-key:
|
||||
use-tls: false
|
||||
|
||||
# 流程编排扩展节点
|
||||
workflow:
|
||||
web-search:
|
||||
zhipu:
|
||||
# 推荐通过环境变量注入;为空时回退到模型管理中的 zhipu 厂商密钥
|
||||
api-key: ${ZAI_API_KEY:}
|
||||
base-url: ${ZHIPU_WEB_SEARCH_BASE_URL:https://open.bigmodel.cn/api/paas/v4/}
|
||||
connect-timeout: ${ZHIPU_WEB_SEARCH_CONNECT_TIMEOUT:10}
|
||||
read-timeout: ${ZHIPU_WEB_SEARCH_READ_TIMEOUT:30}
|
||||
|
||||
# 短剧成片合成
|
||||
short-drama:
|
||||
composition:
|
||||
ffmpeg-path: ${FFMPEG_PATH:ffmpeg}
|
||||
ffprobe-path: ${FFPROBE_PATH:ffprobe}
|
||||
fps: ${SHORT_DRAMA_COMPOSITION_FPS:30}
|
||||
audio-sample-rate: ${SHORT_DRAMA_COMPOSITION_AUDIO_SAMPLE_RATE:48000}
|
||||
video-codec: ${SHORT_DRAMA_COMPOSITION_VIDEO_CODEC:libx264}
|
||||
audio-codec: ${SHORT_DRAMA_COMPOSITION_AUDIO_CODEC:aac}
|
||||
preset: ${SHORT_DRAMA_COMPOSITION_PRESET:medium}
|
||||
crf: ${SHORT_DRAMA_COMPOSITION_CRF:20}
|
||||
audio-bitrate: ${SHORT_DRAMA_COMPOSITION_AUDIO_BITRATE:192k}
|
||||
max-clips: ${SHORT_DRAMA_COMPOSITION_MAX_CLIPS:100}
|
||||
max-transition-seconds: ${SHORT_DRAMA_COMPOSITION_MAX_TRANSITION_SECONDS:2.0}
|
||||
minimum-output-bytes: ${SHORT_DRAMA_COMPOSITION_MINIMUM_OUTPUT_BYTES:1024}
|
||||
max-process-output-bytes: ${SHORT_DRAMA_COMPOSITION_MAX_PROCESS_OUTPUT_BYTES:1048576}
|
||||
max-source-bytes: ${SHORT_DRAMA_COMPOSITION_MAX_SOURCE_BYTES:536870912}
|
||||
max-total-source-bytes: ${SHORT_DRAMA_COMPOSITION_MAX_TOTAL_SOURCE_BYTES:2147483648}
|
||||
probe-timeout: ${SHORT_DRAMA_COMPOSITION_PROBE_TIMEOUT:30s}
|
||||
process-timeout: ${SHORT_DRAMA_COMPOSITION_PROCESS_TIMEOUT:30m}
|
||||
job-stale-after: ${SHORT_DRAMA_COMPOSITION_JOB_STALE_AFTER:45m}
|
||||
watermark-font-file: ${SHORT_DRAMA_COMPOSITION_WATERMARK_FONT_FILE:}
|
||||
worker-core-size: ${SHORT_DRAMA_COMPOSITION_WORKER_CORE_SIZE:1}
|
||||
worker-max-size: ${SHORT_DRAMA_COMPOSITION_WORKER_MAX_SIZE:2}
|
||||
worker-queue-capacity: ${SHORT_DRAMA_COMPOSITION_WORKER_QUEUE_CAPACITY:8}
|
||||
storage-mode: ${SHORT_DRAMA_COMPOSITION_STORAGE_MODE:local}
|
||||
local-output-directory: ${SHORT_DRAMA_COMPOSITION_LOCAL_OUTPUT_DIRECTORY:logs/short-drama-compositions}
|
||||
download:
|
||||
connect-timeout: ${SHORT_DRAMA_DOWNLOAD_CONNECT_TIMEOUT:30s}
|
||||
call-timeout: ${SHORT_DRAMA_DOWNLOAD_CALL_TIMEOUT:10m}
|
||||
max-redirects: ${SHORT_DRAMA_DOWNLOAD_MAX_REDIRECTS:5}
|
||||
# 生产环境建议配置为视频供应商或 OSS/CDN 域名,多个值用逗号分隔。
|
||||
allowed-hosts: ${SHORT_DRAMA_DOWNLOAD_ALLOWED_HOSTS:}
|
||||
fake-ip-allowed-hosts: ${SHORT_DRAMA_DOWNLOAD_FAKE_IP_ALLOWED_HOSTS:atlas-media.oss-us-west-1.aliyuncs.com}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
package org.ruoyi.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.ruoyi.common.json.config.JacksonConfig;
|
||||
import org.ruoyi.system.domain.bo.SysTenantBo;
|
||||
import org.ruoyi.workflow.config.BeanConfig;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.mock.http.MockHttpInputMessage;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Tag("dev")
|
||||
class TenantRequestJacksonTest {
|
||||
|
||||
private static final String TENANT_REQUEST = """
|
||||
{
|
||||
"contactPhone": "13700000000",
|
||||
"expireTime": "2027-09-11 00:00:00",
|
||||
"accountCount": -1,
|
||||
"companyName": "第一集",
|
||||
"contactUserName": "刘备",
|
||||
"username": "user",
|
||||
"password": "123456",
|
||||
"packageId": "2018611998196109314"
|
||||
}
|
||||
""";
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(JacksonConfig.class, JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class))
|
||||
.withUserConfiguration(BeanConfig.class);
|
||||
|
||||
@Test
|
||||
void readsTenantRequestWithApplicationDateFormat() {
|
||||
contextRunner.withPropertyValues("spring.jackson.date-format=yyyy-MM-dd HH:mm:ss").run(context -> {
|
||||
MappingJackson2HttpMessageConverter converter = context.getBean(MappingJackson2HttpMessageConverter.class);
|
||||
assertSame(context.getBean(ObjectMapper.class), converter.getObjectMapper());
|
||||
|
||||
SysTenantBo tenant = readTenant(converter, TENANT_REQUEST);
|
||||
|
||||
assertEquals(expirationDate(), tenant.getExpireTime());
|
||||
assertEquals(2018611998196109314L, tenant.getPackageId());
|
||||
assertEquals(-1L, tenant.getAccountCount());
|
||||
assertEquals("第一集", tenant.getCompanyName());
|
||||
assertEquals("user", tenant.getUsername());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void keepsRegisteredDateDeserializerWithoutDateFormatProperty() {
|
||||
contextRunner.run(context -> {
|
||||
SysTenantBo tenant = readTenant(context.getBean(MappingJackson2HttpMessageConverter.class), TENANT_REQUEST);
|
||||
|
||||
assertEquals(expirationDate(), tenant.getExpireTime());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void honorsConfiguredDateSerializationFormat() {
|
||||
contextRunner.withPropertyValues("spring.jackson.date-format=yyyy/MM/dd HH:mm:ss").run(context -> {
|
||||
ObjectMapper mapper = context.getBean(ObjectMapper.class);
|
||||
|
||||
String json = mapper.writeValueAsString(new DateValue(expirationDate()));
|
||||
|
||||
assertEquals("{\"expireTime\":\"2027/09/11 00:00:00\"}", json);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void preservesWorkflowJsonRoundTripAndNullOmission() {
|
||||
contextRunner.run(context -> {
|
||||
ObjectMapper mapper = context.getBean(ObjectMapper.class);
|
||||
WorkflowValue value = new WorkflowValue(2018611998196109314L,
|
||||
LocalDateTime.of(2027, 9, 11, 0, 0), Optional.of("workflow"), null);
|
||||
|
||||
String json = mapper.writeValueAsString(value);
|
||||
JsonNode tree = mapper.readTree(json);
|
||||
|
||||
assertTrue(tree.get("id").isTextual());
|
||||
assertEquals("2018611998196109314", tree.get("id").asText());
|
||||
assertEquals("2027-09-11 00:00:00", tree.get("createdAt").asText());
|
||||
assertEquals("workflow", tree.get("name").asText());
|
||||
assertFalse(tree.has("remark"));
|
||||
assertEquals(value, mapper.readValue(json, WorkflowValue.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsNullExpirationDate() {
|
||||
contextRunner.run(context -> {
|
||||
String request = TENANT_REQUEST.replace("\"2027-09-11 00:00:00\"", "null");
|
||||
SysTenantBo tenant = readTenant(context.getBean(MappingJackson2HttpMessageConverter.class), request);
|
||||
|
||||
assertNull(tenant.getExpireTime());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsInvalidExpirationDate() {
|
||||
contextRunner.run(context -> {
|
||||
String request = TENANT_REQUEST.replace("2027-09-11 00:00:00", "invalid-date");
|
||||
MappingJackson2HttpMessageConverter converter = context.getBean(MappingJackson2HttpMessageConverter.class);
|
||||
|
||||
assertThrows(HttpMessageNotReadableException.class, () -> readTenant(converter, request));
|
||||
});
|
||||
}
|
||||
|
||||
private static SysTenantBo readTenant(MappingJackson2HttpMessageConverter converter, String json) throws Exception {
|
||||
MockHttpInputMessage input = new MockHttpInputMessage(json.getBytes(StandardCharsets.UTF_8));
|
||||
input.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
return (SysTenantBo) converter.read(SysTenantBo.class, input);
|
||||
}
|
||||
|
||||
private static Date expirationDate() {
|
||||
return Date.from(LocalDateTime.of(2027, 9, 11, 0, 0).atZone(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
private record DateValue(Date expireTime) {
|
||||
}
|
||||
|
||||
private record WorkflowValue(Long id, LocalDateTime createdAt, Optional<String> name, String remark) {
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@
|
||||
<module>ruoyi-common-tenant</module>
|
||||
<module>ruoyi-common-websocket</module>
|
||||
<module>ruoyi-common-sse</module>
|
||||
<module>ruoyi-common-trace</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<revision>3.0.0</revision>
|
||||
<revision>3.1.0</revision>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -186,6 +186,13 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 链路追踪模块 -->
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-trace</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -68,6 +68,12 @@
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>${swagger-annotations.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package org.ruoyi.common.chat.domain.bo.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatModel;
|
||||
import org.ruoyi.common.core.validate.AddGroup;
|
||||
import org.ruoyi.common.core.validate.EditGroup;
|
||||
import org.ruoyi.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
@@ -28,16 +32,19 @@ public class ChatModelBo extends BaseEntity {
|
||||
/**
|
||||
* 模型分类
|
||||
*/
|
||||
@NotBlank(message = "模型分类不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
@NotBlank(message = "模型名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String modelName;
|
||||
|
||||
/**
|
||||
* 模型供应商
|
||||
*/
|
||||
@NotBlank(message = "模型供应商不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String providerCode;
|
||||
|
||||
/**
|
||||
@@ -63,6 +70,9 @@ public class ChatModelBo extends BaseEntity {
|
||||
/**
|
||||
* 密钥
|
||||
*/
|
||||
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
||||
@ToString.Exclude
|
||||
@EqualsAndHashCode.Exclude
|
||||
private String apiKey;
|
||||
|
||||
/**
|
||||
|
||||