239 lines
7.1 KiB
Markdown
239 lines
7.1 KiB
Markdown
# Opentu 二开指南
|
||
|
||
本文面向准备自部署、换成自有 API 中转站、继续开发 Opentu 的团队。
|
||
|
||
## 项目介绍
|
||
|
||
Opentu 是一个以画布为中心的 AI 创作平台。它把白板、流程图、思维导图、素材库、任务队列、PPT/Markdown/Mermaid 转换,以及图片、视频、音频、文本等 AI 生成能力整合在同一个工作区里。
|
||
|
||
核心价值是:用户不需要在多个工具之间复制内容,AI 生成结果、素材、任务状态和知识内容都可以沉淀在画布上继续编辑。
|
||
|
||
## 技术栈
|
||
|
||
- Monorepo:Nx workspace
|
||
- 包管理:pnpm
|
||
- Web 应用:React 18 + Vite
|
||
- UI/画布:Plait、TDesign React、自研 drawnix 包
|
||
- 本地存储:localStorage / IndexedDB,API Key 等敏感配置由设置管理器统一处理
|
||
- 构建产物:`dist/apps/web`
|
||
- PWA:`apps/web/vite.sw.config.ts` 构建 Service Worker
|
||
|
||
## 目录结构
|
||
|
||
```text
|
||
apps/web/ # Web 入口、Vite 配置、public 静态资源、Service Worker
|
||
packages/drawnix/ # 画布、AI 工具、设置弹窗、供应商路由、任务队列等主逻辑
|
||
packages/react-board/ # Plait React 画布适配
|
||
packages/react-text/ # 文本渲染组件
|
||
packages/utils/ # 通用工具
|
||
docs/ # 开发与部署文档
|
||
scripts/ # 版本、发布、构建辅助脚本
|
||
```
|
||
|
||
## 本地开发
|
||
|
||
环境要求:
|
||
|
||
```bash
|
||
node --version # 需要 Node.js 20+
|
||
pnpm --version # 推荐 pnpm 10.x
|
||
```
|
||
|
||
安装依赖:
|
||
|
||
```bash
|
||
NPM_TOKEN=dummy PNPM_HOME=.pnpm-home PNPM_STORE_DIR=.pnpm-store pnpm install --frozen-lockfile
|
||
```
|
||
|
||
本仓库的 `package.json` 声明了 `pnpm@10.21.0`。如果本机 pnpm 版本不同,pnpm 10 可能会尝试自动切换包管理器版本,导致本地递归安装。已在 `.npmrc` 中加入:
|
||
|
||
```ini
|
||
manage-package-manager-versions=false
|
||
```
|
||
|
||
启动开发服务:
|
||
|
||
```bash
|
||
NPM_TOKEN=dummy NX_DAEMON=false pnpm start
|
||
```
|
||
|
||
默认访问:
|
||
|
||
```text
|
||
http://localhost:7200
|
||
```
|
||
|
||
如果 Nx daemon 因本地权限无法启动,保留 `NX_DAEMON=false`。如果只想绕过 Nx 直启 Web:
|
||
|
||
```bash
|
||
cd apps/web
|
||
../../node_modules/.bin/vite serve --host 127.0.0.1 --port 7200
|
||
```
|
||
|
||
## 构建与部署
|
||
|
||
生产构建:
|
||
|
||
```bash
|
||
NPM_TOKEN=dummy NX_DAEMON=false pnpm build:web
|
||
```
|
||
|
||
构建完成后静态文件在:
|
||
|
||
```text
|
||
dist/apps/web
|
||
```
|
||
|
||
部署方式:
|
||
|
||
- 静态托管:把 `dist/apps/web` 部署到 Nginx、Vercel、Netlify、Cloudflare Pages 等。
|
||
- Docker:仓库根目录已有 `Dockerfile`,会执行 `pnpm install --frozen-lockfile && pnpm build`,然后用静态网站镜像托管 `dist/apps/web`。
|
||
- CDN 混合部署:参考 `docs/NPM_CDN_DEPLOY.md` 和 `docs/CDN_DEPLOYMENT.md`。
|
||
|
||
## API 供应商与 Key 绑定
|
||
|
||
当前默认供应商已对接 `https://truemodel.benchu.cloud/`。用户实际输入的 API Key 不写死在代码里,而是通过设置弹窗保存到浏览器本地配置,并同步给 Service Worker 任务队列使用。
|
||
|
||
主要配置入口:
|
||
|
||
```text
|
||
packages/drawnix/src/utils/settings-manager.ts
|
||
```
|
||
|
||
关键常量:
|
||
|
||
```ts
|
||
TUZI_PROVIDER_DEFAULT_BASE_URL = 'https://truemodel.benchu.cloud/';
|
||
TUZI_DEFAULT_PROVIDER_NAME = 'TrueModel';
|
||
```
|
||
|
||
TrueModel 中转站按 OpenAI 兼容方式接入,Base URL 使用:
|
||
|
||
```text
|
||
https://truemodel.benchu.cloud/
|
||
```
|
||
|
||
浏览器实际发起请求时会自动走同源代理:
|
||
|
||
```text
|
||
/api/truemodel/v1
|
||
```
|
||
|
||
这样可以绕开中转站没有开放浏览器 CORS 的问题。用户界面里仍然展示和保存 `https://truemodel.benchu.cloud/`,代理只影响运行时请求地址。
|
||
|
||
供应商类型选择:
|
||
|
||
```text
|
||
providerType: openai-compatible
|
||
authType: bearer
|
||
```
|
||
|
||
也就是说用户绑定 key 后,请求会以:
|
||
|
||
```http
|
||
Authorization: Bearer 用户填写的key
|
||
```
|
||
|
||
发送到 TrueModel 中转站。
|
||
|
||
## 同源代理与 CORS
|
||
|
||
浏览器直接请求 `https://truemodel.benchu.cloud/models` 时,如果中转站没有返回 `Access-Control-Allow-Origin`,会被 CORS 拦截。当前项目已内置同源代理:
|
||
|
||
- 本地开发:`apps/web/vite.config.ts` 把 `/api/truemodel/*` 代理到 `https://truemodel.benchu.cloud/*`。
|
||
- Vercel:`vercel.json` 已增加 `/api/truemodel/:path*` rewrite。
|
||
- Netlify:`netlify.toml` 与 `apps/web/public/_redirects` 已增加 `/api/truemodel/*` proxy。
|
||
- 其他自托管:需要在 Nginx、Caddy 或你的后端里配置同样的反向代理。
|
||
|
||
Nginx 示例:
|
||
|
||
```nginx
|
||
location /api/truemodel/ {
|
||
proxy_pass https://truemodel.benchu.cloud/;
|
||
proxy_set_header Host truemodel.benchu.cloud;
|
||
proxy_set_header Authorization $http_authorization;
|
||
proxy_ssl_server_name on;
|
||
}
|
||
```
|
||
|
||
## TrueModel 对接点
|
||
|
||
默认 Base URL:
|
||
|
||
```text
|
||
packages/drawnix/src/utils/settings-manager.ts
|
||
```
|
||
|
||
```ts
|
||
export const TUZI_PROVIDER_DEFAULT_BASE_URL = 'https://truemodel.benchu.cloud/';
|
||
```
|
||
|
||
注册和领 Key 引导:
|
||
|
||
```text
|
||
packages/drawnix/src/components/settings-dialog/settings-dialog.tsx
|
||
packages/drawnix/src/utils/gemini-api/auth.ts
|
||
```
|
||
|
||
当前指向:
|
||
|
||
```text
|
||
https://truemodel.benchu.cloud
|
||
```
|
||
|
||
内置 iframe 工具透传接口地址:
|
||
|
||
```text
|
||
packages/drawnix/src/tools/built-in-manifests.tsx
|
||
```
|
||
|
||
当前 Chat-MJ 工具 URL 中包含:
|
||
|
||
```text
|
||
https://truemodel.benchu.cloud
|
||
```
|
||
|
||
后续需要重点检查模型能力。
|
||
|
||
Opentu 不只是聊天应用,还会调用图片、视频、音频等生成接口。你的 sub2api 至少需要确认:
|
||
|
||
- `/v1/models` 是否可用,影响模型发现。
|
||
- `/v1/chat/completions` 是否可用,影响文本和 Agent。
|
||
- `/v1/images/generations`、`/v1/images/edits` 是否可用,影响出图和修图。
|
||
- 视频、音乐、异步任务接口是否兼容当前供应商协议;不兼容时要在 `packages/drawnix/src/services/provider-routing/` 增加 binding/adapter。
|
||
|
||
## 用户绑定方式
|
||
|
||
用户可以在应用内打开设置,进入供应商配置,填写:
|
||
|
||
```text
|
||
API 地址: https://truemodel.benchu.cloud/
|
||
API Key: 用户自己的TrueModel key
|
||
```
|
||
|
||
也可以通过 URL 预填配置:
|
||
|
||
```text
|
||
https://你的站点/?settings={"url":"https://truemodel.benchu.cloud/","key":"用户key"}
|
||
```
|
||
|
||
项目会读取 `settings` 参数,写入本地设置后从地址栏移除参数。生产环境不建议长期通过 URL 传 key,只适合首次导入或内部测试。
|
||
|
||
## 后续二开重点
|
||
|
||
- 品牌替换:`README.md`、`apps/web/public/logo*`、`apps/web/public/manifest.json`、`apps/web/public/home.html`。
|
||
- 默认供应商:`settings-manager.ts` 里的默认 profiles 和 presets。
|
||
- 设置弹窗文案:`settings-dialog.tsx` 与 `i18n.tsx`。
|
||
- 模型路由:`packages/drawnix/src/services/provider-routing/`。
|
||
- 具体模型适配:`packages/drawnix/src/services/model-adapters/`、`audio-api-service.ts`、`video-api-service.ts`、`media-api/`。
|
||
- 工具箱:`packages/drawnix/src/tools/` 与 `components/toolbox-drawer/`。
|
||
- PWA 缓存:`apps/web/vite.sw.config.ts`、`apps/web/public/sw-debug/`。
|
||
|
||
## 本次本地验证记录
|
||
|
||
- 已 clone 到 `/Users/jammy/jstudio/opentu`。
|
||
- 已完成依赖安装。
|
||
- 已执行 `NPM_TOKEN=dummy NX_DAEMON=false pnpm build:web`,构建成功。
|
||
- 已通过直启 Vite 方式运行在 `http://127.0.0.1:7200/`。
|
||
- 已验证 `/api/truemodel/v1/models` 代理可转发到 TrueModel 模型接口。
|