ai.service.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import OpenAI from 'openai';
  2. import { ChatRequestDto } from './dto/chat-request.dto';
  3. import { Response } from 'express';
  4. export class AIService {
  5. private openai: OpenAI | null = null;
  6. async chat(chatRequest: ChatRequestDto, res: Response, apiKey: string) {
  7. try {
  8. if (!apiKey) {
  9. throw new Error('API key is required');
  10. }
  11. // Initialize OpenAI client
  12. this.openai = new OpenAI({
  13. apiKey: apiKey,
  14. });
  15. const stream = await this.openai.chat.completions.create({
  16. model: 'gpt-4.1-nano',
  17. messages: chatRequest.messages,
  18. stream: true,
  19. });
  20. // Set headers for SSE
  21. res.writeHead(200, {
  22. 'Content-Type': 'text/event-stream',
  23. 'Cache-Control': 'no-cache',
  24. Connection: 'keep-alive',
  25. 'Transfer-Encoding': 'chunked',
  26. });
  27. let messageId = `msg_${Date.now()}`;
  28. // Handle the stream
  29. for await (const chunk of stream) {
  30. const content = chunk.choices[0]?.delta?.content || '';
  31. if (content) {
  32. // Send each chunk immediately without accumulation
  33. const message = {
  34. id: messageId,
  35. role: 'assistant',
  36. content: content,
  37. createdAt: new Date().toISOString(),
  38. parts: [
  39. {
  40. type: 'text',
  41. text: content,
  42. },
  43. ],
  44. };
  45. // Flush the response immediately
  46. const data = JSON.stringify({
  47. type: 'text',
  48. value: message,
  49. });
  50. res.write(`data: ${data}\n\n`);
  51. res.flush?.(); // Flush if available
  52. }
  53. }
  54. // Send the final message
  55. res.write('data: [DONE]\n\n');
  56. res.end();
  57. } catch (error) {
  58. console.error('API provider error:', error);
  59. if (!res.headersSent) {
  60. res.status(500).json({
  61. error:
  62. error instanceof Error
  63. ? error.message
  64. : 'Failed to get response from API provider',
  65. });
  66. }
  67. }
  68. }
  69. }