"""
好感度计算和管理服务
"""
from typing import Dict, Optional
from datetime import datetime
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update
from app.models.affection import AffectionScore, AffectionLog
from app.models.conversation import Message
import random
import json
# 好感度等级定义
AFFECTION_LEVELS = {
"厌恶": (-100, -60),
"陌生": (-60, -20),
"普通": (-20, 20),
"熟人": (20, 50),
"朋友": (50, 80),
"挚友": (80, 95),
"恋人": (95, 101), # 101是上限
}
def get_affection_level(score: int) -> str:
"""根据分数获取好感度等级"""
for level, (min_score, max_score) in AFFECTION_LEVELS.items():
if min_score <= score < max_score:
return level
return "恋人" # 满分
def get_next_level_score(current_score: int) -> Optional[int]:
"""获取下一等级所需分数"""
current_level = get_affection_level(current_score)
level_names = list(AFFECTION_LEVELS.keys())
if current_level == "恋人":
return None # 已达最高等级
current_index = level_names.index(current_level)
next_level = level_names[current_index + 1]
return AFFECTION_LEVELS[next_level][0]
class AffectionService:
"""好感度服务"""
@staticmethod
async def get_or_create_affection(
db: AsyncSession,
user_id: int,
character_id: int
) -> AffectionScore:
"""获取或创建好感度记录"""
result = await db.execute(
select(AffectionScore).where(
AffectionScore.user_id == user_id,
AffectionScore.character_id == character_id
)
)
affection = result.scalar_one_or_none()
if not affection:
affection = AffectionScore(
user_id=user_id,
character_id=character_id,
current_score=0,
level="普通"
)
db.add(affection)
await db.commit()
await db.refresh(affection)
return affection
@staticmethod
async def update_affection(
db: AsyncSession,
affection_id: int,
score_change: int,
reason: str,
message_id: Optional[int] = None,
sentiment_data: Optional[Dict] = None
):
"""更新好感度"""
# 获取当前好感度
result = await db.execute(
select(AffectionScore).where(AffectionScore.id == affection_id)
)
affection = result.scalar_one()
# 计算新分数(限制在-100到100之间)
new_score = max(-100, min(100, affection.current_score + score_change))
new_level = get_affection_level(new_score)
# 更新好感度
await db.execute(
update(AffectionScore)
.where(AffectionScore.id == affection_id)
.values(
current_score=new_score,
level=new_level,
last_interaction=datetime.now(),
total_interactions=AffectionScore.total_interactions + 1
)
)
# 创建变化记录
log = AffectionLog(
affection_score_id=affection_id,
message_id=message_id,
score_change=score_change,
reason=reason,
sentiment_analysis=sentiment_data
)
db.add(log)
await db.commit()
return new_score, new_level
@staticmethod
def analyze_sentiment_from_ai_response(ai_response: str) -> Dict:
"""
从AI回复中提取情感分析结果
AI回复格式应包含:{"affection_change": 3, "reason": "..."}
"""
try:
# 查找标签
start = ai_response.find("")
end = ai_response.find("")
if start != -1 and end != -1:
sentiment_json = ai_response[start + 11:end]
sentiment_data = json.loads(sentiment_json)
# 提取纯文本内容(去除sentiment标签)
clean_content = ai_response[:start] + ai_response[end + 12:]
return {
"content": clean_content.strip(),
"affection_change": sentiment_data.get("affection_change", 0),
"reason": sentiment_data.get("reason", ""),
"sentiment_data": sentiment_data
}
except Exception as e:
# 解析失败,使用默认值
pass
# 默认返回
return {
"content": ai_response,
"affection_change": 1, # 默认+1
"reason": "正常对话",
"sentiment_data": {}
}
def calculate_proactive_interval(affection_score: int) -> Optional[int]:
"""
根据好感度计算主动消息间隔(分钟)
返回:随机间隔的分钟数,如果不应发送则返回None
"""
if affection_score >= 90:
return random.randint(1, 10) # 1-10分钟
elif affection_score >= 80:
return random.randint(10, 30) # 10-30分钟
elif affection_score >= 60:
return random.randint(30, 120) # 0.5-2小时
elif affection_score >= 40:
return random.randint(120, 360) # 2-6小时
else:
return None # 不发送
def should_send_proactive(affection_score: int, minutes_idle: int) -> bool:
"""判断是否应该发送主动消息"""
if affection_score >= 90 and minutes_idle >= 3:
return True
elif affection_score >= 80 and minutes_idle >= 10:
return True
elif affection_score >= 60 and minutes_idle >= 30:
return True
elif affection_score >= 40 and minutes_idle >= 120:
return True
return False