483 lines
18 KiB
Python
483 lines
18 KiB
Python
import json
|
||
from typing import Dict, List, Tuple
|
||
from volcenginesdkarkruntime import Ark
|
||
import os
|
||
from datetime import datetime
|
||
|
||
class VolcanoAPI:
|
||
"""火山引擎API调用工具类"""
|
||
|
||
def __init__(self, api_key: str):
|
||
self.api_key = api_key
|
||
self.client = Ark(
|
||
base_url="https://ark.cn-beijing.volces.com/api/v3",
|
||
api_key=api_key
|
||
)
|
||
|
||
def test_connection(self) -> Tuple[bool, str]:
|
||
"""测试API连接是否正常
|
||
|
||
Returns:
|
||
Tuple[bool, str]: (是否连接成功, 错误信息)
|
||
"""
|
||
try:
|
||
# 构造一个简单的测试请求
|
||
test_prompt = "你好,这是一个测试消息。"
|
||
response = self.client.chat.completions.create(
|
||
model="Doubao-vision-lite-32k",
|
||
messages=[
|
||
{"role": "user", "content": test_prompt}
|
||
],
|
||
extra_headers={'x-is-encrypted': 'true'}
|
||
)
|
||
|
||
if response and response.choices:
|
||
return True, "API连接成功"
|
||
else:
|
||
return False, "API响应异常:没有返回有效内容"
|
||
|
||
except Exception as e:
|
||
return False, f"API请求异常: {str(e)}"
|
||
|
||
def generate_greeting(self, contact_info: Dict, chat_history: List[Dict], style_prompt: str) -> Dict:
|
||
"""生成新年祝福内容
|
||
|
||
Args:
|
||
contact_info: 联系人信息,包含姓名和wxid
|
||
chat_history: 聊天记录列表
|
||
style_prompt: 风格提示词
|
||
|
||
Returns:
|
||
Dict: 包含生成的祝福内容
|
||
"""
|
||
try:
|
||
# 分析聊天记录,提取关键信息
|
||
chat_analysis = self._analyze_chat_history(chat_history)
|
||
|
||
# 构建完整的提示词
|
||
prompt = self._build_prompt(contact_info, chat_analysis, style_prompt)
|
||
|
||
# 调用API生成内容
|
||
response = self.client.chat.completions.create(
|
||
model="ep-20250120142713-z5cs6",
|
||
messages=[
|
||
{"role": "user", "content": prompt}
|
||
],
|
||
extra_headers={'x-is-encrypted': 'true'}
|
||
)
|
||
|
||
# 解析响应内容
|
||
return self._parse_response(response)
|
||
|
||
except Exception as e:
|
||
raise Exception(f"生成祝福内容失败:{str(e)}")
|
||
|
||
def _analyze_chat_history(self, chat_history: List[Dict]) -> Dict:
|
||
"""深度分析聊天记录,提取有价值的信息用于生成个性化祝福
|
||
|
||
Args:
|
||
chat_history: 聊天记录列表,每条记录包含:
|
||
- message: 消息内容
|
||
- is_sender: 是否为发送者
|
||
- create_time: 消息时间
|
||
|
||
Returns:
|
||
Dict: 分析结果,包含:
|
||
- chat_frequency: 聊天频率
|
||
- relationship_level: 关系亲密度
|
||
- common_topics: 共同话题
|
||
- emotional_keywords: 情感关键词
|
||
- interaction_style: 互动方式
|
||
- chat_time_distribution: 聊天时间分布
|
||
- key_life_events: 重要生活事件
|
||
"""
|
||
from collections import Counter, defaultdict
|
||
import jieba
|
||
import jieba.analyse
|
||
from datetime import datetime
|
||
import re
|
||
|
||
if not chat_history:
|
||
return self._get_default_analysis()
|
||
|
||
# 1. 基础统计
|
||
total_messages = len(chat_history)
|
||
sent_messages = sum(1 for msg in chat_history if msg['is_sender'])
|
||
received_messages = total_messages - sent_messages
|
||
|
||
# 2. 时间分析
|
||
time_distribution = defaultdict(int)
|
||
time_gaps = []
|
||
last_time = None
|
||
|
||
# 3. 文本处理准备
|
||
all_text = []
|
||
life_events = []
|
||
emotional_words = []
|
||
|
||
# 4. 关键词和话题识别的正则模式
|
||
life_event_patterns = [
|
||
r'考试|毕业|工作|加班|项目|旅行|旅游|生日|结婚|搬家|升职|考研',
|
||
r'开心|难过|焦虑|压力|困难|成功|失败|努力|坚持|梦想|目标',
|
||
r'家人|朋友|同事|领导|团队|公司|学校|家庭'
|
||
]
|
||
|
||
emotional_patterns = [
|
||
r'开心|快乐|高兴|激动|兴奋|满意|感动|温暖|感激|感谢',
|
||
r'难过|伤心|焦虑|烦恼|痛苦|压力|疲惫|失望|生气|担心',
|
||
r'加油|支持|鼓励|期待|希望|梦想|努力|坚持|相信|祝福'
|
||
]
|
||
|
||
for msg in chat_history:
|
||
text = msg['message']
|
||
create_time = datetime.strptime(msg['create_time'], '%Y-%m-%d %H:%M:%S')
|
||
|
||
# 更新时间分布
|
||
hour = create_time.hour
|
||
time_distribution[hour] += 1
|
||
|
||
# 计算消息时间间隔
|
||
if last_time:
|
||
gap = (create_time - last_time).total_seconds() / 3600 # 转换为小时
|
||
time_gaps.append(gap)
|
||
last_time = create_time
|
||
|
||
# 文本分析
|
||
all_text.append(text)
|
||
|
||
# 识别生活事件
|
||
for pattern in life_event_patterns:
|
||
matches = re.findall(pattern, text)
|
||
if matches:
|
||
life_events.extend(matches)
|
||
|
||
# 识别情感词
|
||
for pattern in emotional_patterns:
|
||
matches = re.findall(pattern, text)
|
||
if matches:
|
||
emotional_words.extend(matches)
|
||
|
||
# 5. 分析聊天频率
|
||
if time_gaps:
|
||
avg_gap = sum(time_gaps) / len(time_gaps)
|
||
if avg_gap < 24:
|
||
chat_frequency = "频繁"
|
||
elif avg_gap < 72:
|
||
chat_frequency = "较多"
|
||
else:
|
||
chat_frequency = "一般"
|
||
else:
|
||
chat_frequency = "较少"
|
||
|
||
# 6. 分析关系亲密度
|
||
intimacy_score = 0
|
||
intimacy_score += min(total_messages / 1000, 5) # 消息数量得分,最高5分
|
||
intimacy_score += len(set(emotional_words)) / 2 # 情感词丰富度得分
|
||
intimacy_score += min(24 / (avg_gap if time_gaps else 168), 3) # 时间间隔得分,最高3分
|
||
|
||
if intimacy_score > 7:
|
||
relationship_level = "密切"
|
||
elif intimacy_score > 4:
|
||
relationship_level = "友好"
|
||
else:
|
||
relationship_level = "一般"
|
||
|
||
# 7. 提取关键话题
|
||
combined_text = ' '.join(all_text)
|
||
top_keywords = jieba.analyse.extract_tags(
|
||
combined_text,
|
||
topK=10,
|
||
withWeight=True,
|
||
allowPOS=('n', 'v', 'a') # 名词、动词、形容词
|
||
)
|
||
|
||
# 8. 分析互动方式
|
||
response_rate = received_messages / sent_messages if sent_messages > 0 else 0
|
||
avg_msg_length = sum(len(msg['message']) for msg in chat_history) / total_messages
|
||
|
||
if response_rate > 0.8 and avg_msg_length > 10:
|
||
interaction_style = "深入交流"
|
||
elif response_rate > 0.5:
|
||
interaction_style = "积极互动"
|
||
else:
|
||
interaction_style = "一般交流"
|
||
|
||
# 9. 整理分析结果
|
||
return {
|
||
"chat_frequency": chat_frequency,
|
||
"relationship_level": relationship_level,
|
||
"total_messages": total_messages,
|
||
"sent_messages": sent_messages,
|
||
"received_messages": received_messages,
|
||
"common_topics": [word for word, weight in top_keywords[:5]],
|
||
"emotional_keywords": list(set(emotional_words))[:5],
|
||
"key_life_events": list(set(life_events))[:5],
|
||
"interaction_style": interaction_style,
|
||
"chat_time_distribution": dict(sorted(time_distribution.items())),
|
||
"intimacy_score": round(intimacy_score, 2)
|
||
}
|
||
|
||
def _get_default_analysis(self) -> Dict:
|
||
"""返回默认的分析结果"""
|
||
return {
|
||
"chat_frequency": "较少",
|
||
"relationship_level": "一般",
|
||
"total_messages": 0,
|
||
"sent_messages": 0,
|
||
"received_messages": 0,
|
||
"common_topics": ["工作", "生活"],
|
||
"emotional_keywords": [],
|
||
"key_life_events": [],
|
||
"interaction_style": "一般交流",
|
||
"chat_time_distribution": {},
|
||
"intimacy_score": 0
|
||
}
|
||
|
||
def _build_prompt(self, contact_info: Dict, chat_analysis: Dict, style_prompt: str) -> str:
|
||
"""构建完整的提示词
|
||
|
||
Args:
|
||
contact_info: 联系人信息
|
||
chat_analysis: 聊天记录分析结果
|
||
style_prompt: 风格提示词
|
||
|
||
Returns:
|
||
str: 完整的提示词
|
||
"""
|
||
# 将字典转换为更安全的字符串表示
|
||
contact_str = f"姓名:{contact_info.get('name', '')}"
|
||
|
||
# 构建详细的聊天分析信息
|
||
common_topics = '、'.join(chat_analysis.get('common_topics', ['未知']))
|
||
emotional_keywords = '、'.join(chat_analysis.get('emotional_keywords', []))
|
||
key_life_events = '、'.join(chat_analysis.get('key_life_events', []))
|
||
|
||
# 获取主要聊天时间段
|
||
time_dist = chat_analysis.get('chat_time_distribution', {})
|
||
active_hours = []
|
||
if time_dist:
|
||
# 找出消息数量最多的3个时间段
|
||
sorted_hours = sorted(time_dist.items(), key=lambda x: x[1], reverse=True)[:3]
|
||
active_hours = [f"{hour}点" for hour, _ in sorted_hours]
|
||
|
||
analysis_str = (
|
||
f"1) 基础关系:\n"
|
||
f" - 聊天频率:{chat_analysis.get('chat_frequency', '一般')}\n"
|
||
f" - 关系亲密度:{chat_analysis.get('relationship_level', '一般')}\n"
|
||
f" - 互动方式:{chat_analysis.get('interaction_style', '正式')}\n"
|
||
f" - 总消息数:{chat_analysis.get('total_messages', 0)}\n"
|
||
f" - 亲密度评分:{chat_analysis.get('intimacy_score', 0)}\n\n"
|
||
f"2) 深度分析:\n"
|
||
f" - 共同话题:{common_topics}\n"
|
||
f" - 情感关键词:{emotional_keywords}\n"
|
||
f" - 重要生活事件:{key_life_events}\n"
|
||
f" - 主要互动时间:{', '.join(active_hours) if active_hours else '未知'}"
|
||
)
|
||
|
||
prompt = f"""请根据以下详细信息,生成一份2025年蛇年新年祝福:
|
||
|
||
【联系人信息】
|
||
{contact_str}
|
||
|
||
【聊天记录分析】
|
||
{analysis_str}
|
||
|
||
【风格要求】
|
||
{style_prompt}
|
||
|
||
请生成以下内容,并以JSON格式返回:
|
||
1. greeting: 新年祝福寄语(50字左右)
|
||
- 包含2-3个具体互动数据(如消息数、默契值等)
|
||
- 描述3个日常相处场景,用动词短语呈现
|
||
- 用'从...到...'结构展现2组情感变化
|
||
- **给出富有特色的关系定位(如'职场损友')**
|
||
- 以温暖期许作结
|
||
- 语气活泼自然,突出陪伴与成长
|
||
- 总字数控制在50字左右
|
||
|
||
2. idioms: 新年祝福诗(两句,用英文逗号分隔)
|
||
- 每句7个汉字
|
||
- 第一句描写一个美好愿景或意象
|
||
- 第二句表达祝福或期许
|
||
- 整体要押韵,符合"意、形、神"统一
|
||
- 要融入分析出的情感关键词或生活事件
|
||
|
||
3. tags: 新年祝福成语(3个,用英文逗号分隔)
|
||
- 要选用喜庆祥和的成语
|
||
- 要与对方的生活状态和期望相呼应
|
||
- 成语之间要形成递进关系
|
||
|
||
4. wishes: 新岁寄语(30字左右)
|
||
- 要结合对方的生活事件和关注点
|
||
- 表达真挚美好的期望
|
||
- **以诗意笔触勾勒新年祝愿,融入对方生活际遇与心之所系,以婉约含蓄的文字传递真挚祝福,让文字如清泉般流淌,在对方心间激起涟漪**
|
||
|
||
要求:
|
||
1. 内容要体现高度个性化,充分利用聊天分析结果
|
||
2. 要严格遵循指定的风格要求
|
||
3. 整体风格要保持一致性
|
||
4. 要让对方感受到你对他/她的了解和关心
|
||
5. 要体现出诚意和温度
|
||
|
||
返回格式示例:
|
||
{{
|
||
"greeting": "新年祝福寄语...",
|
||
"idioms": "梦想飞扬似朝阳,岁岁安康伴春寒",
|
||
"tags": "前程似锦,蒸蒸日上,前程万里",
|
||
"wishes": "美好祝愿..."
|
||
}}"""
|
||
|
||
# 保存prompt到本地文件
|
||
try:
|
||
# 确保目录存在
|
||
os.makedirs('newYear/prompts', exist_ok=True)
|
||
|
||
# 生成文件名(使用时间戳和联系人ID)
|
||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||
filename = f"prompt_{timestamp}_{contact_info.get('wxid', 'unknown')}.txt"
|
||
filepath = os.path.join('newYear/prompts', filename)
|
||
|
||
# 保存文件
|
||
with open(filepath, 'w', encoding='utf-8') as f:
|
||
f.write(f"=== 生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ===\n\n")
|
||
f.write(prompt)
|
||
|
||
print(f"\nPrompt已保存至: {filepath}")
|
||
|
||
except Exception as e:
|
||
print(f"\nPrompt保存失败: {str(e)}")
|
||
|
||
return prompt
|
||
|
||
def _parse_response(self, response) -> Dict:
|
||
"""解析API响应内容
|
||
|
||
Args:
|
||
response: API响应内容
|
||
|
||
Returns:
|
||
Dict: 解析后的祝福内容
|
||
"""
|
||
try:
|
||
print("\n解析响应...")
|
||
content = response.choices[0].message.content
|
||
print("\n生成的原始内容:", content)
|
||
|
||
# 尝试解析JSON内容
|
||
try:
|
||
result = json.loads(content)
|
||
except json.JSONDecodeError:
|
||
# 如果解析失败,尝试提取内容中的JSON部分
|
||
import re
|
||
json_match = re.search(r'\{[\s\S]*\}', content)
|
||
if json_match:
|
||
result = json.loads(json_match.group())
|
||
else:
|
||
raise Exception("无法从响应中提取JSON内容")
|
||
|
||
# 验证必要的字段
|
||
required_fields = ['greeting', 'wishes', 'idioms', 'tags']
|
||
missing_fields = [field for field in required_fields if field not in result]
|
||
if missing_fields:
|
||
raise KeyError(f"生成的内容缺少必要字段: {', '.join(missing_fields)}")
|
||
|
||
|
||
return {
|
||
'greeting': result['greeting'],
|
||
'wishes': result['wishes'],
|
||
'idioms': result['idioms'],
|
||
'tags': result['tags']
|
||
}
|
||
|
||
except Exception as e:
|
||
raise Exception(f"响应内容解析失败:{str(e)}")
|
||
|
||
def test_generate_greeting(self) -> Tuple[bool, str, Dict]:
|
||
"""测试生成新年祝福内容
|
||
|
||
Returns:
|
||
Tuple[bool, str, Dict]: (是否成功, 错误信息, 生成的内容)
|
||
"""
|
||
try:
|
||
# 模拟联系人信息
|
||
contact_info = {
|
||
"wxid": "test_wxid_001",
|
||
"name": "张三",
|
||
"relationship": "好友"
|
||
}
|
||
|
||
# 模拟聊天记录
|
||
chat_history = [
|
||
{
|
||
"message": "今天工作怎么样?",
|
||
"is_sender": True,
|
||
"create_time": "2023-12-01 10:00:00"
|
||
},
|
||
{
|
||
"message": "还不错,项目进展顺利",
|
||
"is_sender": False,
|
||
"create_time": "2023-12-01 10:05:00"
|
||
},
|
||
{
|
||
"message": "周末要不要一起打球?",
|
||
"is_sender": True,
|
||
"create_time": "2023-12-01 10:10:00"
|
||
}
|
||
]
|
||
|
||
print("\n测试单个风格生成...")
|
||
# 只测试一个风格,简化测试
|
||
style_prompt = "温暖、亲切、感人的新年祝福,表达真挚的关心和美好祝愿"
|
||
|
||
try:
|
||
result = self.generate_greeting(
|
||
contact_info,
|
||
chat_history,
|
||
style_prompt
|
||
)
|
||
print("\n生成结果:")
|
||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||
return True, "测试完成", {"warm": result}
|
||
except Exception as e:
|
||
return False, f"生成失败: {str(e)}", {}
|
||
|
||
except Exception as e:
|
||
return False, f"测试失败:{str(e)}", {}
|
||
|
||
if __name__ == "__main__":
|
||
# 测试代码
|
||
import os
|
||
|
||
# 从环境变量获取API key
|
||
api_key = os.getenv("VOLCANO_API_KEY", "")
|
||
if not api_key:
|
||
print("请先设置环境变量 VOLCANO_API_KEY")
|
||
exit(1)
|
||
|
||
# 创建API实例
|
||
api = VolcanoAPI(api_key)
|
||
|
||
# 测试API连接
|
||
# print("\n=== 测试API连接 ===")
|
||
# success, message = api.test_connection()
|
||
# print(f"API测试结果: {'成功' if success else '失败'}")
|
||
# print(f"详细信息: {message}")
|
||
|
||
# if success:
|
||
# 测试生成祝福内容
|
||
print("\n=== 测试生成祝福内容 ===")
|
||
success, message, results = api.test_generate_greeting()
|
||
print(f"\n生成测试结果: {'成功' if success else '失败'}")
|
||
print(f"详细信息: {message}")
|
||
|
||
if success:
|
||
print("\n=== 生成的内容示例 ===")
|
||
# 选择一个风格的结果作为示例显示
|
||
example = results.get("warm", {})
|
||
if example:
|
||
print("\n新年祝福语:")
|
||
print(example.get("greeting", ""))
|
||
print("\n美好祝愿:")
|
||
print(example.get("wishes", ""))
|
||
print("\n祝福成语:")
|
||
print(example.get("idioms", "")) |