初始化
This commit is contained in:
+1042
File diff suppressed because it is too large
Load Diff
+272
@@ -0,0 +1,272 @@
|
||||
# 第三方服务、接口及密钥说明
|
||||
|
||||
本文档记录第三方服务实际使用的网址、接口和密钥字段。
|
||||
完整明文密钥不得提交到版本库;下文的密钥值使用登记占位符,真实值分别保存在生产环境文件或管理后台加密存储中。
|
||||
|
||||
## 1. 第三方服务总览
|
||||
|
||||
| 第三方服务 | 用途 | 网址或接口入口 | 所需凭证 | 凭证保存位置 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| AP 渠道 | 文本、图片、视频任务及余额查询 | `https://api.apimart.ai/v1` | 渠道 API Key | PostgreSQL `channels.api_key_ciphertext` |
|
||||
| 腾讯云 COS | 上传、读取和删除图片、音频、视频等媒体文件 | `https://cos.ap-chengdu.myqcloud.com` | SecretId、SecretKey | `/etc/juyou_ai/juyou_ai.env` |
|
||||
| 腾讯云 COS 公开域名 | 向前端及第三方渠道提供可访问的媒体 URL | `https://cos.youjuhui.xyz` | 无单独运行时密钥 | `/etc/juyou_ai/juyou_ai.env` |
|
||||
| Let's Encrypt | 申请和续期 HTTPS 证书 | `https://acme-v02.api.letsencrypt.org/directory` | 证书联系邮箱,不使用 API Key | `/opt/juyou_ai/deploy/.deploy.conf` |
|
||||
| jsDelivr | 按需更新部署目录中的 `acme.sh` | `https://cdn.jsdelivr.net/gh/acmesh-official/acme.sh@master/acme.sh` | 无 | 不保存凭证 |
|
||||
| Hugging Face 下载源 | 首次在本地准备离线语音识别文件 | 由 `faster-whisper` 下载工具访问 | 当前未配置访问令牌 | 不保存凭证 |
|
||||
|
||||
## 2. AI 渠道
|
||||
|
||||
### 2.1 当前渠道登记
|
||||
|
||||
| 渠道名称 | 渠道 URL | API Key |
|
||||
| --- | --- | --- |
|
||||
| AP | `https://api.apimart.ai/v1` | `<在管理后台维护>` |
|
||||
|
||||
渠道只需要登记基础网址和 API Key,具体模型不在本文档记录。
|
||||
|
||||
管理后台配置位置:
|
||||
|
||||
```text
|
||||
ADMIN → 渠道管理 → 新增或编辑渠道 → 渠道 URL、API Key
|
||||
```
|
||||
|
||||
### 2.2 认证方式
|
||||
|
||||
所有渠道请求使用 Bearer Token:
|
||||
|
||||
```http
|
||||
Authorization: Bearer <渠道 API Key>
|
||||
```
|
||||
|
||||
提交异步任务时还会根据任务请求编号发送:
|
||||
|
||||
```http
|
||||
Idempotency-Key: <请求编号>
|
||||
X-Request-ID: <请求编号>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
`Idempotency-Key` 和 `X-Request-ID` 是任务标识,不是密钥。
|
||||
|
||||
### 2.3 项目调用的接口路径
|
||||
|
||||
项目会在渠道 URL 后拼接下列路径:
|
||||
|
||||
| 请求 | 完整接口 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| `POST` | `https://api.apimart.ai/v1/chat/completions` | 提交文本类请求,项目强制使用非流式响应 |
|
||||
| `POST` | `https://api.apimart.ai/v1/images/generations` | 提交图片生成任务 |
|
||||
| `POST` | `https://api.apimart.ai/v1/videos/generations` | 提交视频生成任务 |
|
||||
| `GET` | `https://api.apimart.ai/v1/tasks/{task_id}` | 查询异步任务状态和结果地址 |
|
||||
| `GET` | `https://api.apimart.ai/v1/user/balance` | 同步渠道余额 |
|
||||
|
||||
渠道至少需要兼容以上接口、Bearer 认证以及 JSON 请求和响应。图片或视频接口可以直接返回结果网址,也可以返回任务 ID 后由项目轮询。
|
||||
|
||||
### 2.4 渠道密钥如何保存
|
||||
|
||||
1. 管理员在管理后台输入渠道 API Key。
|
||||
2. API 使用 `CONFIG_ENCRYPTION_KEY` 对明文密钥进行 AES-256-GCM 加密。
|
||||
3. 密文写入 PostgreSQL 的 `channels.api_key_ciphertext`。
|
||||
4. 密钥末四位写入 `channels.api_key_last4`,用于无法解密时识别密钥。
|
||||
5. 管理端查询渠道时不会返回完整明文,只显示前后部分字符的掩码。
|
||||
6. Worker 执行任务或同步余额时,才在服务器内存中解密并放入 Authorization 请求头。
|
||||
|
||||
因此,数据库备份中的渠道密钥是密文,但同时取得数据库备份和 `CONFIG_ENCRYPTION_KEY` 的人员仍可恢复明文,两者必须分开保管。
|
||||
|
||||
### 2.5 新增或更换渠道密钥
|
||||
|
||||
新增渠道:
|
||||
|
||||
1. 在渠道服务商处创建 API Key。
|
||||
2. 在管理后台新增渠道。
|
||||
3. 填写渠道名称、基础网址和 API Key。
|
||||
4. 保存后确认后台显示的掩码尾号与新密钥一致。
|
||||
5. 通过渠道余额同步或一项低成本任务验证权限。
|
||||
|
||||
更换密钥:
|
||||
|
||||
1. 先在渠道服务商处创建新密钥,不要立即删除旧密钥。
|
||||
2. 在管理后台编辑渠道,选择“更换 API Key”并保存。
|
||||
3. 确认余额同步和任务提交正常。
|
||||
4. 再到渠道服务商处撤销旧密钥。
|
||||
5. 更新本文档中的密钥尾号和轮换记录,不记录明文。
|
||||
|
||||
## 3. 腾讯云 COS
|
||||
|
||||
### 3.1 当前存储配置
|
||||
|
||||
| 配置项 | 当前值或登记值 | 是否敏感 |
|
||||
| --- | --- | --- |
|
||||
| 腾讯云控制台 | `https://console.cloud.tencent.com/cos` | 否 |
|
||||
| `COS_SECRET_ID` | `<腾讯云子账号 SecretId>` | 是 |
|
||||
| `COS_SECRET_KEY` | `<腾讯云子账号 SecretKey>` | 是,禁止泄露 |
|
||||
| `COS_BUCKET` | `juyouai-1451538162` | 否 |
|
||||
| `COS_REGION` | `ap-chengdu` | 否 |
|
||||
| `COS_ENDPOINT` | `https://cos.ap-chengdu.myqcloud.com` | 否 |
|
||||
| `COS_PUBLIC_BASE_URL` | `https://cos.youjuhui.xyz` | 否 |
|
||||
|
||||
生产环境中的真实凭证保存在:
|
||||
|
||||
```text
|
||||
/etc/juyou_ai/juyou_ai.env
|
||||
```
|
||||
|
||||
本地开发凭证保存在:
|
||||
|
||||
```text
|
||||
API/.env
|
||||
```
|
||||
|
||||
### 3.2 使用的 COS 接口
|
||||
|
||||
项目通过 AWS S3 兼容协议访问 COS,区域使用 `ap-chengdu`,并使用虚拟主机寻址。实际执行的操作包括:
|
||||
|
||||
| S3 操作 | 用途 |
|
||||
| --- | --- |
|
||||
| `PutObject` | 上传用户文件、抽帧、识别结果、任务原始响应和生成结果 |
|
||||
| `GetObject` | 后端读取已存储对象 |
|
||||
| `DeleteObject` | 删除业务数据时清理对应对象 |
|
||||
|
||||
腾讯云子账号至少需要目标存储桶的对象读取、写入和删除权限。若缺少删除权限,业务记录可以删除,但 COS 对象清理会失败并产生遗留文件。
|
||||
|
||||
### 3.3 公开访问域名
|
||||
|
||||
`COS_PUBLIC_BASE_URL` 必须是外部可以访问的 HTTPS 地址。项目会按以下形式生成媒体地址:
|
||||
|
||||
```text
|
||||
https://cos.youjuhui.xyz/juyou_ran/<业务对象键>
|
||||
```
|
||||
|
||||
该网址会提供给:
|
||||
|
||||
- WEB 和 ADMIN 页面展示媒体;
|
||||
- 第三方渠道读取参考图片、音频或视频;
|
||||
- 服务端重新下载上游生成结果。
|
||||
|
||||
公开域名不使用 SecretKey,但必须正确绑定 `juyouai-1451538162` 存储桶。第三方渠道无法访问该域名时,带参考媒体的任务会失败。
|
||||
|
||||
### 3.4 COS CORS
|
||||
|
||||
COS 存储桶需要允许实际 WEB 域名执行 `GET` 和 `HEAD`。建议规则:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"AllowedOrigins": [
|
||||
"https://实际WEB域名"
|
||||
],
|
||||
"AllowedMethods": [
|
||||
"GET",
|
||||
"HEAD"
|
||||
],
|
||||
"AllowedHeaders": [
|
||||
"*"
|
||||
],
|
||||
"ExposeHeaders": [
|
||||
"Accept-Ranges",
|
||||
"Content-Length",
|
||||
"Content-Range",
|
||||
"Content-Type",
|
||||
"ETag"
|
||||
],
|
||||
"MaxAgeSeconds": 3600
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
缺少 CORS 时,媒体可能仍能直接打开或播放,但浏览器中的抽帧、Blob 下载等功能会被拦截。
|
||||
|
||||
### 3.5 更换 COS 密钥
|
||||
|
||||
1. 在腾讯云 CAM 中为程序子账号创建新的 API 密钥。
|
||||
2. 备份 `/etc/juyou_ai/juyou_ai.env`。
|
||||
3. 更新 `COS_SECRET_ID` 和 `COS_SECRET_KEY`。
|
||||
4. 重启 `juyou_ai` 服务。
|
||||
5. 验证上传、读取和删除操作。
|
||||
6. 确认新密钥正常后撤销旧 API 密钥。
|
||||
|
||||
```bash
|
||||
sudo systemctl restart juyou_ai
|
||||
sudo journalctl -u juyou_ai -n 100 --no-pager
|
||||
```
|
||||
|
||||
## 4. Let's Encrypt 与 acme.sh
|
||||
|
||||
### 4.1 服务信息
|
||||
|
||||
| 项目 | 值 |
|
||||
| --- | --- |
|
||||
| 正式 ACME 接口 | `https://acme-v02.api.letsencrypt.org/directory` |
|
||||
| 认证方式 | ACME HTTP-01 |
|
||||
| API Key | 不需要 |
|
||||
| 必需登记信息 | 证书联系邮箱、域名 |
|
||||
| 验证目录 | `/var/www/jcf-acme` |
|
||||
| 证书目录 | `/etc/nginx/ssl` |
|
||||
|
||||
域名和邮箱保存在:
|
||||
|
||||
```text
|
||||
/opt/juyou_ai/deploy/.deploy.conf
|
||||
```
|
||||
|
||||
部署脚本先让 Nginx 提供 `/.well-known/acme-challenge/`,再调用项目内的 `API/acme/acme.sh` 申请证书。证书申请要求域名已解析到服务器,并且公网可以访问 TCP 80。
|
||||
|
||||
已有匹配域名的证书和私钥时,部署脚本直接复用,不会重复申请。
|
||||
|
||||
## 5. 部署阶段使用的无密钥第三方来源
|
||||
|
||||
### 5.1 jsDelivr
|
||||
|
||||
只有手动执行以下脚本时才访问 jsDelivr:
|
||||
|
||||
```bash
|
||||
sudo bash /opt/juyou_ai/deploy/update_acme.sh
|
||||
```
|
||||
|
||||
下载地址:
|
||||
|
||||
```text
|
||||
https://cdn.jsdelivr.net/gh/acmesh-official/acme.sh@master/acme.sh
|
||||
```
|
||||
|
||||
该请求不使用 API Key。脚本下载后会检查内容中是否存在 `VER=` 版本标识,再替换项目中的 `acme.sh`。
|
||||
|
||||
### 5.2 Hugging Face 下载源
|
||||
|
||||
当服务器缺少离线语音识别文件时,`push.bat` 会在 Windows 本机调用 Python 下载工具准备文件,然后上传服务器。当前代码未读取或配置 Hugging Face Access Token,服务器部署和运行阶段不会访问该下载源。
|
||||
|
||||
如果以后使用需要授权的资源,应通过受保护的本机环境变量或 Hugging Face 凭证存储配置,不得把令牌写入部署脚本或本文档。
|
||||
|
||||
## 6. 不是第三方接口密钥的项目安全配置
|
||||
|
||||
下列配置同样敏感,但不属于第三方 API 凭证:
|
||||
|
||||
| 配置项 | 用途 | 保存位置 |
|
||||
| --- | --- | --- |
|
||||
| `CONFIG_ENCRYPTION_KEY` | 加密和解密渠道 API Key | 生产环境文件 |
|
||||
| `JWT_SECRET_KEY` | 签发和校验用户、管理员登录令牌 | 生产环境文件 |
|
||||
| `DATABASE_PASSWORD` | PostgreSQL 应用账号密码 | 生产环境文件 |
|
||||
| `REDIS_PASSWORD` | Redis 密码,当前为空时不启用认证 | 生产环境文件 |
|
||||
| `ADMIN_BOOTSTRAP_PASSWORD` | 数据库没有管理员时创建初始管理员 | 生产环境文件 |
|
||||
|
||||
其中 `CONFIG_ENCRYPTION_KEY` 必须是 32 字节随机值的标准 Base64 编码。丢失该密钥后,数据库中已有的渠道密钥无法解密,只能逐个重新录入;更换它时也不能只修改环境变量,必须先完成渠道密文重加密方案。
|
||||
|
||||
## 7. 密钥存放与权限要求
|
||||
|
||||
- 生产第三方密钥只保存在 `/etc/juyou_ai/juyou_ai.env` 或数据库加密字段中。
|
||||
- `/etc/juyou_ai/juyou_ai.env` 权限应为 `root:root`、`600`。
|
||||
- `API/.env` 不得提交到 Git,也不得通过普通聊天、邮件或工单正文传递。
|
||||
- Markdown 文档只记录密钥负责人、用途、尾号和轮换时间,不记录完整明文。
|
||||
- 渠道密钥、COS 密钥和 `CONFIG_ENCRYPTION_KEY` 不应由同一个公开位置统一保存。
|
||||
- 日志中不得打印 Authorization 请求头、COS SecretKey 或解密后的渠道密钥。
|
||||
- 人员离职、权限范围变化或怀疑泄露时,应立即轮换对应密钥。
|
||||
|
||||
## 8. 密钥轮换登记
|
||||
|
||||
| 服务 | 密钥标识或尾号 | 最近轮换时间 | 负责人 | 下次计划时间 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| AP 渠道 | `7MNC` | `<填写>` | `<填写>` | `<填写>` |
|
||||
| 腾讯云 COS | `<SecretId 尾号>` | `<填写>` | `<填写>` | `<填写>` |
|
||||
| Let's Encrypt 邮箱 | `<邮箱>` | `<填写>` | `<填写>` | `<填写>` |
|
||||
|
||||
轮换登记只用于识别凭证,不填写完整密钥。
|
||||
+519
@@ -0,0 +1,519 @@
|
||||
# 剧核工厂生产环境部署文档
|
||||
|
||||
本文档适用于在 Windows 本地构建项目,并一键部署到 Linux AMD64 服务器。
|
||||
这里的“一键部署”是指服务器上的 `one_click_deployment.sh` 会一次完成环境初始化、数据库迁移、服务注册、Nginx 和 HTTPS 配置。
|
||||
完整发布分为两个明确阶段:本地构建并上传、服务器执行一键部署。`push.bat` 只上传文件,不会自动修改数据库或重启线上服务。
|
||||
|
||||
## 1. 最短操作流程
|
||||
|
||||
首次部署,在 Windows 项目根目录执行:
|
||||
|
||||
```powershell
|
||||
.\API\deploy\push.bat root@服务器IP with-env
|
||||
ssh root@服务器IP
|
||||
sudo bash /opt/juyou_ai/deploy/one_click_deployment.sh
|
||||
```
|
||||
|
||||
日常更新,在 Windows 项目根目录执行:
|
||||
|
||||
```powershell
|
||||
.\API\deploy\push.bat root@服务器IP
|
||||
ssh root@服务器IP
|
||||
sudo bash /opt/juyou_ai/deploy/one_click_deployment.sh
|
||||
```
|
||||
|
||||
首次部署使用 `with-env`,将本地正式环境配置送到服务器;日常更新不使用 `with-env`,继续保留服务器已有的生产配置。
|
||||
上传和服务器部署是两个独立步骤,便于在执行数据库迁移和重启前安排备份与维护窗口。
|
||||
|
||||
## 2. 固定路径与服务
|
||||
|
||||
| 项目 | 固定值 |
|
||||
| --- | --- |
|
||||
| 服务器项目目录 | `/opt/juyou_ai` |
|
||||
| API 二进制 | `/opt/juyou_ai/bin/jcf-api` |
|
||||
| 部署脚本 | `/opt/juyou_ai/deploy/one_click_deployment.sh` |
|
||||
| WEB 静态目录 | `/opt/juyou_ai/static/web` |
|
||||
| ADMIN 静态目录 | `/opt/juyou_ai/static/admin` |
|
||||
| 数据库迁移目录 | `/opt/juyou_ai/migrations` |
|
||||
| systemd 服务名 | `juyou_ai` |
|
||||
| API 内部监听地址 | `127.0.0.1:8123` |
|
||||
| 生产环境文件 | `/etc/juyou_ai/juyou_ai.env` |
|
||||
| 临时环境文件 | `/tmp/juyou_ai.env` |
|
||||
| Whisper 离线模型 | `/opt/juyou_ai/models/faster-whisper-small` |
|
||||
| Whisper 运行缓存 | `/var/cache/juyou_ai/huggingface` |
|
||||
| Nginx 配置 | `/etc/nginx/conf.d/juyou_ai.conf` |
|
||||
| SSL 证书目录 | `/etc/nginx/ssl` |
|
||||
|
||||
API 仅监听服务器本机地址,公网请求统一通过 Nginx 进入。
|
||||
|
||||
## 3. 首次部署
|
||||
|
||||
### 3.1 准备本地环境
|
||||
|
||||
本地需要安装:
|
||||
|
||||
- Node.js 和 npm
|
||||
- Go
|
||||
- Python 3;服务器缺少离线模型时,本机还需要 `faster-whisper`
|
||||
- tar
|
||||
- OpenSSH Client(`ssh`、`scp`)
|
||||
|
||||
在终端确认命令可用:
|
||||
|
||||
```powershell
|
||||
npm --version
|
||||
go version
|
||||
python --version
|
||||
tar --version
|
||||
ssh -V
|
||||
```
|
||||
|
||||
首次在本机下载 Whisper 模型前安装 Python 依赖:
|
||||
|
||||
```powershell
|
||||
python -m pip install faster-whisper==1.2.1
|
||||
```
|
||||
|
||||
`push.bat` 不会自动安装前端依赖。首次构建或 `package-lock.json` 发生变化后,先执行:
|
||||
|
||||
```powershell
|
||||
npm --prefix WEB ci
|
||||
npm --prefix ADMIN ci
|
||||
```
|
||||
|
||||
首次部署使用的正式环境配置保存在本地:
|
||||
|
||||
```text
|
||||
API/.env
|
||||
```
|
||||
|
||||
至少确认以下字段使用正式值,不能保留 `replace-with`、`change-me`、`example.com` 或开发环境默认值:
|
||||
|
||||
```env
|
||||
DATABASE_NAME=juchuang_factory
|
||||
DATABASE_USER=jcf
|
||||
DATABASE_PASSWORD=数据库强密码
|
||||
|
||||
JWT_SECRET_KEY=随机长密钥
|
||||
ADMIN_BOOTSTRAP_USERNAME=admin
|
||||
ADMIN_BOOTSTRAP_PASSWORD=管理员初始强密码
|
||||
|
||||
CONFIG_ENCRYPTION_KEY_VERSION=v1
|
||||
CONFIG_ENCRYPTION_KEY=正式加密密钥
|
||||
|
||||
COS_SECRET_ID=腾讯云子账号SecretId
|
||||
COS_SECRET_KEY=腾讯云子账号SecretKey
|
||||
COS_BUCKET=juyouai-1451538162
|
||||
COS_REGION=ap-chengdu
|
||||
COS_ENDPOINT=https://cos.ap-chengdu.myqcloud.com
|
||||
COS_PUBLIC_BASE_URL=https://cos.youjuhui.xyz
|
||||
```
|
||||
|
||||
COS 媒体使用独立域名时,还必须在腾讯云控制台进入 **对象存储 COS → 对应存储桶 → 安全管理 → 跨域访问 CORS 设置**,添加以下规则。将域名替换为实际访问 WEB 的域名;多个 WEB 域名需要全部列出。
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"AllowedOrigins": [
|
||||
"https://juhefactory.com",
|
||||
"https://www.juhefactory.com"
|
||||
],
|
||||
"AllowedMethods": [
|
||||
"GET",
|
||||
"HEAD"
|
||||
],
|
||||
"AllowedHeaders": [
|
||||
"*"
|
||||
],
|
||||
"ExposeHeaders": [
|
||||
"Accept-Ranges",
|
||||
"Content-Length",
|
||||
"Content-Range",
|
||||
"Content-Type",
|
||||
"ETag"
|
||||
],
|
||||
"MaxAgeSeconds": 3600
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
保存策略后,确认媒体响应包含与当前 WEB 域名一致的 `Access-Control-Allow-Origin`。否则视频可以播放,但浏览器会禁止导出静帧和通过 Blob 直接下载。
|
||||
|
||||
可以使用以下命令生成随机密钥:
|
||||
|
||||
```bash
|
||||
openssl rand -hex 32
|
||||
```
|
||||
|
||||
### 3.2 准备服务器
|
||||
|
||||
目标服务器需要满足:
|
||||
|
||||
- Linux AMD64/x86_64,使用 Debian 或 Ubuntu 最稳妥
|
||||
- 使用 systemd
|
||||
- SSH 登录用户具备 sudo 权限,推荐使用 root
|
||||
- 云安全组及防火墙已放行 TCP 80、443
|
||||
- 启用 HTTPS 时,域名已经解析到服务器公网 IP
|
||||
|
||||
脚本虽然包含 `apt-get`、`dnf` 和 `yum` 的安装分支,但服务账户固定使用 `www-data`。使用非 Debian/Ubuntu 发行版前,需要先确认系统存在 `www-data` 用户和用户组,并确认 PostgreSQL、Redis 的 systemd 服务名与脚本兼容。
|
||||
|
||||
### 3.3 本地构建并上传
|
||||
|
||||
在 Windows 项目根目录执行:
|
||||
|
||||
```powershell
|
||||
.\API\deploy\push.bat root@服务器IP with-env
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```powershell
|
||||
.\API\deploy\push.bat root@192.168.1.1 with-env
|
||||
```
|
||||
|
||||
命令完成并显示以下内容后,才进入服务器执行部署:
|
||||
|
||||
```text
|
||||
Deployment push complete.
|
||||
```
|
||||
|
||||
本地上传完成只表示文件已经同步到 `/opt/juyou_ai`,此时不会自动安装依赖、迁移数据库或重启服务。
|
||||
|
||||
### 3.4 登录服务器并执行首次部署
|
||||
|
||||
本地另行登录服务器:
|
||||
|
||||
```powershell
|
||||
ssh root@服务器IP
|
||||
```
|
||||
|
||||
服务器上执行:
|
||||
|
||||
```bash
|
||||
bash /opt/juyou_ai/deploy/one_click_deployment.sh
|
||||
```
|
||||
|
||||
如果当前不是 root 用户,执行:
|
||||
|
||||
```bash
|
||||
sudo bash /opt/juyou_ai/deploy/one_click_deployment.sh
|
||||
```
|
||||
|
||||
首次运行会询问两项配置。
|
||||
|
||||
域名:
|
||||
|
||||
```text
|
||||
juhefactory.com
|
||||
```
|
||||
|
||||
多个域名使用空格分隔:
|
||||
|
||||
```text
|
||||
juhefactory.com www.juhefactory.com
|
||||
```
|
||||
|
||||
不申请 SSL 时输入:
|
||||
|
||||
```text
|
||||
_
|
||||
```
|
||||
|
||||
然后输入 SSL 证书邮箱;不申请 SSL 时直接回车。域名和邮箱会保存到:
|
||||
|
||||
```text
|
||||
/opt/juyou_ai/deploy/.deploy.conf
|
||||
```
|
||||
|
||||
首次部署完成后,将该文件复制到本地:
|
||||
|
||||
```powershell
|
||||
scp root@服务器IP:/opt/juyou_ai/deploy/.deploy.conf .\API\deploy\.deploy.conf
|
||||
```
|
||||
|
||||
后续上传不会携带本地 `.deploy.conf`;服务器会继续使用 `/opt/juyou_ai/deploy/.deploy.conf`,不会被本地文件覆盖。
|
||||
|
||||
### 3.5 验证首次部署
|
||||
|
||||
查看服务状态:
|
||||
|
||||
```bash
|
||||
systemctl status juyou_ai --no-pager
|
||||
systemctl status nginx --no-pager
|
||||
systemctl status postgresql --no-pager
|
||||
systemctl status redis-server --no-pager
|
||||
```
|
||||
|
||||
检查 API:
|
||||
|
||||
```bash
|
||||
curl -i http://127.0.0.1:8123/health
|
||||
```
|
||||
|
||||
启用 HTTPS 后检查公网入口:
|
||||
|
||||
```bash
|
||||
curl -i https://你的域名/health
|
||||
```
|
||||
|
||||
页面地址:
|
||||
|
||||
```text
|
||||
https://你的域名/
|
||||
https://你的域名/admin/
|
||||
```
|
||||
|
||||
## 4. 更新部署
|
||||
|
||||
每次更新都分为本地上传和服务器部署两步,不能只执行其中一步。
|
||||
|
||||
### 4.1 本地重新构建并上传
|
||||
|
||||
在 Windows 项目根目录执行:
|
||||
|
||||
```powershell
|
||||
.\API\deploy\push.bat root@服务器IP
|
||||
```
|
||||
|
||||
等待出现:
|
||||
|
||||
```text
|
||||
Deployment push complete.
|
||||
```
|
||||
|
||||
### 4.2 服务器应用更新
|
||||
|
||||
登录服务器:
|
||||
|
||||
```powershell
|
||||
ssh root@服务器IP
|
||||
```
|
||||
|
||||
执行:
|
||||
|
||||
```bash
|
||||
bash /opt/juyou_ai/deploy/one_click_deployment.sh
|
||||
```
|
||||
|
||||
更新部署会:
|
||||
|
||||
- 继续使用服务器现有的 `/etc/juyou_ai/juyou_ai.env`
|
||||
- 执行尚未执行的数据库迁移
|
||||
- 更新 systemd 与 Nginx 配置
|
||||
- 重启 systemd 服务 `juyou_ai`
|
||||
|
||||
### 4.3 只更新已上传文件但暂不部署
|
||||
|
||||
只执行本地 `push.bat` 即可。上传完成后不要在服务器运行 `one_click_deployment.sh`。
|
||||
|
||||
此时:
|
||||
|
||||
- `/opt/juyou_ai` 中已经是新文件
|
||||
- `/etc/juyou_ai/juyou_ai.env` 保持不变
|
||||
- 当前运行中的 API 进程仍可能使用旧二进制
|
||||
- 数据库迁移、Nginx 更新和服务重启均未执行
|
||||
|
||||
需要正式应用更新时,再执行服务器部署命令。
|
||||
|
||||
## 5. 推送参数说明
|
||||
|
||||
| 命令 | 是否上传 `API/.env` | 是否自动执行服务器部署 | 使用场景 |
|
||||
| --- | --- | --- | --- |
|
||||
| `push.bat root@服务器IP` | 否 | 否 | 日常增量更新 |
|
||||
| `push.bat root@服务器IP stage-only` | 否 | 否 | 与默认推送行为相同,用于明确表达“只暂存” |
|
||||
| `push.bat root@服务器IP with-env` | 是 | 否 | 首次部署或明确替换整套生产环境配置 |
|
||||
|
||||
三种命令都只负责构建、打包和上传。`stage-only` 当前是语义标记,执行行为与不传第二个参数相同。只有随后在服务器运行 `one_click_deployment.sh`,才会执行迁移、更新服务配置并重启应用。
|
||||
|
||||
## 6. 常用维护命令
|
||||
|
||||
服务管理:
|
||||
|
||||
```bash
|
||||
systemctl restart juyou_ai
|
||||
systemctl stop juyou_ai
|
||||
systemctl start juyou_ai
|
||||
systemctl reload nginx
|
||||
nginx -t
|
||||
```
|
||||
|
||||
查看 API 日志:
|
||||
|
||||
```bash
|
||||
journalctl -u juyou_ai -f
|
||||
journalctl -u juyou_ai -n 200 --no-pager
|
||||
```
|
||||
|
||||
修改域名或证书邮箱:
|
||||
|
||||
```bash
|
||||
nano /opt/juyou_ai/deploy/.deploy.conf
|
||||
```
|
||||
|
||||
也可以删除配置,让下次部署重新询问:
|
||||
|
||||
```bash
|
||||
rm /opt/juyou_ai/deploy/.deploy.conf
|
||||
```
|
||||
|
||||
更新 acme.sh:
|
||||
|
||||
```bash
|
||||
bash /opt/juyou_ai/deploy/update_acme.sh
|
||||
```
|
||||
|
||||
## 7. 备份与故障排查
|
||||
|
||||
正式执行数据库迁移前应先备份数据库。以下示例中的数据库名必须替换为生产环境 `DATABASE_NAME` 的实际值:
|
||||
|
||||
```bash
|
||||
mkdir -p /opt/juyou_ai/backups
|
||||
sudo -u postgres pg_dump -Fc juchuang_factory | tee /opt/juyou_ai/backups/juchuang_factory.dump >/dev/null
|
||||
```
|
||||
|
||||
PostgreSQL:
|
||||
|
||||
```bash
|
||||
systemctl status postgresql --no-pager
|
||||
journalctl -u postgresql -n 200 --no-pager
|
||||
```
|
||||
|
||||
Redis:
|
||||
|
||||
```bash
|
||||
systemctl status redis-server --no-pager
|
||||
redis-cli ping
|
||||
```
|
||||
|
||||
Nginx:
|
||||
|
||||
```bash
|
||||
nginx -t
|
||||
journalctl -u nginx -n 200 --no-pager
|
||||
```
|
||||
|
||||
API:
|
||||
|
||||
```bash
|
||||
systemctl status juyou_ai --no-pager
|
||||
journalctl -u juyou_ai -n 200 --no-pager
|
||||
ls -l /etc/juyou_ai/juyou_ai.env
|
||||
ls -l /opt/juyou_ai/bin/jcf-api
|
||||
```
|
||||
|
||||
如果部署提示环境字段缺失、格式错误或仍为示例值,修改本地 `API/.env`,重新执行 `push.bat`,然后再次在服务器运行部署脚本。
|
||||
|
||||
如果数据库迁移失败,应先核对数据库实际结构和 `jcf_schema_migrations`,不得通过手工插入迁移记录直接绕过错误。数据库迁移不会自动回滚。
|
||||
|
||||
## 8. 自动化部署流程说明
|
||||
|
||||
本节用于解释脚本内部做了什么。日常操作只需要按“首次部署”或“更新部署”章节执行命令。
|
||||
|
||||
### 8.1 `push.bat` 的本地流程
|
||||
|
||||
1. 检查目标 SSH 地址;仅在使用 `with-env` 时检查本地 `API/.env` 是否存在。
|
||||
2. 通过 SSH 检查服务器是否已有完整的 Whisper `small` 模型。缺少时,本机运行 `download_whisper_model.py` 下载模型,并把 `models/` 加入本次上传包。
|
||||
3. 执行 `npm --prefix WEB run build`,类型检查通过后将 WEB 输出到 `API/static/web`。
|
||||
4. 执行 `npm --prefix ADMIN run build`,类型检查通过后将 ADMIN 输出到 `API/static/admin`。
|
||||
5. 使用 `GOOS=linux`、`GOARCH=amd64`、`-trimpath` 和裁剪调试信息的链接参数,编译 `API/bin/jcf-api`。
|
||||
6. 创建本机临时压缩包,包含:
|
||||
|
||||
```text
|
||||
bin/
|
||||
static/
|
||||
deploy/
|
||||
migrations/
|
||||
acme/
|
||||
workers/
|
||||
models/ # 仅服务器缺少离线模型时包含
|
||||
.env # 仅使用 with-env 时包含
|
||||
```
|
||||
|
||||
7. 使用 SCP 将压缩包上传到 `/tmp/juyou-deploy.tar.gz`。
|
||||
8. 使用 SSH 在服务器的 `/tmp/juyou-deploy-work` 临时目录解包。
|
||||
9. 默认删除可能残留的 `/tmp/juyou_ai.env`;使用 `with-env` 时才将 `.env` 安装为权限 `600` 的 `/tmp/juyou_ai.env`,并从项目文件中删除 `.env`。
|
||||
10. 服务器存在 `rsync` 时,以 `--delete` 将发布文件同步到 `/opt/juyou_ai`;不存在时使用 `cp -a` 覆盖复制。
|
||||
11. 删除服务器临时解包目录和压缩包。
|
||||
12. 删除本机临时压缩包。
|
||||
|
||||
同步时保留以下服务器内容:
|
||||
|
||||
```text
|
||||
/opt/juyou_ai/media/
|
||||
/opt/juyou_ai/backups/
|
||||
/opt/juyou_ai/models/
|
||||
```
|
||||
|
||||
`models/` 默认不会被 `rsync --delete` 清理;仅当服务器缺少完整模型且本次压缩包含有模型时,才会单独同步模型内容。
|
||||
|
||||
`/opt/juyou_ai/deploy/.deploy.conf` 仅在服务器首次运行部署脚本时生成;上传包会排除本地 `.deploy.conf`,后续部署不会覆盖服务器配置。
|
||||
|
||||
`.go` 源码、测试代码、`cmd`、`internal`、`tools`、`media` 和 `backups` 不会进入上传包;运行时需要的 `workers` 会进入上传包。
|
||||
|
||||
### 8.2 `one_click_deployment.sh` 的服务器流程
|
||||
|
||||
1. 首次运行时只从 JuYouAI 自己的 Nginx 配置恢复域名;没有该配置时询问域名。仅复用输入域名对应的证书和私钥,不扫描其他项目的证书,并保存 `.deploy.conf`。
|
||||
2. 使用 `with-env` 时检测 `/tmp/juyou_ai.env` 并将其作为本次环境配置来源,否则继续使用服务器生产环境文件。
|
||||
3. 调用 `deploy_with_ssl.sh` 执行正式部署。
|
||||
|
||||
### 8.3 `deploy_with_ssl.sh` 和 `prepare_server.sh` 的服务器流程
|
||||
|
||||
1. 本机执行 `push.bat` 时检查服务器是否已有 Whisper 模型;首次部署会在本机下载并上传到 `/opt/juyou_ai/models/faster-whisper-small`。服务器不访问 Hugging Face。
|
||||
2. 安装 sudo、Nginx、PostgreSQL、Redis、FFmpeg、curl、socat、ca-certificates、openssl、Python 3 和 pip;缺少时安装 `faster-whisper 1.2.1`。
|
||||
3. 启用并启动 PostgreSQL、Redis 和 Nginx。
|
||||
4. 存在 `/tmp/juyou_ai.env` 时将其安装到 `/etc/juyou_ai/juyou_ai.env`;否则保留现有生产环境文件,权限保持 `root:root`、`600`。
|
||||
5. 将生产环境标准化为:
|
||||
|
||||
```env
|
||||
APP_ENV=production
|
||||
DEBUG=false
|
||||
SERVER_ADDRESS=127.0.0.1:8123
|
||||
DATABASE_HOST=127.0.0.1
|
||||
DATABASE_PORT=5432
|
||||
DATABASE_URL=
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PORT=6379
|
||||
CORS_ORIGINS=根据部署域名生成
|
||||
FFMPEG_PATH=ffmpeg
|
||||
FFPROBE_PATH=ffprobe
|
||||
PYTHON_PATH=python3
|
||||
ASR_SCRIPT_PATH=/opt/juyou_ai/workers/transcribe.py
|
||||
JCF_ASR_CACHE_DIR=/var/cache/juyou_ai
|
||||
HF_HOME=/var/cache/juyou_ai/huggingface
|
||||
FASTER_WHISPER_MODEL_PATH=/opt/juyou_ai/models/faster-whisper-small
|
||||
```
|
||||
|
||||
6. 校验离线 Whisper 模型、数据库、JWT、管理员、配置加密和 COS 等必填配置。
|
||||
7. 创建或更新 PostgreSQL 用户和数据库,配置本机认证。
|
||||
8. 按文件名顺序执行 `/opt/juyou_ai/migrations/*.up.sql`,并记录到 `jcf_schema_migrations`。
|
||||
9. 创建或更新 `/etc/systemd/system/juyou_ai.service`:
|
||||
|
||||
```ini
|
||||
[Service]
|
||||
User=www-data
|
||||
Group=www-data
|
||||
WorkingDirectory=/opt/juyou_ai
|
||||
EnvironmentFile=/etc/juyou_ai/juyou_ai.env
|
||||
CacheDirectory=juyou_ai
|
||||
ExecStart=/opt/juyou_ai/bin/jcf-api
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
```
|
||||
|
||||
10. 配置 Nginx:`/api/` 和健康检查路径代理到 `127.0.0.1:8123`,`/admin/` 提供 ADMIN 静态文件,其他路径提供 WEB 静态文件,上传体积上限为 2 GiB。
|
||||
11. 配置域名且已有该域名的证书时直接复用;没有证书但填写邮箱时,先创建 HTTP 验证站点,再使用 acme.sh 通过 HTTP-01 申请并安装 HTTPS 证书;域名填 `_`,或没有证书且未填写邮箱时使用 HTTP。
|
||||
12. 启用 HTTPS 时把 80 端口请求重定向到 HTTPS,并允许 TLS 1.2、TLS 1.3。
|
||||
13. 执行 `nginx -t`,配置检查成功后重载 Nginx。
|
||||
14. 重启 systemd 服务 `juyou_ai`。
|
||||
15. 部署成功后删除 `/tmp/juyou_ai.env`。
|
||||
|
||||
如果部署中途失败,临时环境文件可能保留,以便排查并重新执行部署;问题解决并部署成功后会自动清理。
|
||||
|
||||
### 8.4 重复执行与失败边界
|
||||
|
||||
- 脚本使用 `set -euo pipefail`,关键命令失败时会立即退出。
|
||||
- 已有 PostgreSQL 用户会更新密码,已有数据库不会重复创建。
|
||||
- 已记录在 `jcf_schema_migrations` 的迁移会跳过,未记录迁移按文件名顺序执行。
|
||||
- systemd 和 Nginx 配置每次都会按当前发布内容重新生成。
|
||||
- 已保存的域名、证书邮箱和匹配域名的现有证书会复用。
|
||||
- 部署脚本不会自动恢复旧二进制,也不会自动回滚已经成功执行的数据库迁移。发布前必须自行完成数据库备份;需要应用级回滚时,应重新上传兼容当前数据库结构的旧版本并再次部署。
|
||||
+687
@@ -0,0 +1,687 @@
|
||||
# JuYouAI 项目架构文档
|
||||
|
||||
## 1. 架构概览
|
||||
|
||||
项目采用“双前端、单 Go 服务进程”的结构:
|
||||
|
||||
- `WEB`:面向普通用户的创作端。
|
||||
- `ADMIN`:面向管理员的运营管理端。
|
||||
- `API`:Go 后端,同时承载 HTTP API、静态文件托管、异步任务 Worker 和定时任务。
|
||||
- PostgreSQL:保存用户、项目、任务、积分、渠道和媒体元数据,是业务状态的主要数据源。
|
||||
- Redis:提供 Asynq 队列和运行时缓存,不作为业务任务最终状态的数据源。
|
||||
- 腾讯云 COS:保存图片、音频、视频和任务结果等二进制对象。
|
||||
- 第三方渠道:由 ADMIN 动态配置基础网址和 API Key,后端统一调用。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
User["用户浏览器"] --> Nginx["Nginx"]
|
||||
AdminUser["管理员浏览器"] --> Nginx
|
||||
Nginx -->|"/"| WebStatic["WEB 静态文件"]
|
||||
Nginx -->|"/admin/"| AdminStatic["ADMIN 静态文件"]
|
||||
Nginx -->|"/api/web/*"| API["Go API 进程"]
|
||||
Nginx -->|"/api/admin/*"| API
|
||||
API --> PostgreSQL["PostgreSQL"]
|
||||
API --> Redis["Redis / Asynq"]
|
||||
API --> COS["腾讯云 COS"]
|
||||
API --> Channel["第三方渠道接口"]
|
||||
Redis --> Worker["同一 Go 进程内的 Worker"]
|
||||
Worker --> PostgreSQL
|
||||
Worker --> COS
|
||||
Worker --> Channel
|
||||
Worker --> LocalMedia["FFmpeg / Python 语音识别"]
|
||||
```
|
||||
|
||||
生产环境由一个名为 `juyou_ai` 的 systemd 服务启动 Go 二进制,进程内部并行运行 HTTP Server 和 Asynq Worker。
|
||||
|
||||
## 2. 根目录结构
|
||||
|
||||
```text
|
||||
JuYouAI/
|
||||
├─ WEB/ 用户端 Vue 应用
|
||||
├─ ADMIN/ 管理端 Vue 应用
|
||||
├─ API/ Go API、Worker、迁移和部署文件
|
||||
├─ 文档/ 架构、部署和业务说明
|
||||
├─ docker-compose.yml Windows 本地 PostgreSQL、Redis
|
||||
├─ start_api.bat Windows 本地 API 启动脚本
|
||||
└─ vite-port.ts 两个前端共用的开发端口选择逻辑
|
||||
```
|
||||
|
||||
三个应用相互独立安装依赖,但前端构建结果会进入 API 目录:
|
||||
|
||||
```text
|
||||
WEB build → API/static/web/
|
||||
ADMIN build → API/static/admin/
|
||||
Go build → API/bin/jcf-api
|
||||
```
|
||||
|
||||
## 3. 技术栈
|
||||
|
||||
### 3.1 用户端和管理端
|
||||
|
||||
| 类别 | 技术 |
|
||||
| ------ | -------------------------------------------------------- |
|
||||
| 框架 | Vue 3 |
|
||||
| 语言 | TypeScript |
|
||||
| 构建 | Vite 5 |
|
||||
| 路由 | Vue Router 4 |
|
||||
| 状态 | Pinia |
|
||||
| 请求 | Axios |
|
||||
| 组件库 | Element Plus |
|
||||
| 图标 | Element Plus Icons;WEB 通过 `src/icons.ts` 提供语义映射 |
|
||||
| 图表 | ECharts,仅 WEB 使用 |
|
||||
| 样式 | SCSS、统一变量文件和全局样式 |
|
||||
|
||||
### 3.2 后端
|
||||
|
||||
| 类别 | 技术 |
|
||||
| ------------ | ------------------------------------------ |
|
||||
| 语言 | Go 1.26 |
|
||||
| HTTP 框架 | Gin |
|
||||
| ORM | GORM |
|
||||
| 数据库 | PostgreSQL 16 |
|
||||
| 队列 | Asynq |
|
||||
| 队列存储 | Redis 7 |
|
||||
| 对象存储 | AWS SDK v2,通过 S3 协议访问腾讯云 COS |
|
||||
| 身份认证 | JWT、随机 Refresh Token |
|
||||
| 密码哈希 | Argon2id |
|
||||
| 敏感配置加密 | AES-256-GCM |
|
||||
| 本地媒体处理 | FFmpeg、FFprobe、Python |
|
||||
|
||||
## 4. 前端总体架构
|
||||
|
||||
`WEB` 和 `ADMIN` 都遵循相同的基础分层:
|
||||
|
||||
```text
|
||||
main.ts
|
||||
├─ 注册 Pinia
|
||||
├─ 注册 Vue Router
|
||||
├─ 注册 Element Plus 中文语言包
|
||||
└─ 加载全局样式
|
||||
|
||||
views/ 路由级页面,负责编排业务页面
|
||||
layouts/ 页面整体框架、侧栏和内容区
|
||||
components/ 可复用展示和交互组件
|
||||
composables/ 跨组件复用的组合式逻辑
|
||||
features/ 按业务功能聚合的前端实现(按需使用)
|
||||
api/ Axios 实例及业务接口封装
|
||||
stores/ 登录态、提示消息和界面状态
|
||||
utils/ 时间、下载、媒体、计费展示等纯工具
|
||||
assets/ 图片、统一样式变量和全局样式
|
||||
icons.ts WEB 语义图标到 Element Plus Icons 的统一映射
|
||||
```
|
||||
|
||||
两个前端通过 Vite 动态导入路由页面,降低首次加载体积。API 请求均使用相对地址,开发环境由 Vite 代理,生产环境由 Nginx 代理,因此前端不保存后端服务器地址和第三方密钥。
|
||||
|
||||
### 4.1 样式组织
|
||||
|
||||
两个前端分别维护:
|
||||
|
||||
```text
|
||||
src/assets/styles/variables.scss
|
||||
src/assets/styles/main.scss
|
||||
```
|
||||
|
||||
- `variables.scss` 定义颜色、边框、圆角、间距等统一语义变量。
|
||||
- `main.scss` 放置全局重置、公共基础样式和组件库覆盖。
|
||||
- 页面或组件自身样式放在对应 `.vue` 的 scoped style 或同名样式文件中。
|
||||
- WEB 业务页面和组件的颜色均通过 `variables.scss` 中的语义令牌引用;ECharts 等 Canvas 场景先从 CSS 令牌读取实际色值。
|
||||
- WEB 当前不使用渐变色,也不在业务组件中直接散落十六进制或 `rgb/rgba` 色值。
|
||||
- 复杂组件按职责拆分样式。例如 `AssetPanel` 依次加载核心布局、媒体状态、预览覆盖和全局对话框主题文件。
|
||||
- 响应式布局主要通过统一断点下的媒体查询实现。
|
||||
|
||||
## 5. WEB 用户端
|
||||
|
||||
### 5.1 入口和地址
|
||||
|
||||
| 项目 | 值 |
|
||||
| --------- | ------------------------------------ |
|
||||
| 入口 | `WEB/src/main.ts` |
|
||||
| 路由 | `WEB/src/router/index.ts` |
|
||||
| API 前缀 | `/api/web` |
|
||||
| Vite base | `/` |
|
||||
| 构建输出 | `API/static/web` |
|
||||
| 开发端口 | 从 `127.0.0.1:5501` 开始选择可用端口 |
|
||||
|
||||
### 5.2 路由和业务页面
|
||||
|
||||
| 前端路由 | 页面 | 主要职责 |
|
||||
| ------------------------------------------------- | --------------------------------- | -------------------------------- |
|
||||
| `/login` | `LoginView.vue` | 用户登录 |
|
||||
| `/drama-projects` | `RedrawProjectsView.vue` | 短剧创作项目列表 |
|
||||
| `/drama-projects/:projectId` | `DramaProjectView.vue` | 短剧项目和剧集管理 |
|
||||
| `/drama-projects/:projectId/episodes/:episodeId` | `DramaWorkbenchView.vue` | 短剧分镜工作台 |
|
||||
| `/redraw-projects` | `RedrawProjectsView.vue` | 剧本反推项目列表 |
|
||||
| `/redraw-projects/:projectId` | `RedrawProjectView.vue` | 反推项目详情 |
|
||||
| `/redraw-projects/:projectId/episodes/:episodeId` | `RedrawWorkbenchView.vue` | 视频分析、字幕、反推与生成工作台 |
|
||||
| `/script-analysis` | `ScriptAnalysisView.vue` | 剧本分析列表 |
|
||||
| `/script-analysis/:scriptId` | `ScriptAnalysisWorkbenchView.vue` | 剧本分析处理页 |
|
||||
| `/account` | `AccountView.vue` | 个人资料、积分和消费记录 |
|
||||
|
||||
`RedrawProjectsView.vue` 通过路由元信息区分短剧创作和剧本反推列表,复用同一套项目列表逻辑。
|
||||
|
||||
### 5.3 主要组件
|
||||
|
||||
`WEB/src/components/creative/` 是创作工作台的公共组件区,主要包含:
|
||||
|
||||
- 项目创建和编辑对话框;
|
||||
- 素材面板、素材提示词编辑器;
|
||||
- 模型和提示词配置对话框;
|
||||
- 分镜时间线、任务状态和结果历史;
|
||||
- 视频播放器、视频对比和加载状态;
|
||||
- 剧本导入、剧本分析结果;
|
||||
- 反推来源、文本、剧本和素材面板。
|
||||
|
||||
其中 `AssetPanel.vue` 的样式按职责拆分为:
|
||||
|
||||
```text
|
||||
AssetPanel.core.scss 面板主体、资产卡片和编辑器基础布局
|
||||
AssetPanel.media.css 资产操作、历史记录和分镜媒体状态
|
||||
AssetPanel.preview.css 预览尺寸、缩放入口和播放器覆盖
|
||||
AssetPanel.dialog.css 非 scoped 的预览对话框全局主题
|
||||
```
|
||||
|
||||
这些文件保持固定加载顺序,同名选择器按该顺序形成稳定的覆盖关系。WEB 图标统一从 `@/icons` 语义映射或 `@element-plus/icons-vue` 引入,不再依赖 Lucide。
|
||||
|
||||
页面负责组合这些组件,公共请求和 URL 组装由 `WEB/src/api/creative.ts` 统一封装。
|
||||
|
||||
### 5.4 登录态和请求处理
|
||||
|
||||
用户端的认证数据保存在浏览器 `localStorage`:
|
||||
|
||||
```text
|
||||
web_access_token
|
||||
web_refresh_token
|
||||
web_profile
|
||||
```
|
||||
|
||||
请求流程:
|
||||
|
||||
1. Axios 请求拦截器读取 `web_access_token`,写入 `Authorization: Bearer ...`。
|
||||
2. 后端返回 401 时,前端使用 Refresh Token 请求 `/api/web/auth/refresh`。
|
||||
3. 同一时间只允许一个刷新请求,其余失败请求复用该 Promise。
|
||||
4. 刷新成功后重放原请求。
|
||||
5. 刷新失败后清理本地登录态并跳转登录页。
|
||||
|
||||
用户端还会在创建、分析、生成、取消任务后通知积分余额刷新;发现响应中仍有活动任务时会节流同步余额。
|
||||
|
||||
## 6. ADMIN 管理端
|
||||
|
||||
### 6.1 入口和地址
|
||||
|
||||
| 项目 | 值 |
|
||||
| --------- | ------------------------------------ |
|
||||
| 入口 | `ADMIN/src/main.ts` |
|
||||
| 路由 | `ADMIN/src/router/index.ts` |
|
||||
| API 前缀 | `/api/admin` |
|
||||
| Vite base | `/admin/` |
|
||||
| 构建输出 | `API/static/admin` |
|
||||
| 开发端口 | 从 `127.0.0.1:5500` 开始选择可用端口 |
|
||||
|
||||
### 6.2 页面职责
|
||||
|
||||
| 前端路由 | 页面 | 主要职责 |
|
||||
| ------------------- | --------------------- | ------------------------------------ |
|
||||
| `/login` | `LoginView.vue` | 管理员登录 |
|
||||
| `/redemption-codes` | `RedemptionsView.vue` | 兑换码批次和兑换码管理 |
|
||||
| `/styles` | `StylesView.vue` | 项目风格管理和排序 |
|
||||
| `/prompts` | `PromptsView.vue` | 系统提示词、历史版本和状态管理 |
|
||||
| `/channels` | `ChannelsView.vue` | 第三方渠道网址、密钥、汇率和并发限制 |
|
||||
| `/models` | `ModelsView.vue` | 渠道下的模型配置和价格管理 |
|
||||
| `/users` | `UsersView.vue` | 用户创建、批量操作、状态和积分管理 |
|
||||
| `/security` | `SecurityView.vue` | 管理员密码和安全操作 |
|
||||
|
||||
### 6.3 通用管理页面结构
|
||||
|
||||
- `AdminLayout.vue`:管理后台整体布局。
|
||||
- `AdminMenu.vue`:后台导航菜单。
|
||||
- `MasterDetailLayout.vue`:列表与详情编辑的公共布局。
|
||||
- `PageHeader.vue`:统一页面标题区。
|
||||
- `AdminNumberInput.vue`:统一数字输入行为。
|
||||
- `ChannelFormFields.vue`:渠道连接、密钥、汇率和并发限制表单。
|
||||
- `AppIcon.vue`:第三方图标库的统一封装。
|
||||
|
||||
渠道的完整 API Key 只在新增或主动更换时提交。查询渠道列表时,后端只返回掩码,不把完整密钥返回浏览器。
|
||||
|
||||
### 6.4 管理员认证和二次认证
|
||||
|
||||
管理端在 `localStorage` 保存:
|
||||
|
||||
```text
|
||||
admin_access_token
|
||||
admin_refresh_token
|
||||
admin_profile
|
||||
```
|
||||
|
||||
Access Token 过期后的刷新机制与 WEB 类似。创建兑换码批次等敏感操作还需要调用 `/api/admin/auth/reauth` 完成短时二次认证,随后通过 `X-Admin-Reauth-Token` 提交受保护请求。
|
||||
|
||||
## 7. 后端分层
|
||||
|
||||
后端入口是 `API/cmd/api/main.go`。启动时按依赖顺序完成配置加载、数据库连接、Redis 连接、安全组件、存储组件、Service、Handler、Worker 和 HTTP Server 组装。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Route["Gin Route"] --> Middleware["认证、CORS、Trace ID、Recovery"]
|
||||
Middleware --> Handler["handler:HTTP 参数和响应"]
|
||||
Handler --> Module["modules:独立业务模块公开接口"]
|
||||
Handler --> Service["service:共享业务规则和事务"]
|
||||
Module --> Service
|
||||
Module --> DB
|
||||
Service --> Model["model:领域数据结构"]
|
||||
Service --> DB["PostgreSQL / GORM"]
|
||||
Service --> Queue["Asynq Client"]
|
||||
Handler --> Storage["COS 文件流"]
|
||||
Queue --> Worker["worker:后台任务"]
|
||||
Worker --> DB
|
||||
Worker --> Provider["provider:第三方渠道协议"]
|
||||
Worker --> Storage
|
||||
```
|
||||
|
||||
### 7.1 后端目录职责
|
||||
|
||||
| 目录 | 职责 |
|
||||
| -------------------- | ------------------------------------------- |
|
||||
| `cmd/api/` | 进程入口、依赖组装、启动和优雅关闭 |
|
||||
| `internal/config/` | 读取并校验环境变量 |
|
||||
| `internal/server/` | Gin、路由、中间件、静态站点托管 |
|
||||
| `internal/handler/` | HTTP 参数解析、上传限制、状态码和响应 |
|
||||
| `internal/modules/` | 按业务边界组织的独立模块及公开 Service 接口 |
|
||||
| `internal/service/` | 业务规则、数据库事务、任务创建和资源删除 |
|
||||
| `internal/model/` | GORM 模型和领域数据结构 |
|
||||
| `internal/database/` | PostgreSQL 连接、空库基线和兼容初始化 |
|
||||
| `internal/cache/` | Redis 普通客户端 |
|
||||
| `internal/queue/` | Asynq 客户端、服务端和任务类型 |
|
||||
| `internal/worker/` | 生成、媒体分析、短剧解析、剧本分析任务 |
|
||||
| `internal/provider/` | 第三方渠道 HTTP 协议适配 |
|
||||
| `internal/storage/` | COS 对象存储封装 |
|
||||
| `internal/security/` | 密码哈希、JWT、Refresh Token、密钥加解密 |
|
||||
| `internal/billing/` | 任务计费、积分预扣、结算和退款 |
|
||||
| `internal/drama/` | 短剧文本内容处理 |
|
||||
| `internal/media/` | 媒体命名等公共规则 |
|
||||
| `internal/datetime/` | Asia/Shanghai 时间语义 |
|
||||
| `workers/` | Python 本地语音识别脚本 |
|
||||
| `migrations/` | 正式环境增量数据库迁移 |
|
||||
| `static/` | WEB 和 ADMIN 构建产物 |
|
||||
|
||||
### 7.2 独立业务模块
|
||||
|
||||
后端包含两个独立业务模块目录,并在 `cmd/api/main.go` 完成依赖装配:
|
||||
|
||||
| 模块 | 目录 | 对外职责 |
|
||||
| ---------- | -------------------------- | ---------------------------------------------------------------------- |
|
||||
| 管理业务 | `internal/modules/admin/` | 模型列表与保存、文本模型计费校验、兑换码查询与批量生成、管理员操作审计 |
|
||||
| 提示词业务 | `internal/modules/prompt/` | 系统提示词与版本历史、用户提示词查询和选择、自定义提示词增删改 |
|
||||
|
||||
调用关系如下:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Main["cmd/api/main.go"] --> AdminModule["modules/admin.Service"]
|
||||
Main --> PromptModule["modules/prompt.Service"]
|
||||
AdminHandler["handler/AdminData"] --> AdminModule
|
||||
AdminHandler --> PromptModule
|
||||
CreativeHandler["handler/Creative"] --> PromptModule
|
||||
AdminModule --> DB["GORM / PostgreSQL"]
|
||||
PromptModule --> DB
|
||||
```
|
||||
|
||||
模块通过构造函数接收数据库依赖,并使用明确的参数、返回值和错误类型对外提供能力。Handler 通过模块公开接口调用业务能力,模块测试位于各自目录的 `service_test.go`。
|
||||
|
||||
### 7.3 Handler、Service、Worker 边界
|
||||
|
||||
Handler 负责:
|
||||
|
||||
- 读取路径、Query、JSON 和 multipart 参数;
|
||||
- 验证文件体积和基础输入格式;
|
||||
- 从认证上下文取得用户或管理员;
|
||||
- 调用 Service;
|
||||
- 统一输出 HTTP 状态码、错误码和 Trace ID。
|
||||
|
||||
当前 `internal/handler/` 已不再通过 `h.service.DB`、`h.data.DB` 或同类入口直接执行 GORM 查询和事务。重绘、剧集和资产媒体上传所需的目标校验、记录写入、旧媒体缓存及记录清理由 `internal/service/creative_media.go` 统一提供。
|
||||
|
||||
Service 负责:
|
||||
|
||||
- 业务权限和资源归属判断;
|
||||
- 项目、剧集、素材、分镜和任务规则;
|
||||
- 数据库事务和行锁;
|
||||
- 积分预扣、结算或退款;
|
||||
- 创建持久任务并发送 Asynq 唤醒消息。
|
||||
|
||||
Worker 负责:
|
||||
|
||||
- 从 PostgreSQL 重新读取任务和配置快照;
|
||||
- 调用第三方渠道;
|
||||
- 轮询异步结果;
|
||||
- 下载结果并写入 COS;
|
||||
- 执行本地 FFmpeg、FFprobe 和 Python 处理;
|
||||
- 持久化任务状态、输出和计费结果;
|
||||
- 服务重启后恢复运行中的持久任务。
|
||||
|
||||
## 8. HTTP API 架构
|
||||
|
||||
### 8.1 API 分区
|
||||
|
||||
| 前缀 | 使用方 | 认证 |
|
||||
| ------------------- | -------------------------------- | ------------------------------- |
|
||||
| `/health` | 运维健康检查 | 无 |
|
||||
| `/api/web/health` | WEB 健康检查 | 无 |
|
||||
| `/api/web/auth/*` | 用户登录、刷新、退出 | 登录接口无 Access Token |
|
||||
| `/api/web/*` | 用户账户和创作业务 | Web JWT |
|
||||
| `/api/admin/health` | ADMIN 健康检查 | 无 |
|
||||
| `/api/admin/auth/*` | 管理员登录、刷新、退出和二次认证 | 按接口区分 |
|
||||
| `/api/admin/*` | 后台资源管理 | Admin JWT,敏感接口增加二次认证 |
|
||||
|
||||
### 8.2 通用中间件
|
||||
|
||||
Gin 全局中间件顺序包括:
|
||||
|
||||
1. Trace ID:复用请求的 `X-Request-ID`,没有时生成 UUID,并写回响应头。
|
||||
2. 开发日志:仅 `DEBUG=true` 时启用 Gin Logger。
|
||||
3. Recovery:捕获未处理 panic。
|
||||
4. CORS:仅允许 `CORS_ORIGINS` 中明确配置的来源。
|
||||
|
||||
HTTP Server 主要超时:
|
||||
|
||||
| 配置 | 时间 |
|
||||
| ------------------- | ------ |
|
||||
| Read Header Timeout | 5 秒 |
|
||||
| Read Timeout | 30 秒 |
|
||||
| Write Timeout | 5 分钟 |
|
||||
| Idle Timeout | 60 秒 |
|
||||
| 优雅关闭等待 | 10 秒 |
|
||||
|
||||
长时间生成任务不会占用一个 HTTP 请求等待完成。HTTP 接口只创建任务,页面通过任务查询接口获取进度。
|
||||
|
||||
## 9. 身份认证和安全
|
||||
|
||||
### 9.1 用户和管理员隔离
|
||||
|
||||
用户和管理员使用不同的数据表、Token Claims、接口前缀和前端存储键:
|
||||
|
||||
| 类型 | 账号表 | Refresh Token 表 | Access Token 类型 |
|
||||
| ------ | ------------- | ---------------------- | ----------------- |
|
||||
| 用户 | `web_users` | `web_refresh_tokens` | `web_access` |
|
||||
| 管理员 | `admin_users` | `admin_refresh_tokens` | `access` |
|
||||
|
||||
- 密码使用 Argon2id 哈希,不保存明文。
|
||||
- Access Token 使用 JWT HS256 签名。
|
||||
- Refresh Token 使用加密安全随机数生成,数据库只保存哈希。
|
||||
- 管理员二次认证令牌有效期为 5 分钟。
|
||||
- 渠道 API Key 使用 `CONFIG_ENCRYPTION_KEY` 进行 AES-256-GCM 加密。
|
||||
|
||||
### 9.2 请求追踪
|
||||
|
||||
前后端错误处理会携带或展示:
|
||||
|
||||
```text
|
||||
错误码
|
||||
错误描述
|
||||
X-Request-ID / trace_id
|
||||
```
|
||||
|
||||
运维使用请求追踪 ID 对照 API 日志定位请求。第三方响应体限制长度后进入错误信息,日志不记录认证请求头和密钥。
|
||||
|
||||
## 10. 异步任务架构
|
||||
|
||||
### 10.1 任务类型
|
||||
|
||||
Asynq 当前注册的任务包括:
|
||||
|
||||
| 队列任务 | 处理器 | 用途 |
|
||||
| ----------------------- | ---------------------- | ---------------------------------- |
|
||||
| `ai:dispatch-channel` | Generation Worker | 按渠道和用户并发限制选取待提交任务 |
|
||||
| `ai:submit-task` | Generation Worker | 向第三方渠道提交生成任务 |
|
||||
| `ai:poll-task` | Generation Worker | 轮询第三方异步任务 |
|
||||
| `ai:download-task` | Generation Worker | 下载完成结果并写入 COS |
|
||||
| `media:analyze-episode` | Media Worker | 视频探测、抽帧、语音识别和内容反推 |
|
||||
| `drama:parse-episode` | Drama Parse Worker | 解析剧集文本并形成结构化内容 |
|
||||
| `script:analyze` | Script Analysis Worker | 执行剧本分析任务 |
|
||||
|
||||
队列名称主要为 `ai`,Asynq Worker 并发数由 `AI_WORKER_CONCURRENCY` 控制。
|
||||
|
||||
### 10.2 生成任务状态流
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> pending_submission
|
||||
pending_submission --> submitting: 调度器取得渠道槽位
|
||||
submitting --> submitted: 上游返回任务 ID
|
||||
submitting --> result_ready: 上游直接返回结果 URL
|
||||
submitting --> submit_unknown: 无法确认提交结果
|
||||
submitted --> processing: 轮询仍在处理
|
||||
processing --> result_ready: 上游完成
|
||||
result_ready --> downloading
|
||||
downloading --> succeeded: COS 持久化成功
|
||||
pending_submission --> cancelled
|
||||
submitted --> cancel_requested
|
||||
processing --> cancel_requested
|
||||
cancel_requested --> cancelled
|
||||
submitting --> failed
|
||||
submitted --> failed
|
||||
processing --> failed
|
||||
downloading --> failed
|
||||
```
|
||||
|
||||
实际状态更新以 PostgreSQL `generation_tasks` 为准。Redis 中的 Asynq 任务只负责唤醒处理逻辑,Redis 队列长度不代表业务任务状态。
|
||||
|
||||
### 10.3 持久任务流程
|
||||
|
||||
1. WEB 发起分析或生成请求。
|
||||
2. Service 在 PostgreSQL 事务中校验用户、项目、渠道、配置和积分。
|
||||
3. 创建 `generation_tasks` 等持久任务记录,必要时预扣积分。
|
||||
4. 向 Redis/Asynq 写入轻量任务 ID。
|
||||
5. Worker 根据 ID 回查 PostgreSQL,完整业务快照保存在 PostgreSQL。
|
||||
6. 调度器使用数据库锁和 `SKIP LOCKED` 控制多 Worker 竞争,并执行渠道总并发、单用户并发限制。
|
||||
7. Worker 解密渠道密钥并提交第三方请求。
|
||||
8. 异步上游由轮询任务持续更新状态;直接结果跳过轮询。
|
||||
9. 完成后将结果下载到本地临时文件,再上传 COS。
|
||||
10. 在数据库事务中创建 `generation_outputs`、更新分镜或素材的活动输出并结算积分。
|
||||
11. 失败或取消时按业务规则退款、保留预扣或记录错误。
|
||||
|
||||
### 10.4 重启恢复
|
||||
|
||||
Go 进程启动时会执行恢复逻辑:
|
||||
|
||||
- 找出 `pending_submission` 任务,重新唤醒渠道调度;
|
||||
- 找出 `submitted`、`processing` 和部分 `cancel_requested` 任务,恢复轮询;
|
||||
- 找出 `result_ready`、`downloading` 任务,恢复结果下载;
|
||||
- 把中断的剧本分析处理状态恢复到可重新消费状态;
|
||||
- 恢复短剧解析任务。
|
||||
|
||||
因此 PostgreSQL 中的任务记录是恢复依据。Redis 清理或状态变化不改变 PostgreSQL 中持久化的业务任务状态。
|
||||
|
||||
## 11. 数据库架构
|
||||
|
||||
### 11.1 数据领域
|
||||
|
||||
| 领域 | 主要数据表 |
|
||||
| ------------ | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| 管理员安全 | `admin_users`、`admin_refresh_tokens`、`admin_audit_logs` |
|
||||
| 用户账户 | `web_users`、`web_refresh_tokens` |
|
||||
| 积分和兑换 | `point_ledger`、`point_grants`、`point_ledger_allocations`、`point_packages`、`redemption_batches`、`redemption_codes` |
|
||||
| 渠道和模型 | `channels`、`channel_balance_snapshots`、`models`、`model_prices`、`user_model_configs`、`project_model_configs` |
|
||||
| 提示词和风格 | `prompts`、`user_prompt_preferences`、`project_styles` |
|
||||
| 创作项目 | `creative_projects`、`project_episodes`、`project_assets`、`episode_storyboards`、`episode_sources` |
|
||||
| 短剧解析 | `drama_import_sessions`、`drama_parse_batches`、`drama_parse_tasks`、`episode_continuity_contexts` |
|
||||
| 生成任务 | `generation_tasks`、`generation_outputs` |
|
||||
| 剧本分析 | `script_analyses`、`script_analysis_characters` |
|
||||
| 媒体 | `media_assets`、`channel_asset_cache` |
|
||||
| 其他运营 | `announcements`、`payment_configs`、`recharge_orders`、`inspiration_gallery_items` 等 |
|
||||
|
||||
### 11.2 数据库初始化和迁移
|
||||
|
||||
数据库结构有三个相关机制:
|
||||
|
||||
1. 空库基线:`API/internal/database/schema.sql` 通过 `go:embed` 编译进二进制。数据库完全没有业务表时,API 启动会在事务中执行该基线。
|
||||
2. 缺表补全:启动时只对不存在的 GORM 模型表执行 `AutoMigrate`,不会依赖 AutoMigrate 修改已有表的全部结构。
|
||||
3. 增量迁移:生产部署脚本按文件名执行 `API/migrations/*.up.sql`,成功后记录在 `jcf_schema_migrations`。
|
||||
|
||||
`internal/database/postgres.go` 还包含旧安装兼容 DDL。数据库结构由 GORM Model、空库基线和增量迁移共同表达,部署脚本负责执行正式迁移。
|
||||
|
||||
### 11.3 数据库连接语义
|
||||
|
||||
- 时区固定为 `Asia/Shanghai`。
|
||||
- GORM 最大连接数为 20,最大空闲连接数为 5。
|
||||
- 单连接最长复用时间为 30 分钟。
|
||||
- 启动时先 Ping PostgreSQL,连接失败则整个进程退出。
|
||||
|
||||
## 12. Redis 和队列
|
||||
|
||||
Redis 使用两个逻辑 DB:
|
||||
|
||||
| 配置 | 默认值 | 用途 |
|
||||
| ---------------- | ------ | --------------------------- |
|
||||
| `REDIS_DB` | `0` | 普通 Redis 客户端和健康检查 |
|
||||
| `ASYNQ_REDIS_DB` | `1` | Asynq 队列 |
|
||||
|
||||
API 启动时会同时检查 PostgreSQL 和 Redis。任一基础依赖无法连接,服务不会继续启动。
|
||||
|
||||
Redis 数据用于队列和调度,PostgreSQL 保存任务真实状态、租约、上游任务 ID、错误和计费结果。
|
||||
|
||||
## 13. 媒体和对象存储
|
||||
|
||||
### 13.1 COS 存储职责
|
||||
|
||||
COS 保存:
|
||||
|
||||
- 用户头像和上传素材;
|
||||
- 视频源文件、字幕、音频;
|
||||
- 视频抽帧和缩略图;
|
||||
- 本地识别结果;
|
||||
- 第三方原始响应;
|
||||
- 图片和视频生成结果。
|
||||
|
||||
PostgreSQL 的 `media_assets` 保存对象键、公开 URL、MIME、大小、SHA-256、显示名称和归属关系,不把大文件二进制放入数据库。
|
||||
|
||||
### 13.2 本地媒体处理
|
||||
|
||||
Media Worker 调用:
|
||||
|
||||
- FFprobe:读取时长、分辨率等媒体信息;
|
||||
- FFmpeg:抽帧、提取音频和其他媒体转换;
|
||||
- Python 脚本:执行本地语音识别;
|
||||
- 第三方渠道:执行文本或视觉内容反推;
|
||||
- COS:持久化中间产物和最终结果。
|
||||
|
||||
临时文件处理完成后清理,长期资源进入 COS,并在数据库保留元数据。
|
||||
|
||||
## 14. 第三方渠道适配
|
||||
|
||||
渠道基础网址和 API Key 由 ADMIN 保存到 `channels` 表,具体业务模型配置保存在 `models` 表。渠道密钥以 AES-256-GCM 密文保存,只有 Worker 调用时解密。
|
||||
|
||||
`internal/provider/apimart/` 负责统一的渠道 HTTP 协议:
|
||||
|
||||
- Bearer Token 认证;
|
||||
- 文本请求;
|
||||
- 图片任务提交;
|
||||
- 视频任务提交;
|
||||
- 异步任务查询;
|
||||
- 渠道余额查询;
|
||||
- 上游错误码、`Retry-After` 和响应体截断。
|
||||
|
||||
Service 和 Worker 通过 `internal/provider` 中的适配器访问第三方接口。
|
||||
|
||||
## 15. 计费和积分
|
||||
|
||||
计费逻辑集中在 `internal/billing/`,而不是由前端计算最终扣费:
|
||||
|
||||
- 前端只展示估算价格和积分余额;
|
||||
- Service 创建任务时计算预估积分并按规则预扣;
|
||||
- Worker 从第三方响应或任务结果取得实际用量;
|
||||
- 任务完成时结算,多退少补按现有业务规则执行;
|
||||
- 失败、取消和上游状态不确定分别使用不同处理规则;
|
||||
- `point_ledger` 保存流水,`point_grants` 和分配表支持永久积分批次的顺序扣减及原批次退款;
|
||||
|
||||
扣款、退款、任务终态和输出激活操作在数据库事务中执行,结算以后端持久数据为依据。
|
||||
|
||||
## 16. 静态文件和部署架构
|
||||
|
||||
### 16.1 开发环境
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
WebDev["WEB Vite"] -->|"/api 代理"| Go["Go API :8123"]
|
||||
AdminDev["ADMIN Vite"] -->|"/api 代理"| Go
|
||||
Go --> PG["Docker PostgreSQL :25432"]
|
||||
Go --> Redis["Docker Redis :26379"]
|
||||
```
|
||||
|
||||
- `docker-compose.yml` 只启动 PostgreSQL 和 Redis。
|
||||
- Go API 直接在 Windows 运行。
|
||||
- WEB 和 ADMIN 分别运行 Vite 开发服务器。
|
||||
- 当前两个 Vite 配置都把 `/api` 代理到 `127.0.0.1:8123`。
|
||||
|
||||
### 16.2 生产环境
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Internet["公网请求"] --> Nginx["Nginx :80/:443"]
|
||||
Nginx -->|"静态文件"| Static["/opt/juyou_ai/static"]
|
||||
Nginx -->|"API / Health"| Service["juyou_ai :8123"]
|
||||
Service --> PG["本机 PostgreSQL"]
|
||||
Service --> Redis["本机 Redis"]
|
||||
```
|
||||
|
||||
- API 只监听 `127.0.0.1:8123`,不直接暴露公网。
|
||||
- Nginx 提供 WEB 根路径和 `/admin/` 静态站点。
|
||||
- `/api/`、`/health` 等请求反向代理到 Go API。
|
||||
- systemd 服务名为 `juyou_ai`。
|
||||
- 环境文件位于 `/etc/juyou_ai/juyou_ai.env`。
|
||||
- Go 自身也具备静态文件托管能力,适合本地或没有 Nginx 的场景;生产环境主要由 Nginx 直接提供静态文件。
|
||||
|
||||
## 17. 配置边界
|
||||
|
||||
后端配置统一来自 `API/.env` 或生产环境文件,主要分为:
|
||||
|
||||
| 配置组 | 内容 |
|
||||
| ---------- | ------------------------------------------------ |
|
||||
| 应用 | 运行环境、Debug、监听地址、静态目录 |
|
||||
| PostgreSQL | 主机、端口、库名、用户、密码或完整 URL |
|
||||
| Redis | 主机、端口、密码、普通 DB、Asynq DB |
|
||||
| JWT | 签名密钥和 Token 有效期 |
|
||||
| 管理员引导 | 首次管理员账号和密码 |
|
||||
| 密码哈希 | Argon2 参数 |
|
||||
| 敏感配置 | 渠道密钥加密主密钥和版本 |
|
||||
| COS | Region、Endpoint、Bucket、SecretId、SecretKey、公开域名、体积限制 |
|
||||
| Worker | 并发、轮询间隔、HTTP 连接池、本地工具路径 |
|
||||
| CORS | 允许访问 API 的前端来源 |
|
||||
|
||||
前端运行时不保存 COS SecretKey、渠道 API Key、数据库密码或 JWT Secret。浏览器只接收 API 输出的非敏感展示数据。
|
||||
|
||||
## 18. 测试与验证
|
||||
|
||||
### 18.1 后端测试
|
||||
|
||||
后端测试文件与实现同目录,覆盖计费、数据库基线、文本解析、Provider、Service、业务模块、Storage 和 Worker。`internal/modules/admin` 与 `internal/modules/prompt` 均包含模块级测试。运行:
|
||||
|
||||
```bash
|
||||
cd API
|
||||
go test ./...
|
||||
```
|
||||
|
||||
涉及真实数据库的基线测试通过专用环境变量启用,默认不会连接生产数据库。
|
||||
|
||||
### 18.2 前端验证
|
||||
|
||||
两个前端的构建命令都会先执行 TypeScript/Vue 类型检查:
|
||||
|
||||
```bash
|
||||
npm --prefix WEB run build
|
||||
npm --prefix ADMIN run build
|
||||
```
|
||||
|
||||
格式检查:
|
||||
|
||||
```bash
|
||||
npm --prefix WEB run format:check
|
||||
npm --prefix ADMIN run format:check
|
||||
```
|
||||
|
||||
### 18.3 健康检查
|
||||
|
||||
```text
|
||||
GET /health
|
||||
GET /api/web/health
|
||||
GET /api/admin/health
|
||||
```
|
||||
|
||||
健康检查会同时验证 PostgreSQL 和 Redis 连接。
|
||||
Reference in New Issue
Block a user