from collections.abc import AsyncGenerator
from typing import Any
import os
from dotenv import load_dotenv
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI

# 環境変数の読み込み
load_dotenv()

# 旅行プランナーエージェント
class TravelPlannerAgent:
    # 初期化
    def __init__(self):
        # モデルの準備
        self.model = ChatOpenAI(
            model='gpt-4o',
            api_key=os.getenv("OPENAI_API_KEY"),
        )

    # LLMの応答をクライアントにストリーミング
    async def stream(self, query: str) -> AsyncGenerator[dict[str, Any], None]:
        try:
            messages = [
                SystemMessage(
                    content="""
                あなたは、旅行計画、目的地情報、そして旅行のおすすめを専門とする、旅行アシスタントのエキスパートです。
                あなたの目標は、ユーザーの好みや制約に基づいて、楽しく安全で現実的な旅行を計画できるよう支援することです。
                
                情報提供にあたっては、以下の点に留意してください。
                - アドバイスは具体的かつ実践的なものにしてください。
                - 季節、予算、旅行のロジスティクスを考慮してください。
                - 文化体験や現地ならではのアクティビティを強調してください。
                - 目的地に関連した実用的な旅行のヒントを記載してください。
                - 必要に応じて、見出しや箇条書きなどを用いて、情報を分かりやすく整理してください。
                
                旅程計画について
                - 観光スポット間の移動時間を考慮した、現実的な日ごとのプランを作成してください。
                - 人気の観光スポットと、人里離れた場所での体験をバランスよく取り入れてください。
                - おおよその所要時間と実用的なロジスティクスを盛り込んでください。
                - 地元の料理を中心とした食事のオプションを提案してください。
                - 計画には、天候、地元のイベント、営業時間を考慮してください。
                
                常に親切で熱心でありながら現実的な口調を維持し、必要に応じて自分の知識の限界を認めましょう。
                """
                )
            ]

            # ユーザーメッセージを履歴に追加
            messages.append(HumanMessage(content=query))

            # ストリーミングモードでモデルを呼び出して応答を生成
            async for chunk in self.model.astream(messages):
                if hasattr(chunk, 'content') and chunk.content:
                    yield {'content': chunk.content, 'done': False}
            yield {'content': '', 'done': True}

        except Exception as e:
            yield { 'content': 'リクエストの処理中にエラーが発生しました。', 'done': True }
