feat: 初始化 Nest 服务骨架与多平台 Chat SSE 网关

- 新增 NestJS + Fastify 入口、配置模块与 Swagger 集成
- 划分 client-app / admin-app 与 shared-domain ai-gateway
- 实现统一 SSE Chat 接口,支持千问、DeepSeek、火山引擎非流式上游与网关分片输出
- 补充项目方案与 JWT 最小实现文档

Made-with: Cursor
This commit is contained in:
2026-04-17 02:27:08 +08:00
parent e5f90078ce
commit 0fa6617341
23 changed files with 3961 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
import { Body, Controller, Inject, Post, Res } from '@nestjs/common';
import { FastifyReply } from 'fastify';
import { StreamChatRequest } from '@shared/ai-gateway/types/chat.types';
import { ProviderRouterService } from '@shared/ai-gateway/router/provider-router.service';
function formatSse(event: string, data: unknown) {
return `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
}
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
@Controller('client/v1/chat')
export class ChatController {
constructor(
@Inject(ProviderRouterService)
private readonly router: ProviderRouterService,
) {}
@Post('completions/stream')
async streamChat(
@Body() body: StreamChatRequest,
@Res() reply: FastifyReply,
) {
const response = await this.router.routeAndStream(body);
reply.raw.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
reply.raw.setHeader('Cache-Control', 'no-cache, no-transform');
reply.raw.setHeader('Connection', 'keep-alive');
reply.raw.setHeader('X-Accel-Buffering', 'no');
reply.raw.flushHeaders?.();
reply.raw.write(
formatSse('meta', {
requestId: response.requestId,
platform: response.providerCode,
model: response.model,
}),
);
for (const chunk of response.chunks) {
reply.raw.write(formatSse('delta', { delta: chunk.content }));
await sleep(120);
}
reply.raw.write(formatSse('usage', response.usage));
reply.raw.write(formatSse('done', { finishReason: 'stop' }));
reply.raw.end();
}
}