600 lines
21 KiB
Python
600 lines
21 KiB
Python
|
|
"""
|
|||
|
|
千问大模型集成模块
|
|||
|
|
支持千问API的智能分析功能
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import requests
|
|||
|
|
import json
|
|||
|
|
import os
|
|||
|
|
from typing import Dict, List, Optional, Any
|
|||
|
|
from dataclasses import dataclass
|
|||
|
|
import logging
|
|||
|
|
from datetime import datetime
|
|||
|
|
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class LLMConfig:
|
|||
|
|
"""大模型配置"""
|
|||
|
|
provider: str
|
|||
|
|
api_key: str
|
|||
|
|
base_url: str
|
|||
|
|
model: str
|
|||
|
|
temperature: float = 0.7
|
|||
|
|
max_tokens: int = 2000
|
|||
|
|
|
|||
|
|
|
|||
|
|
class QwenLLMClient:
|
|||
|
|
"""千问大模型客户端"""
|
|||
|
|
|
|||
|
|
def __init__(self, config: LLMConfig):
|
|||
|
|
self.config = config
|
|||
|
|
self.session = requests.Session()
|
|||
|
|
self.session.headers.update({
|
|||
|
|
'Authorization': f'Bearer {config.api_key}',
|
|||
|
|
'Content-Type': 'application/json'
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
def chat_completion(self, messages: List[Dict[str, str]], **kwargs) -> Optional[Dict]:
|
|||
|
|
"""聊天完成"""
|
|||
|
|
try:
|
|||
|
|
# 构建请求数据
|
|||
|
|
data = {
|
|||
|
|
'model': self.config.model,
|
|||
|
|
'messages': messages,
|
|||
|
|
'temperature': kwargs.get('temperature', self.config.temperature),
|
|||
|
|
'max_tokens': kwargs.get('max_tokens', self.config.max_tokens),
|
|||
|
|
'stream': False
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 发送请求
|
|||
|
|
response = self.session.post(
|
|||
|
|
f"{self.config.base_url}/chat/completions",
|
|||
|
|
json=data,
|
|||
|
|
timeout=30
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if response.status_code == 200:
|
|||
|
|
return response.json()
|
|||
|
|
else:
|
|||
|
|
logger.error(f"千问API请求失败: {response.status_code} - {response.text}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"千问API调用失败: {e}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def analyze_user_intent(self, user_input: str, user_context: Dict) -> Dict[str, Any]:
|
|||
|
|
"""分析用户意图"""
|
|||
|
|
system_prompt = """
|
|||
|
|
你是一个专业的营养师和心理学专家,擅长分析用户的饮食需求和心理状态。
|
|||
|
|
|
|||
|
|
你的任务是:
|
|||
|
|
1. 深度理解用户的真实需求,不仅仅是表面的话语
|
|||
|
|
2. 考虑用户的生理状态、情绪状态、历史偏好等多维度因素
|
|||
|
|
3. 提供个性化的饮食建议
|
|||
|
|
4. 特别关注女性用户的生理周期对饮食需求的影响
|
|||
|
|
|
|||
|
|
分析时要:
|
|||
|
|
- 透过现象看本质,理解用户的真实意图
|
|||
|
|
- 综合考虑生理、心理、社会等多重因素
|
|||
|
|
- 提供科学、实用、个性化的建议
|
|||
|
|
- 保持专业性和同理心
|
|||
|
|
|
|||
|
|
请以JSON格式返回分析结果,包含以下字段:
|
|||
|
|
- user_intent: 用户真实意图
|
|||
|
|
- emotional_state: 情绪状态
|
|||
|
|
- nutritional_needs: 营养需求列表
|
|||
|
|
- recommended_foods: 推荐食物列表
|
|||
|
|
- reasoning: 推荐理由
|
|||
|
|
- confidence: 置信度(0-1)
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
user_prompt = f"""
|
|||
|
|
请分析以下用户输入的真实需求和意图:
|
|||
|
|
|
|||
|
|
用户输入: "{user_input}"
|
|||
|
|
|
|||
|
|
用户背景信息:
|
|||
|
|
- 姓名: {user_context.get('name', '未知')}
|
|||
|
|
- 年龄: {user_context.get('age', '未知')}
|
|||
|
|
- 性别: {user_context.get('gender', '未知')}
|
|||
|
|
- 身高体重: {user_context.get('height', '未知')}cm, {user_context.get('weight', '未知')}kg
|
|||
|
|
- 活动水平: {user_context.get('activity_level', '未知')}
|
|||
|
|
|
|||
|
|
口味偏好: {json.dumps(user_context.get('taste_preferences', {}), ensure_ascii=False, indent=2)}
|
|||
|
|
|
|||
|
|
饮食限制:
|
|||
|
|
- 过敏: {', '.join(user_context.get('allergies', []))}
|
|||
|
|
- 不喜欢: {', '.join(user_context.get('dislikes', []))}
|
|||
|
|
- 饮食偏好: {', '.join(user_context.get('dietary_preferences', []))}
|
|||
|
|
|
|||
|
|
最近3天饮食记录: {self._format_meal_history(user_context.get('recent_meals', []))}
|
|||
|
|
|
|||
|
|
用户反馈历史: {self._format_feedback_history(user_context.get('feedback_history', []))}
|
|||
|
|
|
|||
|
|
当前情况:
|
|||
|
|
- 日期: {datetime.now().strftime('%Y-%m-%d')}
|
|||
|
|
- 生理状态: {json.dumps(user_context.get('physiological_state', {}), ensure_ascii=False)}
|
|||
|
|
|
|||
|
|
请从以下维度分析用户需求:
|
|||
|
|
|
|||
|
|
1. **真实意图分析**: 用户真正想要什么?是饿了、馋了、还是需要特定营养?
|
|||
|
|
|
|||
|
|
2. **情绪状态**: 用户当前的情绪如何?压力大、开心、疲惫、焦虑等?
|
|||
|
|
|
|||
|
|
3. **生理需求**: 基于用户的身体状况、生理周期等,需要什么营养?
|
|||
|
|
|
|||
|
|
4. **口味偏好**: 基于历史数据和当前状态,推测用户可能的口味偏好
|
|||
|
|
|
|||
|
|
5. **饮食限制**: 考虑过敏、不喜欢、饮食偏好等限制
|
|||
|
|
|
|||
|
|
6. **推荐食物**: 基于以上分析,推荐3-5种合适的食物
|
|||
|
|
|
|||
|
|
7. **推荐理由**: 解释为什么推荐这些食物
|
|||
|
|
|
|||
|
|
8. **置信度**: 对分析的信心程度 (0-1)
|
|||
|
|
|
|||
|
|
请以JSON格式返回分析结果。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
messages = [
|
|||
|
|
{"role": "system", "content": system_prompt},
|
|||
|
|
{"role": "user", "content": user_prompt}
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
response = self.chat_completion(messages, temperature=0.3)
|
|||
|
|
|
|||
|
|
if response and 'choices' in response:
|
|||
|
|
content = response['choices'][0]['message']['content']
|
|||
|
|
return self._parse_analysis_result(content)
|
|||
|
|
else:
|
|||
|
|
return self._get_fallback_analysis(user_input, user_context)
|
|||
|
|
|
|||
|
|
def analyze_nutrition(self, meal_data: Dict, user_context: Dict) -> Dict[str, Any]:
|
|||
|
|
"""分析营养状况"""
|
|||
|
|
system_prompt = """
|
|||
|
|
你是一个专业的营养师,擅长分析餐食的营养价值和健康建议。
|
|||
|
|
|
|||
|
|
你的任务是:
|
|||
|
|
1. 分析餐食的营养均衡性
|
|||
|
|
2. 评估热量是否合适
|
|||
|
|
3. 识别缺少的营养素
|
|||
|
|
4. 提供改进建议
|
|||
|
|
5. 考虑用户的个人情况
|
|||
|
|
|
|||
|
|
分析时要:
|
|||
|
|
- 基于科学的营养学知识
|
|||
|
|
- 考虑用户的年龄、性别、体重、活动水平等因素
|
|||
|
|
- 提供具体可行的建议
|
|||
|
|
- 保持客观和专业
|
|||
|
|
|
|||
|
|
请以JSON格式返回分析结果,包含以下字段:
|
|||
|
|
- nutrition_balance: 营养均衡性评估
|
|||
|
|
- calorie_assessment: 热量评估
|
|||
|
|
- missing_nutrients: 缺少的营养素列表
|
|||
|
|
- improvements: 改进建议列表
|
|||
|
|
- recommendations: 个性化建议列表
|
|||
|
|
- confidence: 置信度(0-1)
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
user_prompt = f"""
|
|||
|
|
请分析以下餐食的营养状况:
|
|||
|
|
|
|||
|
|
餐食信息:
|
|||
|
|
- 食物: {', '.join(meal_data.get('foods', []))}
|
|||
|
|
- 分量: {', '.join(meal_data.get('quantities', []))}
|
|||
|
|
- 热量: {meal_data.get('calories', '未知')}卡路里
|
|||
|
|
|
|||
|
|
用户信息:
|
|||
|
|
- 年龄: {user_context.get('age', '未知')}
|
|||
|
|
- 性别: {user_context.get('gender', '未知')}
|
|||
|
|
- 身高体重: {user_context.get('height', '未知')}cm, {user_context.get('weight', '未知')}kg
|
|||
|
|
- 活动水平: {user_context.get('activity_level', '未知')}
|
|||
|
|
- 健康目标: {', '.join(user_context.get('health_goals', []))}
|
|||
|
|
|
|||
|
|
请分析:
|
|||
|
|
1. 营养均衡性
|
|||
|
|
2. 热量是否合适
|
|||
|
|
3. 缺少的营养素
|
|||
|
|
4. 建议改进的地方
|
|||
|
|
5. 个性化建议
|
|||
|
|
|
|||
|
|
请以JSON格式返回分析结果。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
messages = [
|
|||
|
|
{"role": "system", "content": system_prompt},
|
|||
|
|
{"role": "user", "content": user_prompt}
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
response = self.chat_completion(messages, temperature=0.2)
|
|||
|
|
|
|||
|
|
if response and 'choices' in response:
|
|||
|
|
content = response['choices'][0]['message']['content']
|
|||
|
|
return self._parse_nutrition_analysis(content)
|
|||
|
|
else:
|
|||
|
|
return self._get_fallback_nutrition_analysis(meal_data, user_context)
|
|||
|
|
|
|||
|
|
def analyze_physiological_state(self, profile: Dict, cycle_info: Dict) -> Dict[str, Any]:
|
|||
|
|
"""分析生理状态"""
|
|||
|
|
system_prompt = """
|
|||
|
|
你是专业的女性健康专家,了解生理周期对营养需求的影响。
|
|||
|
|
|
|||
|
|
你的任务是:
|
|||
|
|
1. 分析女性用户的生理周期状态
|
|||
|
|
2. 评估当前阶段的营养需求
|
|||
|
|
3. 提供针对性的饮食建议
|
|||
|
|
4. 考虑情绪和食欲的变化
|
|||
|
|
5. 提供个性化建议
|
|||
|
|
|
|||
|
|
分析时要:
|
|||
|
|
- 基于科学的生理学知识
|
|||
|
|
- 考虑个体差异
|
|||
|
|
- 提供温和、实用的建议
|
|||
|
|
- 保持专业和同理心
|
|||
|
|
|
|||
|
|
请以JSON格式返回分析结果,包含以下字段:
|
|||
|
|
- physiological_state: 生理状态描述
|
|||
|
|
- nutritional_needs: 营养需求列表
|
|||
|
|
- foods_to_avoid: 需要避免的食物列表
|
|||
|
|
- emotional_changes: 情绪变化描述
|
|||
|
|
- appetite_changes: 食欲变化描述
|
|||
|
|
- recommendations: 个性化建议列表
|
|||
|
|
- confidence: 置信度(0-1)
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
user_prompt = f"""
|
|||
|
|
作为专业的女性健康专家,请分析以下用户的生理状态和营养需求:
|
|||
|
|
|
|||
|
|
用户信息:
|
|||
|
|
- 年龄: {profile.get('age', '未知')}
|
|||
|
|
- 身高体重: {profile.get('height', '未知')}cm, {profile.get('weight', '未知')}kg
|
|||
|
|
- 月经周期长度: {profile.get('menstrual_cycle_length', '未知')}天
|
|||
|
|
- 上次月经: {profile.get('last_period_date', '未知')}
|
|||
|
|
|
|||
|
|
当前生理周期状态:
|
|||
|
|
- 周期阶段: {cycle_info.get('phase', '未知')}
|
|||
|
|
- 距离下次月经: {cycle_info.get('days_to_next_period', '未知')}天
|
|||
|
|
|
|||
|
|
请分析:
|
|||
|
|
1. 当前生理状态对营养需求的影响
|
|||
|
|
2. 建议补充的营养素
|
|||
|
|
3. 需要避免的食物
|
|||
|
|
4. 情绪和食欲的变化
|
|||
|
|
5. 个性化建议
|
|||
|
|
|
|||
|
|
请以JSON格式返回分析结果。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
messages = [
|
|||
|
|
{"role": "system", "content": system_prompt},
|
|||
|
|
{"role": "user", "content": user_prompt}
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
response = self.chat_completion(messages, temperature=0.2)
|
|||
|
|
|
|||
|
|
if response and 'choices' in response:
|
|||
|
|
content = response['choices'][0]['message']['content']
|
|||
|
|
return self._parse_physiological_analysis(content, cycle_info)
|
|||
|
|
else:
|
|||
|
|
return self._get_fallback_physiological_analysis(cycle_info)
|
|||
|
|
|
|||
|
|
def generate_meal_suggestion(self, meal_type: str, preferences: Dict, user_context: Dict) -> Dict[str, Any]:
|
|||
|
|
"""生成餐食建议"""
|
|||
|
|
system_prompt = """
|
|||
|
|
你是一个专业的营养师和厨师,擅长根据用户需求推荐合适的餐食。
|
|||
|
|
|
|||
|
|
你的任务是:
|
|||
|
|
1. 根据用户的口味偏好推荐食物
|
|||
|
|
2. 考虑饮食限制和过敏情况
|
|||
|
|
3. 提供营养均衡的建议
|
|||
|
|
4. 考虑用户的健康目标
|
|||
|
|
5. 提供实用的制作建议
|
|||
|
|
|
|||
|
|
推荐时要:
|
|||
|
|
- 基于营养学原理
|
|||
|
|
- 考虑用户的个人喜好
|
|||
|
|
- 提供多样化的选择
|
|||
|
|
- 保持实用性和可操作性
|
|||
|
|
|
|||
|
|
请以JSON格式返回建议,包含以下字段:
|
|||
|
|
- recommended_foods: 推荐食物列表
|
|||
|
|
- reasoning: 推荐理由
|
|||
|
|
- nutrition_tips: 营养搭配建议列表
|
|||
|
|
- cooking_suggestions: 制作建议列表
|
|||
|
|
- confidence: 置信度(0-1)
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
user_prompt = f"""
|
|||
|
|
请为以下用户推荐{meal_type}:
|
|||
|
|
|
|||
|
|
用户信息:
|
|||
|
|
- 姓名: {user_context.get('name', '未知')}
|
|||
|
|
- 年龄: {user_context.get('age', '未知')}
|
|||
|
|
- 性别: {user_context.get('gender', '未知')}
|
|||
|
|
- 身高体重: {user_context.get('height', '未知')}cm, {user_context.get('weight', '未知')}kg
|
|||
|
|
|
|||
|
|
口味偏好: {json.dumps(user_context.get('taste_preferences', {}), ensure_ascii=False)}
|
|||
|
|
饮食限制: 过敏({', '.join(user_context.get('allergies', []))}), 不喜欢({', '.join(user_context.get('dislikes', []))})
|
|||
|
|
健康目标: {', '.join(user_context.get('health_goals', []))}
|
|||
|
|
|
|||
|
|
特殊偏好: {json.dumps(preferences, ensure_ascii=False)}
|
|||
|
|
|
|||
|
|
请推荐:
|
|||
|
|
1. 3-5种适合的食物
|
|||
|
|
2. 推荐理由
|
|||
|
|
3. 营养搭配建议
|
|||
|
|
4. 制作建议
|
|||
|
|
|
|||
|
|
请以JSON格式返回建议。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
messages = [
|
|||
|
|
{"role": "system", "content": system_prompt},
|
|||
|
|
{"role": "user", "content": user_prompt}
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
response = self.chat_completion(messages, temperature=0.4)
|
|||
|
|
|
|||
|
|
if response and 'choices' in response:
|
|||
|
|
content = response['choices'][0]['message']['content']
|
|||
|
|
return self._parse_meal_suggestion(content)
|
|||
|
|
else:
|
|||
|
|
return self._get_fallback_meal_suggestion(meal_type, user_context)
|
|||
|
|
|
|||
|
|
def _format_meal_history(self, meals: List[Dict]) -> str:
|
|||
|
|
"""格式化餐食历史"""
|
|||
|
|
if not meals:
|
|||
|
|
return "暂无饮食记录"
|
|||
|
|
|
|||
|
|
formatted = []
|
|||
|
|
for meal in meals:
|
|||
|
|
foods = ', '.join(meal.get('foods', []))
|
|||
|
|
satisfaction = meal.get('satisfaction_score', '未知')
|
|||
|
|
formatted.append(f"- {meal.get('date', '')} {meal.get('meal_type', '')}: {foods} (满意度: {satisfaction})")
|
|||
|
|
|
|||
|
|
return '\n'.join(formatted)
|
|||
|
|
|
|||
|
|
def _format_feedback_history(self, feedbacks: List[Dict]) -> str:
|
|||
|
|
"""格式化反馈历史"""
|
|||
|
|
if not feedbacks:
|
|||
|
|
return "暂无反馈记录"
|
|||
|
|
|
|||
|
|
formatted = []
|
|||
|
|
for feedback in feedbacks:
|
|||
|
|
recommended = ', '.join(feedback.get('recommended_foods', []))
|
|||
|
|
choice = feedback.get('user_choice', '未知')
|
|||
|
|
feedback_type = feedback.get('feedback_type', '未知')
|
|||
|
|
formatted.append(f"- 推荐: {recommended} | 选择: {choice} | 反馈: {feedback_type}")
|
|||
|
|
|
|||
|
|
return '\n'.join(formatted)
|
|||
|
|
|
|||
|
|
def _parse_analysis_result(self, analysis_text: str) -> Dict[str, Any]:
|
|||
|
|
"""解析分析结果"""
|
|||
|
|
try:
|
|||
|
|
# 尝试提取JSON部分
|
|||
|
|
start_idx = analysis_text.find('{')
|
|||
|
|
end_idx = analysis_text.rfind('}') + 1
|
|||
|
|
|
|||
|
|
if start_idx != -1 and end_idx != -1:
|
|||
|
|
json_str = analysis_text[start_idx:end_idx]
|
|||
|
|
result_dict = json.loads(json_str)
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
'success': True,
|
|||
|
|
'user_intent': result_dict.get('user_intent', ''),
|
|||
|
|
'emotional_state': result_dict.get('emotional_state', ''),
|
|||
|
|
'nutritional_needs': result_dict.get('nutritional_needs', []),
|
|||
|
|
'recommended_foods': result_dict.get('recommended_foods', []),
|
|||
|
|
'reasoning': result_dict.get('reasoning', ''),
|
|||
|
|
'confidence': result_dict.get('confidence', 0.5)
|
|||
|
|
}
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"解析分析结果失败: {e}")
|
|||
|
|
|
|||
|
|
return self._get_fallback_analysis("", {})
|
|||
|
|
|
|||
|
|
def _parse_nutrition_analysis(self, analysis_text: str) -> Dict[str, Any]:
|
|||
|
|
"""解析营养分析结果"""
|
|||
|
|
try:
|
|||
|
|
start_idx = analysis_text.find('{')
|
|||
|
|
end_idx = analysis_text.rfind('}') + 1
|
|||
|
|
|
|||
|
|
if start_idx != -1 and end_idx != -1:
|
|||
|
|
json_str = analysis_text[start_idx:end_idx]
|
|||
|
|
result_dict = json.loads(json_str)
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
'success': True,
|
|||
|
|
'nutrition_balance': result_dict.get('nutrition_balance', ''),
|
|||
|
|
'calorie_assessment': result_dict.get('calorie_assessment', ''),
|
|||
|
|
'missing_nutrients': result_dict.get('missing_nutrients', []),
|
|||
|
|
'improvements': result_dict.get('improvements', []),
|
|||
|
|
'recommendations': result_dict.get('recommendations', []),
|
|||
|
|
'confidence': result_dict.get('confidence', 0.5)
|
|||
|
|
}
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"解析营养分析结果失败: {e}")
|
|||
|
|
|
|||
|
|
return self._get_fallback_nutrition_analysis({}, {})
|
|||
|
|
|
|||
|
|
def _parse_physiological_analysis(self, analysis_text: str, cycle_info: Dict) -> Dict[str, Any]:
|
|||
|
|
"""解析生理状态分析结果"""
|
|||
|
|
try:
|
|||
|
|
start_idx = analysis_text.find('{')
|
|||
|
|
end_idx = analysis_text.rfind('}') + 1
|
|||
|
|
|
|||
|
|
if start_idx != -1 and end_idx != -1:
|
|||
|
|
json_str = analysis_text[start_idx:end_idx]
|
|||
|
|
result_dict = json.loads(json_str)
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
'success': True,
|
|||
|
|
'physiological_state': result_dict.get('physiological_state', cycle_info.get('phase', '')),
|
|||
|
|
'nutritional_needs': result_dict.get('nutritional_needs', []),
|
|||
|
|
'foods_to_avoid': result_dict.get('foods_to_avoid', []),
|
|||
|
|
'emotional_changes': result_dict.get('emotional_changes', ''),
|
|||
|
|
'appetite_changes': result_dict.get('appetite_changes', ''),
|
|||
|
|
'recommendations': result_dict.get('recommendations', []),
|
|||
|
|
'cycle_info': cycle_info,
|
|||
|
|
'confidence': result_dict.get('confidence', 0.5)
|
|||
|
|
}
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"解析生理分析结果失败: {e}")
|
|||
|
|
|
|||
|
|
return self._get_fallback_physiological_analysis(cycle_info)
|
|||
|
|
|
|||
|
|
def _parse_meal_suggestion(self, suggestion_text: str) -> Dict[str, Any]:
|
|||
|
|
"""解析餐食建议结果"""
|
|||
|
|
try:
|
|||
|
|
start_idx = suggestion_text.find('{')
|
|||
|
|
end_idx = suggestion_text.rfind('}') + 1
|
|||
|
|
|
|||
|
|
if start_idx != -1 and end_idx != -1:
|
|||
|
|
json_str = suggestion_text[start_idx:end_idx]
|
|||
|
|
result_dict = json.loads(json_str)
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
'success': True,
|
|||
|
|
'recommended_foods': result_dict.get('recommended_foods', []),
|
|||
|
|
'reasoning': result_dict.get('reasoning', ''),
|
|||
|
|
'nutrition_tips': result_dict.get('nutrition_tips', []),
|
|||
|
|
'cooking_suggestions': result_dict.get('cooking_suggestions', []),
|
|||
|
|
'confidence': result_dict.get('confidence', 0.5)
|
|||
|
|
}
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.error(f"解析餐食建议结果失败: {e}")
|
|||
|
|
|
|||
|
|
return self._get_fallback_meal_suggestion("lunch", {})
|
|||
|
|
|
|||
|
|
def _get_fallback_analysis(self, user_input: str, user_context: Dict) -> Dict[str, Any]:
|
|||
|
|
"""获取备用分析结果"""
|
|||
|
|
return {
|
|||
|
|
'success': True,
|
|||
|
|
'user_intent': '需要饮食建议',
|
|||
|
|
'emotional_state': '正常',
|
|||
|
|
'nutritional_needs': ['均衡营养'],
|
|||
|
|
'recommended_foods': ['米饭', '蔬菜', '蛋白质'],
|
|||
|
|
'reasoning': '基于基础营养需求',
|
|||
|
|
'confidence': 0.3
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def _get_fallback_nutrition_analysis(self, meal_data: Dict, user_context: Dict) -> Dict[str, Any]:
|
|||
|
|
"""获取备用营养分析结果"""
|
|||
|
|
return {
|
|||
|
|
'success': True,
|
|||
|
|
'nutrition_balance': '基本均衡',
|
|||
|
|
'calorie_assessment': '适中',
|
|||
|
|
'missing_nutrients': [],
|
|||
|
|
'improvements': ['增加蔬菜摄入'],
|
|||
|
|
'recommendations': ['保持均衡饮食'],
|
|||
|
|
'confidence': 0.3
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def _get_fallback_physiological_analysis(self, cycle_info: Dict) -> Dict[str, Any]:
|
|||
|
|
"""获取备用生理状态分析结果"""
|
|||
|
|
return {
|
|||
|
|
'success': True,
|
|||
|
|
'physiological_state': cycle_info.get('phase', '正常'),
|
|||
|
|
'nutritional_needs': ['均衡营养'],
|
|||
|
|
'foods_to_avoid': [],
|
|||
|
|
'emotional_changes': '正常',
|
|||
|
|
'appetite_changes': '正常',
|
|||
|
|
'recommendations': ['保持规律饮食'],
|
|||
|
|
'cycle_info': cycle_info,
|
|||
|
|
'confidence': 0.3
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def _get_fallback_meal_suggestion(self, meal_type: str, user_context: Dict) -> Dict[str, Any]:
|
|||
|
|
"""获取备用餐食建议结果"""
|
|||
|
|
return {
|
|||
|
|
'success': True,
|
|||
|
|
'recommended_foods': ['米饭', '蔬菜', '蛋白质'],
|
|||
|
|
'reasoning': '营养均衡的基础搭配',
|
|||
|
|
'nutrition_tips': ['注意营养搭配'],
|
|||
|
|
'cooking_suggestions': ['简单烹饪'],
|
|||
|
|
'confidence': 0.3
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 千问配置 - 从环境变量获取
|
|||
|
|
def get_qwen_config() -> LLMConfig:
|
|||
|
|
"""获取千问配置"""
|
|||
|
|
api_key = os.getenv('QWEN_API_KEY', 'sk-c0dbefa1718d46eaa897199135066f00')
|
|||
|
|
base_url = os.getenv('QWEN_BASE_URL', 'https://dashscope.aliyuncs.com/compatible-mode/v1')
|
|||
|
|
model = os.getenv('QWEN_MODEL', 'qwen-plus-latest')
|
|||
|
|
|
|||
|
|
return LLMConfig(
|
|||
|
|
provider="qwen",
|
|||
|
|
api_key=api_key,
|
|||
|
|
base_url=base_url,
|
|||
|
|
model=model,
|
|||
|
|
temperature=0.7,
|
|||
|
|
max_tokens=2000
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 全局千问客户端实例
|
|||
|
|
qwen_client: Optional[QwenLLMClient] = None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_qwen_client() -> QwenLLMClient:
|
|||
|
|
"""获取千问客户端实例"""
|
|||
|
|
global qwen_client
|
|||
|
|
if qwen_client is None:
|
|||
|
|
config = get_qwen_config()
|
|||
|
|
qwen_client = QwenLLMClient(config)
|
|||
|
|
return qwen_client
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 便捷函数
|
|||
|
|
def analyze_user_intent_with_qwen(user_input: str, user_context: Dict) -> Dict[str, Any]:
|
|||
|
|
"""使用千问分析用户意图"""
|
|||
|
|
client = get_qwen_client()
|
|||
|
|
return client.analyze_user_intent(user_input, user_context)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def analyze_nutrition_with_qwen(meal_data: Dict, user_context: Dict) -> Dict[str, Any]:
|
|||
|
|
"""使用千问分析营养状况"""
|
|||
|
|
client = get_qwen_client()
|
|||
|
|
return client.analyze_nutrition(meal_data, user_context)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def analyze_physiological_state_with_qwen(profile: Dict, cycle_info: Dict) -> Dict[str, Any]:
|
|||
|
|
"""使用千问分析生理状态"""
|
|||
|
|
client = get_qwen_client()
|
|||
|
|
return client.analyze_physiological_state(profile, cycle_info)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def generate_meal_suggestion_with_qwen(meal_type: str, preferences: Dict, user_context: Dict) -> Dict[str, Any]:
|
|||
|
|
"""使用千问生成餐食建议"""
|
|||
|
|
client = get_qwen_client()
|
|||
|
|
return client.generate_meal_suggestion(meal_type, preferences, user_context)
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
# 测试千问大模型集成
|
|||
|
|
print("测试千问大模型集成...")
|
|||
|
|
|
|||
|
|
# 测试用户意图分析
|
|||
|
|
user_input = "我今天有点累,想吃点甜的,但是又怕胖"
|
|||
|
|
user_context = {
|
|||
|
|
'name': '小美',
|
|||
|
|
'age': 25,
|
|||
|
|
'gender': '女',
|
|||
|
|
'height': 165,
|
|||
|
|
'weight': 55,
|
|||
|
|
'taste_preferences': {'sweet': 4, 'salty': 3, 'spicy': 2},
|
|||
|
|
'allergies': ['花生'],
|
|||
|
|
'dislikes': ['内脏'],
|
|||
|
|
'recent_meals': [],
|
|||
|
|
'feedback_history': []
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result = analyze_user_intent_with_qwen(user_input, user_context)
|
|||
|
|
print(f"用户意图分析结果: {result}")
|
|||
|
|
|
|||
|
|
print("千问大模型集成测试完成!")
|