feat: 更新AI教练服务,支持处理多个图片URL,优化饮食分析逻辑。调整相关DTO以支持数组格式的图片URL,并修改默认视觉模型为'qwen-vl-max'。

This commit is contained in:
richarjiang
2025-08-18 15:07:47 +08:00
parent eb71f845e5
commit 3d36ee90f0
3 changed files with 12 additions and 11 deletions

View File

@@ -42,7 +42,7 @@ export class AiCoachController {
userId,
conversationId,
userContent,
imageUrl: body.imageUrl,
imageUrls: body.imageUrls,
});
let text = '';
for await (const chunk of readable) {
@@ -62,7 +62,7 @@ export class AiCoachController {
userId,
conversationId,
userContent,
imageUrl: body.imageUrl,
imageUrls: body.imageUrls,
});
readable.on('data', (chunk) => {

View File

@@ -103,7 +103,7 @@ export class AiCoachService {
});
// 默认选择通义千问对话模型OpenAI兼容名可通过环境覆盖
this.model = this.configService.get<string>('DASHSCOPE_MODEL') || 'qwen-flash';
this.visionModel = this.configService.get<string>('DASHSCOPE_VISION_MODEL') || 'qwen-vl-plus';
this.visionModel = this.configService.get<string>('DASHSCOPE_VISION_MODEL') || 'qwen-vl-max';
}
async createOrAppendMessages(params: {
@@ -200,7 +200,7 @@ export class AiCoachService {
conversationId: string;
userContent: string;
systemNotice?: string;
imageUrl?: string;
imageUrls?: string[];
}): Promise<Readable> {
// 解析指令(如果以 # 开头)
const commandResult = this.parseCommand(params.userContent);
@@ -227,8 +227,8 @@ export class AiCoachService {
}
} else if (commandResult.command === 'diet') {
// 使用视觉模型分析饮食图片
if (params.imageUrl) {
const dietAnalysis = await this.analyzeDietImage(params.imageUrl);
if (params.imageUrls) {
const dietAnalysis = await this.analyzeDietImage(params.imageUrls);
messages.push({
role: 'user',
content: `用户通过拍照记录饮食,图片分析结果如下:\n${dietAnalysis}`
@@ -418,7 +418,7 @@ export class AiCoachService {
* @param imageUrl 图片URL
* @returns 饮食分析结果
*/
private async analyzeDietImage(imageUrl: string): Promise<string> {
private async analyzeDietImage(imageUrls: string[]): Promise<string> {
try {
const prompt = `请分析这张食物图片,识别其中的食物种类、分量,并提供以下信息:
@@ -445,11 +445,11 @@ export class AiCoachService {
role: 'user',
content: [
{ type: 'text', text: prompt },
{ type: 'image_url', image_url: { url: imageUrl } as any },
...imageUrls.map((imageUrl) => ({ type: 'image_url', image_url: { url: imageUrl } as any })),
] as any,
},
],
temperature: 0,
temperature: 1,
});
this.logger.log(`diet image analysis result: ${completion.choices?.[0]?.message?.content}`);

View File

@@ -25,8 +25,9 @@ export class AiChatRequestDto {
@ApiProperty({ required: false, description: '当用户要记体重时的图片URL电子秤等' })
@IsOptional()
@IsString()
imageUrl?: string;
@IsArray()
@IsString({ each: true })
imageUrls?: string[];
@ApiProperty({ required: false, description: '是否启用流式输出', default: true })
@IsOptional()