| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- """
- 主动消息生成和发送服务
- """
- from typing import List, Dict
- from datetime import datetime, timedelta
- from sqlalchemy.ext.asyncio import AsyncSession
- from sqlalchemy import select
- from app.models.conversation import Message, Conversation, UserActivity
- from app.models.character import Character
- from app.models.affection import AffectionScore
- from app.services.llm_provider import get_llm_provider
- from app.core.security import decrypt_api_key
- import random
- class ProactiveMessageService:
- """主动消息服务"""
- @staticmethod
- async def generate_proactive_message(
- db: AsyncSession,
- conversation_id: int,
- affection_score: int,
- user_api_keys: Dict[str, str]
- ) -> str:
- """生成主动消息内容"""
- # 获取对话和角色信息
- result = await db.execute(
- select(Conversation, Character)
- .join(Character, Conversation.character_id == Character.id)
- .where(Conversation.id == conversation_id)
- )
- conv, character = result.one()
- # 获取最近对话历史
- recent_messages = await ProactiveMessageService._get_recent_messages(db, conversation_id, limit=5)
- # 构建提示词
- prompt = ProactiveMessageService._build_proactive_prompt(
- character, affection_score, recent_messages
- )
- # 调用AI生成消息
- provider = get_llm_provider(character.llm_provider)
- # 解密API Key
- encrypted_key = user_api_keys.get(character.llm_provider)
- if not encrypted_key:
- raise ValueError(f"用户未配置{character.llm_provider}平台的API Key")
- api_key = decrypt_api_key(encrypted_key)
- messages = [
- {"role": "system", "content": character.system_prompt},
- {"role": "user", "content": prompt}
- ]
- response = await provider.chat_completion(
- messages=messages,
- api_key=api_key,
- model=character.llm_model,
- temperature=character.config.get("temperature", 0.9),
- max_tokens=150 # 主动消息简短一些
- )
- return response.strip()
- @staticmethod
- async def _get_recent_messages(
- db: AsyncSession,
- conversation_id: int,
- limit: int = 5
- ) -> List[Message]:
- """获取最近的消息"""
- result = await db.execute(
- select(Message)
- .where(Message.conversation_id == conversation_id)
- .order_by(Message.created_at.desc())
- .limit(limit)
- )
- messages = result.scalars().all()
- return list(reversed(messages)) # 反转为时间正序
- @staticmethod
- def _build_proactive_prompt(
- character: Character,
- affection_score: int,
- recent_messages: List[Message]
- ) -> str:
- """构建主动消息生成提示"""
- # 格式化最近对话
- context = "\n".join([
- f"{'用户' if msg.role == 'user' else '我'}: {msg.content}"
- for msg in recent_messages[-3:] # 只用最近3条
- ])
- # 根据好感度选择消息类型
- if affection_score >= 95:
- message_type = "恋人之间的甜蜜问候或想念"
- elif affection_score >= 80:
- message_type = "挚友之间的关心或分享"
- elif affection_score >= 60:
- message_type = "朋友之间的友好问候"
- else:
- message_type = "熟人之间的礼貌问候"
- prompt = f"""
- 你是{character.name},当前与用户的好感度等级对应的亲密程度需要表现为:{message_type}。
- 最近对话内容:
- {context if context else "(还没有对话记录)"}
- 现在你想主动给用户发一条消息。要求:
- 1. 自然、不突兀,像真实的{character.name}一样
- 2. 可以提及之前的对话内容(如果有的话)
- 3. 根据好感度调整语气和内容的亲密程度
- 4. 30-50字以内
- 5. 不要重复说过的话
- 请直接生成消息内容:
- """
- return prompt
|