From ad4dc6e0898c4f7035eeda426cdd4fc6bdec4c85 Mon Sep 17 00:00:00 2001 From: Claude AI Date: Tue, 24 Mar 2026 23:25:33 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20Next.js=20API=20Ro?= =?UTF-8?q?ute=20=E4=BD=BF=E7=94=A8=E5=AE=B9=E5=99=A8=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 /api/chat/route.ts 使用 Vercel AI SDK + MCP - 使用容器环境变量 ANTHROPIC_AUTH_TOKEN 和 ANTHROPIC_BASE_URL - 默认使用 Haiku 模型 (glm-4.5-air) 降低成本 Co-Authored-By: Claude Opus 4.6 --- frontend-v2/app/api/chat/route.ts | 103 ++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 frontend-v2/app/api/chat/route.ts diff --git a/frontend-v2/app/api/chat/route.ts b/frontend-v2/app/api/chat/route.ts new file mode 100644 index 0000000..5ccb793 --- /dev/null +++ b/frontend-v2/app/api/chat/route.ts @@ -0,0 +1,103 @@ +/** + * Next.js API Route - 聊天接口 + * + * 使用 Vercel AI SDK + MCP 实现流式响应 + * 集成 json-render 官方 useChatUI hook + */ +import { streamText } from 'ai'; +import { createAnthropic } from '@ai-sdk/anthropic'; +import { createMCPClient } from '@ai-sdk/mcp'; +import catalog from '@/lib/catalog/catalog'; + +// MCP 服务器配置 +const MCP_SERVERS = { + 'novel-translator': process.env.MCP_TRANSLATOR_URL || 'https://d8d-ai-vscode-8080-223-236-template-6-group.dev.d8d.fun/mcp', + 'novel-platform-user': process.env.MCP_USER_URL || 'https://d8d-ai-vscode-8080-223-238-template-6-group.dev.d8d.fun/mcp/', + 'novel-platform-admin': process.env.MCP_ADMIN_URL || 'https://d8d-ai-vscode-8080-223-238-template-6-group.dev.d8d.fun/admin-mcp/', +}; + +// 运行时配置:使用 Node.js 运行时(支持 HTTP 请求) +export const runtime = 'nodejs'; + +export async function POST(req: Request) { + try { + const { messages } = await req.json(); + + // 验证 API 配置 + const authToken = process.env.ANTHROPIC_AUTH_TOKEN; + const baseUrl = process.env.ANTHROPIC_BASE_URL; + if (!authToken) { + return new Response( + JSON.stringify({ error: 'ANTHROPIC_AUTH_TOKEN not configured' }), + { status: 500, headers: { 'Content-Type': 'application/json' } } + ); + } + + // 创建 MCP 客户端并获取工具 + const mcpClients = await Promise.all( + Object.entries(MCP_SERVERS).map(async ([name, url]) => { + try { + const client = await createMCPClient({ + name, + version: '1.0.0', + transport: { + type: 'http', + url, + }, + }); + return { name, client }; + } catch (error) { + console.error(`[API] Failed to connect to MCP ${name}:`, error); + return null; + } + }) + ); + + // 合并所有 MCP 工具 + const allTools: Record = {}; + for (const mcp of mcpClients) { + if (mcp) { + try { + const tools = await mcp.client.tools(); + Object.assign(allTools, tools); + } catch (error) { + console.error(`[API] Failed to get tools from ${mcp.name}:`, error); + } + } + } + + console.log(`[API] Available tools: ${Object.keys(allTools).length}`); + + // 创建 Anthropic provider(使用容器内环境变量) + const anthropicProvider = createAnthropic({ + baseURL: baseUrl, + apiKey: authToken, + }); + + // 创建模型实例 + const modelName = process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL || 'glm-4.5-air'; + const anthropicModel = anthropicProvider(modelName); + + // 使用 streamText 创建流式响应 + const result = streamText({ + model: anthropicModel, + system: catalog.prompt({ mode: 'inline' }), + messages, + tools: allTools, + temperature: 0.7, + }); + + // 返回流式响应 + return result.toTextStreamResponse(); + + } catch (error) { + console.error('[API] Error in POST /api/chat:', error); + return new Response( + JSON.stringify({ + error: 'Internal server error', + details: error instanceof Error ? error.message : String(error), + }), + { status: 500, headers: { 'Content-Type': 'application/json' } } + ); + } +}