release: v0.68.0

## Features
- 版本升级至 0.68.0

## Fixes
- 修复 EmptyState 组件标题排版问题
- 修复"开始生成"按钮文字换行问题
- 修复加载历史对话失败问题
  - 修复 parse_message_content 保留 ContentPart 结构
  - 修复 convert_agent_message 添加 reasoning_content 处理
  - 修复 WorkspaceType::from_str 命名冲突,重命名为 parse

## Code Quality
- 修复所有 clippy 警告
  - 修复 manual_flatten 警告
  - 修复 ptr_arg 警告(使用 &Path 替代 &PathBuf)
  - 修复 manual_clamp 警告
  - 修复 match_single_binding 警告
- 所有测试通过 (174 passed)
This commit is contained in:
coso
2026-02-16 20:58:55 +08:00
parent ec9db9f0f6
commit 7851c34bed
71 changed files with 1715 additions and 4914 deletions
+102 -26
View File
@@ -2,23 +2,98 @@
# ProxyCast 🚀
**AI Agent 创作工具平台**
**创作类 AI Agent 平台**
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Tauri](https://img.shields.io/badge/Tauri-2.0-blue.svg)](https://tauri.app/)
[![React](https://img.shields.io/badge/React-18-61dafb.svg)](https://react.dev/)
[![Rust](https://img.shields.io/badge/Rust-1.70+-orange.svg)](https://www.rust-lang.org/)
一句话:把灵感、写作、出图、改稿、沉淀放进同一个工作台,让创作从“想到”直接走到“可发布”。
</div>
---
## ✨ 核心特性
## 👋 这是什么
- **多 Provider 统一管理** - 支持 Kiro、Gemini、通义千问、Antigravity、Vertex AI 等多种 AI 服务
- **智能凭证管理** - 自动检测凭证变化、Token 自动刷新、配额超限自动切换
- **完整 API 兼容** - 支持 OpenAI Chat API 和 Anthropic Messages API
- **友好图形界面** - Dashboard 监控、Provider 管理、日志查看
ProxyCast 是面向普通创作者的 AI Agent 平台。
你不需要先懂复杂设置,只要带着一个想法进来,就可以在同一处完成:
- 和 Agent 对话定方向
- 生成内容与素材
- 继续迭代修改
- 把结果沉淀成可复用资产
---
## 🧩 支持的创作主题
你可以按创作目标选择主题,也可以跨主题组合使用。
1. **通用对话**:灵感发散、问题梳理、快速头脑风暴
2. **社媒内容**:选题、标题、正文、多平台改写
3. **图文海报**:主视觉文案、配图方向、海报内容生成
4. **歌词曲谱**:歌词起稿、段落续写、风格改编
5. **知识探索**:知识点拆解、结构化总结、学习卡片
6. **计划规划**:目标分解、执行节奏、阶段复盘
7. **办公文档**:报告、方案、邮件、会议纪要整理
8. **短视频**:脚本结构、分镜思路、口播文案生成
9. **小说创作**:设定、章节推进、人物对白与续写
---
## 📖 创作场景(不止一种)
### 场景 1:社媒日更
- 场景:每天都要稳定发内容,但选题和表达容易重复。
- 动作:先让 Agent 给出 3 个方向,再选一个生成多版文案与配图思路。
- 结果:当天可直接发布,同时保留素材供后续复用。
### 场景 2:短视频起号
- 场景:有想法但脚本总是“有点散”。
- 动作:用主题工作流先拆结构,再生成口播稿和镜头节奏。
- 结果:从模糊创意变成可拍摄脚本,沟通成本显著降低。
### 场景 3:小说连载
- 场景:长期连载容易设定冲突、节奏断档。
- 动作:在同一项目里持续积累世界观、人物设定和章节草稿。
- 结果:剧情连贯性更强,更新更稳定。
### 场景 4:活动海报与图文
- 场景:活动上线前要快速产出多套视觉方向。
- 动作:先生成文案方向,再出图并按参考图持续迭代。
- 结果:方案选择更快,历史版本可追溯、可复用。
### 场景 5:歌词创作
- 场景:有旋律或主题,但歌词总卡在中段。
- 动作:让 Agent 先给主副歌框架,再逐段续写与改写。
- 结果:成稿速度更快,风格更统一。
### 场景 6:知识内容输出
- 场景:学了很多但难以整理成可分享内容。
- 动作:把资料整理成结构化要点,再输出为卡片或长文。
- 结果:输入和输出形成闭环,知识更容易长期积累。
### 场景 7:计划执行
- 场景:目标很大,但每天不知道先做什么。
- 动作:把目标拆成周计划与日任务,并按进度复盘调整。
- 结果:执行路径清晰,可持续推进。
### 场景 8:办公写作
- 场景:报告、邮件、方案反复改,耗时高。
- 动作:先生成初稿,再按受众快速改成不同版本。
- 结果:沟通更顺,交付更快。
---
## 🎨 3 步开始创作
1. **选主题**:按目标进入对应创作主题
2. **给输入**:一句需求、一个方向或一份素材都可以
3. **持续迭代**:边聊边改边沉淀,最终得到可发布结果
---
## ❤️ 为什么好用
- **一个地方完成全流程**:从想法到成品不用来回切工具
- **结果自动沉淀**:历史对话、素材、版本都可回看
- **越用越顺手**:每个项目都有自己的上下文记忆
---
@@ -37,29 +112,29 @@ brew install --cask proxycast
从 [Releases](https://github.com/aiclientproxy/proxycast/releases) 下载对应平台安装包。
### 使用
---
1. 启动 ProxyCast
2. 加载凭证 - Provider 管理页面点击"一键读取凭证"
3. 启动服务 - Dashboard 点击"启动服务器"
4. 配置客户端:
```
API Base URL: http://localhost:8999/v1
API Key: 启动时自动生成(设置页查看)
```
## 🧭 适合谁
- 自媒体创作者
- 短视频团队
- 小说与剧情创作者
- 运营与品牌内容团队
- 需要长期沉淀创作资产的个人与小团队
---
## 🛠️ 开发构建
## 📚 文档与开发(可选)
如果你是开发者,可查看:
- 项目文档:`docs/aiprompts/`
- Agent 指南:`AGENTS.md`
开发命令:
```bash
# 安装依赖
npm install
# 开发模式
npm run tauri dev
# 构建发布
npm run tauri build
```
@@ -71,4 +146,5 @@ npm run tauri build
## ⚠️ 免责声明
本项目仅供学习研究使用,用户需自行承担使用风险。本项目不提供 AI 模型服务,所有服务由第三方提供商提供。
本项目仅供学习研究使用,用户需自行承担使用风险。
本项目不直接提供 AI 模型服务,模型能力由第三方提供商提供。
+26 -39
View File
@@ -1,50 +1,37 @@
# docs
<!-- 一旦我所属的文件夹有所变化,请更新我 -->
## 目录定位
## 架构说明
`docs/` 是 ProxyCast 文档中心,分为两类受众:
项目文档目录,包含技术规格、操作指南、AI Agent 文档和文档站点配置。
使用 Nuxt Content 构建文档站点。
- 普通创作者:优先阅读 `content/` 下的入门与用户指南
- 开发者与维护者:阅读 `aiprompts/`、`develop/`、`tests/` 等工程文档
## 文件索引
文档站基于 Nuxt Content 构建。
- `aiprompts/` - AI Agent 模块文档(参考 aster-rust 模式)
- `content/` - 文档内容(Markdown)
- `develop/` - 开发文档
- `images/` - 文档图片资源
- `plugins/` - 插件文档
- `prd/` - 产品需求文档
- `tests/` - 测试文档
- `TECH_SPEC.md` - 技术规格文档
- `LLM_FLOW_MONITOR_SPEC.md` - LLM 流量监控规格
- `ops.md` - 运维操作指南
- `plugin-ui-design.md` - 插件 UI 设计文档
- `three-stage-workflow-guide.md` - 三阶段工作流指南
- `app.config.ts` - Nuxt 应用配置
- `nuxt.config.ts` - Nuxt 框架配置
- `package.json` - 文档站点依赖
## 目录索引
## aiprompts 文档索引
- `content/`:对外文档站正文(产品介绍、用户指南、进阶能力)
- `aiprompts/`:模块级工程文档(前后端组件、服务、命令、数据层)
- `develop/`:开发流程与协作规范
- `plugins/`:插件与扩展相关文档
- `tests/`:测试策略与用例文档
- `images/`:文档图片资源
- `TECH_SPEC.md`:技术规格文档
- `ops.md`:运维与发布说明
- `app.config.ts` / `nuxt.config.ts` / `package.json`:文档站配置
AI Agent 专用文档,提供模块级别的详细说明:
## 当前叙事基线
- `overview.md` - 项目架构概览
- `providers.md` - Provider 系统
- `credential-pool.md` - 凭证池管理
- `converter.md` - 协议转换
- `server.md` - HTTP 服务器
- `flow-monitor.md` - 流量监控
- `components.md` - 组件系统
- `hooks.md` - React Hooks
- `services.md` - 业务服务
- `commands.md` - Tauri 命令
- `mcp.md` - MCP 服务器
- `lib.md` - 工具库
- `plugins.md` - 插件系统
- `database.md` - 数据库层
- `terminal.md` - 内置终端
对外文档(`content/`)默认采用以下口径:
## 更新提醒
1. 主叙事是“创作类 AI Agent 平台”,不再以“代理服务”作为首页主线
2. 先讲创作流程与场景,再讲模型连接和 API 兼容
3. 首页与入门页优先覆盖九大创作主题与资源沉淀能力
任何文件变更后,请更新此文档和相关的上级文档。
## 维护原则
1. 先读后写:更新章节前先核对真实功能实现
2. 用户优先:首屏文案避免工程术语堆叠
3. 分层清晰:用户文档与工程文档分开表达
4. 同步更新:功能改动后同步修正文档入口页与对应章节
+31 -48
View File
@@ -1,73 +1,56 @@
---
title: 概述
description: ProxyCast 项目介绍和核心价值
description: 了解 ProxyCast 如何支持从灵感到发布的完整创作流程
navigation:
icon: i-heroicons-home
---
# ProxyCast 概述
ProxyCast 是一款基于 Tauri 2.0 的跨平台桌面应用,让你可以**把 AI 客户端的订阅额度用到任何地方**。
ProxyCast 是一款创作类 AI Agent 桌面应用。
它把对话、内容生成、图片创作、项目管理、资源沉淀放到同一个工作台里。
::alert{type="warning"}
**免责声明**: 本工具仅限于个人合法使用,严禁用于非法盈利目的。初衷是帮助用户充分利用已订阅的 AI 服务 Token。[查看完整声明](/legal/disclaimer)
**免责声明**: 请在合法合规前提下使用本产品。[查看完整声明](/legal/disclaimer)
::
## 核心价值
## 你可以用它做什么
你是否有以下困扰?
### 九大创作主题
- 订阅了 Kiro、Claude Code 等 AI 编程助手,但只能在特定 IDE 中使用
- 想在其他工具(如 Cursor、Continue、自定义脚本)中使用已有的 AI 额度
- 需要管理多个 AI 服务的凭证,频繁切换很麻烦
- 通用对话
- 社媒内容
- 图文海报
- 歌词曲谱
- 知识探索
- 计划规划
- 办公文档
- 短视频
- 小说创作
ProxyCast 解决这些问题:将你的 AI 客户端凭证转换为标准的 OpenAI/Claude 兼容 API,让任何支持 OpenAI 接口的工具都能使用你的订阅额度。
### 创作全流程
## 支持的 Provider
1. 用 Agent 把想法变成清晰方向
2. 生成文案、脚本或结构化草稿
3. 按需要生成图片并继续迭代
4. 把结果沉淀到项目和资源库,方便长期复用
| Provider | 类型 | 认证方式 | 说明 |
|----------|------|----------|------|
| Kiro Claude | OAuth | 自动刷新 | AWS Kiro IDE 的 Claude 凭证 |
| Gemini CLI | OAuth | 自动刷新 | Google Gemini CLI 凭证 |
| Qwen (通义千问) | OAuth | 自动刷新 | 阿里云通义千问凭证 |
| OpenAI Custom | API Key | 手动配置 | 自定义 OpenAI 兼容服务 |
| Claude Custom | API Key | 手动配置 | 自定义 Claude 兼容服务 |
### 一站式工作台
## 核心特性
### 🔑 凭证池管理
- 支持多个 Provider 凭证的统一管理
- 自动检测和加载本地凭证文件
- OAuth Token 自动刷新机制
### ⚖️ 智能路由
- 基于模型名称的请求路由
- 负载均衡和优先级配置
- 健康检查和自动故障转移
### 🛡️ 容错机制
- 可配置的重试策略
- 超时控制和熔断器
- 多 Provider 故障转移
### 🔄 协议转换
- OpenAI Chat Completions API 兼容
- Claude Messages API 兼容
- 自动格式转换
### 📊 监控统计
- 实时请求统计
- Token 使用追踪
- 详细的请求日志
- AI 对话与创作在同一处完成
- 项目隔离上下文,避免内容串线
- 资源按文档/图片/语音/视频分类管理
- 支持参考图参与图片生成与编辑链路
## 使用场景
1. **IDE 集成**: 在 Cursor、Continue 等编辑器中使用 Kiro/Claude Code 额度
2. **脚本调用**: 在 Python/Node.js 脚本中调用 AI API
3. **多账户管理**: 统一管理多个 AI 服务账户
4. **团队共享**: 通过配置导出分享 Provider 设置
1. **自媒体创作**:每天稳定产出选题、文案、配图
2. **短视频团队**:快速完成脚本与分镜草稿
3. **小说连载**:持续积累设定、章节与角色信息
4. **品牌运营**:统一管理活动素材与历史版本
## 下一步
- [安装指南](/introduction/installation) - 下载并安装 ProxyCast
- [快速开始](/introduction/quickstart) - 5 分钟内完成首次 API 调用
- [快速开始](/introduction/quickstart) - 3 步完成首次创作
- [首页与工作台](/user-guide/dashboard) - 熟悉核心入口
@@ -1,6 +1,6 @@
---
title: 安装指南
description: 下载并安装 ProxyCast
description: 下载、安装并验证 ProxyCast 可正常启动
navigation:
icon: i-heroicons-arrow-down-tray
---
@@ -16,7 +16,7 @@ navigation:
## 下载
从 GitHub Tags 下载最新版本:
从 GitHub Releases/Tags 下载最新版本安装包:
[下载 ProxyCast](https://github.com/aiclientproxy/proxycast/tags)
@@ -49,9 +49,9 @@ navigation:
启动 ProxyCast 后,你应该看到:
1. 系统托盘图标出现
2. 主窗口显示仪表盘
3. 服务状态显示"已停止"(首次启动)
1. 主窗口正常打开
2. 左侧出现主要入口(AI Agent、项目、资源、图片生成等)
3. 可以进入设置页并看到版本信息
## 常见安装问题
@@ -68,4 +68,4 @@ xattr -cr /Applications/ProxyCast.app
## 下一步
安装完成后,继续阅读 [快速开始](/introduction/quickstart) 配置你的第一个 Provider。
安装完成后,继续阅读 [快速开始](/introduction/quickstart),用 3 步完成第一次创作。
+32 -84
View File
@@ -1,116 +1,64 @@
---
title: 快速开始
description: 5 分钟内完成首次 API 调用
description: 3 步完成首次创作并沉淀到项目资源库
navigation:
icon: i-heroicons-rocket-launch
---
# 快速开始
本指南帮助你在 5 分钟内完成 ProxyCast 的基本配置和首次 API 调用。
本指南帮助你在几分钟内完成第一次完整创作流程。
## 前置准备
确保你已经:
- [x] 安装了 ProxyCast
- [x] 拥有至少一个 AI 客户端的有效订阅(Kiro、Gemini CLI、Qwen 等)
- [x] 可以正常打开应用主界面
## 步骤 1: 启动 ProxyCast
## 步骤 1:选择创作主题与项目
1. 启动 ProxyCast 应用
2. 主窗口会显示仪表盘界面
1. 启动 ProxyCast,进入 AI Agent 或项目入口
2. 选择你的主题方向(如社媒、短视频、小说)
3. 新建项目,作为本次创作的工作空间
## 步骤 2: 加载凭证
## 步骤 2:输入需求并生成内容
ProxyCast 会自动检测本地的 AI 客户端凭证文件。
1. 用一句话描述你的目标
2. 让 Agent 先给结构,再生成首稿
3. 如需视觉内容,进入图片生成功能继续产出与迭代
### 凭证文件位置
## 步骤 3:沉淀到资源库
| Provider | 凭证路径 |
|----------|----------|
| Kiro Claude | `~/.kiro/credentials.json` |
| Gemini CLI | `~/.config/gemini-cli/oauth_creds.json` |
| Qwen | `~/.config/qwen/credentials.json` |
1. 将文档、图片等结果保存到当前项目资源库
2. 在资源页按分类查看(文档/图片/语音/视频)
3. 下次创作直接复用历史素材和上下文
### 手动添加凭证
## 一个最小创作示例
如果自动检测未找到凭证:
1. 主题:`短视频`
2. 输入:`做一条 30 秒“高效晨间复盘”口播内容`
3. 产出:
- 3 个开场钩子
- 1 版结构化口播稿
- 1 组配图提示词或参考图改写结果
1. 进入 **凭证池** 页面
2. 点击 **添加凭证**
3. 选择 Provider 类型
4. 输入凭证信息或选择凭证文件
## 常见问题
## 步骤 3: 启动 API Server
### 我可以只用对话,不做图片吗?
1. 在仪表盘点击 **启动服务**
2. 服务状态变为"运行中"
3. 记下 API 地址(默认 `http://127.0.0.1:8999`)
可以。你可以只用 AI Agent 完成文本创作和项目沉淀。
## 步骤 4: 测试 API
### 我可以直接改图吗?
### 使用内置测试面板
可以。上传参考图后,若所选模型支持编辑接口,会自动走编辑链路。
1. 在仪表盘找到 **API 测试** 区域
2. 输入测试消息
3. 点击发送,查看响应
### 我还需要 API 接入能力怎么办?
### 使用 curl 测试
**OpenAI 格式:**
```bash
curl http://127.0.0.1:8999/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-api-key" \
-d '{
"model": "claude-sonnet-4-20250514",
"messages": [{"role": "user", "content": "Hello!"}]
}'
```
**Claude 格式:**
```bash
curl http://127.0.0.1:8999/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-sonnet-4-20250514",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello!"}]
}'
```
## 步骤 5: 集成到其他工具
### Cursor 配置
在 Cursor 设置中配置 OpenAI API:
- API Base URL: `http://127.0.0.1:8999/v1`
- API Key: 你在 ProxyCast 中设置的 API Key
### Continue 配置
编辑 `~/.continue/config.json`:
```json
{
"models": [{
"title": "ProxyCast Claude",
"provider": "openai",
"model": "claude-sonnet-4-20250514",
"apiBase": "http://127.0.0.1:8999/v1",
"apiKey": "your-api-key"
}]
}
```
可以继续阅读 [API Server](/user-guide/api-server) 和 [API 参考](/api-reference/overview)。
## 下一步
- [仪表盘](/user-guide/dashboard) - 了解仪表盘功能
- [凭证池](/user-guide/credential-pool) - 管理多个凭证
- [智能路由](/user-guide/smart-routing) - 配置请求路由规则
- [首页与工作台](/user-guide/dashboard) - 理解核心导航
- [资源库](/user-guide/resources) - 管理创作资产
- [图片生成与编辑](/user-guide/image-generation) - 深入图片链路
+38 -55
View File
@@ -1,75 +1,58 @@
---
title: 仪表盘
description: 监控和控制代理服务
title: 首页与工作台
description: 首页与创作工作台总览
navigation:
icon: i-heroicons-chart-bar
---
# 仪表盘
# 首页与工作台
仪表盘是 ProxyCast 的主界面,提供服务状态监控和快速操作入口。
首页是你进入 ProxyCast 后的主入口。
建议把它理解为“创作操作台”,而不是单一功能面板。
## 服务状态
## 左侧核心入口
仪表盘顶部显示当前服务状态:
- **AI Agent**:对话、任务推进、内容初稿
- **项目**:按创作目标管理长期内容
- **资源**:统一查看文档、图片、语音、视频
- **图片生成**:生成图片、参考图编辑、结果回流资源库
- **设置**:调整主题、模块开关、连接与高级选项
| 状态 | 说明 |
|------|------|
| 🟢 运行中 | API Server 正在运行,可以接收请求 |
| 🔴 已停止 | API Server 未启动 |
| 🟡 启动中 | 服务正在初始化 |
## 推荐工作方式
## 控制按钮
1. 先在项目中选择一个创作主题
2. 在 AI Agent 中完成结构和首稿
3. 需要视觉时进入图片生成
4. 回到资源库统一管理结果
- **启动服务**: 启动 API Server
- **停止服务**: 停止 API Server
- **重启服务**: 重新启动服务
## 创作主题
## API 信息
当前支持的主题包括:
服务运行时显示:
- 通用对话
- 社媒内容
- 图文海报
- 歌词曲谱
- 知识探索
- 计划规划
- 办公文档
- 短视频
- 小说创作
- **API 地址**: 本地 API 端点(如 `http://127.0.0.1:8999`)
- **API Key**: 当前配置的访问密钥
- **复制按钮**: 一键复制 API 地址或 Key
## 常见操作
## API 测试面板
### 新建一个创作项目
内置的 API 测试工具:
1. 进入项目页
2. 选择主题并创建项目
3. 开始持续沉淀对话与素材
1. **消息输入**: 输入测试消息
2. **模型选择**: 选择要使用的模型
3. **发送请求**: 点击发送测试请求
4. **响应显示**: 查看 AI 响应结果
### 从资源继续创作
### 测试示例
1. 在资源页选中历史文档或图片
2. 跳转到 AI Agent 继续改写或扩展
3. 将新结果再次沉淀回资源库
```
用户: Hello, how are you?
助手: I'm doing well, thank you for asking! How can I help you today?
```
### 只看某类素材
## 请求统计
实时统计信息:
- **总请求数**: 累计处理的请求数量
- **成功率**: 请求成功百分比
- **平均延迟**: 请求平均响应时间
- **Token 使用**: 累计 Token 消耗
## 凭证状态
显示当前可用的凭证:
| 字段 | 说明 |
|------|------|
| Provider | 凭证类型 |
| 状态 | 有效/过期/错误 |
| 剩余额度 | 可用额度(如支持) |
## 快捷操作
- **打开设置**: 进入设置页面
- **查看日志**: 打开请求日志
- **刷新凭证**: 重新加载凭证文件
在资源页切换分类视图,可只看文档、图片、语音或视频。
+29 -129
View File
@@ -1,150 +1,50 @@
---
title: Prompts 管理
description: 提示词存储和管理
title: 提示词模板
description: 管理可复用提示词,提升稳定产出效率
navigation:
icon: i-heroicons-document-text
---
# Prompts 管理
# 提示词模板
Prompts 功能帮助你存储、组织和复用常用的提示词模板。
提示词模板用于把“经常重复的表达方式”沉淀下来,减少每次从零开始。
## 提示词存储
## 模板结构建议
### 创建提示词
每个模板建议包含:
1. 进入 **Prompts** 页面
2. 点击 **新建提示词**
3. 填写提示词信息:
- 名称(便于检索)
- 使用场景(何时用)
- 模板正文(可复用)
- 变量占位(可选)
| 字段 | 说明 |
|------|------|
| 名称 | 提示词标识名称 |
| 描述 | 提示词用途说明 |
| 内容 | 提示词正文 |
| 标签 | 分类标签 |
## 示例:短视频口播模板
### 提示词示例
```yaml
name: "代码审查"
description: "审查代码质量和最佳实践"
content: |
请审查以下代码,关注:
1. 代码质量和可读性
2. 潜在的 bug 和安全问题
3. 性能优化建议
4. 最佳实践遵循情况
请提供具体的改进建议。
tags:
- 代码
- 审查
```text
你是一名内容策划。
请基于主题「{{topic}}」生成一段 {{duration}} 秒口播稿,要求:
1. 开头 3 秒有抓力
2. 中段给出 3 个关键点
3. 结尾有明确行动引导
语气风格:{{tone}}
```
## 组织方式
## 推荐组织方式
### 文件夹分类
- 按主题分类:社媒、短视频、小说、办公
- 按阶段分类:灵感、初稿、润色、发布
- 统一标签:例如 `#高频`、`#可复用`
创建文件夹组织提示词:
## 使用建议
- 📁 代码相关
- 代码审查
- 代码重构
- 单元测试
- 📁 写作相关
- 文档撰写
- 邮件回复
- 📁 翻译相关
- 中英翻译
- 技术翻译
### 一次只优化一个模板
### 标签系统
避免同时改太多模板,难以判断效果。
使用标签快速筛选:
### 模板要留“可变空间”
- `#代码` - 代码相关提示词
- `#写作` - 写作相关提示词
- `#常用` - 常用提示词
把固定规则写清楚,把创意部分留给变量。
### 搜索功能
### 和项目结合
支持按以下条件搜索:
- 名称
- 描述
- 内容
- 标签
## 注入请求
### 系统提示词
将提示词作为系统消息注入:
```json
{
"model": "claude-sonnet-4-20250514",
"messages": [
{"role": "system", "content": "你是一个代码审查专家..."},
{"role": "user", "content": "请审查这段代码..."}
]
}
```
### 使用方式
1. **手动复制**: 复制提示词内容到请求
2. **快捷插入**: 在 API 测试面板选择提示词
3. **自动注入**: 配置默认系统提示词
### 配置默认提示词
1. 进入 **设置** > **API Server**
2. 选择 **默认系统提示词**
3. 所有请求自动注入该提示词
## 变量支持
### 定义变量
在提示词中使用变量:
```
请将以下 {{source_lang}} 文本翻译成 {{target_lang}}:
{{content}}
```
### 使用变量
调用时替换变量值:
```json
{
"prompt": "翻译模板",
"variables": {
"source_lang": "英文",
"target_lang": "中文",
"content": "Hello, world!"
}
}
```
## 导入导出
### 导出提示词
1. 选择要导出的提示词
2. 点击 **导出**
3. 保存为 `.json` 或 `.yaml` 文件
### 导入提示词
1. 点击 **导入**
2. 选择提示词文件
3. 确认导入
### 分享提示词
导出的提示词文件可以分享给他人使用。
在项目中沉淀效果好的模板,后续同类任务可直接复用。
+35 -151
View File
@@ -1,171 +1,55 @@
---
title: Skills 技能
description: 可扩展的技能模块系统
title: 技能工作流
description: 把常见任务封装成可复用的 AI 技能
navigation:
icon: i-heroicons-sparkles
---
# Skills 技能
# 技能工作流
Skills 是预定义的 AI 交互模式,封装了特定任务的提示词、参数和工具配置。
技能可以理解为“可复用的任务卡片”:
## 技能定义
- 预设目标
- 预设风格
- 预设步骤
### 什么是技能
这样每次执行同类任务时,不必重复手工组织提示。
技能是一个完整的 AI 交互配置包,包含:
## 技能适合做什么
- 系统提示词
- 参数配置
- 工具绑定
- 输出格式
- 固定流程写作(如周报、复盘、活动文案)
- 固定结构产出(如短视频脚本、小说章节骨架)
- 固定标准检查(如发布前检查清单)
### 技能示例
## 技能卡建议字段
- 名称:明确任务类型
- 描述:写清输入与输出
- 系统指令:定义角色与规则
- 参数:控制风格与长度
- 输出格式:约束结果结构
## 示例:活动文案技能
```yaml
name: "代码解释器"
description: "解释代码功能和逻辑"
name: "活动文案生成"
description: "根据主题生成活动预热文案与发布文案"
system_prompt: |
你是一个代码解释专家。请详细解释用户提供的代码:
1. 代码的整体功能
2. 关键逻辑的解释
3. 使用的设计模式
4. 潜在的改进点
parameters:
temperature: 0.3
max_tokens: 2000
output_format: markdown
你是一名品牌内容策划,输出要简洁、有行动感。
output_format: "markdown"
```
## 创建技能
## 组合为流程
### 新建技能
你可以把多个技能串成流程,例如:
1. 进入 **Skills** 页面
2. 点击 **新建技能**
3. 配置技能信息
1. 选题拆解
2. 初稿生成
3. 风格统一
4. 发布前检查
### 配置选项
## 团队使用建议
| 字段 | 说明 |
|------|------|
| 名称 | 技能标识名称 |
| 描述 | 技能用途说明 |
| 系统提示词 | 技能的核心提示词 |
| 参数 | 模型参数配置 |
| 工具 | 绑定的 MCP 工具 |
| 输出格式 | 期望的输出格式 |
## 参数配置
### 模型参数
| 参数 | 说明 | 默认值 |
|------|------|--------|
| temperature | 创造性程度 | 0.7 |
| max_tokens | 最大输出长度 | 4096 |
| top_p | 采样范围 | 1.0 |
| presence_penalty | 重复惩罚 | 0 |
### 参数模板
为不同场景预设参数:
```yaml
# 精确任务
precise:
temperature: 0.1
top_p: 0.9
# 创意任务
creative:
temperature: 0.9
top_p: 1.0
# 代码生成
coding:
temperature: 0.2
max_tokens: 8000
```
## 应用技能
### 在 API 测试中使用
1. 打开 **API 测试** 面板
2. 点击 **选择技能**
3. 选择要使用的技能
4. 输入用户消息
5. 发送请求
### 通过 API 调用
```bash
curl http://127.0.0.1:8999/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-api-key" \
-d '{
"model": "claude-sonnet-4-20250514",
"skill": "代码解释器",
"messages": [
{"role": "user", "content": "解释这段代码: function add(a, b) { return a + b; }"}
]
}'
```
### 技能链
组合多个技能形成工作流:
```yaml
name: "代码审查流程"
steps:
- skill: "代码分析"
- skill: "安全检查"
- skill: "性能评估"
- skill: "改进建议"
```
## 内置技能
### 代码相关
| 技能 | 说明 |
|------|------|
| 代码解释 | 解释代码功能 |
| 代码审查 | 审查代码质量 |
| 代码重构 | 提供重构建议 |
| Bug 修复 | 分析和修复 bug |
### 写作相关
| 技能 | 说明 |
|------|------|
| 文档撰写 | 撰写技术文档 |
| 邮件回复 | 生成邮件回复 |
| 内容总结 | 总结长文内容 |
### 翻译相关
| 技能 | 说明 |
|------|------|
| 通用翻译 | 中英互译 |
| 技术翻译 | 技术文档翻译 |
## 技能管理
### 编辑技能
1. 点击技能的 **编辑** 按钮
2. 修改配置
3. 保存更改
### 删除技能
1. 点击 **删除** 按钮
2. 确认删除
### 导入导出
- **导出**: 将技能导出为 `.yaml` 文件
- **导入**: 从文件导入技能
1. 共享高频技能模板
2. 每个技能指定维护人
3. 定期清理低使用技能,保持列表可维护
+34 -115
View File
@@ -1,141 +1,60 @@
---
title: 设置
description: 应用设置和偏好管理
description: 管理应用偏好、导航模块和进阶系统选项
navigation:
icon: i-heroicons-cog-6-tooth
---
# 设置
设置页面用于配置 ProxyCast 的各项参数和偏好。
设置页用于管理你的创作体验与系统行为。
## 通用设置
## 通用
### 应用行为
常见选项:
| 选项 | 说明 |
|------|------|
| 开机自启动 | 系统启动时自动运行 ProxyCast |
| 启动时运行服务 | 应用启动时自动启动 API Server |
| 最小化到托盘 | 关闭窗口时最小化到系统托盘 |
| 显示托盘图标 | 在系统托盘显示图标 |
- 主题模式(浅色 / 深色 / 跟随系统)
- 语言选择
- 启动行为(开机自启动、最小化到托盘)
- 声音反馈开关
### 更新设置
## 创作与导航偏好
| 选项 | 说明 |
|------|------|
| 自动检查更新 | 定期检查新版本 |
| 自动下载更新 | 有新版本时自动下载 |
| 更新通知 | 有更新时显示通知 |
你可以按使用习惯定制入口:
## 认证目录
- 启用或停用创作主题(如社媒、短视频、小说)
- 启用或停用导航模块(如 AI Agent、项目、图片生成、终端、工具、插件)
### 默认凭证路径
这样可以让侧边栏更聚焦,减少干扰。
ProxyCast 默认扫描以下路径:
## 连接与系统
| Provider | 默认路径 |
|----------|----------|
| Kiro | `~/.kiro/credentials.json` |
| Gemini CLI | `~/.config/gemini-cli/oauth_creds.json` |
| Qwen | `~/.config/qwen/credentials.json` |
系统相关设置在这里管理:
### 自定义路径
- 连接与网络代理
- 安全与证书
- 存储目录与配额
- 外部工具联动
- 实验室与开发者选项
添加自定义凭证扫描路径:
## 关于与版本
1. 进入 **设置** > **认证目录**
2. 点击 **添加路径**
3. 选择目录或文件
4. 指定 Provider 类型
在“关于”标签页可以查看:
### 路径配置
- 当前版本号
- 更新检查入口
- 相关项目信息
```yaml
auth_dirs:
- path: "~/.kiro"
provider: kiro
pattern: "credentials*.json"
- path: "/custom/path"
provider: gemini
pattern: "*.json"
```
## 建议配置
## 偏好管理
### 个人创作者
### 主题设置
- 保留:AI Agent、项目、资源、图片生成
- 关闭:暂时不用的高级模块
- 目的:让工作台聚焦在“日常产出”
| 选项 | 说明 |
|------|------|
| 浅色模式 | 使用浅色主题 |
| 深色模式 | 使用深色主题 |
| 跟随系统 | 跟随系统主题设置 |
### 团队协作
### 语言设置
支持的语言:
- 简体中文
- English
### 通知设置
| 选项 | 说明 |
|------|------|
| 服务状态通知 | 服务启动/停止时通知 |
| 错误通知 | 发生错误时通知 |
| 凭证过期通知 | 凭证即将过期时通知 |
## 数据管理
### 数据存储位置
ProxyCast 数据存储在:
| 平台 | 路径 |
|------|------|
| macOS | `~/Library/Application Support/ProxyCast` |
| Windows | `%APPDATA%\ProxyCast` |
### 清除数据
| 选项 | 说明 |
|------|------|
| 清除日志 | 删除所有请求日志 |
| 清除统计 | 重置统计数据 |
| 清除缓存 | 清除应用缓存 |
| 重置设置 | 恢复默认设置 |
::alert{type="warning"}
清除数据操作不可恢复,请谨慎操作。
::
## 高级设置
### 日志级别
| 级别 | 说明 |
|------|------|
| Error | 仅记录错误 |
| Warn | 记录警告和错误 |
| Info | 记录一般信息 |
| Debug | 记录调试信息 |
| Trace | 记录所有信息 |
### 代理设置
配置网络代理:
| 选项 | 说明 |
|------|------|
| HTTP 代理 | HTTP 代理地址 |
| HTTPS 代理 | HTTPS 代理地址 |
| 不代理地址 | 不使用代理的地址列表 |
### 性能设置
| 选项 | 默认值 | 说明 |
|------|--------|------|
| 最大并发请求 | 10 | 同时处理的最大请求数 |
| 请求队列大小 | 100 | 等待队列的最大长度 |
| 日志保留天数 | 30 | 日志文件保留时间 |
- 统一主题配置
- 固定项目命名规则
- 约定资源标签方式
+26 -38
View File
@@ -1,35 +1,28 @@
---
title: 插件中心
description: 安装和管理扩展插件,按需扩展创作能力
navigation:
icon: i-heroicons-puzzle-piece
---
# 插件中心
::alert{type="info"}
📢 本文档已迁移至开放平台。请访问 [开放平台 - 插件中心](/open-platform/plugins) 获取最新内容。
📢 插件属于进阶能力。若你只做日常创作,可先跳过本页。
::
ProxyCast 支持通过插件扩展功能。插件中心提供插件的安装、管理和配置。
插件中心用于扩展 ProxyCast 的能力,例如新增工具、接入外部流程、扩展特定场景工作流。
## 访问插件中心
点击左侧导航栏的「插件中心」进入插件管理页面。
## 功能概览
## 你能做什么
### 推荐插件
插件中心会显示推荐的插件列表,点击「一键安装」即可快速安装。
### 已安装插件
显示所有已安装的插件,包括:
- 插件名称和版本
- 安装来源(本地/URL/GitHub)
- 启用/禁用状态
- 卸载按钮
### 已加载插件
显示当前运行中的插件状态:
- 执行次数
- 错误次数
- 最后执行时间
- 浏览推荐插件并一键安装
- 通过本地文件或 URL 安装插件包
- 管理启用状态与卸载
- 查看插件加载与执行状态
## 安装插件
@@ -56,22 +49,19 @@ ProxyCast 支持通过插件扩展功能。插件中心提供插件的安装、
3. 选择本地的 `.zip` 文件
4. 点击「安装」
## 使用插件
## 使用建议
安装完成后,插件会根据类型出现在不同位置:
### 从小处开始
### 工具类插件
先安装 1 到 2 个高频插件,观察是否真正提升你的创作效率,再决定是否扩展更多插件。
工具类插件会出现在「工具箱」页面:
### 明确用途
1. 点击左侧导航栏的「工具」
2. 在工具列表中找到已安装的插件
3. 点击「打开工具」使用
每个插件都应对应明确目的,例如:
### 其他类型插件
- **Hook 插件**: 自动在请求/响应时执行
- **侧边栏插件**: 出现在主侧边栏(规划中)
- 扩展素材处理
- 增加内容生成模板
- 对接外部工作流
## 管理插件
@@ -87,13 +77,11 @@ ProxyCast 支持通过插件扩展功能。插件中心提供插件的安装、
卸载会删除插件文件和配置,但不会删除插件产生的数据。
## 二进制组件
## 进阶阅读
部分功能需要安装额外的二进制组件:
- **aster-server**: AI Agent 框架,提供 Agent 对话能力
在「二进制组件」区域可以查看和管理这些组件。
- [开放平台 - 总览](/open-platform/overview)
- [开放平台 - 插件中心](/open-platform/plugins)
- [开放平台 - 插件开发](/open-platform/plugin-development)
## 常见问题
@@ -0,0 +1,65 @@
---
title: 资源库
description: 管理项目中的文档、图片、语音和视频素材
navigation:
icon: i-heroicons-folder-open
---
# 资源库
资源库是 ProxyCast 的创作资产中心。
它和项目绑定,用来长期沉淀你的创作结果。
## 资源分类
资源页支持按分类查看:
- 全部
- 文档
- 图片
- 语音
- 视频
当你只想找图或找文档时,直接切换分类即可。
## 常见操作
### 新建与上传
1. 选择左侧资源库(项目)
2. 新建文件夹或新建文档
3. 上传本地文件到当前目录
### 搜索与排序
- 支持按名称、描述、标签搜索
- 支持按更新时间、创建时间、名称排序
### 重命名与删除
在资源列表的操作菜单中,可对资源进行重命名、删除等操作。
## 资源与创作联动
### 从图片生成回流资源库
在图片生成页选择目标资源库后,成功生成的图片可自动写入当前项目。
### 从资源继续对话创作
在资源页选中素材后,可继续进入 AI Agent 进行改写、扩写或二次创作。
## 常见问题
### 为什么看不到某些图片?
先确认:
1. 当前选择的是否是正确资源库(项目)
2. 是否切到了“图片”分类
3. 文件后缀或 MIME 类型是否被识别为图片
### 为什么资源数量和预期不一致?
常见原因是“分类过滤”或“项目切换”导致显示范围变化。
建议先切换到“全部”分类再确认总量。
@@ -0,0 +1,60 @@
---
title: 图片生成与编辑
description: 通过文本与参考图完成图片生成、编辑与资产沉淀
navigation:
icon: i-heroicons-photo
---
# 图片生成与编辑
图片生成页用于完成从“文字描述”到“可用图片素材”的全过程。
## 基本流程
1. 选择模型与参数(尺寸、比例、数量)
2. 输入提示词
3. 可选上传参考图
4. 生成后选图并沉淀到资源库
## 参考图与编辑
### 上传参考图
可上传参考图作为创作输入,帮助模型更贴近目标风格或构图。
### 编辑链路
当模型支持图片编辑接口时,系统会优先尝试编辑端点;
若不可用,会自动回退到可用生成端点,尽量保障出图成功率。
## 历史记录
历史区域会保存你的生成记录,支持:
- 查看单张或批次结果
- 重新选择目标图继续迭代
- 将历史结果补录到资源库
## 与资源库联动
### 目标资源库
生成前可指定目标资源库(项目),用于自动沉淀图片资产。
### 补录历史
如果历史图片尚未入库,可使用“补录历史到资源库”进行批量回填。
## 实用建议
### 先定方向再出图
先在 AI Agent 里明确画面目标,再进入图片生成功能,会减少无效尝试。
### 一次只改一个变量
每轮仅调整一个维度(提示词、比例、参考图),更容易稳定收敛到理想结果。
### 把可用版本及时入库
选中可用图片后尽快入库,方便后续在资源页检索和复用。
+34 -76
View File
@@ -1,103 +1,61 @@
---
title: 监控中心
description: 请求统计和性能监控
title: 创作数据与监控
description: 查看创作产出趋势、调用状态与问题定位信息
navigation:
icon: i-heroicons-eye
---
# 监控中心
# 创作数据与监控
监控中心提供详细的请求统计、性能指标和日志查看功能。
监控页帮助你回答三个问题:
## 监控界面
1. 最近创作是否稳定
2. 哪些任务成功率更高
3. 出现异常时该从哪里排查
### 概览面板
## 你能看到什么
显示关键指标的实时数据:
### 概览指标
- **请求总数**: 今日/本周/本月请求量
- **成功率**: 请求成功百分比
- **平均延迟**: 响应时间统计
- **活跃凭证**: 当前可用凭证数量
常见指标包括:
### 图表展示
- 请求总量与成功率
- 平均响应耗时
- 活跃连接数量
- 近期错误趋势
- **请求趋势图**: 按时间显示请求量变化
- **延迟分布图**: 响应时间分布
- **Provider 使用占比**: 各 Provider 请求比例
### 趋势视图
## 请求统计
你可以按时间查看:
### 按 Provider 统计
- 调用量变化
- 成功率变化
- 延迟波动
| Provider | 请求数 | 成功率 | 平均延迟 |
|----------|--------|--------|----------|
| Kiro Claude | 1,234 | 99.2% | 1.2s |
| Gemini CLI | 567 | 98.5% | 0.8s |
| Qwen | 890 | 99.0% | 1.0s |
这能帮助你判断问题是偶发,还是持续性异常。
### 按模型统计
## 日志排查
查看每个模型的使用情况:
当某次生成失败时,优先看请求日志:
- 请求次数
- Token 消耗
- 平均响应时间
1. 找到失败时间点
2. 查看模型与请求参数
3. 对照错误信息定位问题(超时、认证、限流等)
## Token 使用追踪
## 对创作者最有用的用法
### 使用量统计
### 判断工作流是否健康
| 指标 | 说明 |
|------|------|
| 输入 Token | 请求消息的 Token 数 |
| 输出 Token | 响应消息的 Token 数 |
| 总计 Token | 输入 + 输出 |
如果成功率持续下降,建议先减少并发任务,确认连接状态后再恢复批量生成。
### 按时间段查看
### 对比不同创作任务
- 今日使用量
- 本周使用量
- 本月使用量
- 自定义时间范围
同样是生成任务,不同主题的耗时差异可能很大。通过趋势图可以更快选择稳定方案。
## 请求日志
### 复盘高峰时段
### 日志列表
高峰期(例如集中出图)出现波动时,可根据日志回看是否需要拆分任务批次。
每条日志包含:
## 数据导出
| 字段 | 说明 |
|------|------|
| 时间 | 请求时间戳 |
| 模型 | 请求的模型名称 |
| Provider | 实际使用的 Provider |
| 状态 | 成功/失败 |
| 延迟 | 响应时间 |
| Token | Token 使用量 |
### 日志过滤
支持按以下条件过滤:
- 时间范围
- Provider
- 模型
- 状态(成功/失败)
### 日志详情
点击日志条目查看详细信息:
- 完整请求内容
- 完整响应内容
- 错误信息(如有)
- 请求头信息
## 导出数据
支持导出统计数据:
- CSV 格式
- JSON 格式
- 自定义时间范围
如果你需要做团队复盘,可导出统计数据用于周报或复盘记录。
+31 -106
View File
@@ -1,130 +1,55 @@
---
title: 凭证池
description: 管理多个 AI 服务凭证
title: 模型连接与账号
description: 管理模型连接方式与多账号状态(进阶)
navigation:
icon: i-heroicons-key
---
# 凭证池
# 模型连接与账号
凭证池用于管理多个 AI 服务凭证,支持负载均衡和故障转移。
::alert{type="info"}
这是进阶页。普通创作者可直接使用默认连接能力,按需再回来配置。
::
## 池管理界面
该页面用于管理模型连接与账号状态,适合以下场景:
### 凭证列表
- 你有多个账号需要统一管理
- 你需要手动添加 API Key
- 你希望在连接异常时快速排查
显示所有已添加的凭证:
| 字段 | 说明 |
|------|------|
| 名称 | 凭证标识名称 |
| Provider | 凭证类型 |
| 状态 | 有效/过期/错误 |
| 优先级 | 负载均衡优先级 |
| 操作 | 编辑/删除/测试 |
### 状态指示
- 🟢 **有效**: 凭证可正常使用
- 🟡 **即将过期**: Token 即将过期,需要刷新
- 🔴 **已过期**: Token 已过期
- ⚪ **未验证**: 尚未验证凭证有效性
## 添加凭证
## 常见连接方式
### 自动检测
ProxyCast 会自动检测以下位置的凭证:
应用会尝试检测本地常见凭证文件,检测成功后可直接使用。
```
~/.kiro/credentials.json # Kiro Claude
~/.config/gemini-cli/oauth_creds.json # Gemini CLI
~/.config/qwen/credentials.json # Qwen
```
### 手动添加
点击 **刷新凭证** 重新扫描。
如果自动检测失败,可手动添加:
### 从文件加载
1. 选择连接类型
2. 填写必要凭证信息
3. 保存后执行连接测试
1. 点击 **添加凭证**
2. 选择 **从文件加载**
3. 选择凭证文件
4. 确认 Provider 类型
## 账号状态说明
### 手动输入
- 可用:可正常调用
- 即将过期:建议尽快刷新
- 已失效:需重新登录或更新凭证
- 未验证:建议先执行测试
1. 点击 **添加凭证**
2. 选择 **手动输入**
3. 选择 Provider 类型
4. 填写凭证信息:
## 多账号使用建议
**OAuth 类型 (Kiro/Gemini/Qwen):**
- Access Token
- Refresh Token
- 过期时间
### 日常创作
**API Key 类型 (OpenAI/Claude Custom):**
- API Key
- Base URL(可选)
保留 1 到 2 个稳定账号即可,优先保证可用性。
## 负载均衡配置
### 高强度创作
### 策略选择
如果你需要长时间连续生成,可配置多个账号做冗余,降低单点失败影响。
| 策略 | 说明 |
|------|------|
| 轮询 (Round Robin) | 依次使用每个凭证 |
| 优先级 (Priority) | 按优先级顺序使用 |
| 随机 (Random) | 随机选择凭证 |
| 最少使用 (Least Used) | 优先使用请求数最少的凭证 |
## 安全建议
### 优先级设置
为每个凭证设置优先级(1-100):
- 数值越小优先级越高
- 相同优先级按策略选择
- 优先级为 0 表示禁用
### 健康检查
启用健康检查后:
- 定期验证凭证有效性
- 自动跳过失效凭证
- 凭证恢复后自动重新启用
配置选项:
| 选项 | 默认值 | 说明 |
|------|--------|------|
| 检查间隔 | 60s | 健康检查频率 |
| 失败阈值 | 3 | 连续失败次数后标记为不健康 |
| 恢复阈值 | 1 | 成功次数后恢复健康状态 |
## 凭证操作
### 测试凭证
点击 **测试** 按钮验证凭证:
1. 发送测试请求
2. 显示测试结果
3. 更新凭证状态
### 刷新 Token
对于 OAuth 凭证:
- 自动刷新:Token 过期前自动刷新
- 手动刷新:点击 **刷新** 按钮
### 删除凭证
1. 点击 **删除** 按钮
2. 确认删除操作
3. 凭证从池中移除
::alert{type="warning"}
删除凭证不会删除本地凭证文件,只是从 ProxyCast 中移除。
::
1. 不在聊天记录或公开文档里粘贴密钥
2. 定期清理失效连接
3. 导出配置时确认敏感信息不会被带出
@@ -1,342 +1,79 @@
---
title: 完整配置示例
description: ProxyCast 完整 YAML 配置示例
title: 进阶配置示例
description: 按创作场景选择配置思路(示例)
navigation:
icon: i-heroicons-document-text
---
# 完整配置示例
# 进阶配置示例
本文档提供 ProxyCast 的完整 YAML 配置示例,包含所有新增功能。
::alert{type="info"}
本页示例用于说明配置思路,不要求你逐字段照抄。具体字段以应用设置界面为准。
::
## 基础配置
## 示例 1:个人创作者(推荐起步)
目标:少配置、快开始。
```yaml
# 服务器配置
server:
profile: "solo-creator"
navigation:
enabled:
- agent
- projects
- resources
- image-gen
themes:
enabled:
- social-media
- video
- novel
```
适用:自媒体、短视频、小说日更。
## 示例 2:团队协作
目标:统一入口和主题,降低沟通成本。
```yaml
profile: "team-content"
navigation:
enabled:
- agent
- projects
- resources
- tools
themes:
enabled:
- social-media
- poster
- document
resource:
naming: "project-date-version"
```
适用:品牌运营、活动策划、小团队协作。
## 示例 3:进阶接入
目标:在保留创作工作台的同时开放 API 给外部工具。
```yaml
profile: "creator-plus-api"
api_server:
enabled: true
host: "127.0.0.1"
port: 8999
api_key: "your-api-key"
# TLS/HTTPS 配置
tls:
enable: false
cert_path: "/path/to/cert.pem"
key_path: "/path/to/key.pem"
# 注意:当前版本暂不支持 TLS。启用后服务将无法启动,请使用反向代理做 TLS 终止。
# 全局代理 URL(支持 socks5/http/https)
proxy_url: "socks5://127.0.0.1:1080"
# 认证目录(存储 OAuth Token 文件)
auth_dir: "~/.proxycast/auth"
```
## 远程管理配置
```yaml
# 远程管理 API 配置
remote_management:
# 是否允许远程访问(非 localhost)
allow_remote: false
# 管理 API 密钥(为空时禁用管理 API)
secret_key: "your-secret-key"
# 是否禁用控制面板
disable_control_panel: false
```
## 配额超限配置
```yaml
# 配额超限自动切换策略
quota_exceeded:
# 是否自动切换到下一个凭证
switch_project: true
# 是否尝试使用预览模型
switch_preview_model: true
# 冷却时间(秒)
cooldown_seconds: 300
```
## Amp CLI 集成配置
```yaml
# Amp CLI 配置
ampcode:
# 上游 URL
upstream_url: "https://ampcode.com"
# 是否限制管理端点只能从 localhost 访问
restrict_management_to_localhost: false
# 模型映射列表
model_mappings:
- from: "claude-opus-4.5"
to: "claude-sonnet-4"
- from: "gpt-5"
to: "gemini-2.5-pro"
- from: "claude-3-opus-20240229"
to: "claude-3-5-sonnet-20241022"
```
## 凭证池配置
### OAuth Provider
```yaml
credential_pool:
# Kiro OAuth 凭证
kiro:
- id: "kiro-main"
token_file: "kiro/main-token.json"
disabled: false
proxy_url: "socks5://proxy1:1080" # 可选:单独代理
- id: "kiro-backup"
token_file: "kiro/backup-token.json"
disabled: false
# Gemini OAuth 凭证
gemini:
- id: "gemini-main"
token_file: "gemini/oauth_creds.json"
disabled: false
# Qwen OAuth 凭证
qwen:
- id: "qwen-main"
token_file: "qwen/oauth_creds.json"
disabled: false
# Codex OAuth 凭证
codex:
- id: "codex-main"
token_file: "codex/oauth.json"
proxy_url: "http://proxy2:8080"
```
### iFlow Provider
```yaml
credential_pool:
# iFlow 凭证(支持 OAuth 和 Cookie)
iflow:
# OAuth 模式
- id: "iflow-oauth"
token_file: "iflow/oauth.json"
auth_type: "oauth"
disabled: false
# Cookie 模式
- id: "iflow-cookie"
auth_type: "cookie"
cookies: "session_id=abc123; auth_token=xyz789"
disabled: false
```
### API Key Provider
```yaml
credential_pool:
# OpenAI API Key
openai:
- id: "openai-main"
api_key: "sk-xxx..."
base_url: "https://api.openai.com/v1"
disabled: false
proxy_url: "http://proxy:8080"
# Claude API Key
claude:
- id: "claude-main"
api_key: "sk-ant-xxx..."
base_url: "https://api.anthropic.com"
disabled: false
```
### Gemini API Key 多账号
```yaml
credential_pool:
# Gemini API Key 多账号负载均衡
gemini_api_keys:
- id: "gemini-key-1"
api_key: "AIzaSy...01"
base_url: "https://generativelanguage.googleapis.com"
proxy_url: "socks5://proxy1:1080"
excluded_models:
- "gemini-2.5-pro" # 排除特定模型
- "gemini-2.5-*" # 通配符前缀匹配
- "*-preview" # 通配符后缀匹配
disabled: false
- id: "gemini-key-2"
api_key: "AIzaSy...02"
disabled: false
```
### Vertex AI Provider
```yaml
credential_pool:
# Vertex AI 凭证
vertex_api_keys:
- id: "vertex-main"
api_key: "vk-123..."
base_url: "https://example.com/api"
proxy_url: "socks5://proxy:1080"
# 模型别名映射
models:
- name: "gemini-2.0-flash"
alias: "vertex-flash"
- name: "gemini-1.5-pro"
alias: "vertex-pro"
disabled: false
```
## 路由配置
```yaml
# 路由配置
auth: "api-key"
routing:
# 默认 Provider
default_provider: "kiro"
# 路由规则
rules:
- pattern: "claude-*"
provider: "kiro"
priority: 1
- pattern: "gemini-*"
provider: "gemini"
priority: 2
- pattern: "gpt-*"
provider: "openai"
priority: 3
# 模型别名
model_aliases:
"claude-latest": "claude-sonnet-4-5-20250514"
"gemini-latest": "gemini-2.5-pro"
# 排除列表
exclusions:
kiro:
- "claude-3-opus-*"
gemini:
- "gemini-1.0-*"
fallback: true
```
## 重试配置
适用:有脚本联动、自动化流程需求的用户。
```yaml
# 重试配置
retry:
max_retries: 3
base_delay_ms: 1000
max_delay_ms: 30000
auto_switch_provider: true
```
## 调整顺序建议
## 日志配置
```yaml
# 日志配置
logging:
enabled: true
level: "info"
retention_days: 7
include_request_body: false
```
## 参数注入配置
```yaml
# 参数注入配置
injection:
enabled: true
rules:
- id: "thinking-budget"
pattern: "gemini-2.5-*"
parameters:
generationConfig:
thinkingConfig:
thinkingBudget: 32768
mode: "default" # default: 仅在参数缺失时设置
priority: 1
enabled: true
- id: "reasoning-effort"
pattern: "gpt-*"
parameters:
reasoning:
effort: "high"
mode: "override" # override: 总是覆盖
priority: 2
enabled: true
```
## 完整配置示例
以下是一个完整的配置文件示例:
```yaml
# ProxyCast 完整配置示例
server:
host: "127.0.0.1"
port: 8999
api_key: "your-api-key"
tls:
enable: false
cert_path: ""
key_path: ""
proxy_url: ""
auth_dir: "~/.proxycast/auth"
remote_management:
allow_remote: false
secret_key: ""
disable_control_panel: false
quota_exceeded:
switch_project: true
switch_preview_model: true
cooldown_seconds: 300
ampcode:
upstream_url: ""
restrict_management_to_localhost: false
model_mappings: []
credential_pool:
kiro:
- id: "kiro-main"
token_file: "kiro/main-token.json"
disabled: false
gemini: []
qwen: []
openai: []
claude: []
gemini_api_keys: []
vertex_api_keys: []
codex: []
iflow: []
routing:
default_provider: "kiro"
rules: []
model_aliases: {}
exclusions: {}
retry:
max_retries: 3
base_delay_ms: 1000
max_delay_ms: 30000
auto_switch_provider: true
logging:
enabled: true
level: "info"
retention_days: 7
include_request_body: false
injection:
enabled: false
rules: []
```
1. 先确认导航与主题
2. 再确认连接与稳定性
3. 最后再做 API 与自动化扩展
+38 -114
View File
@@ -1,142 +1,66 @@
---
title: 智能路由
description: 配置请求路由规则
title: 模型分发规则
description: 按任务类型将请求分发到不同模型(进阶)
navigation:
icon: i-heroicons-arrows-right-left
---
# 智能路由
# 模型分发规则
智能路由允许你根据模型名称将请求定向到特定的 Provider。
::alert{type="info"}
这是进阶能力。只有在“多模型并行使用”时才需要配置。
::
## 模型映射
分发规则用于把不同任务自动交给更合适的模型。
### 映射规则
## 什么时候需要它
将请求中的模型名称映射到实际的 Provider 和模型:
- 文本创作和图片任务使用不同模型
- 同一主题需要“快速草稿 + 高质量润色”两种路径
- 你希望把高成本任务限制在特定模型上
| 请求模型 | 目标 Provider | 目标模型 |
|----------|---------------|----------|
| `gpt-4` | Kiro Claude | `claude-sonnet-4-20250514` |
| `gpt-3.5-turbo` | Gemini CLI | `gemini-2.0-flash` |
| `claude-*` | Kiro Claude | 保持原样 |
## 常见策略
### 配置映射
### 按任务类型分发
1. 进入 **智能路由** 页面
2. 点击 **添加规则**
3. 配置映射:
- 长文写作走高质量模型
- 快速问答走低延迟模型
- 图片任务走图片专用模型
```yaml
# 示例配置
routes:
- pattern: "gpt-4*"
provider: kiro-claude
model: claude-sonnet-4-20250514
- pattern: "gpt-3.5*"
provider: gemini-cli
model: gemini-2.0-flash
```
### 按阶段分发
## 规则语法
- 初稿阶段:速度优先
- 定稿阶段:质量优先
### 模式匹配
### 按兜底分发
| 模式 | 说明 | 示例 |
|------|------|------|
| `exact` | 精确匹配 | `gpt-4` 只匹配 `gpt-4` |
| `prefix*` | 前缀匹配 | `gpt-4*` 匹配 `gpt-4`, `gpt-4-turbo` |
| `*suffix` | 后缀匹配 | `*-turbo` 匹配 `gpt-4-turbo` |
| `*contains*` | 包含匹配 | `*claude*` 匹配任何包含 claude 的模型 |
主模型异常时,自动回退到备用模型。
### 规则字段
| 字段 | 必填 | 说明 |
|------|------|------|
| pattern | ✅ | 模型名称匹配模式 |
| provider | ✅ | 目标 Provider |
| model | ❌ | 目标模型(不填则保持原样) |
| priority | ❌ | 规则优先级(默认 100) |
| enabled | ❌ | 是否启用(默认 true) |
## 优先级排序
### 规则优先级
- 数值越小优先级越高
- 相同优先级按添加顺序
- 第一个匹配的规则生效
### 示例
## 示例(示意)
```yaml
routes:
# 优先级 10:精确匹配优先
- pattern: "gpt-4-turbo"
provider: openai-custom
- pattern: "video-script-*"
provider: "primary"
model: "high-quality-model"
priority: 10
# 优先级 50:前缀匹配
- pattern: "gpt-4*"
provider: kiro-claude
priority: 50
# 优先级 100:默认规则
- pattern: "quick-*"
provider: "fast-lane"
model: "fast-model"
priority: 20
- pattern: "*"
provider: gemini-cli
provider: "fallback"
priority: 100
```
## 默认回退
## 配置建议
### 无规则匹配时
1. 先只配 2 到 3 条关键规则
2. 给兜底规则留最后优先级
3. 每次改完都做一次路由测试
当请求的模型不匹配任何规则时:
## 常见误区
1. 使用默认 Provider
2. 保持原始模型名称
3. 如果默认 Provider 不支持该模型,返回错误
### 配置默认 Provider
```yaml
default:
provider: kiro-claude
fallback: true # 启用回退
```
## Provider 选择
### 可用 Provider
| Provider | 标识 | 说明 |
|----------|------|------|
| Kiro Claude | `kiro-claude` | Kiro IDE 的 Claude |
| Gemini CLI | `gemini-cli` | Google Gemini |
| Qwen | `qwen` | 通义千问 |
| OpenAI Custom | `openai-custom` | 自定义 OpenAI |
| Claude Custom | `claude-custom` | 自定义 Claude |
### 多 Provider 负载均衡
同一规则可以指定多个 Provider:
```yaml
routes:
- pattern: "gpt-4*"
providers:
- kiro-claude
- claude-custom
strategy: round-robin
```
## 测试路由
### 路由测试工具
1. 输入模型名称
2. 点击 **测试路由**
3. 查看匹配结果:
- 匹配的规则
- 目标 Provider
- 目标模型
- 规则过多导致难以维护
- 没有兜底规则,异常时直接失败
- 频繁改规则但不做回归测试
+39 -116
View File
@@ -1,145 +1,68 @@
---
title: 容错配置
description: 重试、超时和故障转移设置
title: 稳定性与容错
description: 在高强度创作下保持调用稳定(进阶)
navigation:
icon: i-heroicons-shield-check
---
# 容错配置
# 稳定性与容错
容错配置帮助你的应用优雅地处理 API 故障,确保服务稳定性。
::alert{type="info"}
这是进阶能力。只有在你频繁遇到超时、失败、波动时才需要细调。
::
## 重试机制
稳定性配置的核心目标是:
### 重试配置
- 少失败
- 失败后可恢复
- 出错时可定位
| 选项 | 默认值 | 说明 |
|------|--------|------|
| 最大重试次数 | 3 | 失败后重试的最大次数 |
| 初始延迟 | 1s | 首次重试前的等待时间 |
| 最大延迟 | 30s | 重试延迟的上限 |
| 退避倍数 | 2 | 每次重试延迟的增长倍数 |
## 三个关键参数
### 退避策略
### 重试
```
第1次重试: 1s
第2次重试: 2s
第3次重试: 4s
...
```
用于处理偶发失败。
### 可重试错误
建议:
以下错误会触发重试:
- 最大重试次数:2 到 3 次
- 首次重试延迟:1 秒左右
- 使用递增退避,避免短时间反复打满请求
- 网络超时
- 连接失败
- 5xx 服务器错误
- 429 速率限制
### 超时
不重试的错误:
用于避免单次请求长时间卡住。
- 4xx 客户端错误(除 429)
- 认证失败
- 无效请求
建议:
## 超时设置
- 普通文本任务:较短超时
- 长文或复杂任务:适当放宽
- 图片任务:通常需要更长超时
### 超时配置
### 故障回退
| 选项 | 默认值 | 说明 |
|------|--------|------|
| 连接超时 | 10s | 建立连接的超时时间 |
| 请求超时 | 120s | 整个请求的超时时间 |
| 流式超时 | 300s | 流式响应的超时时间 |
主连接失败后自动走备用连接,减少中断。
### 按 Provider 配置
## 推荐调参顺序
可以为不同 Provider 设置不同的超时:
1. 先调超时
2. 再调重试
3. 最后配置回退策略
```yaml
timeouts:
default:
connect: 10s
request: 120s
kiro-claude:
request: 180s # Claude 响应较慢
gemini-cli:
request: 60s # Gemini 响应较快
```
## 诊断建议
## 故障转移
### 连续失败
### 自动故障转移
优先检查:
当主 Provider 失败时,自动切换到备用 Provider:
1. 连接状态是否可用
2. 当前模型是否可调用
3. 是否触发限流
1. 主 Provider 请求失败
2. 检查是否有可用的备用 Provider
3. 使用备用 Provider 重试请求
4. 记录故障转移事件
### 偶发失败
### 配置故障转移
通常先提高重试效果更明显。
```yaml
failover:
enabled: true
providers:
- kiro-claude # 主 Provider
- claude-custom # 备用 Provider 1
- gemini-cli # 备用 Provider 2
maxAttempts: 3 # 最大尝试 Provider 数
```
### 高峰波动
### 故障转移条件
| 条件 | 说明 |
|------|------|
| 连接失败 | 无法连接到 Provider |
| 认证失败 | Token 过期或无效 |
| 速率限制 | 达到 Provider 限制 |
| 服务不可用 | Provider 返回 503 |
## 熔断器
### 熔断器状态
| 状态 | 说明 |
|------|------|
| 关闭 | 正常工作,请求通过 |
| 打开 | 熔断激活,请求直接失败 |
| 半开 | 尝试恢复,允许部分请求 |
### 熔断配置
| 选项 | 默认值 | 说明 |
|------|--------|------|
| 失败阈值 | 5 | 触发熔断的连续失败次数 |
| 恢复时间 | 30s | 熔断后尝试恢复的等待时间 |
| 半开请求数 | 3 | 半开状态允许的测试请求数 |
### 熔断流程
```
正常 → 连续失败5次 → 熔断打开
熔断打开 → 等待30s → 半开状态
半开状态 → 3次成功 → 恢复正常
半开状态 → 1次失败 → 重新熔断
```
## 监控告警
### 告警条件
- 错误率超过阈值
- 延迟超过阈值
- 熔断器打开
- 所有 Provider 不可用
### 告警通知
当前支持:
- 应用内通知
- 系统通知(macOS/Windows)
建议拆分任务批次,避免同一时刻大量并发。
+35 -145
View File
@@ -1,173 +1,63 @@
---
title: 配置管理
description: 导出和导入配置
title: 配置管理与迁移
description: 导出、导入、备份与跨设备迁移配置
navigation:
icon: i-heroicons-document-duplicate
---
# 配置管理
# 配置管理与迁移
配置管理功能允许你导出、导入和分享 ProxyCast 配置。
配置管理适合两类人:
## YAML 导出
- 想把当前工作台快速迁移到另一台设备
- 团队内需要统一一套基础配置
### 导出内容
## 导出配置
导出的 YAML 文件包含:
你可以将当前设置导出为配置文件,常用于备份和迁移。
- Provider 配置
- 路由规则
- 容错设置
- API Server 配置
- 通用设置
常见导出内容:
### 导出步骤
1. 进入 **设置** > **配置管理**
2. 点击 **导出配置**
3. 选择保存位置
4. 配置保存为 `.yaml` 文件
### 导出格式
```yaml
version: "1.0"
providers:
- name: kiro-claude
type: kiro
enabled: true
priority: 1
- name: gemini-cli
type: gemini
enabled: true
priority: 2
routes:
- pattern: "gpt-4*"
provider: kiro-claude
model: claude-sonnet-4-20250514
resilience:
retry:
maxAttempts: 3
initialDelay: 1s
timeout:
request: 120s
server:
host: "127.0.0.1"
port: 8999
```
### 敏感信息处理
- 主题与导航偏好
- 部分连接与路由策略
- 稳定性相关参数
::alert{type="warning"}
导出的配置**不包含**凭证信息(Token、API Key)。导入后需要重新配置凭证。
导出文件通常不包含敏感凭证信息。导入后需重新检查连接状态。
::
## 导入配置
### 导入步骤
1. 在设置页选择导入
2. 预览配置差异
3. 选择覆盖或合并策略
4. 导入后做一次连接与功能自检
1. 进入 **设置** > **配置管理**
2. 点击 **导入配置**
3. 选择 `.yaml` 配置文件
4. 预览导入内容
5. 确认导入
## 备份建议
### 冲突解决
### 个人用户
当导入的配置与现有配置冲突时:
至少保留最近 2 到 3 份配置备份。
| 选项 | 说明 |
|------|------|
| 覆盖 | 用导入的配置替换现有配置 |
| 跳过 | 保留现有配置,跳过冲突项 |
| 合并 | 合并两个配置(仅适用于列表类型) |
### 团队用户
### 验证导入
建议按版本管理配置文件,例如:
导入前会验证:
- `team-config-v1.yaml`
- `team-config-v1.1.yaml`
- YAML 语法正确性
- 配置版本兼容性
- 必填字段完整性
## 跨设备迁移清单
## .env 格式导出
1. 导出配置文件
2. 在新设备导入配置
3. 重新校验连接状态
4. 检查主题、导航、资源路径是否符合预期
5. 进行一次完整创作演练
### 用途
## 什么时候需要重置
导出为 `.env` 格式,方便在其他工具中使用:
当你长期调参后“越调越乱”,最稳妥的方式是:
- 脚本调用
- Docker 环境
- CI/CD 配置
### 导出内容
```bash
# ProxyCast API Configuration
PROXYCAST_API_BASE=http://127.0.0.1:8999/v1
PROXYCAST_API_KEY=your-api-key
# OpenAI Compatible
OPENAI_API_BASE=http://127.0.0.1:8999/v1
OPENAI_API_KEY=your-api-key
# Claude Compatible
ANTHROPIC_API_BASE=http://127.0.0.1:8999
ANTHROPIC_API_KEY=your-api-key
```
### 导出步骤
1. 进入 **设置** > **配置管理**
2. 点击 **导出 .env**
3. 选择保存位置
## 配置备份
### 自动备份
ProxyCast 会自动备份配置:
- 每次修改后自动保存
- 保留最近 10 个版本
- 备份位置:`~/.proxycast/backups/`
### 恢复备份
1. 进入 **设置** > **配置管理**
2. 点击 **备份历史**
3. 选择要恢复的版本
4. 点击 **恢复**
## 完整备份与恢复(生产建议)
仅导出配置无法覆盖数据库与凭证文件。生产环境建议定期备份以下路径:
- 配置文件:macOS `~/Library/Application Support/proxycast/config.yaml`;Linux `~/.config/proxycast/config.yaml`;Windows `%APPDATA%\\proxycast\\config.yaml`
- 凭证副本目录:macOS `~/Library/Application Support/proxycast/credentials/`;Linux `~/.local/share/proxycast/credentials/`;Windows `%APPDATA%\\proxycast\\credentials\\`
- 数据库与日志:`~/.proxycast/`(含 `proxycast.db`、`logs/`、`request_logs/`、`auth/`)
```bash
# 示例:备份数据库与日志目录
cp -a ~/.proxycast ~/.proxycast.backup-$(date +%Y%m%d%H%M%S)
```
恢复时将备份内容替换回原路径,并确保应用已退出。
## 旧版本迁移说明
如果检测到旧版 `~/.proxycast/config.json`,当前版本会阻止启动并提示手动迁移。请先导出旧配置或重新导入 YAML 配置,再启动应用。
## 配置同步
### 跨设备同步
通过导出/导入实现跨设备配置同步:
1. 在设备 A 导出配置
2. 将配置文件传输到设备 B
3. 在设备 B 导入配置
4. 重新配置凭证
1. 先备份当前配置
2. 恢复到基础配置
3. 只按必要场景逐项开启进阶能力
+29 -131
View File
@@ -1,152 +1,50 @@
---
title: 配置切换
description: 快速切换 AI 客户端配置
title: 工作模式切换
description: 在不同创作场景间快速切换配置
navigation:
icon: i-heroicons-arrows-up-down
---
# 配置切换
# 工作模式切换
配置切换功能让你可以一键在不同的 AI 客户端配置之间切换。
如果你在不同场景下有明显不同的工作方式,可以使用配置档案快速切换。
## 功能目的
## 典型模式
当你需要在不同场景使用不同的 AI 服务时:
### 日更模式
- 开发时使用 Kiro Claude
- 测试时使用 Gemini CLI
- 生产时使用自定义 OpenAI
- 目标:快速产出
- 适合:社媒短内容、灵感快写
- 特点:速度优先、流程简化
配置切换让你无需手动修改配置,一键完成切换。
### 深度创作模式
## 预设配置
- 目标:质量优先
- 适合:长文、小说章节、方案定稿
- 特点:更强调结构和多轮迭代
### 内置配置档案
### 出图冲刺模式
| 档案 | 说明 |
|------|------|
| Claude Code | 适用于 Claude Code 客户端 |
| Codex | 适用于 OpenAI Codex |
| Gemini CLI | 适用于 Gemini CLI |
- 目标:集中生成并沉淀图片素材
- 适合:活动海报、视觉素材周更
- 特点:图片相关入口前置、资源回流优先
### 配置内容
## 建议的档案字段
每个档案包含:
每个档案建议包含:
- 默认 Provider
- 路由规则
- 模型映射
- API 端点配置
- 启用的导航模块
- 启用的创作主题
- 关键连接与稳定性偏好
## 创建配置档案
### 新建档案
1. 进入 **配置切换** 页面
2. 点击 **新建档案**
3. 输入档案名称
4. 配置以下内容:
```yaml
name: "我的配置"
description: "自定义配置档案"
provider: kiro-claude
routes:
- pattern: "*"
provider: kiro-claude
settings:
timeout: 120s
retry: 3
```
### 从当前配置创建
1. 配置好当前设置
2. 点击 **保存为档案**
3. 输入档案名称
4. 档案保存成功
## 切换配置
### 一键切换
1. 进入 **配置切换** 页面
2. 查看可用档案列表
3. 点击目标档案的 **应用** 按钮
4. 配置立即生效
### 快捷切换
使用标签页快速切换:
- **Claude Code** 标签
- **Codex** 标签
- **Gemini CLI** 标签
点击标签即可切换到对应配置。
## 设置活动配置
### 标记当前配置
当前使用的配置会显示 **当前使用中** 标记。
### 切换活动配置
## 切换步骤
1. 选择目标档案
2. 点击 **设为活动**
3. 该档案成为当前活动配置
2. 应用后检查核心入口是否符合预期
3. 用一个小任务做快速验证
## 档案管理
## 使用建议
### 编辑档案
1. 点击档案的 **编辑** 按钮
2. 修改配置内容
3. 点击 **保存**
### 删除档案
1. 点击档案的 **删除** 按钮
2. 确认删除操作
::alert{type="warning"}
内置档案无法删除,但可以修改。
::
### 导出档案
单独导出某个档案:
1. 点击档案的 **导出** 按钮
2. 选择保存位置
3. 档案保存为 `.yaml` 文件
### 导入档案
1. 点击 **导入档案**
2. 选择 `.yaml` 文件
3. 档案添加到列表
## 使用场景
### 场景 1: 开发/测试切换
```
开发环境: 使用 Kiro Claude(免费额度)
测试环境: 使用 Gemini CLI(快速响应)
```
### 场景 2: 模型切换
```
代码生成: Claude Sonnet(高质量)
快速问答: Gemini Flash(低延迟)
```
### 场景 3: 团队协作
```
团队成员 A: 使用个人 Kiro 账户
团队成员 B: 使用共享 API Key
```
1. 档案数量控制在 3 个以内
2. 一个档案只服务一个明确场景
3. 变更档案后记录用途,避免后续混乱
+25 -140
View File
@@ -1,167 +1,52 @@
---
title: API Server
description: 配置和管理 API 服务
title: 本地 API 接入
description: 将 ProxyCast 能力暴露给外部工具(进阶)
navigation:
icon: i-heroicons-server
---
# API Server
# 本地 API 接入
API Server 是 ProxyCast 的核心组件,提供 OpenAI/Claude 兼容的 API 端点。
## 服务器配置
### 基本配置
| 选项 | 默认值 | 说明 |
|------|--------|------|
| 主机地址 | `127.0.0.1` | 监听地址 |
| 端口 | `8999` | 监听端口 |
| API Key | 自动生成 | 访问密钥 |
### 配置步骤
1. 进入 **设置** > **API Server**
2. 修改配置选项
3. 点击 **保存**
4. 重启服务生效
### 监听地址
| 地址 | 说明 |
|------|------|
| `127.0.0.1` | 仅本机访问 |
| `localhost` | 仅本机访问 |
::alert{type="warning"}
当前版本仅支持本地监听(127.0.0.1/localhost/::1),不支持对外开放。
::alert{type="info"}
这是进阶能力。普通创作者可以不配置,直接在应用内完成创作。
::
## API 端点
当你希望把 ProxyCast 接入脚本、自动化工具或第三方客户端时,可启用本地 API。
### OpenAI 兼容端点
## 核心说明
| 端点 | 方法 | 说明 |
|------|------|------|
| `/v1/chat/completions` | POST | 聊天补全 |
| `/v1/models` | GET | 模型列表 |
| `/v1/embeddings` | POST | 文本嵌入 |
- 服务默认在本地地址运行
- 通过 API Key 控制访问
- 支持常见兼容接口形态
### Claude 兼容端点
## 快速配置
| 端点 | 方法 | 说明 |
|------|------|------|
| `/v1/messages` | POST | 消息 API |
| `/v1/messages/count_tokens` | POST | Token 计数 |
## 请求日志
### 日志查看
1. 进入 **监控中心**
2. 查看 **请求日志** 标签
3. 实时显示所有请求
### 日志内容
每条日志包含:
- 时间戳
- 请求方法和路径
- 请求模型
- 响应状态
- 响应时间
- Token 使用量
### 日志过滤
支持按以下条件过滤:
- 时间范围
- 状态码
- 模型名称
- Provider
## 访问控制
### API Key 认证
启用 API Key 认证:
1. 进入 **设置** > **API Server**
2. 开启 **启用认证**
1. 进入设置中的 API Server
2. 开启服务并确认端口
3. 设置或生成 API Key
4. 保存配置
4. 使用一条测试请求验证连通性
### 请求认证
## 最小测试示例
请求时需要携带 API Key:
**OpenAI 格式:**
```bash
curl http://127.0.0.1:8999/v1/chat/completions \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4", "messages": [...]}'
-d '{"model":"your-model","messages":[{"role":"user","content":"你好"}]}'
```
**Claude 格式:**
```bash
curl http://127.0.0.1:8999/v1/messages \
-H "x-api-key: your-api-key" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"model": "claude-3-sonnet", "messages": [...]}'
```
## 安全建议
### 多 API Key
1. 只在本机环境使用
2. 不要把 API Key 提交到代码仓库
3. 定期更换密钥并清理无效连接
支持配置多个 API Key:
## 常见问题
```yaml
auth:
keys:
- name: "开发环境"
key: "dev-key-xxx"
- name: "生产环境"
key: "prod-key-xxx"
```
### 启动后无法访问
## CORS 配置
先确认端口未被占用,再检查本地防火墙策略。
### 跨域设置
### 请求总是 401
| 选项 | 默认值 | 说明 |
|------|--------|------|
| 允许来源 | `*` | 允许的请求来源 |
| 允许方法 | `GET,POST,OPTIONS` | 允许的 HTTP 方法 |
| 允许头部 | `*` | 允许的请求头 |
### 配置示例
```yaml
cors:
origins:
- "http://localhost:3000"
- "https://myapp.com"
methods:
- GET
- POST
headers:
- Authorization
- Content-Type
```
## 服务管理
### 启动/停止
- **启动**: 点击仪表盘的 **启动服务** 按钮
- **停止**: 点击 **停止服务** 按钮
- **重启**: 点击 **重启服务** 按钮
### 开机自启
1. 进入 **设置** > **通用**
2. 开启 **开机自动启动**
3. 开启 **启动时自动运行服务**
通常是 API Key 填写错误或请求头格式不正确。
+27 -159
View File
@@ -1,185 +1,53 @@
---
title: MCP 服务器
description: Model Context Protocol 集成
title: MCP 工具扩展
description: 让 AI 调用外部工具与资源(进阶)
navigation:
icon: i-heroicons-puzzle-piece
---
# MCP 服务器
# MCP 工具扩展
MCP (Model Context Protocol) 是一种标准协议,允许 AI 模型与外部工具和数据源交互。
MCP 可以让 AI 不只“回答问题”,还可以调用外部工具完成动作。
## MCP 概念
::alert{type="info"}
这是进阶能力。建议先熟悉基础创作流程,再接入 MCP。
::
### 什么是 MCP
## 适合的场景
MCP 定义了 AI 模型与外部系统交互的标准方式:
- 让 AI 读取指定目录素材
- 连接外部知识源或服务
- 把重复操作做成可调用工具
- **工具调用**: AI 可以调用外部工具执行操作
- **资源访问**: AI 可以读取外部数据源
- **上下文扩展**: 为 AI 提供额外的上下文信息
## 基本使用流程
### 集成优势
1. 添加 MCP 服务器配置
2. 启动并确认连接状态
3. 在工具列表里验证可用工具
4. 在实际任务里小范围试跑
- 扩展 AI 能力,执行实际操作
- 访问实时数据和外部服务
- 标准化的工具接口
## 服务器配置
### 添加 MCP 服务器
1. 进入 **MCP** 页面
2. 点击 **添加服务器**
3. 配置服务器信息:
| 字段 | 说明 |
|------|------|
| 名称 | 服务器标识名称 |
| 命令 | 启动命令 |
| 参数 | 命令参数 |
| 环境变量 | 环境变量配置 |
### 配置示例
## 一个简单示例
```json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"],
"env": {}
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "your-token"
}
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/workspace"]
}
}
}
```
### 连接设置
## 安全边界建议
| 选项 | 说明 |
|------|------|
| 自动启动 | 应用启动时自动连接 |
| 重连间隔 | 断开后重连的等待时间 |
| 超时时间 | 连接超时设置 |
1. 只授权必要目录和资源
2. 敏感环境变量不要硬编码在公开配置里
3. 新工具先在测试项目验证
## 工具调用
## 排错顺序
### 可用工具
连接 MCP 服务器后,可以查看提供的工具:
1. 进入 **MCP** 页面
2. 选择已连接的服务器
3. 查看 **工具列表**
### 工具信息
每个工具显示:
- 工具名称
- 功能描述
- 输入参数
- 返回类型
### 调用示例
通过 API 调用 MCP 工具:
```bash
curl http://127.0.0.1:8999/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-api-key" \
-d '{
"model": "claude-sonnet-4-20250514",
"messages": [
{"role": "user", "content": "读取 /tmp/test.txt 文件内容"}
],
"tools": [
{
"type": "function",
"function": {
"name": "read_file",
"description": "读取文件内容",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string"}
}
}
}
}
]
}'
```
## 常用 MCP 服务器
### 文件系统
```json
{
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/allowed/path"]
}
}
```
### GitHub
```json
{
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "ghp_xxx"
}
}
}
```
### 数据库
```json
{
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "postgresql://..."
}
}
}
```
## 服务器管理
### 启动/停止
- **启动**: 点击服务器的 **启动** 按钮
- **停止**: 点击 **停止** 按钮
- **重启**: 点击 **重启** 按钮
### 状态监控
| 状态 | 说明 |
|------|------|
| 🟢 已连接 | 服务器正常运行 |
| 🔴 已断开 | 服务器未连接 |
| 🟡 连接中 | 正在建立连接 |
### 日志查看
查看 MCP 服务器的运行日志:
1. 选择服务器
2. 点击 **查看日志**
3. 实时显示服务器输出
1. 看连接状态是否正常
2. 看工具是否成功注册
3. 看调用参数是否符合工具定义
4. 看服务器日志定位具体错误
+32 -98
View File
@@ -1,134 +1,68 @@
---
title: Provider 概述
description: 支持的 AI 服务提供商
title: 模型连接概览
description: 了解不同连接方式,并按你的创作目标选择
navigation:
icon: i-heroicons-squares-2x2
---
# Provider 概述
# 模型连接概览
ProxyCast 支持多种 AI 服务提供商(Provider),每种 Provider 有不同的认证方式和特点。
::alert{type="info"}
本章节属于进阶内容。普通创作者可先使用默认连接,只有在需要多账号或精细控制时再深入配置。
::
## Provider 类型
ProxyCast 支持多种模型连接方式,你可以按自己的使用习惯选择。
### OAuth 类型
## 两类连接方式
通过 OAuth 协议认证,支持自动刷新 Token:
### 自动连接(推荐)
| Provider | 说明 |
|----------|------|
| Kiro Claude | AWS Kiro IDE 的 Claude 凭证 |
| Gemini CLI | Google Gemini CLI 凭证 |
| Qwen | 阿里云通义千问凭证 |
| Codex | OpenAI Codex OAuth 凭证 |
| iFlow | iFlow OAuth 凭证(也支持 Cookie) |
适合希望“少配置、快开始”的用户:
### API Key 类型
- 登录对应客户端后自动识别
- 日常创作可直接使用
使用 API Key 认证,需要手动配置:
### 手动连接
| Provider | 说明 |
|----------|------|
| OpenAI Custom | 自定义 OpenAI 兼容服务 |
| Claude Custom | 自定义 Claude 兼容服务 |
| Gemini API Key | Gemini API Key 多账号负载均衡 |
| Vertex AI | Google Cloud Vertex AI 服务 |
适合有明确工程需求的用户:
## 选择指南
- 手动填写 API Key
- 自定义 Base URL
- 多账号并行管理
### 根据使用场景选择
## 如何选择
| 场景 | 推荐 Provider |
|------|---------------|
| 已有 Kiro 订阅 | Kiro Claude |
| 已有 Google AI 订阅 | Gemini CLI |
| 已有阿里云订阅 | Qwen |
| 有 OpenAI API Key | OpenAI Custom |
| 有 Anthropic API Key | Claude Custom |
### 追求稳定创作
### 根据模型需求选择
优先选择你最常用、最稳定的连接方式,保持单一主连接即可。
| 模型系列 | Provider |
|----------|----------|
| Claude 系列 | Kiro Claude, Claude Custom |
| Gemini 系列 | Gemini CLI |
| Qwen 系列 | Qwen |
| GPT 系列 | OpenAI Custom |
### 追求多模型组合
## Provider 特性对比
可按任务分配不同连接,例如:
| 特性 | Kiro | Gemini | Qwen | Codex | iFlow | Gemini API Key | Vertex AI |
|------|------|--------|------|-------|-------|----------------|-----------|
| 自动刷新 Token | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| 流式响应 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 工具调用 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 视觉能力 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 自定义 Base URL | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
| 多账号负载均衡 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 模型排除 | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ |
| 模型别名 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
| Per-Key 代理 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
- 长文与定稿使用质量优先模型
- 快速草稿与批量任务使用速度优先模型
- 图片任务使用视觉能力更强的模型
## 配置流程
### 追求高可用
### OAuth Provider
可配置多个连接作为冗余,避免单点失败影响创作。
1. 确保已安装对应的 AI 客户端
2. 在客户端中完成登录
3. ProxyCast 自动检测凭证文件
4. 在凭证池中确认凭证状态
## 配置建议
### API Key Provider
1. 获取 API Key
2. 在 ProxyCast 中添加凭证
3. 配置 Base URL(如需要)
4. 测试凭证有效性
## 多 Provider 配置
### 负载均衡
配置多个 Provider 实现负载均衡:
```yaml
providers:
- name: kiro-1
type: kiro
priority: 1
- name: kiro-2
type: kiro
priority: 2
- name: gemini-backup
type: gemini
priority: 10
```
### 故障转移
主 Provider 失败时自动切换:
```yaml
failover:
enabled: true
order:
- kiro-claude
- claude-custom
- gemini-cli
```
1. 先完成一个主连接并测试可用
2. 再按场景增加备用连接
3. 每次新增连接后做一次小任务验证
## 下一步
选择你要配置的 Provider:
按你的连接类型进入对应页面:
### OAuth Provider
- [Kiro Claude](/providers/kiro-claude)
- [Gemini CLI](/providers/gemini-cli)
- [Qwen](/providers/qwen)
- [Codex](/providers/codex)
- [iFlow](/providers/iflow)
### API Key Provider
- [OpenAI Custom](/providers/openai-custom)
- [Claude Custom](/providers/claude-custom)
- [Gemini API Key](/providers/gemini-api-key)
@@ -7,6 +7,10 @@ navigation:
# Vertex AI Provider
::alert{type="info"}
本页属于进阶连接配置。若你已能正常创作,可先跳过。
::
使用 API Key 访问 Google Cloud Vertex AI 服务,支持模型别名映射。
## 概述
@@ -7,6 +7,10 @@ navigation:
# Kiro Claude
::alert{type="info"}
本页属于进阶连接配置。若你已能正常创作,可先跳过。
::
Kiro Claude 是 AWS Kiro IDE 提供的 Claude AI 服务凭证。
## 凭证位置
@@ -7,6 +7,10 @@ navigation:
# Gemini CLI
::alert{type="info"}
本页属于进阶连接配置。若你已能正常创作,可先跳过。
::
Gemini CLI 是 Google 提供的命令行 AI 工具,使用 OAuth 认证。
## 凭证位置
+4
View File
@@ -7,6 +7,10 @@ navigation:
# Qwen (通义千问)
::alert{type="info"}
本页属于进阶连接配置。若你已能正常创作,可先跳过。
::
Qwen 是阿里云提供的大语言模型服务。
## 凭证位置
@@ -7,6 +7,10 @@ navigation:
# OpenAI Custom
::alert{type="info"}
本页属于进阶连接配置。若你已能正常创作,可先跳过。
::
OpenAI Custom 允许你配置任何 OpenAI 兼容的 API 服务。
## 适用场景
@@ -7,6 +7,10 @@ navigation:
# Claude Custom
::alert{type="info"}
本页属于进阶连接配置。若你已能正常创作,可先跳过。
::
Claude Custom 允许你配置 Anthropic 官方 API 或其他 Claude 兼容服务。
## 适用场景
+4
View File
@@ -7,6 +7,10 @@ navigation:
# Codex Provider
::alert{type="info"}
本页属于进阶连接配置。若你已能正常创作,可先跳过。
::
通过 OAuth 认证使用 OpenAI Codex 服务。
## 概述
+4
View File
@@ -7,6 +7,10 @@ navigation:
# iFlow Provider
::alert{type="info"}
本页属于进阶连接配置。若你已能正常创作,可先跳过。
::
iFlow Provider 支持两种认证方式:OAuth 和 Cookie。
## 概述
@@ -7,6 +7,10 @@ navigation:
# Gemini API Key Provider
::alert{type="info"}
本页属于进阶连接配置。若你已能正常创作,可先跳过。
::
使用 API Key 访问 Google Gemini 服务,支持多账号负载均衡和模型排除。
## 概述
+29 -81
View File
@@ -1,107 +1,55 @@
---
title: API 概述
description: ProxyCast API 端点和认证
title: API 概览
description: 面向进阶用户的本地接口能力说明
navigation:
icon: i-heroicons-code-bracket
---
# API 概述
# API 概览
ProxyCast 提供 OpenAI 和 Claude 兼容的 API 端点。
::alert{type="info"}
本章节面向进阶用户与开发者。普通创作者可直接在应用内使用,无需 API 接入。
::
## 支持的端点
当你需要把 ProxyCast 接入脚本、自动化流程或第三方工具时,可使用本地 API。
### OpenAI 兼容
## 常见端点类型
| 端点 | 方法 | 说明 |
|------|------|------|
| `/v1/chat/completions` | POST | 聊天补全 |
| `/v1/models` | GET | 模型列表 |
| `/v1/embeddings` | POST | 文本嵌入 |
### 通用对话端点
### Claude 兼容
用于文本生成、对话续写等任务。
| 端点 | 方法 | 说明 |
|------|------|------|
| `/v1/messages` | POST | 消息 API |
| `/v1/messages/count_tokens` | POST | Token 计数 |
### 模型与管理端点
### Amp CLI 路由
用于读取模型列表、状态信息和部分管理能力。
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/provider/{provider}/v1/chat/completions` | POST | Amp 聊天补全 |
| `/api/provider/{provider}/v1/messages` | POST | Amp 消息 API |
| `/api/auth/*` | ANY | Amp 认证代理 |
| `/api/user/*` | ANY | Amp 用户代理 |
### 扩展端点
### 管理 API
| 端点 | 方法 | 说明 |
|------|------|------|
| `/v0/management/status` | GET | 服务器状态 |
| `/v0/management/credentials` | GET/POST/DELETE | 凭证管理 |
| `/v0/management/config` | GET/PUT | 配置管理 |
用于特定平台或集成场景。
## 认证方式
### OpenAI 格式
- `Authorization: Bearer <api-key>`
- 或使用兼容格式的密钥头
使用 `Authorization` 头:
请确保 API Key 仅在可信环境使用。
```bash
curl http://127.0.0.1:8999/v1/chat/completions \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '...'
```
## 默认地址
### Claude 格式
默认本地地址:`http://127.0.0.1:8999`
使用 `x-api-key` 头:
通常建议保持本地监听,不对公网暴露。
```bash
curl http://127.0.0.1:8999/v1/messages \
-H "x-api-key: your-api-key" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '...'
```
## 错误排查建议
## 基础 URL
默认地址:`http://127.0.0.1:8999`
可在设置中修改主机和端口。
## 错误响应
### 错误格式
```json
{
"error": {
"message": "错误描述",
"type": "error_type",
"code": "error_code"
}
}
```
### 常见错误码
| 状态码 | 说明 |
|--------|------|
| 400 | 请求格式错误 |
| 401 | 认证失败 |
| 404 | 端点不存在 |
| 429 | 速率限制 |
| 500 | 服务器错误 |
| 503 | 服务不可用 |
- `401`:密钥错误或请求头格式错误
- `404`:端点路径错误
- `429`:请求频率过高
- `5xx`:服务端异常或上游波动
## 下一步
- [OpenAI API](/api-reference/openai-api) - OpenAI 兼容端点详情
- [Claude API](/api-reference/claude-api) - Claude 兼容端点详情
- [管理 API](/api-reference/management-api) - 远程管理端点详情
- [Amp CLI API](/api-reference/amp-cli-api) - Amp CLI 集成端点详情
- [OpenAI API](/api-reference/openai-api)
- [Claude API](/api-reference/claude-api)
- [管理 API](/api-reference/management-api)
- [Amp CLI API](/api-reference/amp-cli-api)
@@ -7,6 +7,10 @@ navigation:
# OpenAI API
::alert{type="info"}
本页是开发者进阶文档。普通创作者可直接在应用内使用,无需 API 调用。
::
ProxyCast 提供完整的 OpenAI Chat Completions API 兼容。
## /v1/chat/completions
@@ -7,6 +7,10 @@ navigation:
# Claude API
::alert{type="info"}
本页是开发者进阶文档。普通创作者可直接在应用内使用,无需 API 调用。
::
ProxyCast 提供 Anthropic Claude Messages API 兼容。
## /v1/messages
@@ -7,6 +7,10 @@ navigation:
# 管理 API
::alert{type="info"}
本页是开发者进阶文档,主要用于自动化管理与运维集成。
::
ProxyCast 提供远程管理 API,用于配置和监控服务。
## 认证
@@ -7,6 +7,10 @@ navigation:
# Amp CLI API
::alert{type="info"}
本页是开发者进阶文档。若你不涉及 Amp CLI 集成,可跳过。
::
ProxyCast 提供 Amp CLI 兼容的路由端点,支持将 Amp CLI 请求路由到本地 OAuth 凭证。
## 概述
@@ -1,144 +1,107 @@
---
title: 常见问题
description: 常见问题汇总和解决方案
description: 按症状快速定位问题并恢复创作
navigation:
icon: i-heroicons-question-mark-circle
---
# 常见问题
本页汇总了 ProxyCast 使用中的常见问题和解决方案。
本页给你一个最快排查顺序:
## 启动问题
1. 看页面提示
2. 看当前项目与资源选择是否正确
3. 看连接状态与网络
4. 再进入详细排查页
### 应用无法启动
## 启动后看不到内容
**症状**: 双击应用图标后无反应
### 症状
**解决方案**:
- 页面空白或内容未刷新
- 明明生成过,但当前列表看不到
1. **macOS**: 右键点击应用,选择"打开"
2. **Windows**: 以管理员身份运行
3. 检查系统日志查看错误信息
### 先检查
### 端口被占用
1. 是否选错了项目
2. 是否切到了筛选分类(例如只看图片)
3. 是否处于搜索过滤状态
**症状**: 服务启动失败,提示端口已被使用
### 处理建议
**解决方案**:
- 先切回“全部”分类
- 清空搜索词
- 刷新当前页面再确认
```bash
# 查找占用端口的进程
# macOS/Linux
lsof -i :8999
## 图片没显示或数量不对
# Windows
netstat -ano | findstr :8999
```
### 症状
或在设置中更改端口号。
- 资源页看不到已生成图片
- 图片数量和预期不一致
## 凭证问题
### 先检查
### 凭证未检测到
1. 当前资源库(项目)是否正确
2. 是否选在“图片”分类
3. 图片是否已入库(自动或手动补录)
**症状**: 凭证池为空,未显示任何凭证
### 处理建议
**解决方案**:
- 回到图片生成页确认目标资源库
- 对历史结果执行“补录到资源库”
- 回资源页切换“全部”核对总量
1. 确认 AI 客户端已安装并登录
2. 检查凭证文件是否存在
3. 点击"刷新凭证"重新扫描
4. 手动添加凭证
## 生成失败或超时
详见 [凭证错误](/troubleshooting/credential-errors)
### 症状
### Token 过期
- 请求长时间无响应
- 返回超时或失败提示
**症状**: 请求返回 401 错误
### 处理建议
**解决方案**:
1. 降低同一时间的并发任务数
2. 缩短单次输入长度或拆成批次
3. 稍后重试,观察是否为瞬时波动
4. 必要时切换备用连接
1. 打开对应的 AI 客户端
2. 确认登录状态
3. 在 ProxyCast 中刷新凭证
## 认证或权限错误
## 连接问题
### 常见提示
### 无法连接到 Provider
- `401`:认证失败
- `403`:权限不足
**症状**: 请求超时或连接失败
### 处理建议
**解决方案**:
1. 重新确认连接状态
2. 刷新或重建对应连接
3. 再做一次小请求测试
1. 检查网络连接
2. 确认 Provider 服务正常
3. 检查代理设置
详见 [连接鉴权问题](/troubleshooting/credential-errors)。
详见 [连接问题](/troubleshooting/connection-issues)
## 网络连接不稳定
### SSL 证书错误
### 常见提示
**症状**: 提示证书验证失败
- 网络超时
- DNS 解析失败
- TLS/证书错误
**解决方案**:
### 处理建议
1. 检查系统时间是否正确
2. 更新系统根证书
3. 检查代理是否拦截 HTTPS
1. 检查本机网络
2. 检查代理配置是否正确
3. 避开高峰时段进行批量任务
## API 问题
详见 [网络与连接问题](/troubleshooting/connection-issues)。
### 请求返回错误
## 仍然无法解决
**常见错误码**:
请整理以下信息后反馈:
| 错误码 | 原因 | 解决方案 |
|--------|------|----------|
| 400 | 请求格式错误 | 检查请求参数 |
| 401 | 认证失败 | 检查 API Key |
| 404 | 端点不存在 | 检查 URL |
| 429 | 速率限制 | 降低请求频率 |
| 500 | 服务器错误 | 查看日志 |
### 流式响应中断
**症状**: 流式响应突然停止
**解决方案**:
1. 检查网络稳定性
2. 增加超时时间
3. 检查 Provider 状态
## 性能问题
### 响应缓慢
**可能原因**:
1. Provider 响应慢
2. 网络延迟高
3. 请求内容过长
**解决方案**:
1. 切换到更快的 Provider
2. 使用更快的模型
3. 减少请求内容长度
### 内存占用高
**解决方案**:
1. 清除请求日志
2. 减少日志保留天数
3. 重启应用
## 获取帮助
如果以上方案无法解决问题:
1. 查看应用日志
2. 在 GitHub 提交 Issue
3. 提供详细的错误信息和复现步骤
1. 问题发生时间
2. 页面截图与错误文案
3. 复现步骤(尽量 3 步内)
4. 当前版本号
@@ -1,146 +1,61 @@
---
title: 凭证错误
description: OAuth Token 问题诊断
title: 连接鉴权问题
description: 处理连接失效、认证失败与账号状态异常
navigation:
icon: i-heroicons-key
---
# 凭证错误
# 连接鉴权问题
本页帮助你诊断和解决凭证相关的问题。
本页用于处理“能打开应用,但调用失败”的问题。
## 诊断步骤
## 快速判断
### 1. 检查凭证文件
如果你看到以下报错,通常属于连接鉴权问题:
确认凭证文件存在:
- `401` 认证失败
- `403` 权限不足
- 连接状态显示已失效
```bash
# Kiro
ls -la ~/.kiro/credentials.json
## 3 步排查
# Gemini CLI
ls -la ~/.config/gemini-cli/oauth_creds.json
### 第 1 步:检查连接状态
# Qwen
ls -la ~/.config/qwen/credentials.json
```
在连接管理页面确认当前连接是否可用。
### 2. 验证文件格式
### 第 2 步:刷新或重建连接
检查 JSON 格式是否正确:
- 先尝试刷新
- 刷新失败则重新登录或重新添加连接
```bash
# 验证 JSON 格式
cat ~/.kiro/credentials.json | python -m json.tool
```
### 第 3 步:做最小测试
### 3. 检查 Token 有效性
使用一条简短请求验证是否恢复。
在 ProxyCast 中:
## 常见场景
1. 进入凭证池
2. 点击凭证的"测试"按钮
3. 查看测试结果
### 场景 1:昨天还能用,今天突然失败
## 常见错误
高概率是连接过期或上游状态变化。建议先重建该连接。
### Token 已过期
### 场景 2:部分模型可用,部分模型失败
**症状**: 凭证状态显示"已过期"
可能是模型权限差异或连接配置不匹配。先换一个已知可用模型测试。
**原因**:
- Access Token 超过有效期
- Refresh Token 也已过期
### 场景 3:导入配置后无法调用
**解决方案**:
导入通常不包含敏感凭证信息,需要重新校验连接。
1. 打开对应的 AI 客户端
2. 重新登录
3. 在 ProxyCast 中刷新凭证
## 进阶检查(可选)
### Token 无效
如果你需要定位更深层原因,可检查:
**症状**: 测试凭证返回 401 错误
- 本地凭证文件是否存在且可读
- 连接使用的账号是否仍有效
- 代理或网络环境是否变更
**原因**:
- Token 被撤销
- 账户状态异常
## 预防建议
**解决方案**:
1. 检查 AI 客户端账户状态
2. 重新登录获取新 Token
3. 删除旧凭证,重新添加
### 刷新失败
**症状**: 自动刷新 Token 失败
**原因**:
- Refresh Token 过期
- 网络问题
- 服务端问题
**解决方案**:
1. 检查网络连接
2. 手动刷新凭证
3. 如仍失败,重新登录客户端
## Provider 特定问题
### Kiro Claude
**凭证位置**: `~/.kiro/credentials.json`
**常见问题**:
1. **未安装 Kiro**: 安装 Kiro IDE
2. **未登录**: 在 Kiro 中完成登录
3. **订阅过期**: 检查 Kiro 订阅状态
### Gemini CLI
**凭证位置**: `~/.config/gemini-cli/oauth_creds.json`
**常见问题**:
1. **未安装 CLI**: 安装 Gemini CLI
2. **未认证**: 运行 `gemini auth login`
3. **项目配额用尽**: 检查 Google Cloud 配额
### Qwen
**凭证位置**: `~/.config/qwen/credentials.json`
**常见问题**:
1. **账户未开通**: 开通阿里云通义千问服务
2. **配额用尽**: 检查阿里云账户余额
3. **区域限制**: 确认服务区域设置
## 手动修复
### 重置凭证
1. 删除凭证文件
2. 重新登录 AI 客户端
3. 在 ProxyCast 中刷新凭证
### 手动添加凭证
如果自动检测失败:
1. 从 AI 客户端获取 Token
2. 在 ProxyCast 中手动添加
3. 测试凭证有效性
## 日志查看
查看详细错误信息:
1. 进入设置 > 高级
2. 设置日志级别为 Debug
3. 重现问题
4. 查看日志文件
1. 保留一个备用连接
2. 关键活动前做一次连通性测试
3. 定期清理长期失效连接
@@ -1,176 +1,72 @@
---
title: 连接问题
description: 网络和代理故障排除
title: 网络与连接问题
description: 处理超时、DNS、证书和代理相关问题
navigation:
icon: i-heroicons-signal
---
# 连接问题
# 网络与连接问题
本页帮助你诊断和解决网络连接相关的问题。
当你频繁遇到超时、连接失败或证书错误时,按下面顺序排查。
## 诊断步骤
## 排查顺序
### 1. 检查网络连接
1. 本机网络是否正常
2. 代理是否配置正确
3. 请求是否过于集中
4. 是否为上游短时波动
```bash
# 测试网络连通性
ping api.anthropic.com
ping api.openai.com
```
### 2. 检查 DNS 解析
```bash
# 测试 DNS 解析
nslookup api.anthropic.com
```
### 3. 测试 HTTPS 连接
```bash
# 测试 HTTPS 连接
curl -I https://api.anthropic.com
```
## 常见问题
## 常见症状与处理
### 连接超时
**症状**: 请求长时间无响应后超时
处理建议:
**可能原因**:
- 网络不稳定
- 防火墙阻止
- Provider 服务不可用
**解决方案**:
1. 检查网络连接
2. 检查防火墙设置
3. 尝试使用代理
4. 增加超时时间
1. 先减少并发
2. 拆分任务批次
3. 适当增加超时
4. 稍后重试
### DNS 解析失败
**症状**: 无法解析域名
处理建议:
**解决方案**:
1. 切换网络后重试
2. 检查系统 DNS 设置
3. 清理 DNS 缓存后重试
1. 检查 DNS 设置
2. 尝试使用公共 DNS(如 8.8.8.8)
3. 清除 DNS 缓存
### 证书错误
```bash
# macOS
sudo dscacheutil -flushcache
处理建议:
# Windows
ipconfig /flushdns
```
1. 校准系统时间
2. 检查网络代理是否拦截 HTTPS
3. 更换网络环境复测
### SSL/TLS 错误
## 代理相关
**症状**: 证书验证失败
如果你使用代理,请重点检查:
**可能原因**:
- 系统时间不正确
- 根证书过期
- 代理拦截 HTTPS
1. 代理地址格式是否正确
2. 账号密码是否有效
3. 排除列表是否包含本地地址
**解决方案**:
常见格式示例:
1. 同步系统时间
2. 更新系统证书
3. 检查代理设置
- `http://proxy.example.com:8080`
- `http://user:password@proxy.example.com:8080`
- `socks5://proxy.example.com:1080`
## 代理配置
## 什么时候判断是上游问题
### 设置代理
满足以下特征时,通常是上游波动:
在 ProxyCast 设置中配置代理:
- 同一配置偶发失败、重试可恢复
- 不同网络环境都出现短时错误
- 一段时间后无需改配置自动恢复
1. 进入 **设置** > **高级**
2. 配置代理设置:
## 仍未恢复怎么办
| 选项 | 说明 |
|------|------|
| HTTP 代理 | HTTP 代理地址 |
| HTTPS 代理 | HTTPS 代理地址 |
| 不代理地址 | 排除的地址列表 |
### 代理格式
```
http://proxy.example.com:8080
http://user:password@proxy.example.com:8080
socks5://proxy.example.com:1080
```
### 环境变量
也可以通过环境变量设置:
```bash
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
export NO_PROXY=localhost,127.0.0.1
```
## Provider 特定问题
### Anthropic API
**端点**: `https://api.anthropic.com`
**常见问题**:
- 某些地区可能需要代理
- 检查 API 状态页面
### Google Gemini
**端点**: `https://generativelanguage.googleapis.com`
**常见问题**:
- 需要 Google Cloud 项目
- 检查 API 是否启用
### 阿里云 Qwen
**端点**: `https://dashscope.aliyuncs.com`
**常见问题**:
- 海外访问可能需要代理
- 检查区域设置
## 防火墙设置
### 允许的端口
确保防火墙允许以下端口:
| 端口 | 用途 |
|------|------|
| 443 | HTTPS 请求 |
| 8999 | ProxyCast API(默认) |
### macOS 防火墙
1. 系统偏好设置 > 安全性与隐私
2. 防火墙 > 防火墙选项
3. 允许 ProxyCast 接收传入连接
### Windows 防火墙
1. 控制面板 > Windows Defender 防火墙
2. 允许应用通过防火墙
3. 添加 ProxyCast
## 调试模式
启用详细日志:
1. 进入 **设置** > **高级**
2. 设置日志级别为 **Debug**
3. 重现问题
4. 查看网络请求日志
1. 记录失败时间段
2. 保存错误提示和关键日志
3. 先切换备用连接保障创作不中断
@@ -1,249 +1,17 @@
# 插件开发指南
---
title: 插件开发(迁移说明)
description: 本章节已迁移至开放平台文档
navigation:
icon: i-heroicons-arrow-top-right-on-square
---
# 插件开发(迁移说明)
::alert{type="info"}
📢 本文档已迁移至开放平台。请访问 [开放平台 - 插件开发](/open-platform/plugin-development) 获取最新内容。
插件开发文档已迁移,请阅读:[开放平台 - 插件开发指南](/open-platform/plugin-development)。
::
本文档描述 ProxyCast 插件系统的规范和开发指南,为插件市场做准备。
迁移后,开发者文档与用户文档分层更清晰:
## 插件类型
ProxyCast 支持两种类型的插件:
### 1. 脚本插件 (Script Plugin)
纯 JavaScript/TypeScript 插件,通过 Hook 机制扩展功能。
```json
{
"plugin_type": "script",
"entry": "main.js",
"hooks": ["on_request", "on_response"]
}
```
### 2. 二进制插件 (Binary Plugin)
独立的可执行文件,通过 CLI 接口与 ProxyCast 通信。适合需要系统级操作的工具。
```json
{
"plugin_type": "binary",
"entry": "my-tool-cli",
"binary": {
"binary_name": "my-tool-cli",
"github_owner": "your-org",
"github_repo": "your-repo",
"platform_binaries": {
"macos-arm64": "my-tool-aarch64-apple-darwin",
"macos-x64": "my-tool-x86_64-apple-darwin",
"linux-x64": "my-tool-x86_64-unknown-linux-gnu",
"linux-arm64": "my-tool-aarch64-unknown-linux-gnu",
"windows-x64": "my-tool-x86_64-pc-windows-msvc.exe"
},
"checksum_file": "checksums.txt"
}
}
```
## 插件包结构
插件以 ZIP 包形式分发,包含以下文件:
```
my-plugin.zip
├── plugin.json # 插件元数据(必需)
└── config.json # 默认配置(可选)
```
### plugin.json 规范
```json
{
"name": "my-plugin",
"version": "1.0.0",
"description": "插件描述",
"author": "作者名",
"homepage": "https://github.com/org/repo",
"license": "MIT",
"plugin_type": "binary",
"entry": "my-tool-cli",
"hooks": [],
"min_proxycast_version": "1.0.0",
"binary": { ... },
"ui": {
"surfaces": ["tools"],
"icon": "Cpu",
"title": "我的工具",
"default_width": 800,
"default_height": 600
}
}
```
#### 字段说明
| 字段 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `name` | string | ✅ | 插件唯一标识符,小写字母和连字符 |
| `version` | string | ✅ | 语义化版本号 (semver) |
| `description` | string | ✅ | 插件描述 |
| `author` | string | ❌ | 作者名称 |
| `homepage` | string | ❌ | 项目主页 URL |
| `license` | string | ❌ | 开源许可证 |
| `plugin_type` | string | ✅ | `script` 或 `binary` |
| `entry` | string | ✅ | 入口文件/二进制名称 |
| `hooks` | array | ❌ | 注册的 Hook 列表 |
| `min_proxycast_version` | string | ❌ | 最低 ProxyCast 版本要求 |
| `binary` | object | ❌ | 二进制插件配置 |
| `ui` | object | ❌ | UI 配置 |
## UI 展示位置 (Surfaces)
插件可以在以下位置显示 UI:
| Surface | 说明 | 入口位置 |
|---------|------|----------|
| `tools` | 工具箱 | 导航栏「工具」页面 |
| `sidebar` | 侧边栏 | 主侧边栏(规划中) |
| `settings` | 设置页 | 设置页扩展区域(规划中) |
### 示例:工具类插件
```json
{
"ui": {
"surfaces": ["tools"],
"icon": "Cpu",
"title": "机器码管理工具"
}
}
```
安装后,插件会出现在「工具箱」页面,用户点击即可打开。
## 图标规范
使用 [Lucide Icons](https://lucide.dev/icons/) 图标名称:
```json
{
"ui": {
"icon": "Cpu"
}
}
```
常用图标:
- `Cpu` - 系统/硬件工具
- `Globe` - 网络工具
- `Database` - 数据工具
- `Shield` - 安全工具
- `Wrench` - 通用工具
- `Terminal` - 命令行工具
## 二进制插件 CLI 接口规范
二进制插件通过 CLI 与 ProxyCast 通信,必须遵循以下规范:
### 输出格式
所有输出必须是 JSON 格式:
```bash
# 成功
$ my-tool-cli get
{"machine_id": "550e8400-e29b-41d4-a716-446655440000"}
# 错误
$ my-tool-cli invalid-command
{"error": "未知命令: invalid-command"}
```
### 退出码
- `0` - 成功
- `1` - 错误
### 命令结构
```bash
my-tool-cli <command> [arguments]
```
建议实现 `help` 命令:
```bash
$ my-tool-cli help
MachineIdTool CLI v1.0.0
用法: my-tool-cli <命令> [参数]
命令:
get 获取当前值
set <value> 设置新值
help 显示帮助
```
## 插件安装流程
1. **下载插件包** - 从 URL 或本地文件获取 ZIP
2. **解压验证** - 解压并验证 plugin.json
3. **下载二进制** - 如果是二进制插件,根据当前平台下载对应二进制
4. **校验完整性** - 验证 checksum
5. **注册插件** - 将插件信息写入数据库
6. **加载插件** - 启用插件功能
## 插件发布
### GitHub Release 发布
推荐通过 GitHub Release 发布插件:
1. 创建 `plugin/` 目录,包含 `plugin.json` 和 `config.json`
2. 在 GitHub Actions 中打包 ZIP
3. 上传到 Release Assets
```yaml
- name: Package plugin
run: |
mkdir -p plugin-package
cp plugin/plugin.json plugin-package/
cp plugin/config.json plugin-package/
cd plugin-package
zip -j ../release/my-plugin.zip plugin.json config.json
```
### 插件市场(规划中)
未来将支持:
- 插件市场浏览和搜索
- 一键安装
- 自动更新
- 评分和评论
## 推荐插件
ProxyCast 内置推荐插件列表,在「工具箱」和「插件中心」显示未安装的推荐插件。
要将插件添加到推荐列表,请提交 PR 修改:
- `src/components/tools/ToolsPage.tsx` - `recommendedPlugins`
- `src/components/plugins/PluginManager.tsx` - `recommendedPlugins`
## 示例插件
参考 [MachineIdTool](https://github.com/aiclientproxy/MachineIdTool) 作为二进制插件的完整示例。
## 开发调试
### 本地安装测试
1. 打包插件 ZIP
2. 在「插件中心」点击「安装插件」
3. 选择本地 ZIP 文件安装
### 日志调试
插件执行日志保存在:
- macOS: `~/Library/Application Support/proxycast/logs/`
- Windows: `%APPDATA%/proxycast/logs/`
- Linux: `~/.local/share/proxycast/logs/`
- 开放平台:插件规范、接入流程、生态能力
- 用户指南:插件安装与使用
+26 -48
View File
@@ -1,63 +1,41 @@
# 开放平台概述
---
title: 开放平台概览
description: 面向开发者与生态合作方的扩展能力
navigation:
icon: i-heroicons-cube-transparent
---
ProxyCast 开放平台为开发者和服务商提供扩展能力,包括插件系统和中转商生态合作方案。
# 开放平台概览
开放平台面向开发者与生态合作方,用于扩展 ProxyCast 的能力边界。
::alert{type="info"}
如果你是普通创作者,可先跳过本章节。
::
## 平台能力
### 🔌 插件系统
### 插件系统
通过插件扩展 ProxyCast 功能:
- **脚本插件** - JavaScript/TypeScript 插件,通过 Hook 机制扩展
- **二进制插件** - 独立可执行文件,适合系统级操作
- **工具插件** - 在工具箱中显示的独立工具
用于扩展工具、工作流和界面能力。
[了解更多 →](/open-platform/plugins)
### 🔗 ProxyCast Connect
### Connect 能力
中转商生态合作方案,实现一键配置:
- **一键配置** - 用户点击链接即可完成配置
- **品牌展示** - 中转商在 ProxyCast 内有专属展示位
- **统计回调** - 追踪推广效果
用于外部平台与 ProxyCast 的配置联动与生态集成。
[了解更多 →](/open-platform/connect)
## 核心价值
## 谁适合阅读
| 角色 | 价值 |
|------|------|
| **开发者** | 扩展功能、定制工具、集成服务 |
| **中转商** | 用户转化率提升、品牌曝光、差异化竞争 |
| **用户** | 一键配置、开箱即用、统一管理 |
| **ProxyCast** | 生态繁荣、用户增长 |
- 需要开发自定义插件的团队
- 需要对接外部系统的开发者
- 需要建设生态能力的合作方
## 快速开始
## 快速入口
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 my-6">
<a href="/open-platform/plugins" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">🔌 开发插件</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">创建自定义插件扩展 ProxyCast 功能</p>
</a>
<a href="/open-platform/connect" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">🔗 接入 Connect</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">中转商接入一键配置功能</p>
</a>
<a href="/open-platform/plugin-development" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">📖 插件开发指南</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">详细的插件开发文档和规范</p>
</a>
<a href="/open-platform/connect-integration" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">📖 Connect 接入指南</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">中转商接入的详细步骤</p>
</a>
</div>
## 相关仓库
| 仓库 | 说明 |
|------|------|
| [proxycast](https://github.com/aiclientproxy/proxycast) | ProxyCast 主项目 |
| [connect](https://github.com/aiclientproxy/connect) | 中转商注册仓库 |
| [MachineIdTool](https://github.com/aiclientproxy/MachineIdTool) | 插件示例项目 |
- [插件中心](/open-platform/plugins)
- [插件开发指南](/open-platform/plugin-development)
- [Connect 接入](/open-platform/connect)
- [Connect 集成说明](/open-platform/connect-integration)
+27 -101
View File
@@ -1,112 +1,38 @@
# 插件中心
---
title: 开放平台 - 插件中心
description: 面向开发者的插件安装、管理与发布能力
navigation:
icon: i-heroicons-puzzle-piece
---
ProxyCast 支持通过插件扩展功能。插件中心提供插件的安装、管理和配置。
# 开放平台 - 插件中心
## 访问插件中心
::alert{type="info"}
本页面向开发者与高级用户。普通创作者可使用用户指南中的插件页。
::
点击左侧导航栏的「插件中心」进入插件管理页面。
ProxyCast 支持通过插件扩展能力,适用于自定义工具、自动化流程和生态集成。
## 功能概览
## 你可以做什么
### 推荐插件
- 安装推荐插件或第三方插件包
- 管理插件启用状态与版本
- 查看插件加载与执行状态
- 在工具入口中使用插件能力
插件中心会显示推荐的插件列表,点击「一键安装」即可快速安装。
## 安装方式
### 已安装插件
1. 推荐插件一键安装
2. 通过 URL 安装 ZIP 包
3. 通过本地文件安装 ZIP 包
显示所有已安装的插件,包括:
- 插件名称和版本
- 安装来源(本地/URL/GitHub)
- 启用/禁用状态
- 卸载按钮
## 管理建议
### 已加载插件
1. 先安装高频插件,再逐步扩展
2. 每次新增插件后做一次功能验证
3. 定期清理长期不用的插件
显示当前运行中的插件状态:
- 执行次数
- 错误次数
- 最后执行时间
## 下一步
## 安装插件
### 方式一:推荐插件一键安装
1. 在「推荐插件」区域找到想要的插件
2. 点击「一键安装」
3. 等待下载和安装完成
### 方式二:从 URL 安装
1. 点击「安装插件」按钮
2. 输入插件 ZIP 包的下载 URL
3. 点击「安装」
支持的 URL 格式:
- GitHub Release: `https://github.com/org/repo/releases/latest/download/plugin.zip`
- 直接下载链接: `https://example.com/plugin.zip`
### 方式三:从本地文件安装
1. 点击「安装插件」按钮
2. 点击「选择文件」
3. 选择本地的 `.zip` 文件
4. 点击「安装」
## 使用插件
安装完成后,插件会根据类型出现在不同位置:
### 工具类插件
工具类插件会出现在「工具箱」页面:
1. 点击左侧导航栏的「工具」
2. 在工具列表中找到已安装的插件
3. 点击「打开工具」使用
### 其他类型插件
- **Hook 插件**: 自动在请求/响应时执行
- **侧边栏插件**: 出现在主侧边栏(规划中)
## 管理插件
### 启用/禁用
在已加载插件列表中,点击电源图标可以启用或禁用插件。
### 卸载
1. 在「已安装插件包」列表中找到要卸载的插件
2. 点击红色的删除按钮
3. 确认卸载
卸载会删除插件文件和配置,但不会删除插件产生的数据。
## 二进制组件
部分功能需要安装额外的二进制组件:
- **aster-server**: AI Agent 框架,提供 Agent 对话能力
在「二进制组件」区域可以查看和管理这些组件。
## 常见问题
### 插件安装失败
1. 检查网络连接
2. 确认 URL 正确且可访问
3. 检查 ZIP 包格式是否正确
### 插件无法加载
1. 检查 ProxyCast 版本是否满足插件要求
2. 查看日志了解详细错误信息
3. 尝试重新安装插件
### 二进制插件权限问题
部分二进制插件需要管理员权限:
- **Windows**: 以管理员身份运行 ProxyCast
- **macOS/Linux**: 插件会提示需要的权限
- [插件开发指南](/open-platform/plugin-development)
- [开放平台概览](/open-platform/overview)
@@ -1,219 +1,44 @@
# 插件开发指南
---
title: 开放平台 - 插件开发指南
description: 开发 ProxyCast 插件的规范与最佳实践
navigation:
icon: i-heroicons-code-bracket-square
---
本文档描述 ProxyCast 插件系统的规范和开发指南。
# 开放平台 - 插件开发指南
::alert{type="info"}
本页面向开发者。若你不开发插件,可跳过。
::
本文档说明插件类型、打包方式和开发建议,帮助你把能力稳定接入 ProxyCast。
## 插件类型
ProxyCast 支持两种类型的插件:
### 脚本插件
### 1. 脚本插件 (Script Plugin)
基于 JavaScript/TypeScript,通过 Hook 扩展行为。
纯 JavaScript/TypeScript 插件,通过 Hook 机制扩展功能。
### 二进制插件
```json
{
"plugin_type": "script",
"entry": "main.js",
"hooks": ["on_request", "on_response"]
}
```
通过独立可执行文件提供系统级能力,适合重计算或本地工具集成。
### 2. 二进制插件 (Binary Plugin)
## 基础结构
独立的可执行文件,通过 CLI 接口与 ProxyCast 通信。适合需要系统级操作的工具。
插件以 ZIP 分发,至少包含:
```json
{
"plugin_type": "binary",
"entry": "my-tool-cli",
"binary": {
"binary_name": "my-tool-cli",
"github_owner": "your-org",
"github_repo": "your-repo",
"platform_binaries": {
"macos-arm64": "my-tool-aarch64-apple-darwin",
"macos-x64": "my-tool-x86_64-apple-darwin",
"linux-x64": "my-tool-x86_64-unknown-linux-gnu",
"linux-arm64": "my-tool-aarch64-unknown-linux-gnu",
"windows-x64": "my-tool-x86_64-pc-windows-msvc.exe"
},
"checksum_file": "checksums.txt"
}
}
```
- `plugin.json`:元数据与入口定义
- 可选配置文件与资源文件
## 插件包结构
## 开发建议
插件以 ZIP 包形式分发,包含以下文件:
1. 先做最小可用版本
2. 明确输入输出协议
3. 做异常与超时处理
4. 提供清晰的版本兼容说明
```
my-plugin.zip
├── plugin.json # 插件元数据(必需)
└── config.json # 默认配置(可选)
```
## 发布建议
### plugin.json 规范
```json
{
"name": "my-plugin",
"version": "1.0.0",
"description": "插件描述",
"author": "作者名",
"homepage": "https://github.com/org/repo",
"license": "MIT",
"plugin_type": "binary",
"entry": "my-tool-cli",
"hooks": [],
"min_proxycast_version": "1.0.0",
"binary": { ... },
"ui": {
"surfaces": ["tools"],
"icon": "Cpu",
"title": "我的工具",
"default_width": 800,
"default_height": 600
}
}
```
### 字段说明
| 字段 | 类型 | 必需 | 说明 |
|------|------|------|------|
| `name` | string | ✅ | 插件唯一标识符,小写字母和连字符 |
| `version` | string | ✅ | 语义化版本号 (semver) |
| `description` | string | ✅ | 插件描述 |
| `author` | string | ❌ | 作者名称 |
| `homepage` | string | ❌ | 项目主页 URL |
| `license` | string | ❌ | 开源许可证 |
| `plugin_type` | string | ✅ | `script` 或 `binary` |
| `entry` | string | ✅ | 入口文件/二进制名称 |
| `hooks` | array | ❌ | 注册的 Hook 列表 |
| `min_proxycast_version` | string | ❌ | 最低 ProxyCast 版本要求 |
| `binary` | object | ❌ | 二进制插件配置 |
| `ui` | object | ❌ | UI 配置 |
## UI 展示位置 (Surfaces)
插件可以在以下位置显示 UI:
| Surface | 说明 | 入口位置 |
|---------|------|----------|
| `tools` | 工具箱 | 导航栏「工具」页面 |
| `sidebar` | 侧边栏 | 主侧边栏(规划中) |
| `settings` | 设置页 | 设置页扩展区域(规划中) |
### 示例:工具类插件
```json
{
"ui": {
"surfaces": ["tools"],
"icon": "Cpu",
"title": "机器码管理工具"
}
}
```
## 图标规范
使用 [Lucide Icons](https://lucide.dev/icons/) 图标名称:
常用图标:
- `Cpu` - 系统/硬件工具
- `Globe` - 网络工具
- `Database` - 数据工具
- `Shield` - 安全工具
- `Wrench` - 通用工具
- `Terminal` - 命令行工具
## 二进制插件 CLI 接口规范
二进制插件通过 CLI 与 ProxyCast 通信,必须遵循以下规范:
### 输出格式
所有输出必须是 JSON 格式:
```bash
# 成功
$ my-tool-cli get
{"machine_id": "550e8400-e29b-41d4-a716-446655440000"}
# 错误
$ my-tool-cli invalid-command
{"error": "未知命令: invalid-command"}
```
### 退出码
- `0` - 成功
- `1` - 错误
### 命令结构
```bash
my-tool-cli <command> [arguments]
```
建议实现 `help` 命令:
```bash
$ my-tool-cli help
MachineIdTool CLI v1.0.0
用法: my-tool-cli <命令> [参数]
命令:
get 获取当前值
set <value> 设置新值
help 显示帮助
```
## 插件安装流程
1. **下载插件包** - 从 URL 或本地文件获取 ZIP
2. **解压验证** - 解压并验证 plugin.json
3. **下载二进制** - 如果是二进制插件,根据当前平台下载对应二进制
4. **校验完整性** - 验证 checksum
5. **注册插件** - 将插件信息写入数据库
6. **加载插件** - 启用插件功能
## 插件发布
### GitHub Release 发布
推荐通过 GitHub Release 发布插件:
1. 创建 `plugin/` 目录,包含 `plugin.json` 和 `config.json`
2. 在 GitHub Actions 中打包 ZIP
3. 上传到 Release Assets
```yaml
- name: Package plugin
run: |
mkdir -p plugin-package
cp plugin/plugin.json plugin-package/
cp plugin/config.json plugin-package/
cd plugin-package
zip -j ../release/my-plugin.zip plugin.json config.json
```
## 开发调试
### 本地安装测试
1. 打包插件 ZIP
2. 在「插件中心」点击「安装插件」
3. 选择本地 ZIP 文件安装
### 日志调试
插件执行日志保存在:
- macOS: `~/Library/Application Support/proxycast/logs/`
- Windows: `%APPDATA%/proxycast/logs/`
- Linux: `~/.local/share/proxycast/logs/`
## 示例插件
参考 [MachineIdTool](https://github.com/aiclientproxy/MachineIdTool) 作为二进制插件的完整示例。
1. 版本号语义化管理
2. 发布前做跨平台验证
3. 提供回滚策略与变更日志
+28 -152
View File
@@ -1,169 +1,45 @@
# ProxyCast Connect
---
title: 开放平台 - Connect
description: 面向服务提供方的一键配置接入能力
navigation:
icon: i-heroicons-link
---
ProxyCast Connect 是一套中转商生态合作方案,通过 Deep Link 协议实现一键配置功能。
# 开放平台 - Connect
::alert{type="info"}
本页面向生态合作方与平台接入方。普通创作者可跳过。
::
Connect 通过 Deep Link 提供“一键配置”能力,帮助外部平台将配置快速带入 ProxyCast。
## 核心价值
| 角色 | 价值 |
|------|------|
| **中转商** | 用户转化率提升、品牌曝光、差异化竞争 |
| **用户** | 一键配置、开箱即用、统一管理多个中转 |
| **ProxyCast** | 用户增长、生态繁荣、市场占有率 |
- 用户:减少手动配置步骤
- 服务提供方:降低接入门槛
- 平台:提升配置成功率
## 工作原理
## 一键配置流程
### 一键配置流程
1. 用户在外部平台点击一键配置
2. 浏览器打开 `proxycast://` 链接
3. ProxyCast 弹出确认
4. 用户确认后完成导入
1. 用户在中转商后台点击「一键配置 ProxyCast」
2. 浏览器打开 `proxycast://connect?relay=xxx&key=sk-xxx` 链接
3. ProxyCast 自动打开,显示确认弹窗
4. 用户确认后,API Key 自动添加到 ProxyCast
5. 配置完成,可以立即使用
## 基础协议
### Deep Link 协议
```
```text
proxycast://connect?relay={relay_id}&key={api_key}&name={key_name}&ref={ref_code}
```
| 参数 | 必填 | 说明 |
|------|------|------|
| `relay` | ✅ | 中转商 ID(需在 ProxyCast 注册) |
| `relay` | ✅ | 服务方唯一标识 |
| `key` | ✅ | API Key |
| `name` | ❌ | Key 名称(默认使用中转商名称) |
| `ref` | ❌ | 推广码(用于统计) |
### 示例
```
# 基础用法
proxycast://connect?relay=openrouter&key=sk-or-v1-xxxx
# 带名称
proxycast://connect?relay=siliconflow&key=sk-xxxx&name=硅基流动-主账号
# 带推广码
proxycast://connect?relay=myrelay&key=sk-xxxx&ref=promo2024
```
## 中转商注册
ProxyCast 是开源软件,中转商通过 **GitHub PR** 方式注册,无需网站注册。
### 注册仓库
```
https://github.com/aiclientproxy/connect
```
### 注册流程
1. **Fork 仓库** - Fork [aiclientproxy/connect](https://github.com/aiclientproxy/connect)
2. **创建配置文件** - 在 `providers/` 目录下创建 `{your-id}.json`
3. **提交 PR** - 提交 Pull Request 到主仓库
4. **自动化检查** - GitHub Actions 自动验证配置
5. **社区审核** - 维护者审核并合并 PR
6. **自动发布** - 合并后自动构建 registry.json
### 配置文件格式
```json
{
"id": "myrelay",
"name": "我的中转站",
"description": "稳定、便宜、快速的 AI API 中转服务",
"branding": {
"logo": "https://myrelay.com/logo.png",
"color": "#6366f1"
},
"links": {
"homepage": "https://myrelay.com",
"register": "https://myrelay.com/register",
"recharge": "https://myrelay.com/recharge",
"docs": "https://docs.myrelay.com",
"status": "https://status.myrelay.com"
},
"api": {
"base_url": "https://api.myrelay.com/v1",
"protocol": "openai",
"auth_header": "Authorization",
"auth_prefix": "Bearer "
},
"contact": {
"email": "support@myrelay.com",
"telegram": "@myrelay"
},
"features": {
"streaming": true,
"models_endpoint": true
},
"webhook": {
"callback_url": "https://api.myrelay.com/proxycast/callback",
"secret": "whsec_xxxxxxxxxxxxxxxx"
}
}
```
### 字段说明
| 字段 | 必填 | 说明 |
|------|------|------|
| `id` | ✅ | 唯一标识,小写字母、数字、连字符 |
| `name` | ✅ | 显示名称 |
| `description` | ✅ | 简短描述,≤100 字 |
| `branding.logo` | ✅ | Logo URL,256x256 PNG |
| `branding.color` | ❌ | 主题色,默认 `#6366f1` |
| `links.homepage` | ✅ | 官网地址 |
| `api.base_url` | ✅ | API 地址(必须 HTTPS) |
| `api.protocol` | ✅ | 协议:`openai` 或 `anthropic` |
| `contact.email` | ✅ | 联系邮箱 |
| `webhook.callback_url` | ❌ | 统计回调地址 |
| `webhook.secret` | ❌ | 回调签名密钥 |
### 审核标准
PR 合并前需满足:
- JSON Schema 验证通过
- 文件名与 `id` 字段一致
- Logo 图片可访问(256x256 PNG)
- API 地址使用 HTTPS
- 官网可访问
- 联系方式有效
## 品牌展示
注册成功后,中转商会在 ProxyCast 内获得品牌展示:
- **扩展市场** - 在中转服务分类中展示
- **已安装页面** - 显示品牌信息、快捷链接
- **API Key 管理** - 统一管理该中转商的所有 Key
## 安全设计
### Deep Link 安全
| 风险 | 防护措施 |
|------|---------|
| 恶意链接 | relay_id 必须在注册表中存在 |
| Key 泄露 | 确认弹窗显示脱敏 Key,用户确认后才添加 |
| 钓鱼攻击 | 显示中转商完整信息,用户可核实 |
### 确认弹窗
所有通过 Deep Link 添加的 Key 必须经过用户确认,显示:
- 中转商名称和 Logo
- 脱敏后的 API Key
- Key 名称(如果有)
- 安全提示
| `name` | ❌ | 显示名称 |
| `ref` | ❌ | 推广或渠道标记 |
## 下一步
- [Connect 接入指南](/open-platform/connect-integration) - 详细的接入步骤
- [统计回调](/open-platform/connect-webhook) - 配置统计回调追踪推广效果
- [Connect 接入指南](/open-platform/connect-integration)
- [统计回调(Webhook)](/open-platform/connect-webhook)
@@ -1,229 +1,45 @@
# Connect 接入指南
---
title: 开放平台 - Connect 接入指南
description: 外部服务接入 Connect 的实施步骤与字段规范
navigation:
icon: i-heroicons-wrench-screwdriver
---
本文档详细介绍中转商如何接入 ProxyCast Connect,实现一键配置功能。
# 开放平台 - Connect 接入指南
## 接入流程
::alert{type="info"}
本页面向生态合作方技术团队。
::
### Step 1: Fork 仓库
本文档说明如何把你的服务接入 Connect,并完成一键配置联动。
Fork [aiclientproxy/connect](https://github.com/aiclientproxy/connect) 仓库到你的 GitHub 账号。
## 接入步骤
### Step 2: 创建配置文件
1. 准备服务方元数据
2. 按规范生成配置文件
3. 提交审核或接入申请
4. 联调 Deep Link
5. 灰度发布并观察回调数据
在 `providers/` 目录下创建 `{your-id}.json` 文件:
## 配置文件建议
```json
{
"id": "myrelay",
"name": "我的中转站",
"description": "稳定、便宜、快速的 AI API 中转服务",
"branding": {
"logo": "https://myrelay.com/logo.png",
"color": "#6366f1"
},
"links": {
"homepage": "https://myrelay.com",
"register": "https://myrelay.com/register",
"recharge": "https://myrelay.com/recharge",
"docs": "https://docs.myrelay.com",
"status": "https://status.myrelay.com"
},
"api": {
"base_url": "https://api.myrelay.com/v1",
"protocol": "openai",
"auth_header": "Authorization",
"auth_prefix": "Bearer "
},
"contact": {
"email": "support@myrelay.com",
"telegram": "@myrelay"
},
"features": {
"streaming": true,
"models_endpoint": true
},
"webhook": {
"callback_url": "https://api.myrelay.com/proxycast/callback",
"secret": "whsec_xxxxxxxxxxxxxxxx"
}
}
```
建议包含:
### Step 3: 提交 PR
- 唯一标识与展示信息
- 官网与文档链接
- API 基础信息
- 回调地址(可选)
提交 Pull Request 到主仓库,填写 PR 模板说明你的中转服务。
## 联调重点
### Step 4: 等待审核
1. Deep Link 参数完整性
2. 用户确认流程体验
3. 异常输入的兜底处理
4. 回调状态与业务统计一致性
GitHub Actions 会自动验证配置文件,维护者会在 1-3 个工作日内审核。
## 上线前检查
### Step 5: 合并上线
PR 合并后,registry.json 会自动构建,ProxyCast 客户端会自动同步。
## 配置字段说明
### 必填字段
| 字段 | 说明 | 示例 |
|------|------|------|
| `id` | 唯一标识,小写字母、数字、连字符 | `myrelay` |
| `name` | 显示名称 | `我的中转站` |
| `description` | 简短描述,≤100 字 | `稳定、便宜、快速的 AI API 中转服务` |
| `branding.logo` | Logo URL,256x256 PNG | `https://myrelay.com/logo.png` |
| `links.homepage` | 官网地址 | `https://myrelay.com` |
| `api.base_url` | API 地址(必须 HTTPS) | `https://api.myrelay.com/v1` |
| `api.protocol` | 协议类型 | `openai` 或 `anthropic` |
| `contact.email` | 联系邮箱 | `support@myrelay.com` |
### 可选字段
| 字段 | 说明 | 默认值 |
|------|------|--------|
| `branding.color` | 主题色 | `#6366f1` |
| `links.register` | 注册页面 | - |
| `links.recharge` | 充值页面 | - |
| `links.docs` | 文档地址 | - |
| `links.status` | 状态页面 | - |
| `api.auth_header` | 认证头 | `Authorization` |
| `api.auth_prefix` | 认证前缀 | `Bearer ` |
| `contact.telegram` | Telegram 联系方式 | - |
| `contact.discord` | Discord 联系方式 | - |
| `features.streaming` | 是否支持流式响应 | `true` |
| `features.models_endpoint` | 是否提供 /models 端点 | `false` |
| `webhook.callback_url` | 统计回调地址 | - |
| `webhook.secret` | 回调签名密钥 | - |
## 集成方式
### 方式一:直接链接
最简单的方式,在用户后台放置链接:
```html
<a href="proxycast://connect?relay=myrelay&key=USER_API_KEY">
一键配置 ProxyCast
</a>
```
### 方式二:JavaScript SDK
提供更好的用户体验:
```html
<script src="https://proxycast.dev/sdk/connect.js"></script>
<button onclick="ProxyCast.connect({ relay: 'myrelay', key: userApiKey })">
一键配置 ProxyCast
</button>
```
SDK 功能:
- 自动检测 ProxyCast 是否安装
- 未安装时显示下载引导
- 支持回调函数
```javascript
ProxyCast.connect({
relay: 'myrelay',
key: userApiKey,
name: '我的Key',
onSuccess: () => {
showToast('配置成功!');
},
onNotInstalled: () => {
showDownloadModal();
}
});
```
### 方式三:配置文件下载
生成 `.proxycast` 配置文件供用户下载:
```javascript
function downloadConfig(apiKey) {
const config = {
relay: 'myrelay',
key: apiKey,
name: '我的Key'
};
const blob = new Blob([JSON.stringify(config)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'myrelay.proxycast';
a.click();
}
```
用户双击 `.proxycast` 文件,ProxyCast 自动打开并导入配置。
## Deep Link 参数
```
proxycast://connect?relay={relay_id}&key={api_key}&name={key_name}&ref={ref_code}
```
| 参数 | 必填 | 说明 |
|------|------|------|
| `relay` | ✅ | 中转商 ID(需在 ProxyCast 注册) |
| `key` | ✅ | API Key |
| `name` | ❌ | Key 名称(默认使用中转商名称) |
| `ref` | ❌ | 推广码(用于统计) |
### 示例
```
# 基础用法
proxycast://connect?relay=openrouter&key=sk-or-v1-xxxx
# 带名称
proxycast://connect?relay=siliconflow&key=sk-xxxx&name=硅基流动-主账号
# 带推广码
proxycast://connect?relay=myrelay&key=sk-xxxx&ref=promo2024
```
## 品牌素材要求
| 素材 | 规格 | 说明 |
|------|------|------|
| Logo | 256x256 PNG | 透明背景,正方形 |
| 主题色 | HEX 色值 | 用于 UI 强调色 |
| 简介 | ≤50 字 | 一句话描述 |
| 详细描述 | ≤200 字 | 详细介绍 |
## API 要求
中转商的 API 需要满足:
| 要求 | 说明 |
|------|------|
| 协议兼容 | OpenAI 或 Anthropic 协议 |
| HTTPS | 必须使用 HTTPS |
| 模型列表 | 提供 `/models` 端点(可选) |
| 稳定性 | 99% 以上可用性 |
## 审核标准
PR 合并前需满足:
- JSON Schema 验证通过
- 文件名与 `id` 字段一致
- Logo 图片可访问(256x256 PNG)
- API 地址使用 HTTPS
- 官网可访问
- 联系方式有效
## 下一步
- [统计回调](/open-platform/connect-webhook) - 配置 Webhook 追踪推广效果
1. 参数合法性校验
2. 失效 Key 的处理策略
3. 安全与速率限制策略
4. 版本兼容说明
@@ -1,198 +1,58 @@
# 统计回调(Webhook)
---
title: 开放平台 - 统计回调(Webhook)
description: Connect 回调事件格式与接入建议
navigation:
icon: i-heroicons-arrow-path-rounded-square
---
ProxyCast Connect 提供统计回调机制,让中转商追踪推广效果。
# 开放平台 - 统计回调(Webhook)
## 回调流程
::alert{type="info"}
本页面向生态合作方技术团队。
::
```
用户点击一键配置
│
▼
ProxyCast 打开,显示确认弹窗
│
├─── 用户取消 ───▶ 发送回调: status=cancelled
│
└─── 用户确认 ───▶ Key 添加成功
│
▼
发送回调: status=success
│
▼
中转商收到回调,更新统计
```
Webhook 用于回传配置行为结果,帮助你统计接入效果。
## 配置回调
## 回调时机
在 `providers/{id}.json` 中添加 webhook 配置:
常见状态:
```json
{
"id": "myrelay",
"name": "我的中转站",
"webhook": {
"callback_url": "https://api.myrelay.com/proxycast/callback"
}
}
```
- `success`:用户确认并配置成功
- `cancelled`:用户取消
- `error`:执行失败
| 字段 | 必填 | 说明 |
|------|------|------|
| `webhook.callback_url` | ✅ | 回调地址(必须 HTTPS) |
## 回调请求格式
ProxyCast 向中转商发送 POST 请求:
## 请求示例
```http
POST https://api.myrelay.com/proxycast/callback
POST https://your-domain.com/proxycast/callback
Content-Type: application/json
User-Agent: ProxyCast/1.2.0
{
"event": "connect",
"status": "success",
"relay_id": "myrelay",
"ref": "promo2024",
"key_prefix": "sk-xxxx",
"timestamp": "2026-01-05T12:00:00Z",
"client": {
"version": "1.2.0",
"platform": "macos"
}
"relay_id": "your-relay",
"ref": "campaign-2026",
"timestamp": "2026-02-16T10:00:00Z"
}
```
## 回调字段说明
## 字段建议
| 字段 | 说明 |
|------|------|
| `event` | 事件类型:`connect` |
| `status` | 状态:`success`(成功)、`cancelled`(用户取消)、`error`(失败) |
| `relay_id` | 中转商 ID |
| `ref` | 推广码(如果有) |
| `key_prefix` | Key 前缀(脱敏,仅前 7 位) |
| `timestamp` | 事件时间(ISO 8601 格式) |
| `client.version` | ProxyCast 版本 |
| `client.platform` | 平台:`macos`、`windows`、`linux` |
| `error_code` | 错误码(仅 status=error 时) |
| `error_message` | 错误信息(仅 status=error 时) |
- `event`:事件类型
- `status`:状态值
- `relay_id`:服务方标识
- `ref`:渠道标记
- `timestamp`:事件时间
## 请求验证
## 安全建议
由于 ProxyCast 是开源软件,不使用签名验证。中转商应通过以下方式验证请求:
1. 仅接受 HTTPS 回调
2. 校验来源与参数完整性
3. 对回调做幂等处理
4. 记录失败重试日志
1. **检查 key_prefix** - 验证该 Key 前缀是否为自己下发的 Key
2. **检查 relay_id** - 确认是自己的中转商 ID
3. **检查 User-Agent** - 确认包含 `ProxyCast`
## 监控建议
### Express 示例
```javascript
app.post('/proxycast/callback', async (req, res) => {
const { relay_id, key_prefix, status, ref } = req.body;
const userAgent = req.headers['user-agent'] || '';
// 验证 User-Agent
if (!userAgent.includes('ProxyCast')) {
return res.status(403).json({ error: 'Invalid User-Agent' });
}
// 验证 relay_id
if (relay_id !== 'myrelay') {
return res.status(403).json({ error: 'Invalid relay_id' });
}
// 验证 key_prefix 是否为自己下发的 Key
const isValidKey = await db.apiKeys.exists({
key: { $regex: `^${key_prefix}` }
});
if (!isValidKey) {
return res.status(403).json({ error: 'Unknown key_prefix' });
}
// 处理回调
if (status === 'success') {
await db.stats.increment({
relay_id,
ref: ref || 'direct',
date: new Date().toISOString().split('T')[0]
});
}
res.json({ received: true });
});
```
## 重试机制
| 重试次数 | 间隔 | 说明 |
|----------|------|------|
| 第 1 次 | 立即 | 首次发送 |
| 第 2 次 | 1 分钟 | 首次失败后 |
| 第 3 次 | 5 分钟 | 第二次失败后 |
| 第 4 次 | 30 分钟 | 第三次失败后 |
| 放弃 | - | 超过 4 次不再重试 |
成功响应:HTTP 2xx 状态码
## 统计数据示例
基于回调数据,中转商可以构建统计面板:
```
┌─────────────────────────────────────────────────────────────┐
│ ProxyCast Connect 统计 2026-01-05 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 今日概览 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 128 │ │ 115 │ │ 13 │ │ 89.8% │ │
│ │ 点击次数 │ │ 成功配置 │ │ 用户取消 │ │ 转化率 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ 推广码效果 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 推广码 点击 成功 取消 转化率 │ │
│ ├─────────────────────────────────────────────────────┤ │
│ │ promo2024 56 52 4 92.9% │ │
│ │ twitter 38 33 5 86.8% │ │
│ │ (无推广码) 34 30 4 88.2% │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
## 隐私保护
回调数据遵循最小化原则:
| 数据 | 是否发送 | 说明 |
|------|----------|------|
| 完整 API Key | ❌ | 仅发送前 7 位前缀 |
| 用户 ID | ❌ | 不发送任何用户标识 |
| 设备 ID | ❌ | 不发送设备标识 |
| IP 地址 | ❌ | 不发送用户 IP |
| 推广码 | ✅ | 用于统计推广效果 |
| 平台信息 | ✅ | 仅操作系统类型 |
## 错误码
当 `status=error` 时,会包含错误信息:
| 错误码 | 说明 |
|--------|------|
| `invalid_relay` | 中转商 ID 无效 |
| `invalid_key` | API Key 格式无效 |
| `relay_not_found` | 中转商未注册 |
| `network_error` | 网络错误 |
| `internal_error` | 内部错误 |
## 最佳实践
1. **验证 key_prefix** - 检查是否为自己下发的 Key
2. **幂等处理** - 同一事件可能重复发送
3. **快速响应** - 在 5 秒内返回响应
4. **异步处理** - 复杂逻辑放到后台队列
1. 统计成功率与取消率
2. 跟踪错误类型占比
3. 区分渠道来源效果
+36 -133
View File
@@ -1,149 +1,52 @@
---
title: ProxyCast - 把你的 AI 客户端额度用到任何地方
description: 一款基于 Tauri 的桌面应用,将 Kiro、Gemini CLI、Qwen 等 AI 客户端凭证转换为标准 OpenAI/Claude 兼容 API
title: ProxyCast 文档中心
description: 创作类 AI Agent 平台文档,从灵感到发布的一站式指南
navigation: false
---
<div class="max-w-4xl mx-auto">
# ProxyCast 文档中心
<div class="text-center py-8">
<h1 class="text-5xl font-bold text-primary-600 mb-4">ProxyCast</h1>
<p class="text-3xl font-semibold text-gray-700 dark:text-gray-300 mb-2">把你的 AI 客户端额度用到任何地方</p>
<p class="text-xl text-gray-600 dark:text-gray-400 mb-4">一款基于 Tauri 的桌面应用,将 Kiro、Gemini CLI、Qwen 等 AI 客户端凭证转换为标准 OpenAI/Claude 兼容 API</p>
<p class="text-base text-gray-500 dark:text-gray-500 mb-10">凭证池管理 • 智能路由 • 协议转换 • 容错机制</p>
<div class="flex gap-4 justify-center flex-wrap">
<a href="/introduction/quickstart" class="inline-block px-8 py-3 bg-primary-600 text-white font-medium rounded-lg hover:bg-primary-700 transition-colors">快速开始</a>
<a href="https://github.com/aiclientproxy/proxycast" target="_blank" class="inline-block px-8 py-3 border-2 border-gray-300 dark:border-gray-600 font-medium rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">GitHub</a>
</div>
</div>
ProxyCast 是创作类 AI Agent 平台。
你可以在同一个工作台里完成对话、创作、图片生成、项目沉淀与资源复用。
<div class="text-center py-3 px-4 mb-6 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
<p class="text-yellow-800 dark:text-yellow-200">
<strong>⚠️ 免责声明:</strong> 本工具仅限于个人合法使用,严禁用于非法盈利目的。初衷是帮助用户充分利用已订阅的 AI 服务 Token。
<a href="/legal/disclaimer" class="text-primary-600 hover:underline ml-1">查看完整声明</a>
</p>
</div>
## 从这里开始
## ✨ 核心特性
1. [概述](/introduction/overview):先了解平台能帮你完成什么
2. [安装指南](/introduction/installation):安装到本地桌面
3. [快速开始](/introduction/quickstart):3 步走完首次创作
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 my-8">
<div class="p-6 border border-gray-200 dark:border-gray-700 rounded-lg">
<h3 class="text-xl font-semibold mb-3">🔑 凭证池管理</h3>
<p class="text-gray-600 dark:text-gray-400">支持多种 AI 客户端凭证的统一管理,包括 Kiro、Gemini CLI、Qwen、Claude Code 等,自动检测和刷新 OAuth Token。</p>
</div>
<div class="p-6 border border-gray-200 dark:border-gray-700 rounded-lg">
<h3 class="text-xl font-semibold mb-3">🔀 智能路由</h3>
<p class="text-gray-600 dark:text-gray-400">基于模型名称的请求路由,支持负载均衡、优先级配置、健康检查和自动故障转移。</p>
</div>
<div class="p-6 border border-gray-200 dark:border-gray-700 rounded-lg">
<h3 class="text-xl font-semibold mb-3">🛡️ 容错配置</h3>
<p class="text-gray-600 dark:text-gray-400">内置熔断器、重试机制、超时控制,确保服务稳定性,优雅处理 API 故障。</p>
</div>
<div class="p-6 border border-gray-200 dark:border-gray-700 rounded-lg">
<h3 class="text-xl font-semibold mb-3">⚡ 配置切换</h3>
<p class="text-gray-600 dark:text-gray-400">一键切换 Claude Code、Codex、Gemini CLI 等客户端配置,快速适应不同使用场景。</p>
</div>
<div class="p-6 border border-gray-200 dark:border-gray-700 rounded-lg">
<h3 class="text-xl font-semibold mb-3">📊 监控统计</h3>
<p class="text-gray-600 dark:text-gray-400">实时监控请求统计、Token 使用追踪、详细的请求日志和性能指标。</p>
</div>
<div class="p-6 border border-gray-200 dark:border-gray-700 rounded-lg">
<h3 class="text-xl font-semibold mb-3">🔌 API 兼容</h3>
<p class="text-gray-600 dark:text-gray-400">完整支持 OpenAI Chat Completions API 和 Claude Messages API,无缝集成现有工具。</p>
</div>
</div>
## 九大创作主题
## 🎯 支持的 Provider
| 主题 | 常见产出 |
|------|----------|
| 通用对话 | 灵感梳理、问题分析、方案草稿 |
| 社媒内容 | 选题、标题、多平台文案 |
| 图文海报 | 主视觉文案、配图方向、活动海报内容 |
| 歌词曲谱 | 主题歌词、段落续写、风格改编 |
| 知识探索 | 知识卡片、结构化总结、学习资料 |
| 计划规划 | 周计划、项目拆解、执行清单 |
| 办公文档 | 报告、方案、邮件、纪要 |
| 短视频 | 脚本、分镜、口播稿 |
| 小说创作 | 设定、章节、人物对白 |
| Provider | 类型 | 认证方式 | 说明 |
|----------|------|----------|------|
| Kiro Claude | OAuth | 自动刷新 | AWS Kiro IDE 的 Claude 凭证 |
| Gemini CLI | OAuth | 自动刷新 | Google Gemini CLI 凭证 |
| Qwen (通义千问) | OAuth | 自动刷新 | 阿里云通义千问凭证 |
| OpenAI Custom | API Key | 手动配置 | 自定义 OpenAI 兼容服务 |
| Claude Custom | API Key | 手动配置 | 自定义 Claude 兼容服务 |
## 常用功能入口
## 🚀 快速开始
- [首页与工作台](/user-guide/dashboard)
- [资源库](/user-guide/resources)
- [图片生成与编辑](/user-guide/image-generation)
- [设置](/user-guide/settings)
- [插件中心](/user-guide/plugins)
### 1. 下载安装
## 进阶能力(可选)
从 [GitHub Tags](https://github.com/aiclientproxy/proxycast/tags) 下载适合你系统的安装包。
当你需要更深度的模型接入或工程能力时,可继续阅读:
### 2. 加载凭证
- [Provider 概述](/providers/overview)
- [API 参考](/api-reference/overview)
- [开放平台](/open-platform/overview)
- [故障排查](/troubleshooting/common-issues)
ProxyCast 会自动检测本地的 AI 客户端凭证文件:
## 免责声明
```
~/.kiro/credentials.json # Kiro Claude
~/.config/gemini-cli/oauth_creds.json # Gemini CLI
~/.config/qwen/credentials.json # Qwen
```
### 3. 启动服务
点击仪表盘的「启动服务」按钮,API Server 默认运行在 `http://127.0.0.1:8999`。
### 4. 测试 API
```bash
curl http://127.0.0.1:8999/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-api-key" \
-d '{
"model": "claude-sonnet-4-20250514",
"messages": [{"role": "user", "content": "Hello!"}]
}'
```
## 📖 文档导航
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 my-8">
<a href="/introduction/overview" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">📋 概述</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">了解 ProxyCast 的核心功能和价值</p>
</a>
<a href="/introduction/installation" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">📥 安装指南</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">下载并安装 ProxyCast</p>
</a>
<a href="/introduction/quickstart" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">🚀 快速开始</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">5 分钟内完成首次 API 调用</p>
</a>
<a href="/providers/overview" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">🔧 Provider 配置</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">配置各种 AI 服务提供商</p>
</a>
<a href="/api-reference/overview" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">📚 API 参考</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">完整的 API 端点文档</p>
</a>
<a href="/troubleshooting/common-issues" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">🔍 故障排除</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">常见问题和解决方案</p>
</a>
</div>
## 🌐 开放平台
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 my-8">
<a href="/open-platform/overview" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">🔌 插件系统</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">通过插件扩展 ProxyCast 功能,支持工具类、Hook 类等多种插件类型</p>
</a>
<a href="/open-platform/connect" class="block p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-primary-500 transition-colors">
<h3 class="font-semibold mb-2">🔗 ProxyCast Connect</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">中转商生态合作方案,一键配置 API Key,提升用户转化率</p>
</a>
</div>
## 🤝 社区与支持
- **GitHub Issues**: [报告问题](https://github.com/aiclientproxy/proxycast/issues)
- **GitHub Discussions**: [参与讨论](https://github.com/aiclientproxy/proxycast/discussions)
## 📄 开源协议
ProxyCast 采用 [MIT License](https://github.com/aiclientproxy/proxycast/blob/main/LICENSE) 开源。
</div>
请在合法合规前提下使用本产品。
完整说明见 [免责声明](/legal/disclaimer)。
+75 -234
View File
@@ -1,285 +1,126 @@
# ProxyCast AI 创作工作站 - 产品介绍
# ProxyCast 创作类 AI Agent 平台 - 产品介绍
> 版本: 1.0.0
> 更新: 2026-02-04
> 用途: 客户演示、产品介绍
> 版本: 2.0.0
> 更新: 2026-02-16
> 用途: 产品介绍、客户演示、团队对齐
---
## 一、产品定位
**中文创作者的本地 AI 工作站**
**面向创作者的一站式 AI Agent 平台**
核心理念:**AI 增强人,而非替代人**
ProxyCast 不是单点工具,而是一条完整创作链路:
设计原则:
- **对话即创作** - 用自然语言描述需求,AI 理解意图
- **一个对话,多种画布** - 同一对话可切换不同创作画布
- **人机协作** - AI 建议透明可审查,用户掌控最终决策
- 从灵感讨论开始
- 到文本与图片产出
- 再到项目沉淀与长期复用
核心理念:**让创作更快,但主导权始终在创作者手中**。
---
## 二、六大创作画布
## 二、九大创作主题
ProxyCast 提供 **6 种专业画布**,覆盖主流内容创作场景:
| 画布类型 | 图标 | 适用场景 | 核心能力 |
|---------|------|---------|---------|
| **通用对话** | 💬 | 日常问答、头脑风暴 | 智能对话、知识问答 |
| **社媒内容** | 📱 | 公众号、小红书、知乎 | 6 步工作流、多平台适配 |
| **图文海报** | 🖼️ | 营销海报、社交图片 | 可视化设计、多尺寸导出 |
| **音乐歌词** | 🎵 | 歌词创作、简谱编曲 | 旋律学习、Suno 导出 |
| **短剧脚本** | 🎬 | 短视频、微短剧 | 场景管理、对白编辑 |
| **小说创作** | 📖 | 网文、长篇小说 | 章节管理、大纲规划 |
| 主题 | 典型任务 | 常见产出 |
|------|----------|----------|
| 通用对话 | 灵感发散、问题梳理 | 对话结论、行动草案 |
| 社媒内容 | 选题、标题、正文 | 多平台文案 |
| 图文海报 | 活动视觉、品牌传播 | 海报文案、配图方案 |
| 歌词曲谱 | 主题创作、段落续写 | 歌词草稿、结构框架 |
| 知识探索 | 学习拆解、资料整合 | 知识卡片、总结笔记 |
| 计划规划 | 目标拆解、执行跟踪 | 周计划、任务清单 |
| 办公文档 | 报告、邮件、纪要 | 可交付文档 |
| 短视频 | 口播、脚本、分镜 | 拍摄脚本、内容提纲 |
| 小说创作 | 世界观、人物、章节 | 连载章节、剧情草案 |
---
## 三、各画布详细能力
## 三、创作流程
### 3.1 📱 社媒内容画布
### 1) 对话定方向
**6 步引导式创作流程**:
先用 AI Agent 明确目标、受众和输出形式。
```
选题研究 → 竞品分析 → 大纲生成 → 初稿写作 → 多轮优化 → 平台发布
10% 20% 40% 70% 90% 100%
```
### 2) 生成首稿
**多平台一键适配**:
按主题工作流生成内容初稿,快速得到可迭代版本。
| 平台 | 特点 | 自动处理 |
|-----|------|---------|
| 公众号 | 深度长文 | 外链转二维码、排版优化 |
| 小红书 | 种草短文 | emoji 风格、话题标签 |
| 知乎 | 专业问答 | 引用来源、脚注格式 |
| 小说平台 | 章节连载 | 作者说、字数统计 |
### 3) 图片与素材补齐
**专业 Agent 协作**:
在图片生成功能中完成视觉产出,支持参考图参与编辑。
| Agent | 功能 |
|-------|------|
| 选题 Agent | 热点分析、选题推荐 |
| 标题 Agent | 爆款标题优化 |
| 开头 Agent | 吸睛开场设计 |
| 互动 Agent | 评论区引导 |
| 金句 Agent | 金句提取与优化 |
### 4) 资产沉淀
### 3.2 🎵 音乐歌词画布
**支持歌曲类型**:
| 类型 | 说明 |
|-----|------|
| 流行 (pop) | 主流流行音乐 |
| 民谣 (folk) | 抒情民谣 |
| 摇滚 (rock) | 摇滚乐 |
| 古风 (guofeng) | 中国风 |
| 说唱 (rap) | Hip-hop |
| R&B | 节奏蓝调 |
| 电子 (electronic) | 电子音乐 |
**三种创作模式**:
| 模式 | 说明 | 适合人群 |
|-----|------|---------|
| 教练模式 | AI 逐段引导创作 | 新手创作者 |
| 快速模式 | AI 直接生成完整歌词 | 追求效率 |
| 混合模式 | AI 生成框架,用户填充细节 | 专业创作者 |
**四种视图模式**:
- 🎤 纯歌词视图 - 专注歌词编辑
- 🎼 简谱视图 - 数字简谱展示
- 🎸 吉他谱视图 - 和弦指法图
- 🎹 钢琴谱视图 - 钢琴键位标注
**旋律学习功能**:
- 上传 MIDI/MP3 参考曲目
- AI 分析旋律特征(调式、节奏、音程)
- 智能借鉴风格创作新曲
- 一致性评分(结构、风格、旋律适配度)
**导出格式**:
- PDF 歌词本
- MIDI 文件
- MusicXML
- **Suno 提示词** - 直接生成 AI 音乐
- **Tunee 素材包** - 对话素材导出
### 3.3 🖼️ 图文海报画布
**基于 Fabric.js 的专业设计器**:
- 文字元素 - 多字体、多样式
- 图片元素 - 裁剪、滤镜
- 形状元素 - 矩形、圆形、线条
- 背景元素 - 纯色、渐变、图片
**专业功能**:
- 图层管理 - 上移、下移、置顶、置底
- 对齐工具 - 左对齐、居中、右对齐、分布
- 多页面支持 - 批量设计
**预设尺寸**:
| 平台 | 比例 | 像素 |
|-----|------|-----|
| 小红书封面 | 3:4 | 1080×1440 |
| 公众号头图 | 2.35:1 | 900×383 |
| 朋友圈 | 1:1 | 1080×1080 |
| 自定义 | 任意 | 自定义 |
**导出格式**:PNG、JPEG、PDF
### 3.4 🎬 短剧脚本画布
**专业剧本格式**:
- 场景管理 - 内景/外景、日/夜/晨/昏
- 角色对白编辑
- 表演指示标注(括号内)
- 情绪标记
**结构化编辑示例**:
```
第1场:咖啡厅(日)
*女主角坐在窗边,若有所思*
女主:(叹气)为什么事情总是这样...
男主:(走近)你还好吗?
```
**场景元素**:
- 场景编号
- 地点描述
- 时间设定
- 场景描述
- 对白列表
### 3.5 📖 小说创作画布
**长篇创作支持**:
- 章节管理 - 拖拽排序、批量操作
- 大纲树形结构 - 多级展开
- 字数统计 - 章节/全书
- 版本历史 - 随时回溯
**章节状态**:
- 草稿 (draft) - 创作中
- 已完成 (completed) - 定稿
**创作辅助**:
- 世界观设定
- 角色档案
- 剧情线索追踪
- AI 续写建议
把文档、图片、语音、视频统一沉淀到项目资源库,便于复用。
---
## 四、通用能力
## 四、典型用户场景
### 4.1 人设系统
### 场景 1:自媒体日更
**人设配置项**:
- 名称与简介
- 写作风格描述
- 语气设定
- 目标读者画像
- 禁用词列表
- 偏好词列表
- 示例文章(供 AI 学习)
- 适用平台
- 早上 10 分钟定选题
- 中午完成首稿与配图
- 下午发布并沉淀素材用于复盘
**使用方式**:
- 项目级默认人设
- 话题级人设覆盖
- 多人设快速切换
### 场景 2:短视频团队周更
- 统一脚本结构
- 批量生成口播与镜头要点
- 版本资产留档,便于协同交接
### 场景 3:小说连载
### 4.2 素材库
**支持素材类型**:
- 文档 (document) - PDF、Word、Markdown
- 图片 (image) - PNG、JPEG、GIF
- 文本 (text) - 纯文本片段
- 数据 (data) - Excel、CSV
- 链接 (link) - 网页引用
**管理功能**:
- 标签分类
- 描述备注
- 预览查看
- 写作时一键引用
### 4.3 项目管理
**层级关系**:
```
项目 (Project) - 内容容器
└── 话题 (Topic) - 内容载体
└── 消息 (Message) - 对话记录
└── 产出物 (Artifact) - 生成内容
```
**项目类型**:
- general - 通用
- social - 社媒内容
- novel - 小说创作
- drama - 短剧脚本
- document - 办公文档
- paper - 学术论文
- music - 歌词曲谱
- poster - 图文海报
- 持续维护设定与角色
- 章节迭代不丢上下文
- 连载节奏稳定、可持续推进
### 场景 4:品牌与运营活动
- 快速生成多套文案与视觉方向
- 统一保存历史版本与素材
- 缩短从想法到上线的周期
---
## 五、产品亮点
## 五、产品价值
| 特性 | 说明 |
|-----|------|
| **本地运行** | 数据安全,无需上传云端 |
| **多画布** | 6 种专业画布,覆盖主流场景 |
| **人机协作** | AI 建议透明可审查,用户掌控最终决策 |
| **多平台适配** | 一份内容,自动适配多个发布平台 |
| **专业导出** | 支持 Suno、Tunee 等 AI 音乐平台 |
| **项目化管理** | 人设/素材/排版 项目级复用 |
| 价值 | 体现 |
|------|------|
| 创作效率提升 | 同一处完成对话、出稿、出图、沉淀 |
| 结果可复用 | 项目化管理历史内容与素材 |
| 团队协作更顺畅 | 上下文和资产都可追溯 |
| 门槛更低 | 先用再学,按需开启进阶能力 |
---
## 六、目标用户
| 用户群体 | 典型场景 |
|---------|---------|
| 自媒体创作者 | 公众号、小红书、知乎日更 |
| 音乐创作者 | 歌词创作、编曲辅助 |
| 短剧编剧 | 微短剧、短视频脚本 |
| 网文作者 | 小说连载、大纲规划 |
| 设计师 | 营销海报、社交图片 |
| 内容运营 | 品牌文案、多平台分发 |
- 自媒体与内容创作者
- 短视频脚本团队
- 小说与剧情创作者
- 品牌运营与营销团队
- 需要长期沉淀创作资产的个人与小团队
---
## 七、技术架构(简述)
## 七、进阶能力(可选)
- **前端**:React + TypeScript + Vite + TailwindCSS
- **后端**:Rust + Tauri
- **数据库**:SQLite(本地存储)
- **AI 框架**:集成 Aster-Rust Agent 框架
对于开发者或自动化场景,ProxyCast 还提供:
- 本地 API 接入
- MCP 工具扩展
- 插件扩展体系
普通创作者不需要先配置这些能力,也能完成完整创作流程。
---
## 相关文档
## 八、推荐阅读
- [社媒内容创作 PRD](prd/ai-content-creator.md)
- [SheMedia 工作流设计](prd/shemei/workflow.md)
- [画布系统架构](../src/components/content-creator/canvas/README.md)
- [统一内容系统](prd/unified-content-system.md)
- [文档首页](content/index.md)
- [快速开始](content/01.introduction/3.quickstart.md)
- [首页与工作台](content/02.user-guide/1.dashboard.md)
- [资源库](content/02.user-guide/14.resources.md)
- [图片生成与编辑](content/02.user-guide/15.image-generation.md)
-348
View File
@@ -1,348 +0,0 @@
# 三阶段工作流使用指南
基于 planning-with-files 的核心理念,ProxyCast 和 aster-rust 现已集成完整的三阶段工作流系统,解决 AI Agent 的上下文丢失、目标漂移、错误重复问题。
## 核心理念
```
Context Window = RAM (易失性,有限)
Filesystem = Disk (持久性,无限)
→ 重要信息都写入磁盘存储
```
## 三阶段工作流
### 1. Pre-Action 阶段
- **目的**: 执行前的上下文刷新和检查
- **功能**:
- 读取任务计划和历史记忆
- 检查 3次错误协议
- 刷新目标和上下文
### 2. Action 阶段
- **目的**: 执行实际操作
- **功能**:
- 记录操作过程
- 跟踪视觉操作计数
- 监控执行状态
### 3. Post-Action 阶段
- **目的**: 操作后的状态更新和学习
- **功能**:
- 应用 2-Action 规则
- 记录错误和解决方案
- 更新进度和发现
## 核心文件系统
### 三文件模式
1. **task_plan.md** - 任务计划和阶段跟踪
2. **findings.md** - 研究发现和重要信息
3. **progress.md** - 会话进度日志
### 自动化规则
- **2-Action 规则**: 每2次视觉操作后立即保存发现
- **3次错误协议**: 永不重复相同的失败操作
- **上下文刷新**: 重要决策前重新阅读计划文件
## ProxyCast 使用方法
### 1. 基础集成
```typescript
import { useWorkflowIntegration } from './hooks/useWorkflowIntegration';
function ChatComponent({ sessionId }: { sessionId: string }) {
const [workflowState, workflowActions] = useWorkflowIntegration({
sessionId,
enableAutoWorkflow: true,
workflowThreshold: 5, // 5条消息后自动启用
});
// 初始化工作流
const handleInitWorkflow = async () => {
await workflowActions.initializeWorkflow(
'数据分析项目',
'帮助用户分析销售数据并生成报告'
);
};
// 处理消息发送
const handleSendMessage = async (content: string) => {
// Pre-Action: 获取上下文
const preActionInfo = await workflowActions.handlePreMessage(content, 'user');
// Action: 发送消息
const response = await sendMessageToAPI(content);
// Post-Action: 更新状态
const postActionInfo = await workflowActions.handlePostMessage(response);
return { response, preActionInfo, postActionInfo };
};
return (
<div>
<WorkflowStatusPanel
sessionId={sessionId}
isWorkflowActive={workflowState.isWorkflowActive}
isWorkflowInitialized={workflowState.isWorkflowInitialized}
messageCount={workflowState.messageCount}
visualOperationCount={workflowState.visualOperationCount}
onInitializeWorkflow={handleInitWorkflow}
onFinalizeWorkflow={workflowActions.finalizeSession}
/>
{/* 其他聊天组件 */}
</div>
);
}
```
### 2. 手动记录重要信息
```typescript
// 记录重要发现
await workflowActions.recordFinding(
'关键数据洞察',
'发现销售数据中存在明显的季节性趋势,Q4销量比Q1高出40%',
['数据分析', '季节性', '重要']
);
// 记录决策
await workflowActions.recordDecision(
'使用时间序列分析',
'考虑到数据的季节性特征,决定采用ARIMA模型进行预测分析'
);
// 更新阶段状态
await workflowActions.updatePhaseStatus(2, 'complete', '数据清洗和初步分析已完成');
```
### 3. 工具使用集成
```typescript
// 工具使用前后自动记录
const handleToolUse = async (toolName: string, params: any) => {
try {
const result = await executeTool(toolName, params);
// 自动记录成功的工具使用
await workflowActions.handleToolUse(toolName, params, result);
return result;
} catch (error) {
// 自动记录失败的工具使用
await workflowActions.handleToolUse(toolName, params, '', error.message);
throw error;
}
};
```
## aster-rust 使用方法
### 1. 基础工具集成
```rust
use aster::tools::{ThreeStageWorkflowTool, WorkflowIntegratedTool, ToolHookManager};
// 创建带钩子的工具
let hook_manager = Arc::new(ToolHookManager::new(true));
hook_manager.register_default_hooks().await;
let workflow_tool = WorkflowIntegratedTool::default()
.with_hook_manager(hook_manager.clone());
// 注册到工具注册表
registry.register(Box::new(workflow_tool));
```
### 2. 三阶段工作流工具
```rust
// 初始化工作流
let init_params = serde_json::json!({
"action": "init_workflow",
"project_name": "Rust项目重构"
});
let result = three_stage_tool.execute(init_params, &context).await?;
// 记录发现
let finding_params = serde_json::json!({
"action": "add_finding",
"finding": "发现代码中存在大量重复逻辑,需要提取公共模块"
});
let result = three_stage_tool.execute(finding_params, &context).await?;
// 应用 2-Action 规则
let rule_params = serde_json::json!({
"action": "apply_2action_rule",
"finding": "通过代码审查发现了性能瓶颈"
});
let result = three_stage_tool.execute(rule_params, &context).await?;
```
### 3. 自定义钩子
```rust
use aster::tools::hooks::{ToolHook, HookContext, HookTrigger};
#[derive(Debug)]
struct CustomWorkflowHook {
name: String,
}
#[async_trait]
impl ToolHook for CustomWorkflowHook {
fn name(&self) -> &str {
&self.name
}
fn description(&self) -> &str {
"自定义工作流钩子"
}
async fn execute(&self, context: &HookContext) -> Result<()> {
// 自定义钩子逻辑
tracing::info!("执行自定义工作流钩子: {}", context.tool_name);
Ok(())
}
}
// 注册自定义钩子
hook_manager.register_hook(
HookTrigger::PreExecution,
Box::new(CustomWorkflowHook {
name: "custom_workflow_hook".to_string(),
})
).await;
```
## 最佳实践
### 1. 工作流初始化时机
- **自动模式**: 消息数量达到阈值时自动初始化
- **手动模式**: 用户明确表达复杂任务意图时初始化
- **智能模式**: 结合消息内容分析和用户行为模式
### 2. 记忆管理策略
- **及时记录**: 重要发现立即保存,不要依赖记忆
- **分类标记**: 使用标签系统便于后续检索
- **定期清理**: 自动归档过期记忆,保持系统性能
### 3. 错误处理原则
- **详细记录**: 记录错误的完整上下文和尝试的解决方案
- **避免重复**: 严格执行 3次错误协议
- **学习改进**: 从错误中提取经验,更新工作流程
### 4. 阶段管理技巧
- **明确划分**: 每个阶段有清晰的目标和完成标准
- **及时更新**: 阶段状态变化时立即更新
- **灵活调整**: 根据实际情况调整阶段计划
## 故障排除
### 常见问题
1. **工作流未自动初始化**
- 检查 `enableAutoWorkflow` 设置
- 确认消息数量是否达到阈值
- 查看控制台错误信息
2. **钩子未触发**
- 验证钩子管理器是否正确初始化
- 检查钩子条件是否匹配
- 确认钩子是否已启用
3. **记忆保存失败**
- 检查会话ID是否有效
- 验证存储权限
- 查看后端服务状态
4. **性能问题**
- 定期清理过期记忆
- 限制单次记录的内容长度
- 优化钩子执行频率
### 调试技巧
```typescript
// 启用详细日志
const [workflowState, workflowActions] = useThreeStageWorkflow({
sessionId,
debugMode: true, // 启用调试模式
});
// 获取详细统计信息
const stats = await workflowActions.getSessionStats();
console.log('工作流统计:', stats);
// 检查记忆状态
const memoryStats = await ContextMemoryAPI.getMemoryStats(sessionId);
console.log('记忆统计:', memoryStats);
```
## 扩展开发
### 自定义钩子规则
```typescript
// 创建自定义钩子规则
const customRule = ToolHooksAPI.createCustomRule(
'code-review-reminder',
'代码审查提醒',
'检测到代码相关操作时提醒进行代码审查',
'post_tool_use',
[
{ message_contains: '代码' },
{ tool_name_contains: 'edit' },
],
[
{
save_finding: {
title: '代码审查提醒',
content: '建议对修改的代码进行审查',
tags: ['代码审查', '提醒'],
priority: 3,
},
},
],
50 // 优先级
);
await ToolHooksAPI.addHookRule(customRule);
```
### 自定义记忆类型
```typescript
// 扩展记忆文件类型
type ExtendedMemoryFileType = MemoryFileType | 'code_review' | 'test_results';
// 保存自定义类型记忆
await ContextMemoryAPI.saveMemoryEntry({
session_id: sessionId,
file_type: 'code_review' as any,
title: '代码审查结果',
content: '审查发现3个潜在问题...',
tags: ['代码审查', '质量'],
priority: 4,
});
```
## 总结
三阶段工作流系统为 ProxyCast 和 aster-rust 提供了强大的上下文管理和自动化能力:
- **解决核心问题**: 上下文丢失、目标漂移、错误重复
- **自动化工程**: Pre-Action → Action → Post-Action 流程
- **持久化记忆**: 基于文件系统的可靠存储
- **智能学习**: 错误跟踪和经验积累
- **灵活扩展**: 支持自定义钩子和记忆类型
通过正确使用这个系统,可以显著提升 AI Agent 的工作效率和可靠性,让复杂任务的执行更加有序和可控。
+29 -15
View File
@@ -203,6 +203,7 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "aster"
version = "0.11.0"
source = "git+https://github.com/astercloud/aster-rust?tag=v0.11.0#c4a9c40b48bcb0c77375b10ccb1313366fb4e7ba"
dependencies = [
"ahash",
"anyhow",
@@ -291,6 +292,14 @@ dependencies = [
"zip",
]
[[package]]
name = "aster-models"
version = "0.12.0"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "async-broadcast"
version = "0.7.2"
@@ -6621,7 +6630,7 @@ dependencies = [
[[package]]
name = "proxycast"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"anyhow",
"arboard",
@@ -6719,7 +6728,7 @@ dependencies = [
[[package]]
name = "proxycast-agent"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"aster",
"async-trait",
@@ -6742,7 +6751,7 @@ dependencies = [
[[package]]
name = "proxycast-config"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"async-trait",
"parking_lot",
@@ -6758,8 +6767,9 @@ dependencies = [
[[package]]
name = "proxycast-core"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"aster-models",
"async-trait",
"axum 0.7.9",
"bytes",
@@ -6797,7 +6807,7 @@ dependencies = [
[[package]]
name = "proxycast-credential"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -6828,7 +6838,7 @@ dependencies = [
[[package]]
name = "proxycast-infra"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"chrono",
"dashmap 5.5.3",
@@ -6848,7 +6858,7 @@ dependencies = [
[[package]]
name = "proxycast-mcp"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"async-trait",
"glob",
@@ -6879,7 +6889,7 @@ dependencies = [
[[package]]
name = "proxycast-processor"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"async-trait",
"parking_lot",
@@ -6898,7 +6908,7 @@ dependencies = [
[[package]]
name = "proxycast-providers"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"anyhow",
"async-stream",
@@ -6950,7 +6960,7 @@ dependencies = [
[[package]]
name = "proxycast-server"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"async-stream",
"axum 0.7.9",
@@ -6989,7 +6999,7 @@ dependencies = [
[[package]]
name = "proxycast-server-utils"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"axum 0.7.9",
"futures",
@@ -7004,7 +7014,7 @@ dependencies = [
[[package]]
name = "proxycast-services"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"anyhow",
"aster",
@@ -7045,7 +7055,7 @@ dependencies = [
[[package]]
name = "proxycast-skills"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"async-trait",
"dirs 5.0.1",
@@ -7061,7 +7071,7 @@ dependencies = [
[[package]]
name = "proxycast-terminal"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"async-trait",
"base64 0.22.1",
@@ -7088,7 +7098,7 @@ dependencies = [
[[package]]
name = "proxycast-websocket"
version = "0.67.0"
version = "0.68.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -12114,3 +12124,7 @@ dependencies = [
"syn 2.0.114",
"winnow 0.7.14",
]
[[patch.unused]]
name = "aster-core"
version = "0.12.0"
+4 -2
View File
@@ -3,7 +3,7 @@ members = ["crates/*"]
resolver = "2"
[workspace.package]
version = "0.67.0"
version = "0.68.0"
edition = "2021"
authors = ["you"]
repository = "https://github.com/aiclientproxy/proxycast"
@@ -121,6 +121,8 @@ enigo = "0.3"
# CI/CD: git = "https://github.com/astercloud/aster-rust", tag = "v0.11.0"
# aster = { path = "../../../astercloud/aster-rust/crates/aster" }
aster = { git = "https://github.com/astercloud/aster-rust", tag = "v0.11.0" }
# CI/CD: aster-models = { git = "https://github.com/astercloud/aster-rust", tag = "v0.12.0" }
aster-models = { path = "../../../astercloud/aster-rust/crates/aster-models" }
# MCP (Model Context Protocol)
rmcp = { version = "0.12.0", features = ["client", "transport-io", "transport-child-process"] }
@@ -183,7 +185,7 @@ version = "2.4"
[package]
name = "proxycast"
version = "0.67.0"
version = "0.68.0"
description = "AI API Proxy Desktop App"
authors = ["you"]
edition = "2021"
+50 -2
View File
@@ -26,6 +26,7 @@ use aster::agents::{Agent, SessionConfig};
use aster::model::ModelConfig;
#[cfg(test)]
use aster::skills::{global_registry, load_skills_from_directory, SkillSource};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::sync::RwLock;
use tokio_util::sync::CancellationToken;
@@ -61,6 +62,10 @@ pub struct AsterAgentState {
current_provider_config: Arc<RwLock<Option<ProviderConfig>>>,
/// 凭证桥接器
credential_bridge: CredentialBridge,
/// Agent 初始化状态缓存(避免每次都获取锁)
initialized_cache: Arc<AtomicBool>,
/// Provider 配置状态缓存(避免每次都获取锁)
provider_configured_cache: Arc<AtomicBool>,
}
impl Default for AsterAgentState {
@@ -77,6 +82,8 @@ impl AsterAgentState {
cancel_tokens: Arc::new(RwLock::new(std::collections::HashMap::new())),
current_provider_config: Arc::new(RwLock::new(None)),
credential_bridge: CredentialBridge::new(),
initialized_cache: Arc::new(AtomicBool::new(false)),
provider_configured_cache: Arc::new(AtomicBool::new(false)),
}
}
@@ -91,6 +98,11 @@ impl AsterAgentState {
/// # 参数
/// - `db`: 数据库连接,用于创建 SessionStore
pub async fn init_agent_with_db(&self, db: &DbConnection) -> Result<(), String> {
// 快速路径:检查缓存
if self.initialized_cache.load(Ordering::Relaxed) {
return Ok(());
}
let mut agent_guard = self.agent.write().await;
if agent_guard.is_none() {
// 创建 SessionStore
@@ -116,10 +128,16 @@ impl AsterAgentState {
crate::reload_proxycast_skills();
*agent_guard = Some(agent);
// 更新缓存
self.initialized_cache.store(true, Ordering::Relaxed);
tracing::info!(
"[AsterAgent] Agent 初始化成功,已注入 ProxyCastSessionStore、ProxyCast 身份和 Skills"
);
} else {
// 更新缓存
self.initialized_cache.store(true, Ordering::Relaxed);
tracing::debug!("[AsterAgent] Agent 已初始化,跳过");
}
Ok(())
@@ -196,6 +214,10 @@ impl AsterAgentState {
let mut config_guard = self.current_provider_config.write().await;
*config_guard = Some(config.clone());
// 更新缓存
self.provider_configured_cache
.store(true, Ordering::Relaxed);
tracing::info!(
"[AsterAgent] Provider 配置成功: {} / {}",
config.provider_name,
@@ -256,6 +278,10 @@ impl AsterAgentState {
let mut config_guard = self.current_provider_config.write().await;
*config_guard = Some(config);
// 更新缓存
self.provider_configured_cache
.store(true, Ordering::Relaxed);
// 记录凭证使用
if let Err(e) = self
.credential_bridge
@@ -362,12 +388,26 @@ impl AsterAgentState {
pub async fn clear_provider_config(&self) {
let mut config_guard = self.current_provider_config.write().await;
*config_guard = None;
// 更新缓存
self.provider_configured_cache
.store(false, Ordering::Relaxed);
tracing::info!("[AsterAgent] Provider 配置已清除");
}
/// 检查 Provider 是否已配置
pub async fn is_provider_configured(&self) -> bool {
self.current_provider_config.read().await.is_some()
// 快速路径:检查缓存
if self.provider_configured_cache.load(Ordering::Relaxed) {
return true;
}
// 慢速路径:检查实际状态
let result = self.current_provider_config.read().await.is_some();
self.provider_configured_cache
.store(result, Ordering::Relaxed);
result
}
/// 获取 Agent 的只读引用并执行同步操作
@@ -511,7 +551,15 @@ impl AsterAgentState {
/// 检查 Agent 是否已初始化
pub async fn is_initialized(&self) -> bool {
self.agent.read().await.is_some()
// 快速路径:检查缓存
if self.initialized_cache.load(Ordering::Relaxed) {
return true;
}
// 慢速路径:检查实际状态
let result = self.agent.read().await.is_some();
self.initialized_cache.store(result, Ordering::Relaxed);
result
}
}
+46 -7
View File
@@ -127,6 +127,29 @@ pub fn get_session_sync(db: &DbConnection, session_id: &str) -> Result<SessionDe
let messages =
AgentDao::get_messages(&conn, session_id).map_err(|e| format!("获取消息失败: {e}"))?;
let tauri_messages: Vec<TauriMessage> = messages
.into_iter()
.map(|message| convert_agent_message(&message))
.collect();
// 测试序列化
let test_content = vec![
TauriMessageContent::Text {
text: "Hello".to_string(),
},
TauriMessageContent::Thinking {
text: "Thinking...".to_string(),
},
];
if let Ok(json) = serde_json::to_string(&test_content) {
tracing::info!("[SessionStore] 测试序列化: {}", json);
}
// 调试日志:序列化后的 JSON
if let Ok(json) = serde_json::to_string_pretty(&tauri_messages) {
tracing::debug!("[SessionStore] 序列化消息 JSON:\n{}", json);
}
Ok(SessionDetail {
id: session.id,
name: session.title.unwrap_or_else(|| "未命名".to_string()),
@@ -136,10 +159,7 @@ pub fn get_session_sync(db: &DbConnection, session_id: &str) -> Result<SessionDe
updated_at: chrono::DateTime::parse_from_rfc3339(&session.updated_at)
.map(|dt| dt.timestamp())
.unwrap_or(0),
messages: messages
.into_iter()
.map(|message| convert_agent_message(&message))
.collect(),
messages: tauri_messages,
})
}
@@ -170,7 +190,7 @@ pub fn delete_session_sync(db: &DbConnection, session_id: &str) -> Result<(), St
/// 将 AgentMessage 转换为 TauriMessage
fn convert_agent_message(message: &AgentMessage) -> TauriMessage {
let content = match &message.content {
let mut content = match &message.content {
MessageContent::Text(text) => vec![TauriMessageContent::Text { text: text.clone() }],
MessageContent::Parts(parts) => parts
.iter()
@@ -184,14 +204,33 @@ fn convert_agent_message(message: &AgentMessage) -> TauriMessage {
.collect(),
};
// 添加 reasoning_content 作为 thinking 类型
if let Some(reasoning) = &message.reasoning_content {
content.insert(
0,
TauriMessageContent::Thinking {
text: reasoning.clone(),
},
);
}
let timestamp = chrono::DateTime::parse_from_rfc3339(&message.timestamp)
.map(|dt| dt.timestamp())
.unwrap_or(0);
TauriMessage {
let result = TauriMessage {
id: None,
role: message.role.clone(),
content,
timestamp,
}
};
// 调试日志
tracing::debug!(
"[SessionStore] 转换消息: role={}, content={:?}",
result.role,
result.content
);
result
}
+3
View File
@@ -6,6 +6,9 @@ authors.workspace = true
repository.workspace = true
[dependencies]
# Shared API models
aster-models.workspace = true
# 序列化
serde.workspace = true
serde_json.workspace = true
+1 -1
View File
@@ -107,7 +107,7 @@ impl ContentManager {
);
let workspace_type = match workspace_type {
Ok(value) => WorkspaceType::from_str(&value),
Ok(value) => WorkspaceType::parse(&value),
Err(_) => return ContentType::Document,
};
@@ -2,7 +2,7 @@
//!
//! 提供 Agent 会话和消息的持久化存储功能
use crate::agent::types::{AgentMessage, AgentSession, MessageContent, ToolCall};
use crate::agent::types::{AgentMessage, AgentSession, ContentPart, MessageContent, ToolCall};
use rusqlite::{params, Connection};
/// 解析消息内容 JSON,支持多种格式
@@ -14,28 +14,34 @@ use rusqlite::{params, Connection};
fn parse_message_content(content_json: &str) -> MessageContent {
// 尝试解析为 Aster 格式 (Vec<AsterMessageContent>)
if let Ok(aster_contents) = serde_json::from_str::<Vec<serde_json::Value>>(content_json) {
let mut text_parts: Vec<String> = Vec::new();
let mut parts: Vec<ContentPart> = Vec::new();
for item in aster_contents {
// Aster 格式: {"Text": "..."} 或 {"ToolRequest": ...}
if let Some(text) = item.get("Text").and_then(|v| v.as_str()) {
text_parts.push(text.to_string());
parts.push(ContentPart::Text {
text: text.to_string(),
});
}
// 也支持小写 "text" 格式
else if let Some(text) = item.get("text").and_then(|v| v.as_str()) {
text_parts.push(text.to_string());
parts.push(ContentPart::Text {
text: text.to_string(),
});
}
// ProxyCast Parts 格式: {"type": "text", "text": "..."}
else if item.get("type").and_then(|v| v.as_str()) == Some("text") {
if let Some(text) = item.get("text").and_then(|v| v.as_str()) {
text_parts.push(text.to_string());
parts.push(ContentPart::Text {
text: text.to_string(),
});
}
}
// 忽略 ToolRequest、ToolResponse 等非文本内容
}
if !text_parts.is_empty() {
return MessageContent::Text(text_parts.join("\n"));
if !parts.is_empty() {
return MessageContent::Parts(parts);
}
}
@@ -464,15 +464,13 @@ pub fn cleanup_legacy_api_key_credentials(conn: &Connection) -> Result<usize, St
})
.map_err(|e| format!("查询旧凭证失败: {e}"))?;
for row_result in rows {
if let Ok((uuid, name, provider_type)) = row_result {
tracing::info!(
"[清理] 将删除旧凭证: {} (name: {}, type: {})",
uuid,
name.as_deref().unwrap_or("未命名"),
provider_type
);
}
for (uuid, name, provider_type) in rows.into_iter().filter_map(|row_result| row_result.ok()) {
tracing::info!(
"[清理] 将删除旧凭证: {} (name: {}, type: {})",
uuid,
name.as_deref().unwrap_or("未命名"),
provider_type
);
}
// 删除旧的 API Key 凭证
+11
View File
@@ -40,6 +40,17 @@ pub fn init_database() -> Result<DbConnection, String> {
conn.busy_timeout(std::time::Duration::from_secs(5))
.map_err(|e| format!("设置 busy_timeout 失败: {e}"))?;
// 启用 WAL 模式提升并发性能
conn.execute_batch(
"PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA cache_size = -64000;
PRAGMA temp_store = MEMORY;",
)
.map_err(|e| format!("设置数据库优化参数失败: {e}"))?;
tracing::info!("[数据库] 已启用 WAL 模式和性能优化参数");
// 创建表结构
schema::create_tables(&conn).map_err(|e| e.to_string())?;
migration::migrate_from_json(&conn)?;
+3 -141
View File
@@ -1,142 +1,4 @@
//! Anthropic/Claude API 数据模型
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AnthropicContentBlock {
#[serde(rename = "text")]
Text { text: String },
#[serde(rename = "tool_use")]
ToolUse {
id: String,
name: String,
input: serde_json::Value,
},
#[serde(rename = "tool_result")]
ToolResult {
tool_use_id: String,
content: serde_json::Value,
},
#[serde(rename = "image")]
Image { source: ImageSource },
/// Extended Thinking 块
#[serde(rename = "thinking")]
Thinking {
thinking: String,
/// 签名字段,用于验证思维内容的完整性
signature: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageSource {
#[serde(rename = "type")]
pub source_type: String,
pub media_type: String,
pub data: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnthropicMessage {
pub role: String,
pub content: serde_json::Value, // Can be string or array
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnthropicTool {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub input_schema: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnthropicMessagesRequest {
pub model: String,
pub messages: Vec<AnthropicMessage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub temperature: Option<f32>,
#[serde(default)]
pub stream: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub tools: Option<Vec<AnthropicTool>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_choice: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnthropicUsage {
pub input_tokens: u32,
pub output_tokens: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(dead_code)]
pub struct AnthropicMessagesResponse {
pub id: String,
#[serde(rename = "type")]
pub response_type: String,
pub role: String,
pub content: Vec<AnthropicContentBlock>,
pub model: String,
pub stop_reason: Option<String>,
pub usage: AnthropicUsage,
}
// Streaming events
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AnthropicStreamEvent {
#[serde(rename = "message_start")]
MessageStart { message: AnthropicMessageStart },
#[serde(rename = "content_block_start")]
ContentBlockStart {
index: u32,
content_block: AnthropicContentBlock,
},
#[serde(rename = "content_block_delta")]
ContentBlockDelta { index: u32, delta: AnthropicDelta },
#[serde(rename = "content_block_stop")]
ContentBlockStop { index: u32 },
#[serde(rename = "message_delta")]
MessageDelta {
delta: AnthropicMessageDelta,
usage: AnthropicUsage,
},
#[serde(rename = "message_stop")]
MessageStop,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnthropicMessageStart {
pub id: String,
#[serde(rename = "type")]
pub msg_type: String,
pub role: String,
pub model: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AnthropicDelta {
#[serde(rename = "text_delta")]
TextDelta { text: String },
#[serde(rename = "input_json_delta")]
InputJsonDelta { partial_json: String },
/// Extended Thinking delta
#[serde(rename = "thinking_delta")]
ThinkingDelta { thinking: String },
/// Signature delta for thinking blocks
#[serde(rename = "signature_delta")]
SignatureDelta { signature: String },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnthropicMessageDelta {
pub stop_reason: Option<String>,
}
//!
//! Types re-exported from `aster-models` crate (single source of truth).
pub use aster_models::anthropic::*;
+5 -228
View File
@@ -1,236 +1,13 @@
//! OpenAI API 数据模型
//!
//! 支持标准 OpenAI 格式以及扩展的工具类型(如 web_search)。
//!
//! # 工具类型支持
//!
//! - `function`: 标准函数调用工具
//! - `web_search`: 联网搜索工具(Claude Code 使用 `web_search_20250305`)
//!
//! # 更新日志
//!
//! - 2025-12-27: 添加 web_search 工具支持,修复 Issue #49
//! Chat Completion types re-exported from `aster-models` crate (single source of truth).
//! Image generation types are ProxyCast-specific and defined locally.
pub use aster_models::openai::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageUrl {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum ContentPart {
#[serde(rename = "text")]
Text { text: String },
#[serde(rename = "image_url")]
ImageUrl { image_url: ImageUrl },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolCall {
pub id: String,
#[serde(rename = "type")]
pub call_type: String,
pub function: FunctionCall,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionCall {
pub name: String,
pub arguments: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum MessageContent {
Text(String),
Parts(Vec<ContentPart>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatMessage {
pub role: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<MessageContent>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_calls: Option<Vec<ToolCall>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_call_id: Option<String>,
/// 推理内容(DeepSeek R1 等模型的思维链内容)
/// DeepSeek Reasoner 在 Tool Calls 场景下要求此字段
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning_content: Option<String>,
}
impl ChatMessage {
pub fn get_content_text(&self) -> String {
match &self.content {
Some(MessageContent::Text(s)) => s.clone(),
Some(MessageContent::Parts(parts)) => parts
.iter()
.filter_map(|p| {
if let ContentPart::Text { text } = p {
Some(text.clone())
} else {
None
}
})
.collect::<Vec<_>>()
.join(""),
None => String::new(),
}
}
/// 提取消息中的图片 URL 列表
/// 返回 (format, base64_data) 元组列表
pub fn get_images(&self) -> Vec<(String, String)> {
match &self.content {
Some(MessageContent::Parts(parts)) => parts
.iter()
.filter_map(|p| {
if let ContentPart::ImageUrl { image_url } = p {
// 解析 data URL: data:image/jpeg;base64,xxxxx
if image_url.url.starts_with("data:") {
let parts: Vec<&str> = image_url.url.splitn(2, ',').collect();
if parts.len() == 2 {
// 提取 media_type: data:image/jpeg;base64 -> image/jpeg
let header = parts[0];
let data = parts[1];
let media_type = header
.strip_prefix("data:")
.and_then(|s| s.split(';').next())
.unwrap_or("image/jpeg");
// 提取格式: image/jpeg -> jpeg
let format =
media_type.split('/').nth(1).unwrap_or("jpeg").to_string();
return Some((format, data.to_string()));
}
}
None
} else {
None
}
})
.collect(),
_ => Vec::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionDef {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<serde_json::Value>,
}
/// 工具定义
///
/// 支持多种工具类型:
/// - `function`: 标准函数调用工具,包含 function 字段
/// - `web_search`: 联网搜索工具,无需额外字段
/// - `web_search_20250305`: Claude Code 的联网搜索工具类型
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum Tool {
/// 标准函数调用工具
#[serde(rename = "function")]
Function { function: FunctionDef },
/// 联网搜索工具(Codex/Kiro 格式)
#[serde(rename = "web_search")]
WebSearch,
/// 联网搜索工具(Claude Code 格式)
#[serde(rename = "web_search_20250305")]
WebSearch20250305,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionRequest {
pub model: String,
pub messages: Vec<ChatMessage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub temperature: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub top_p: Option<f32>,
#[serde(default)]
pub stream: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub tools: Option<Vec<Tool>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_choice: Option<serde_json::Value>,
/// 思维链强度:none, low, medium, high
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning_effort: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Usage {
pub prompt_tokens: u32,
pub completion_tokens: u32,
pub total_tokens: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResponseMessage {
pub role: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_calls: Option<Vec<ToolCall>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Choice {
pub index: u32,
pub message: ResponseMessage,
pub finish_reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionResponse {
pub id: String,
pub object: String,
pub created: u64,
pub model: String,
pub choices: Vec<Choice>,
pub usage: Usage,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamDelta {
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_calls: Option<Vec<ToolCall>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamChoice {
pub index: u32,
pub delta: StreamDelta,
#[serde(skip_serializing_if = "Option::is_none")]
pub finish_reason: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatCompletionChunk {
pub id: String,
pub object: String,
pub created: u64,
pub model: String,
pub choices: Vec<StreamChoice>,
}
// ============================================================================
// 图像生成 API 数据模型
// 图像生成 API 数据模型 (ProxyCast 特有)
// ============================================================================
/// OpenAI 图像生成请求
@@ -7,7 +7,7 @@ use crate::database::DbConnection;
use chrono::Utc;
use rusqlite::params;
use std::collections::HashSet;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use uuid::Uuid;
/// Workspace 管理器
@@ -186,7 +186,7 @@ impl WorkspaceManager {
}
/// 通过路径获取 workspace
pub fn get_by_path(&self, root_path: &PathBuf) -> Result<Option<Workspace>, String> {
pub fn get_by_path(&self, root_path: &Path) -> Result<Option<Workspace>, String> {
let root_path_str = root_path.to_str().ok_or("无效的路径")?;
let conn = self.db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
@@ -464,7 +464,7 @@ impl WorkspaceManager {
Ok(Workspace {
id,
name,
workspace_type: WorkspaceType::from_str(&workspace_type_str),
workspace_type: WorkspaceType::parse(&workspace_type_str),
root_path: PathBuf::from(root_path_str),
is_default,
created_at: chrono::DateTime::from_timestamp_millis(created_at_ms)
+18 -33
View File
@@ -55,7 +55,7 @@ impl WorkspaceType {
}
}
pub fn from_str(s: &str) -> Self {
pub fn parse(s: &str) -> Self {
match s {
"temporary" => WorkspaceType::Temporary,
"general" => WorkspaceType::General,
@@ -221,51 +221,36 @@ mod tests {
#[test]
fn test_workspace_type_from_str() {
assert_eq!(
WorkspaceType::from_str("persistent"),
WorkspaceType::parse("persistent"),
WorkspaceType::Persistent
);
assert_eq!(WorkspaceType::parse("temporary"), WorkspaceType::Temporary);
assert_eq!(WorkspaceType::parse("general"), WorkspaceType::General);
assert_eq!(
WorkspaceType::from_str("temporary"),
WorkspaceType::Temporary
);
assert_eq!(WorkspaceType::from_str("general"), WorkspaceType::General);
assert_eq!(
WorkspaceType::from_str("social-media"),
WorkspaceType::parse("social-media"),
WorkspaceType::SocialMedia
);
assert_eq!(WorkspaceType::from_str("poster"), WorkspaceType::Poster);
assert_eq!(WorkspaceType::from_str("music"), WorkspaceType::Music);
assert_eq!(
WorkspaceType::from_str("knowledge"),
WorkspaceType::Knowledge
);
assert_eq!(WorkspaceType::from_str("planning"), WorkspaceType::Planning);
assert_eq!(WorkspaceType::from_str("document"), WorkspaceType::Document);
assert_eq!(WorkspaceType::from_str("video"), WorkspaceType::Video);
assert_eq!(WorkspaceType::from_str("novel"), WorkspaceType::Novel);
assert_eq!(WorkspaceType::parse("poster"), WorkspaceType::Poster);
assert_eq!(WorkspaceType::parse("music"), WorkspaceType::Music);
assert_eq!(WorkspaceType::parse("knowledge"), WorkspaceType::Knowledge);
assert_eq!(WorkspaceType::parse("planning"), WorkspaceType::Planning);
assert_eq!(WorkspaceType::parse("document"), WorkspaceType::Document);
assert_eq!(WorkspaceType::parse("video"), WorkspaceType::Video);
assert_eq!(WorkspaceType::parse("novel"), WorkspaceType::Novel);
}
#[test]
fn test_legacy_type_migration() {
// 旧类型应该正确映射到新类型
assert_eq!(WorkspaceType::from_str("drama"), WorkspaceType::Video);
assert_eq!(
WorkspaceType::from_str("social"),
WorkspaceType::SocialMedia
);
assert_eq!(WorkspaceType::parse("drama"), WorkspaceType::Video);
assert_eq!(WorkspaceType::parse("social"), WorkspaceType::SocialMedia);
}
#[test]
fn test_unknown_type_defaults_to_persistent() {
assert_eq!(
WorkspaceType::from_str("unknown"),
WorkspaceType::Persistent
);
assert_eq!(WorkspaceType::from_str(""), WorkspaceType::Persistent);
assert_eq!(
WorkspaceType::from_str("invalid"),
WorkspaceType::Persistent
);
assert_eq!(WorkspaceType::parse("unknown"), WorkspaceType::Persistent);
assert_eq!(WorkspaceType::parse(""), WorkspaceType::Persistent);
assert_eq!(WorkspaceType::parse("invalid"), WorkspaceType::Persistent);
}
#[test]
@@ -330,7 +315,7 @@ mod tests {
for wt in types {
let s = wt.as_str();
let parsed = WorkspaceType::from_str(s);
let parsed = WorkspaceType::parse(s);
assert_eq!(wt, parsed, "Roundtrip failed for {wt:?}");
}
}
+1 -1
View File
@@ -114,7 +114,7 @@ pub fn calculate_approval_rate(feedbacks: &[UserFeedback]) -> f32 {
}
}
(score / total).max(0.0).min(1.0)
(score / total).clamp(0.0, 1.0)
}
// ==================== Extraction Parameters ====================
+1 -4
View File
@@ -146,10 +146,7 @@ fn parse_memory_from_row(
let vec_len = blob.len() / 4;
let mut vec = Vec::with_capacity(vec_len);
for chunk in blob.chunks_exact(4) {
let bytes: [u8; 4] = match chunk.try_into() {
Ok(arr) => arr,
Err(_) => [0; 4],
};
let bytes: [u8; 4] = chunk.try_into().unwrap_or_default();
let val = f32::from_le_bytes(bytes);
vec.push(val);
}
@@ -31,6 +31,7 @@ pub fn convert_cw_event_to_openai_chunk(
role: Some("assistant".to_string()),
content: Some(content.clone()),
tool_calls: None,
reasoning_content: None,
},
finish_reason: None,
}],
@@ -58,6 +59,7 @@ pub fn convert_cw_event_to_openai_chunk(
.unwrap_or_default(),
},
}]),
reasoning_content: None,
},
finish_reason: None,
}],
@@ -131,6 +133,7 @@ pub fn create_stream_end_chunk(model: &str, response_id: &str) -> ChatCompletion
role: None,
content: None,
tool_calls: None,
reasoning_content: None,
},
finish_reason: Some("stop".to_string()),
}],
@@ -187,7 +187,7 @@ impl ProjectContextBuilder {
Ok(Workspace {
id,
name,
workspace_type: WorkspaceType::from_str(&workspace_type_str),
workspace_type: WorkspaceType::parse(&workspace_type_str),
root_path: PathBuf::from(root_path_str),
is_default,
created_at: chrono::DateTime::from_timestamp_millis(created_at_ms)
+131 -49
View File
@@ -123,10 +123,16 @@ pub async fn chat_create_session(
updated_at: now,
};
// 保存到数据库
// 保存到数据库(异步化)
{
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
ChatDao::create_session(&conn, &session).map_err(|e| format!("创建会话失败: {e}"))?;
let db = db.inner().clone();
let session_clone = session.clone();
tokio::task::spawn_blocking(move || {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
ChatDao::create_session(&conn, &session_clone).map_err(|e| format!("创建会话失败: {e}"))
})
.await
.map_err(|e| format!("任务执行失败: {e}"))??;
}
// 初始化 Aster Agent(如果是 Agent 或 Creator 模式)
@@ -158,20 +164,25 @@ pub async fn chat_list_sessions(
db: State<'_, DbConnection>,
mode: Option<ChatMode>,
) -> Result<Vec<SessionResponse>, String> {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
let db = db.inner().clone();
tokio::task::spawn_blocking(move || {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
let sessions =
ChatDao::list_sessions(&conn, mode).map_err(|e| format!("获取会话列表失败: {e}"))?;
let sessions =
ChatDao::list_sessions(&conn, mode).map_err(|e| format!("获取会话列表失败: {e}"))?;
let mut result: Vec<SessionResponse> = Vec::new();
for session in sessions {
let message_count = ChatDao::get_message_count(&conn, &session.id).unwrap_or(0);
let mut resp = SessionResponse::from(session);
resp.message_count = message_count;
result.push(resp);
}
let mut result: Vec<SessionResponse> = Vec::new();
for session in sessions {
let message_count = ChatDao::get_message_count(&conn, &session.id).unwrap_or(0);
let mut resp = SessionResponse::from(session);
resp.message_count = message_count;
result.push(resp);
}
Ok(result)
Ok(result)
})
.await
.map_err(|e| format!("任务执行失败: {e}"))?
}
/// 获取会话详情
@@ -180,17 +191,22 @@ pub async fn chat_get_session(
db: State<'_, DbConnection>,
session_id: String,
) -> Result<SessionResponse, String> {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
let db = db.inner().clone();
tokio::task::spawn_blocking(move || {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
let session = ChatDao::get_session(&conn, &session_id)
.map_err(|e| format!("获取会话失败: {e}"))?
.ok_or_else(|| "会话不存在".to_string())?;
let session = ChatDao::get_session(&conn, &session_id)
.map_err(|e| format!("获取会话失败: {e}"))?
.ok_or_else(|| "会话不存在".to_string())?;
let message_count = ChatDao::get_message_count(&conn, &session_id).unwrap_or(0);
let mut resp = SessionResponse::from(session);
resp.message_count = message_count;
let message_count = ChatDao::get_message_count(&conn, &session_id).unwrap_or(0);
let mut resp = SessionResponse::from(session);
resp.message_count = message_count;
Ok(resp)
Ok(resp)
})
.await
.map_err(|e| format!("任务执行失败: {e}"))?
}
/// 删除会话
@@ -199,16 +215,21 @@ pub async fn chat_delete_session(
db: State<'_, DbConnection>,
session_id: String,
) -> Result<bool, String> {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
let db = db.inner().clone();
tokio::task::spawn_blocking(move || {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
let deleted =
ChatDao::delete_session(&conn, &session_id).map_err(|e| format!("删除会话失败: {e}"))?;
let deleted = ChatDao::delete_session(&conn, &session_id)
.map_err(|e| format!("删除会话失败: {e}"))?;
if deleted {
tracing::info!("[UnifiedChat] 删除会话: id={}", session_id);
}
if deleted {
tracing::info!("[UnifiedChat] 删除会话: id={}", session_id);
}
Ok(deleted)
Ok(deleted)
})
.await
.map_err(|e| format!("任务执行失败: {e}"))?
}
/// 重命名会话
@@ -218,18 +239,23 @@ pub async fn chat_rename_session(
session_id: String,
title: String,
) -> Result<(), String> {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
let db = db.inner().clone();
tokio::task::spawn_blocking(move || {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
ChatDao::update_title(&conn, &session_id, &title)
.map_err(|e| format!("重命名会话失败: {e}"))?;
ChatDao::update_title(&conn, &session_id, &title)
.map_err(|e| format!("重命名会话失败: {e}"))?;
tracing::info!(
"[UnifiedChat] 重命名会话: id={}, title={}",
session_id,
title
);
tracing::info!(
"[UnifiedChat] 重命名会话: id={}, title={}",
session_id,
title
);
Ok(())
Ok(())
})
.await
.map_err(|e| format!("任务执行失败: {e}"))?
}
// ============================================================================
@@ -243,12 +269,17 @@ pub async fn chat_get_messages(
session_id: String,
limit: Option<i32>,
) -> Result<Vec<ChatMessage>, String> {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
let db = db.inner().clone();
tokio::task::spawn_blocking(move || {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
let messages = ChatDao::get_messages(&conn, &session_id, limit)
.map_err(|e| format!("获取消息失败: {e}"))?;
let messages = ChatDao::get_messages(&conn, &session_id, limit)
.map_err(|e| format!("获取消息失败: {e}"))?;
Ok(messages)
Ok(messages)
})
.await
.map_err(|e| format!("任务执行失败: {e}"))?
}
/// 发送消息并获取流式响应
@@ -261,6 +292,8 @@ pub async fn chat_send_message(
agent_state: State<'_, AsterAgentState>,
request: SendMessageRequest,
) -> Result<(), String> {
let start_time = std::time::Instant::now();
let image_count = request.images.as_ref().map(|v| v.len()).unwrap_or(0);
tracing::info!(
"[UnifiedChat] 发送消息: session={}, event={}, images={}",
@@ -287,16 +320,25 @@ pub async fn chat_send_message(
}
}
// 获取会话信息
// 获取会话信息(异步化数据库操作)
let db_start = std::time::Instant::now();
let session = {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
ChatDao::get_session(&conn, &request.session_id)
.map_err(|e| format!("获取会话失败: {e}"))?
.ok_or_else(|| "会话不存在".to_string())?
let db = db.inner().clone();
let session_id = request.session_id.clone();
tokio::task::spawn_blocking(move || {
let conn = db.lock().map_err(|e| format!("数据库锁定失败: {e}"))?;
ChatDao::get_session(&conn, &session_id)
.map_err(|e| format!("获取会话失败: {e}"))?
.ok_or_else(|| "会话不存在".to_string())
})
.await
.map_err(|e| format!("任务执行失败: {e}"))??
};
let db_elapsed = db_start.elapsed();
tracing::debug!("[UnifiedChat] 数据库查询耗时: {:?}", db_elapsed);
// 根据模式处理
match session.mode {
let result = match session.mode {
ChatMode::Agent | ChatMode::Creator => {
// 使用 Aster Agent 处理
send_message_with_aster(
@@ -323,7 +365,16 @@ pub async fn chat_send_message(
)
.await
}
}
};
let total_elapsed = start_time.elapsed();
tracing::info!(
"[UnifiedChat] 消息发送完成: session={}, 总耗时={:?}",
request.session_id,
total_elapsed
);
result
}
/// 使用 Aster Agent 发送消息
@@ -336,15 +387,26 @@ async fn send_message_with_aster(
event_name: &str,
system_prompt: Option<&str>,
) -> Result<(), String> {
let start_time = std::time::Instant::now();
// 确保 Agent 已初始化
let init_start = std::time::Instant::now();
if !agent_state.is_initialized().await {
agent_state.init_agent_with_db(db).await?;
}
let init_elapsed = init_start.elapsed();
tracing::debug!("[UnifiedChat] Agent 初始化检查耗时: {:?}", init_elapsed);
// 检查 Provider 是否已配置
let provider_check_start = std::time::Instant::now();
if !agent_state.is_provider_configured().await {
return Err("Provider 未配置,请先配置凭证".to_string());
}
let provider_check_elapsed = provider_check_start.elapsed();
tracing::debug!(
"[UnifiedChat] Provider 配置检查耗时: {:?}",
provider_check_elapsed
);
// 创建取消令牌
let cancel_token = agent_state.create_cancel_token(session_id).await;
@@ -365,15 +427,27 @@ async fn send_message_with_aster(
let agent = guard.as_ref().ok_or("Agent 未初始化")?;
// 调用 Agent
let reply_start = std::time::Instant::now();
let stream_result = agent
.reply(user_message, session_config, Some(cancel_token.clone()))
.await;
let mut first_chunk_time: Option<std::time::Instant> = None;
let mut chunk_count = 0;
match stream_result {
Ok(mut stream) => {
while let Some(event_result) = stream.next().await {
match event_result {
Ok(agent_event) => {
// 记录首个 chunk 时间(TTFB)
if first_chunk_time.is_none() {
first_chunk_time = Some(std::time::Instant::now());
let ttfb = first_chunk_time.unwrap() - reply_start;
tracing::info!("[UnifiedChat] TTFB (首字节时间): {:?}", ttfb);
}
chunk_count += 1;
let tauri_events = convert_agent_event(agent_event);
for tauri_event in tauri_events {
if let Err(e) = app.emit(event_name, &tauri_event) {
@@ -393,6 +467,14 @@ async fn send_message_with_aster(
// 发送完成事件
let done_event = TauriAgentEvent::FinalDone { usage: None };
let _ = app.emit(event_name, &done_event);
let stream_elapsed = start_time.elapsed();
tracing::info!(
"[UnifiedChat] 流式传输完成: session={}, chunks={}, 总耗时={:?}",
session_id,
chunk_count,
stream_elapsed
);
}
Err(e) => {
let error_event = TauriAgentEvent::Error {
+1 -1
View File
@@ -136,7 +136,7 @@ pub async fn workspace_create(
let workspace_type = request
.workspace_type
.map(|t| WorkspaceType::from_str(&t))
.map(|t| WorkspaceType::parse(&t))
.unwrap_or_default();
let workspace = manager.create_with_type(
+20
View File
@@ -0,0 +1,20 @@
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum TauriMessageContent {
#[serde(rename = "text")]
Text { text: String },
#[serde(rename = "thinking")]
Thinking { text: String },
}
fn main() {
let content = vec![
TauriMessageContent::Text { text: "Hello".to_string() },
TauriMessageContent::Thinking { text: "Thinking...".to_string() },
];
let json = serde_json::to_string_pretty(&content).unwrap();
println!("{}", json);
}
@@ -825,8 +825,7 @@ export const EmptyState: React.FC<EmptyStateProps> = ({
<ContentWrapper>
<Header>
<MainTitle>
{themeHeadline.lead} <br />
<span>{themeHeadline.focus}</span>
{themeHeadline.lead}<span>{themeHeadline.focus}</span>
</MainTitle>
</Header>
@@ -1199,7 +1198,7 @@ export const EmptyState: React.FC<EmptyStateProps> = ({
size="sm"
onClick={handleSend}
disabled={!input.trim() && !isEntryTheme}
className="bg-primary hover:bg-primary/90 text-primary-foreground h-9 px-5 rounded-xl shadow-lg shadow-primary/20 transition-all hover:scale-105 active:scale-95"
className="bg-primary hover:bg-primary/90 text-primary-foreground h-9 px-5 rounded-xl shadow-lg shadow-primary/20 transition-all hover:scale-105 active:scale-95 whitespace-nowrap"
>
开始生成
<ArrowRight className="h-4 w-4 ml-2" />
@@ -1011,11 +1011,12 @@ export function useAsterAgentChat(options: UseAsterAgentChatOptions) {
toast.info("已切换话题");
} catch (error) {
console.error("[AsterChat] 切换话题失败:", error);
console.error("[AsterChat] 错误详情:", JSON.stringify(error, null, 2));
setMessages([]);
setSessionId(null);
saveTransient(getScopedSessionKey(), null);
savePersisted(getScopedPersistedSessionKey(), null);
toast.error("加载对话历史失败");
toast.error(`加载对话历史失败: ${error instanceof Error ? error.message : String(error)}`);
}
},
[