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.
1 line
3.7 KiB
JSON
1 line
3.7 KiB
JSON
{"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"}}}} |