Files
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
3.7 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "chenwenwen1007/ai-creat-pptx", "files": {"src/pages/api/generateOutline.ts": {"a69b5c574facfbfd7a27ac0f5d724f5ae97af447": {"t": 1786067564.5103936, "n": 3130, "h": "d2a557a02b1f3ed8", "c": "/**\n * 本地 AI API 代理路由\n * 接收前端的 AI 请求,使用用户自定义的 API 配置调用 AI 服务\n * 解决前端直接调用 AI API 时的 CORS 限制问题\n *\n * 请求头:\n * x-custom-api-url: AI API 基础地址(如 https://api.deepseek.com)\n * x-custom-api-model: AI 模型名称(如 deepseek-chat)\n * x-custom-api-token: API 密钥\n *\n * 请求体:与 OpenAI Chat Completions API 兼容的 JSON\n */\n\nimport type { IncomingMessage } from 'http'\n\ninterface ApiRequest extends IncomingMessage {\n method?: string\n headers: Record<string, string | string[] | undefined>\n body: any\n}\n\ninterface ApiResponse {\n status: (code: number) => ApiResponse\n json: (data: any) => void\n setHeader: (name: string, value: string | string[]) => ApiResponse\n write: (chunk: any) => void\n end: () => void\n}\n\nconst handler = async (req: ApiRequest, res: ApiResponse) => {\n // 仅支持 POST 请求\n if (req.method !== 'POST') {\n res.status(405).json({ error: 'Method not allowed' })\n\n return\n }\n\n // 从请求头读取用户自定义的 API 配置\n const apiUrl = req.headers['x-custom-api-url'] as string\n const apiModel = req.headers['x-custom-api-model'] as string\n const apiToken = req.headers['x-custom-api-token'] as string\n\n if (!apiUrl || !apiToken) {\n res.status(400).json({ error: '缺少 API 配置,请在参数设置中配置 API URL 和 Token' })\n\n return\n }\n\n // 构建完整的 AI API 请求地址\n const fullUrl = apiUrl.endsWith('/')\n ? `${apiUrl}chat/completions`\n : `${apiUrl}/chat/completions`\n\n // 构建请求体 - 兼容 OpenAI Chat Completions API 格式\n const requestBody = {\n model: apiModel || 'deepseek-chat',\n messages: req.body.messages || [],\n stream: true,\n }\n\n try {\n // 调用 AI API\n const response = await fetch(fullUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiToken}`,\n },\n body: JSON.stringify(requestBody),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n console.error('AI API 请求失败:', response.status, errorText)\n res.status(response.status).json({\n error: `AI API 请求失败 (${response.status})`,\n detail: errorText,\n })\n\n return\n }\n\n // 设置 SSE 响应头\n res.setHeader('Content-Type', 'text/event-stream')\n res.setHeader('Cache-Control', 'no-cache')\n res.setHeader('Connection', 'keep-alive')\n\n // 流式转发 AI 响应\n const reader = response.body?.getReader()\n if (!reader) {\n res.status(500).json({ error: '无法读取 AI 响应流' })\n\n return\n }\n\n const decoder = new TextDecoder()\n\n // 读取流式响应并转发给客户端\n const processStream = async () => {\n try {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read()\n\n if (done) {\n break\n }\n\n const chunk = decoder.decode(value, { stream: true })\n res.write(chunk)\n }\n\n res.end()\n } catch (streamError) {\n console.error('流式传输错误:', streamError)\n res.end()\n }\n }\n\n await processStream()\n } catch (error: any) {\n console.error('AI API 代理错误:', error)\n res.status(500).json({\n error: 'AI API 代理请求失败',\n detail: error.message,\n })\n }\n}\n\nexport default handler\n"}}}}