import traceback import datetime import random def generate_dialogue_with_swallow(history, message, affection, stage_name, scene_params, instruction=None, use_simple_prompt=False, swallow_model=None, tokenizer=None, SYSTEM_PROMPT_MARI=None): """ Swallowモデル(GGUF版)を使用して対話応答を生成する関数 Args: history: 会話履歴のリスト [(ユーザー発言, ボット応答), ...] message: 現在のユーザー発言 affection: 好感度の数値 stage_name: 関係ステージの名前 scene_params: シーンパラメータの辞書 instruction: 特別な指示(シーン遷移時など) use_simple_prompt: 簡潔なプロンプトを使用するかどうか swallow_model: Swallowモデル(llama-cpp)のインスタンス tokenizer: 未使用(llama-cppでは不要) SYSTEM_PROMPT_MARI: システムプロンプト Returns: 生成された応答テキスト """ # デバッグ情報を追加 print(f"generate_dialogue_with_swallow呼び出し: instruction={instruction}, use_simple_prompt={use_simple_prompt}") print(f"scene_params: {scene_params}") # モデルがロードされていない場合はフォールバック応答を返す if swallow_model is None: print("モデルがロードされていないため、フォールバック応答を返します") return "(……システムエラーが発生しました)" history_text = "\n".join([f"ユーザー: {u}\n麻理: {m}" for u, m in history]) task_prompt = f"指示: {instruction}" if instruction else f"ユーザー: {message}" if use_simple_prompt: # シーン遷移時には同じプロンプトを使用 system_prompt = f""" {SYSTEM_PROMPT_MARI} # 現在の状況 - 現在の好感度: {affection} - 現在の関係ステージ: {stage_name} - 性格: {scene_params.get("personality_mod", "特になし")} - 話し方のトーン: {scene_params.get("tone", "特になし")} # タスク {task_prompt} 麻理: """ else: # 通常会話時には完全なシステムプロンプトを使用 system_prompt = f""" {SYSTEM_PROMPT_MARI} # 現在の状況 - 現在の好感度: {affection} - 現在の関係ステージ: {stage_name} - 性格(シーン特有): {scene_params.get("personality_mod", "特になし")} - 話し方のトーン(シーン特有): {scene_params.get("tone", "特になし")} # 会話履歴 {history_text} --- # タスク {task_prompt} 麻理: """ print(f"Swallowモデルに応答生成をリクエストします (モード: {'シーン遷移' if instruction else '通常会話'}, 簡潔プロンプト: {use_simple_prompt})") print(f"プロンプト長: {len(system_prompt)}") try: # デバッグ情報を追加 print(f"Swallowモデル呼び出し開始...") print(f"システムプロンプト: {system_prompt[:100]}...(省略)") try: # llama-cppを使用して生成 output = swallow_model( system_prompt, max_tokens=200, temperature=0.95, top_p=0.9, stop=["ユーザー:", "\n\n"], echo=True # 入力プロンプトも含めて返す ) # 生成されたテキストを取得 generated_text = output["choices"][0]["text"] # プロンプトを除去して応答のみを取得 response_text = generated_text[len(system_prompt):].strip() print(f"Swallowモデル呼び出し成功") print(f"応答テキスト: {response_text}") return response_text except Exception as api_error: print(f"Swallowモデル呼び出しエラー: {api_error}") raise except Exception as e: print(f"応答生成エラー(Swallow): {e}") traceback.print_exc() # スタックトレースを出力 # エラー情報をログファイルに記録 with open("swallow_errors.log", "a") as f: f.write(f"時刻: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") f.write(f"例外発生: {e}\n") f.write(f"スタックトレース:\n") traceback.print_exc(file=f) f.write("\n") # フォールバック:シーン名に応じた自然な応答を返す if instruction and "に来た感想" in instruction: scene = instruction.split("に来た感想")[0] # シーンに応じたフォールバック応答のバリエーション scene_responses = { "aquarium_night": [ "(水槽の青い光に照らされた魚たちを見つめている)こんな時間に来ると、また違った雰囲気だな。", "(暗がりの中で光る魚たちを見て)夜の水族館か…意外と悪くないかも。", "(水槽に近づいて)夜になると、昼間とは違う魚が活動してるんだな。" ], "beach_sunset": [ "(夕日に照らされた海を見つめて)こんな景色、久しぶりに見たな…", "(砂浜に足跡をつけながら)夕暮れの海って、なんか落ち着くな。", "(波の音を聞きながら)この時間の浜辺は、人も少なくていいかも。" ], "festival_night": [ "(提灯の明かりを見上げて)意外と…悪くない雰囲気だな。", "(周囲の賑わいを見回して)こういう場所は、あまり来ないんだけどな…", "(屋台の匂いを感じて)なんか…懐かしい感じがするな。" ], "shrine_day": [ "(静かな境内を見回して)こういう静かな場所も、たまにはいいかも。", "(鳥居を見上げて)なんか、空気が違うな、ここは。", "(参道を歩きながら)静かで…落ち着くな。" ], "cafe_afternoon": [ "(窓の外を見ながら)こういう時間の過ごし方も、悪くないな。", "(コーヒーの香りを感じて)ここの雰囲気、悪くないな。", "(店内を見回して)意外と落ち着く場所だな、ここ。" ], "room_night": [ "(窓の外の夜景を見て)夜の景色って、なんか落ち着くな。", "(部屋の明かりを見つめて)こういう静かな時間も、たまにはいいかも。", "(窓際に立ち)夜の静けさって、考え事するのにちょうどいいな。" ] } # シーン名に応じた応答を選択(なければデフォルト応答) if scene in scene_responses: return random.choice(scene_responses[scene]) else: return f"({scene}の様子を静かに見回して)ここか…悪くない場所かもな。" else: return "(……何か言おうとしたけど、言葉に詰まった)"