AI 发送功能允许用户将剪切板内容(文本)发送到 AI 接口(OpenAI Responses API)进行处理,并返回 AI 的回复。
┌─────────────────────────────────────────────────────────────────────────────┐
│ AI 发送功能完整流程 │
└─────────────────────────────────────────────────────────────────────────────┘
┌──────────────┐
│ 偏好设置页面 │ ◄── 启用/禁用 AI 发送,配置 API 参数
└──────┬───────┘
│
▼
┌──────────────┐ ┌──────────────────┐
│ clipboardStore│────►│ aiSend: { │
│ (valtio) │ │ enabled │
└──────────────┘ │ baseUrl │
│ apiKey │
│ model │
│ customHeaders │
│ showInUI │
│ } │
└──────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 主界面历史列表 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Item │─────►│ Header │─────►│操作按钮UI │─────►│ 点击 send │ │
│ └──────────┘ └──────────┘ └──────────┘ └────┬─────┘ │
│ │ │ │
│ │ ┌──────────────────┐ │ │
│ └─────────────►│ SendModal (ref) │◄─────────────────┘ │
│ └────────┬─────────┘ │
│ │ │
└────────────────────────────────┼───────────────────────────────────────────┘
▼
┌──────────────────────┐
│ 1. open(id) │
│ 2. 查找 item │
│ 3. 显示模态框 │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 用户点击发送按钮 │
│ handleSend(extra) │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 构建请求数据 │
│ { │
│ input: [ │
│ { content, role } ◄── 剪切板内容
│ { content, role } ◄── 用户补充信息(可选)
│ ],
│ model │
│ } │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ POST /v1/responses │
│ Authorization: Bearer
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 解析响应 │
│ output[0].content[0].text
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 显示成功/失败提示 │
└──────────────────────┘
文件: src/stores/clipboard.ts
export const clipboardStore = proxy<ClipboardStore>({
aiSend: {
apiKey: "",
baseUrl: "https://api.openai.com",
customHeaders: {},
enabled: false,
model: "gpt-4o",
showInUI: true,
},
// ... 其他配置
});文件: src/types/store.d.ts
export interface ClipboardStore {
// AI 发送配置
aiSend?: {
enabled: boolean;
baseUrl: string;
apiKey: string;
model: string;
customHeaders: Record<string, string>;
showInUI: boolean;
};
}
export type OperationButton =
| "copy"
| "pastePlain"
| "note"
| "star"
| "delete"
| "send"; // 发送按钮类型文件:
src/pages/Preference/components/AiSend/index.tsx- 主入口src/pages/Preference/components/AiSend/components/ApiSettings/index.tsx- API 配置
功能:
- 总开关控制
enabled状态 - 配置
baseUrl(默认: https://api.openai.com) - 配置
apiKey - 配置
model(默认: gpt-4o) - 配置
customHeaders(JSON 格式自定义请求头)
文件: src/pages/Preference/components/Clipboard/components/OperationButton/index.tsx
export const transferData: TransferData[] = [
// ... 其他按钮
{
icon: "i-lucide:send",
key: "send",
title: "preference.clipboard.content_settings.label.operation_button_option.send",
},
// ... 其他按钮
];说明:
- 发送按钮使用
i-lucide:send图标 - 可以在偏好设置中自定义显示哪些按钮及排序
- 默认操作按钮顺序:
["copy", "send", "star", "delete"]
文件: src/pages/Main/components/HistoryList/index.tsx
const sendModalRef = useRef<SendModalRef>(null);
// 渲染 Item 时传递 handleSend 回调
<Item
data={data}
handleSend={() => sendModalRef.current?.open(data.id)}
// ... 其他 props
/>
// 渲染 SendModal
<SendModal ref={sendModalRef} />文件: src/pages/Main/components/HistoryList/components/Item/index.tsx
export interface ItemProps {
data: DatabaseSchemaHistory;
handleSend: () => void; // 从 HistoryList 接收
// ... 其他 props
}
// 传递给 Header 组件
<Header
data={data}
handleSend={handleSend}
// ... 其他 props
/>
// 也传递给右键菜单
const { handleContextMenu, ...rest } = useContextMenu({
...props,
handleSend,
});文件: src/pages/Main/components/HistoryList/components/Header/index.tsx
const handleClick = (event: MouseEvent, key: OperationButton) => {
switch (key) {
// ... 其他 case
case "send":
return handleSend(); // 触发发送
// ... 其他 case
}
};
// 渲染操作按钮
{operationButtons.map((item) => (
<UnoIcon
key={key}
name={icon}
onClick={(event) => handleClick(event, key)}
title={t(title)}
/>
))}文件: src/pages/Main/components/HistoryList/components/SendModal/index.tsx
核心逻辑:
export interface SendModalRef {
open: (id: string) => void; // 暴露给父组件的方法
}
const handleSend = async (extraMessage?: string) => {
if (!item || !aiSend?.enabled) return;
// 构建消息数组
const messages = [
{
content: item.value, // 剪切板内容
role: "user",
},
];
if (extraMessage) {
messages.push({
content: extraMessage, // 用户补充信息
role: "user",
});
}
// 调用 OpenAI Responses API
const response = await fetch(`${aiSend.baseUrl}/v1/responses`, {
method: "POST",
headers: {
Authorization: `Bearer ${aiSend.apiKey}`,
"Content-Type": "application/json",
...aiSend.customHeaders,
},
body: JSON.stringify({
input: messages,
model: aiSend.model || "gpt-4o",
}),
});
// 解析响应
const data = await response.json();
const result = data.output?.[0]?.content?.[0]?.text || "发送成功";
};界面:
- 模态框标题: "发送"
- 输入框: 补充信息(可选)
- 按钮: 取消、直接发送
POST /v1/responses
Content-Type: application/json
Authorization: Bearer {apiKey}
{
"input": [
{
"content": "剪切板内容",
"role": "user"
},
{
"content": "用户补充信息(可选)",
"role": "user"
}
],
"model": "gpt-4o"
}{
"output": [
{
"content": [
{
"text": "AI 回复内容"
}
]
}
]
}中文 (src/locales/zh-CN.json):
{
"component.send_modal": {
"button": {
"cancel": "取消",
"direct_send": "直接发送"
},
"hints": {
"input_extra_message": "请输入补充信息(可选)"
},
"label": {
"send": "发送"
}
},
"preference.ai_send.settings": {
"title": "AI 发送设置",
"label.enable": "启用 AI 发送",
"label.base_url": "API 地址",
"label.api_key": "API Key",
"label.model": "模型",
"label.custom_headers": "自定义请求头"
}
}- 启用开关: AI 发送功能需要在偏好设置中启用后才能使用
- API 兼容: 当前使用 OpenAI Responses API (
/v1/responses),不是标准的 Chat Completions API - 内容类型: 当前仅支持文本类型内容发送,图片和文件类型暂不支持
- 按钮显示: 发送按钮只在
aiSend.enabled为 true 且操作按钮配置中包含 "send" 时显示 - 错误处理: 网络错误或 API 返回错误时会显示错误提示
- 多厂商支持: 可考虑添加 Anthropic、Google 等厂商支持
- 图片支持: 实现图片 base64 编码后发送给支持视觉的模型
- 流式输出: 使用
streamText实现 AI 回复的流式显示 - 历史记录: 保存 AI 回复到数据库,支持查看历史对话
- 快捷指令: 支持自定义提示词模板,如"总结这段文字"、"翻译为英文"等