mari-chat-3 / core_sentiment.py
sirochild's picture
Upload 57 files
a73fa4e verified
"""
感情分析モジュール
ユーザーのメッセージから感情を分析し、好感度を更新する
"""
import logging
from typing import Optional
logger = logging.getLogger(__name__)
class SentimentAnalyzer:
"""感情分析を担当するクラス"""
def __init__(self):
self.analyzer = None
self._initialize_analyzer()
def _initialize_analyzer(self):
"""感情分析モデルの初期化"""
try:
# transformersが利用可能な場合は使用
from transformers import pipeline
self.analyzer = pipeline(
"sentiment-analysis",
model="koheiduck/bert-japanese-finetuned-sentiment"
)
logger.info("感情分析モデルのロード完了。")
except Exception as e:
logger.warning(f"感情分析モデルのロードに失敗、ルールベース分析を使用: {e}")
self.analyzer = None
def analyze_sentiment(self, message: str) -> Optional[str]:
"""メッセージの感情を分析する"""
if not isinstance(message, str) or len(message.strip()) == 0:
return None
# transformersが利用可能な場合
if self.analyzer:
try:
result = self.analyzer(message)[0]
label = result.get('label', '').upper()
# ラベルを統一形式に変換
if 'POSITIVE' in label:
return 'positive'
elif 'NEGATIVE' in label:
return 'negative'
else:
return 'neutral'
except Exception as e:
logger.error(f"感情分析エラー: {e}")
# フォールバック:ルールベース感情分析
return self._rule_based_sentiment(message)
def _rule_based_sentiment(self, message: str) -> str:
"""ルールベースの感情分析"""
positive_words = [
'ありがとう', 'うれしい', '嬉しい', '楽しい', '好き', '愛してる',
'素晴らしい', 'いい', '良い', 'すごい', '最高', '幸せ', '感謝',
'かわいい', '可愛い', '美しい', '優しい', '親切', '素敵'
]
negative_words = [
'嫌い', '悲しい', 'つらい', '辛い', '苦しい', '痛い', '怒り',
'むかつく', 'うざい', 'きらい', '最悪', 'だめ', 'ダメ',
'死ね', 'バカ', 'ばか', 'アホ', 'あほ', 'クソ', 'くそ'
]
message_lower = message.lower()
positive_count = sum(1 for word in positive_words if word in message_lower)
negative_count = sum(1 for word in negative_words if word in message_lower)
if positive_count > negative_count:
return 'positive'
elif negative_count > positive_count:
return 'negative'
else:
return 'neutral'
def update_affection(self, message: str, current_affection: int,
conversation_context: list = None) -> tuple:
"""
メッセージに基づいて好感度を更新する
Args:
message: ユーザーのメッセージ
current_affection: 現在の好感度
conversation_context: 会話の文脈(最近のメッセージ)
Returns:
(新しい好感度, 変化量, 変化理由)
"""
if not isinstance(current_affection, (int, float)):
current_affection = 30 # デフォルト値
sentiment = self.analyze_sentiment(message)
if not sentiment:
return current_affection, 0, "感情分析失敗"
# 基本的な感情に基づく変化量
base_change = 0
if sentiment == 'positive':
base_change = 3
elif sentiment == 'negative':
base_change = -3
else: # neutral
base_change = 0
# メッセージの特徴による調整
change_modifiers = []
# メッセージの長さによる調整
if len(message) > 100:
base_change = int(base_change * 1.3)
change_modifiers.append("長文")
elif len(message) > 50:
base_change = int(base_change * 1.1)
change_modifiers.append("中文")
# 特定のキーワードによる追加調整
positive_keywords = ['ありがとう', '感謝', '好き', '愛してる', '素晴らしい', 'かわいい', '美しい']
negative_keywords = ['嫌い', '死ね', 'バカ', 'アホ', 'クソ', 'うざい', 'きらい']
message_lower = message.lower()
# ポジティブキーワードのチェック
positive_count = sum(1 for word in positive_keywords if word in message_lower)
if positive_count > 0:
base_change += positive_count * 2
change_modifiers.append(f"ポジティブ語({positive_count})")
# ネガティブキーワードのチェック
negative_count = sum(1 for word in negative_keywords if word in message_lower)
if negative_count > 0:
base_change -= negative_count * 3
change_modifiers.append(f"ネガティブ語({negative_count})")
# 現在の好感度レベルによる調整
if current_affection < 20: # 敵対状態
if base_change > 0:
base_change = int(base_change * 0.5) # ポジティブな変化を抑制
change_modifiers.append("敵対状態")
elif current_affection > 80: # 親密状態
if base_change < 0:
base_change = int(base_change * 0.7) # ネガティブな変化を抑制
change_modifiers.append("親密状態")
# 会話の文脈による調整
if conversation_context and len(conversation_context) > 0:
recent_messages = conversation_context[-3:] # 最近の3メッセージ
context_sentiment_count = {'positive': 0, 'negative': 0, 'neutral': 0}
for ctx_msg in recent_messages:
if isinstance(ctx_msg, dict) and 'content' in ctx_msg:
ctx_sentiment = self.analyze_sentiment(ctx_msg['content'])
if ctx_sentiment:
context_sentiment_count[ctx_sentiment] += 1
# 連続したポジティブ/ネガティブメッセージの場合は効果を減衰
if sentiment == 'positive' and context_sentiment_count['positive'] >= 2:
base_change = int(base_change * 0.8)
change_modifiers.append("連続ポジティブ")
elif sentiment == 'negative' and context_sentiment_count['negative'] >= 2:
base_change = int(base_change * 0.8)
change_modifiers.append("連続ネガティブ")
# 最終的な好感度を計算
new_affection = current_affection + base_change
new_affection = max(0, min(100, new_affection)) # 0-100の範囲に制限
# 変化理由を生成
if base_change == 0:
reason = "中立的なメッセージ"
else:
reason = f"{sentiment}({base_change:+d})"
if change_modifiers:
reason += f" [{', '.join(change_modifiers)}]"
return new_affection, base_change, reason
def get_relationship_stage(self, affection: int) -> str:
"""好感度から関係性のステージを取得する"""
if not isinstance(affection, (int, float)):
affection = 30 # デフォルト値
if affection < 20:
return "敵対"
elif affection < 40:
return "中立"
elif affection < 60:
return "好意"
elif affection < 80:
return "親密"
else:
return "最接近"