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' } } + ); + } +}