feat: 更新AI教练服务,支持处理多个图片URL,优化饮食分析逻辑。调整相关DTO以支持数组格式的图片URL,并修改默认视觉模型为'qwen-vl-max'。
This commit is contained in:
@@ -42,7 +42,7 @@ export class AiCoachController {
|
|||||||
userId,
|
userId,
|
||||||
conversationId,
|
conversationId,
|
||||||
userContent,
|
userContent,
|
||||||
imageUrl: body.imageUrl,
|
imageUrls: body.imageUrls,
|
||||||
});
|
});
|
||||||
let text = '';
|
let text = '';
|
||||||
for await (const chunk of readable) {
|
for await (const chunk of readable) {
|
||||||
@@ -62,7 +62,7 @@ export class AiCoachController {
|
|||||||
userId,
|
userId,
|
||||||
conversationId,
|
conversationId,
|
||||||
userContent,
|
userContent,
|
||||||
imageUrl: body.imageUrl,
|
imageUrls: body.imageUrls,
|
||||||
});
|
});
|
||||||
|
|
||||||
readable.on('data', (chunk) => {
|
readable.on('data', (chunk) => {
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export class AiCoachService {
|
|||||||
});
|
});
|
||||||
// 默认选择通义千问对话模型(OpenAI兼容名),可通过环境覆盖
|
// 默认选择通义千问对话模型(OpenAI兼容名),可通过环境覆盖
|
||||||
this.model = this.configService.get<string>('DASHSCOPE_MODEL') || 'qwen-flash';
|
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: {
|
async createOrAppendMessages(params: {
|
||||||
@@ -200,7 +200,7 @@ export class AiCoachService {
|
|||||||
conversationId: string;
|
conversationId: string;
|
||||||
userContent: string;
|
userContent: string;
|
||||||
systemNotice?: string;
|
systemNotice?: string;
|
||||||
imageUrl?: string;
|
imageUrls?: string[];
|
||||||
}): Promise<Readable> {
|
}): Promise<Readable> {
|
||||||
// 解析指令(如果以 # 开头)
|
// 解析指令(如果以 # 开头)
|
||||||
const commandResult = this.parseCommand(params.userContent);
|
const commandResult = this.parseCommand(params.userContent);
|
||||||
@@ -227,8 +227,8 @@ export class AiCoachService {
|
|||||||
}
|
}
|
||||||
} else if (commandResult.command === 'diet') {
|
} else if (commandResult.command === 'diet') {
|
||||||
// 使用视觉模型分析饮食图片
|
// 使用视觉模型分析饮食图片
|
||||||
if (params.imageUrl) {
|
if (params.imageUrls) {
|
||||||
const dietAnalysis = await this.analyzeDietImage(params.imageUrl);
|
const dietAnalysis = await this.analyzeDietImage(params.imageUrls);
|
||||||
messages.push({
|
messages.push({
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: `用户通过拍照记录饮食,图片分析结果如下:\n${dietAnalysis}`
|
content: `用户通过拍照记录饮食,图片分析结果如下:\n${dietAnalysis}`
|
||||||
@@ -418,7 +418,7 @@ export class AiCoachService {
|
|||||||
* @param imageUrl 图片URL
|
* @param imageUrl 图片URL
|
||||||
* @returns 饮食分析结果
|
* @returns 饮食分析结果
|
||||||
*/
|
*/
|
||||||
private async analyzeDietImage(imageUrl: string): Promise<string> {
|
private async analyzeDietImage(imageUrls: string[]): Promise<string> {
|
||||||
try {
|
try {
|
||||||
const prompt = `请分析这张食物图片,识别其中的食物种类、分量,并提供以下信息:
|
const prompt = `请分析这张食物图片,识别其中的食物种类、分量,并提供以下信息:
|
||||||
|
|
||||||
@@ -445,11 +445,11 @@ export class AiCoachService {
|
|||||||
role: 'user',
|
role: 'user',
|
||||||
content: [
|
content: [
|
||||||
{ type: 'text', text: prompt },
|
{ 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,
|
] as any,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
temperature: 0,
|
temperature: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.log(`diet image analysis result: ${completion.choices?.[0]?.message?.content}`);
|
this.logger.log(`diet image analysis result: ${completion.choices?.[0]?.message?.content}`);
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ export class AiChatRequestDto {
|
|||||||
|
|
||||||
@ApiProperty({ required: false, description: '当用户要记体重时的图片URL(电子秤等)' })
|
@ApiProperty({ required: false, description: '当用户要记体重时的图片URL(电子秤等)' })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsArray()
|
||||||
imageUrl?: string;
|
@IsString({ each: true })
|
||||||
|
imageUrls?: string[];
|
||||||
|
|
||||||
@ApiProperty({ required: false, description: '是否启用流式输出', default: true })
|
@ApiProperty({ required: false, description: '是否启用流式输出', default: true })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
|||||||
Reference in New Issue
Block a user