From b56dc0797efb04a0d046862166c4a3678f5c48e7 Mon Sep 17 00:00:00 2001 From: kingecg Date: Tue, 10 Jun 2025 20:41:51 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ai):=20=E5=AE=9E=E7=8E=B0=20DeepSeek?= =?UTF-8?q?=20=E5=92=8C=20Tongyi=20API=20=E9=80=82=E9=85=8D=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 ai.adapter.ts 中的 DeepSeekAdapter 和 TongyiAdapter 类 - 在 deepseek.adapter.ts 和 tongyi.adapter.ts 中实现具体的 API 调用逻辑 - 添加错误处理和响应解析功能 - 优化代码结构,提高可维护性和可扩展性 --- backend/src/ai/ai.adapter.ts | 28 ---------- backend/src/ai/deepseek.adapter.ts | 82 +++++++++++++++++++++++++--- backend/src/ai/tongyi.adapter.ts | 87 +++++++++++++++++++++++++++--- 3 files changed, 155 insertions(+), 42 deletions(-) diff --git a/backend/src/ai/ai.adapter.ts b/backend/src/ai/ai.adapter.ts index dbe58ec..e9bd0db 100644 --- a/backend/src/ai/ai.adapter.ts +++ b/backend/src/ai/ai.adapter.ts @@ -4,31 +4,3 @@ export interface AiServiceAdapter { generateText(model: string, prompt: string, config?: Record): Promise; chat(model: string, messages: Array<{role: string, content: string}>, config?: Record): Promise; } - -export class DeepSeekAdapter implements AiServiceAdapter { - constructor(private readonly config: AiConfig) {} - - async generateText(model: string, prompt: string): Promise { - // 实现DeepSeek的文本生成逻辑 - return `Generated text by ${model}: ${prompt}`; - } - - async chat(model: string, messages: Array<{role: string, content: string}>): Promise { - // 实现DeepSeek的对话交互逻辑 - return `Chat response from ${model}: ${JSON.stringify(messages)}`; - } -} - -export class TongyiAdapter implements AiServiceAdapter { - constructor(private readonly config: AiConfig) {} - - async generateText(model: string, prompt: string): Promise { - // 实现通义千问的文本生成逻辑 - return `Tongyi generated text: ${prompt}`; - } - - async chat(model: string, messages: Array<{role: string, content: string}>): Promise { - // 实现通义千问的对话交互逻辑 - return `Tongyi chat response: ${JSON.stringify(messages)}`; - } -} \ No newline at end of file diff --git a/backend/src/ai/deepseek.adapter.ts b/backend/src/ai/deepseek.adapter.ts index 530d99e..8b1f84d 100644 --- a/backend/src/ai/deepseek.adapter.ts +++ b/backend/src/ai/deepseek.adapter.ts @@ -1,16 +1,84 @@ +import { HttpService } from '@nestjs/axios'; +import { Injectable } from '@nestjs/common'; +import { firstValueFrom } from 'rxjs'; +import { AiConfig } from './ai-config.entity'; import { AiServiceAdapter } from './ai.adapter'; +@Injectable() export class DeepSeekAdapter implements AiServiceAdapter { - constructor(private readonly config: any) {} + private readonly httpService: HttpService; - // 实现AiServiceAdapter接口定义的方法 - async generateText(model: string, prompt: string, config?: Record): Promise { - // 这里添加调用DeepSeek API的具体实现 - return `Response from DeepSeek: ${prompt}`; + constructor(private readonly config: AiConfig) { + this.httpService = new HttpService({ + baseURL: this.config.apiUrl, + headers: { + 'Authorization': `Bearer ${this.config.apiKey}`, + 'Content-Type': 'application/json', + }, + }); } + /** + * 生成文本 + * @param model 模型名称 + * @param prompt 提示文本 + * @param config 可选配置 + * @returns 生成的文本 + */ + async generateText(model: string, prompt: string, config?: Record): Promise { + try { + const response = await firstValueFrom( + this.httpService.post('/v1/completions', { + model, + prompt, + max_tokens: config?.max_tokens || 1000, + temperature: config?.temperature || 0.7, + top_p: config?.top_p || 1, + frequency_penalty: config?.frequency_penalty || 0, + presence_penalty: config?.presence_penalty || 0, + }) + ); + + if (response.data && response.data.choices && response.data.choices.length > 0) { + return response.data.choices[0].text; + } + + throw new Error('Invalid response from DeepSeek API'); + } catch (error:any) { + console.error('DeepSeek API error:', error.response?.data || error.message); + throw new Error(`Failed to generate text: ${error.message}`); + } + } + + /** + * 聊天对话 + * @param model 模型名称 + * @param messages 消息数组 + * @param config 可选配置 + * @returns 聊天回复 + */ async chat(model: string, messages: Array<{role: string, content: string}>, config?: Record): Promise { - // 这里添加调用DeepSeek API的具体实现 - return `Chat response from DeepSeek: ${messages[messages.length - 1].content}`; + try { + const response = await firstValueFrom( + this.httpService.post('/v1/chat/completions', { + model, + messages, + max_tokens: config?.max_tokens || 1000, + temperature: config?.temperature || 0.7, + top_p: config?.top_p || 1, + frequency_penalty: config?.frequency_penalty || 0, + presence_penalty: config?.presence_penalty || 0, + }) + ); + + if (response.data && response.data.choices && response.data.choices.length > 0) { + return response.data.choices[0].message.content; + } + + throw new Error('Invalid response from DeepSeek API'); + } catch (error:any) { + console.error('DeepSeek API error:', error.response?.data || error.message); + throw new Error(`Failed to chat: ${error.message}`); + } } } \ No newline at end of file diff --git a/backend/src/ai/tongyi.adapter.ts b/backend/src/ai/tongyi.adapter.ts index f4a482a..2ded782 100644 --- a/backend/src/ai/tongyi.adapter.ts +++ b/backend/src/ai/tongyi.adapter.ts @@ -1,16 +1,89 @@ +import { HttpService } from '@nestjs/axios'; +import { Injectable } from '@nestjs/common'; +import { firstValueFrom } from 'rxjs'; +import { AiConfig } from './ai-config.entity'; import { AiServiceAdapter } from './ai.adapter'; +@Injectable() export class TongyiAdapter implements AiServiceAdapter { - constructor(private readonly config: any) {} + private readonly httpService: HttpService; - // 实现AiServiceAdapter接口定义的方法 - async generateText(model: string, prompt: string, config?: Record): Promise { - // 这里添加调用Tongyi API的具体实现 - return `Response from Tongyi: ${prompt}`; + constructor(private readonly config: AiConfig) { + this.httpService = new HttpService({ + baseURL: this.config.apiUrl, + headers: { + 'Authorization': `Bearer ${this.config.apiKey}`, + 'Content-Type': 'application/json', + }, + }); } + /** + * 生成文本 + * @param model 模型名称 + * @param prompt 提示文本 + * @param config 可选配置 + * @returns 生成的文本 + */ + async generateText(model: string, prompt: string, config?: Record): Promise { + try { + const response = await firstValueFrom( + this.httpService.post('/v1/text/generation', { + model, + input: { + prompt, + max_tokens: config?.max_tokens || 1000, + temperature: config?.temperature || 0.7, + top_p: config?.top_p || 1, + stop: config?.stop || [], + } + }) + ); + + if (response.data && response.data.output && response.data.output.text) { + return response.data.output.text; + } + + throw new Error('Invalid response from Tongyi API'); + } catch (error:any) { + console.error('Tongyi API error:', error.response?.data || error.message); + throw new Error(`Failed to generate text: ${error.message}`); + } + } + + /** + * 聊天对话 + * @param model 模型名称 + * @param messages 消息数组 + * @param config 可选配置 + * @returns 聊天回复 + */ async chat(model: string, messages: Array<{role: string, content: string}>, config?: Record): Promise { - // 这里添加调用Tongyi API的具体实现 - return `Chat response from Tongyi: ${messages[messages.length - 1].content}`; + try { + const response = await firstValueFrom( + this.httpService.post('/v1/chat/completions', { + model, + messages: messages.map(msg => ({ + role: msg.role, + content: msg.content + })), + parameters: { + max_tokens: config?.max_tokens || 1000, + temperature: config?.temperature || 0.7, + top_p: config?.top_p || 1, + stop: config?.stop || [], + } + }) + ); + + if (response.data && response.data.output && response.data.output.text) { + return response.data.output.text; + } + + throw new Error('Invalid response from Tongyi API'); + } catch (error:any) { + console.error('Tongyi API error:', error.response?.data || error.message); + throw new Error(`Failed to chat: ${error.message}`); + } } } \ No newline at end of file