import streamlit as st import os import json from datetime import datetime, timedelta import base64 import pandas as pd import pydeck as pdk from travel import ( destination_research_task, accommodation_task, transportation_task, activities_task, dining_task, itinerary_task, chatbot_task, run_task ) from geopy.geocoders import Nominatim # st.set_page_config()는 다른 Streamlit 함수보다 가장 먼저 실행되어야 합니다. st.set_page_config( page_title="Your AI Agent for Travelling", page_icon="✈️", layout="wide", initial_sidebar_state="expanded" ) # ------------------------------------------ # 다국어 지원을 위한 번역 사전 및 헬퍼 함수 # ------------------------------------------ translations = { "en": { "page_title": "Your AI Agent for Travelling", "header": "Your AI Agent for Travelling", "create_itinerary": "Create Your Itinerary", "trip_details": "Trip Details", "origin": "Origin", "destination": "Destination", "travel_dates": "Travel Dates", "duration": "Duration (days)", "preferences": "Preferences", "additional_preferences": "Additional Preferences", "interests": "Interests", "special_requirements": "Special Requirements", "submit": "🚀 Create My Personal Travel Itinerary", "request_details": "Your Travel Request", "from": "From", "when": "When", "budget": "Budget", "travel_style": "Travel Style", "live_agent_outputs": "Live Agent Outputs", "full_itinerary": "Full Itinerary", "details": "Details", "download_share": "Download & Share", "save_itinerary": "Save Your Itinerary", "plan_another_trip": "🔄 Plan Another Trip", "about": "About", "how_it_works": "How it works", "travel_agents": "Travel Agents", "share_itinerary": "Share Your Itinerary", "save_for_mobile": "Save for Mobile", "built_with": "Built with ❤️ for you", # 출력 관련 추가 텍스트 "itinerary_ready": "Your Travel Itinerary is Ready! 🎉", "personalized_experience": "We've created a personalized travel experience just for you. Explore your itinerary below.", "agent_activity": "Agent Activity", "error_origin_destination": "Please enter both origin and destination.", "your_itinerary_file": "Your Itinerary File", "text_format": "Text format - Can be opened in any text editor" }, "ko": { "page_title": "당신의 여행을 위한 AI 에이전트", "header": "당신의 여행을 위한 AI 에이전트", "create_itinerary": "여행 일정 생성", "trip_details": "여행 세부 정보", "origin": "출발지", "destination": "목적지", "travel_dates": "여행 날짜", "duration": "기간 (일수)", "preferences": "선호사항", "additional_preferences": "추가 선호사항", "interests": "관심사", "special_requirements": "특별 요구사항", "submit": "🚀 나만의 여행 일정 생성", "request_details": "여행 요청 정보", "from": "출발지", "when": "여행 기간", "budget": "예산", "travel_style": "여행 스타일", "live_agent_outputs": "실시간 에이전트 결과", "full_itinerary": "전체 일정", "details": "세부사항", "download_share": "다운로드 및 공유", "save_itinerary": "일정 저장", "plan_another_trip": "🔄 다른 여행 계획", "about": "소개", "how_it_works": "작동 방식", "travel_agents": "여행 에이전트", "share_itinerary": "일정 공유", "save_for_mobile": "모바일 저장", "built_with": "당신을 위해 ❤️ 만들어졌습니다", # 출력 관련 추가 텍스트 "itinerary_ready": "여행 일정이 준비되었습니다! 🎉", "personalized_experience": "당신만을 위한 맞춤형 여행 경험이 만들어졌습니다. 아래에서 일정을 확인하세요.", "agent_activity": "에이전트 활동", "error_origin_destination": "출발지와 목적지를 모두 입력하세요.", "your_itinerary_file": "당신의 여행 일정 파일", "text_format": "텍스트 형식 - 모든 텍스트 편집기에서 열 수 있습니다." }, "ja": { "page_title": "あなたの旅行のためのAIエージェント", "header": "あなたの旅行のためのAIエージェント", "create_itinerary": "旅行プラン作成", "trip_details": "旅行詳細", "origin": "出発地", "destination": "目的地", "travel_dates": "旅行日程", "duration": "期間(日数)", "preferences": "好み", "additional_preferences": "追加の好み", "interests": "興味", "special_requirements": "特別な要件", "submit": "🚀 私のための旅行プラン作成", "request_details": "旅行リクエスト", "from": "出発地", "when": "旅行期間", "budget": "予算", "travel_style": "旅行スタイル", "live_agent_outputs": "リアルタイムエージェント出力", "full_itinerary": "全行程", "details": "詳細", "download_share": "ダウンロードと共有", "save_itinerary": "旅行プランを保存", "plan_another_trip": "🔄 他の旅行を計画", "about": "概要", "how_it_works": "使い方", "travel_agents": "旅行エージェント", "share_itinerary": "旅行プランを共有", "save_for_mobile": "モバイル保存", "built_with": "愛を込めて作られました", # 출력 관련 추가 텍스트 "itinerary_ready": "旅行プランの準備ができました! 🎉", "personalized_experience": "あなたのためにパーソナライズされた旅行体験を作成しました。下のプランをご覧ください。", "agent_activity": "エージェントアクティビティ", "error_origin_destination": "出発地と目的地の両方を入力してください。", "your_itinerary_file": "あなたの旅行プランファイル", "text_format": "テキスト形式 - 任意のテキストエディタで開けます。" }, "zh": { "page_title": "您的旅行 AI 代理", "header": "您的旅行 AI 代理", "create_itinerary": "创建您的行程", "trip_details": "旅行详情", "origin": "出发地", "destination": "目的地", "travel_dates": "旅行日期", "duration": "天数", "preferences": "偏好", "additional_preferences": "其他偏好", "interests": "兴趣", "special_requirements": "特殊需求", "submit": "🚀 创建我的个性化行程", "request_details": "您的旅行请求", "from": "出发地", "when": "旅行时间", "budget": "预算", "travel_style": "旅行风格", "live_agent_outputs": "实时代理输出", "full_itinerary": "完整行程", "details": "详情", "download_share": "下载与分享", "save_itinerary": "保存行程", "plan_another_trip": "🔄 计划另一趟旅行", "about": "关于", "how_it_works": "工作原理", "travel_agents": "旅行代理", "share_itinerary": "分享行程", "save_for_mobile": "保存到手机", "built_with": "用❤️为您制作", # 출력 관련 추가 텍스트 "itinerary_ready": "您的旅行行程已准备就绪! 🎉", "personalized_experience": "我们已为您创建了个性化的旅行体验,请在下方查看您的行程。", "agent_activity": "代理活动", "error_origin_destination": "请输入出发地和目的地。", "your_itinerary_file": "您的行程文件", "text_format": "文本格式 - 可在任何文本编辑器中打开。" }, "es": { "page_title": " Tu Agente de IA para Viajar", "header": " Tu Agente de IA para Viajar", "create_itinerary": "Crea Tu Itinerario", "trip_details": "Detalles del Viaje", "origin": "Origen", "destination": "Destino", "travel_dates": "Fechas del Viaje", "duration": "Duración (días)", "preferences": "Preferencias", "additional_preferences": "Preferencias Adicionales", "interests": "Intereses", "special_requirements": "Requisitos Especiales", "submit": "🚀 Crea Mi Itinerario Personalizado", "request_details": "Tu Solicitud de Viaje", "from": "Desde", "when": "Cuándo", "budget": "Presupuesto", "travel_style": "Estilo de Viaje", "live_agent_outputs": "Salidas en Vivo del Agente", "full_itinerary": "Itinerario Completo", "details": "Detalles", "download_share": "Descargar y Compartir", "save_itinerary": "Guardar Itinerario", "plan_another_trip": "🔄 Planear Otro Viaje", "about": "Acerca de", "how_it_works": "Cómo Funciona", "travel_agents": "Agentes de Viaje", "share_itinerary": "Compartir Itinerario", "save_for_mobile": "Guardar para Móvil", "built_with": "Hecho con ❤️ para ti", # 출력 관련 추가 텍스트 "itinerary_ready": "¡Tu itinerario de viaje está listo! 🎉", "personalized_experience": "Hemos creado una experiencia de viaje personalizada solo para ti. Explora tu itinerario a continuación.", "agent_activity": "Actividad del Agente", "error_origin_destination": "Por favor, ingresa tanto el origen como el destino.", "your_itinerary_file": "Tu Archivo de Itinerario", "text_format": "Formato de texto - Se puede abrir en cualquier editor de texto." }, "fr": { "page_title": " Votre Agent IA pour Voyager", "header": " Votre Agent IA pour Voyager", "create_itinerary": "Créez Votre Itinéraire", "trip_details": "Détails du Voyage", "origin": "Origine", "destination": "Destination", "travel_dates": "Dates du Voyage", "duration": "Durée (jours)", "preferences": "Préférences", "additional_preferences": "Préférences Supplémentaires", "interests": "Centres d'intérêt", "special_requirements": "Exigences Spéciales", "submit": "🚀 Créez Mon Itinéraire Personnalisé", "request_details": "Votre Demande de Voyage", "from": "De", "when": "Quand", "budget": "Budget", "travel_style": "Style de Voyage", "live_agent_outputs": "Résultats en Direct de l'Agent", "full_itinerary": "Itinéraire Complet", "details": "Détails", "download_share": "Télécharger et Partager", "save_itinerary": "Enregistrer l'Itinéraire", "plan_another_trip": "🔄 Planifier un Autre Voyage", "about": "À Propos", "how_it_works": "Fonctionnement", "travel_agents": "Agents de Voyage", "share_itinerary": "Partager l'Itinéraire", "save_for_mobile": "Enregistrer pour Mobile", "built_with": "Conçu avec ❤️ pour vous", # 출력 관련 추가 텍스트 "itinerary_ready": "Votre itinéraire de voyage est prêt ! 🎉", "personalized_experience": "Nous avons créé une expérience de voyage personnalisée rien que pour vous. Découvrez votre itinéraire ci-dessous.", "agent_activity": "Activité de l'Agent", "error_origin_destination": "Veuillez saisir à la fois le lieu de départ et la destination.", "your_itinerary_file": "Votre Fichier d'Itinéraire", "text_format": "Format texte - Peut être ouvert dans n'importe quel éditeur de texte." }, "de": { "page_title": "Ihr KI-Reiseassistent", "header": " Ihr KI-Reiseassistent", "create_itinerary": "Erstellen Sie Ihre Reiseroute", "trip_details": "Reisedetails", "origin": "Abfahrtsort", "destination": "Zielort", "travel_dates": "Reisedaten", "duration": "Dauer (Tage)", "preferences": "Vorlieben", "additional_preferences": "Zusätzliche Vorlieben", "interests": "Interessen", "special_requirements": "Besondere Anforderungen", "submit": "🚀 Erstellen Sie meine personalisierte Reiseroute", "request_details": "Ihre Reiseanfrage", "from": "Von", "when": "Wann", "budget": "Budget", "travel_style": "Reisestil", "live_agent_outputs": "Live Agent Ausgaben", "full_itinerary": "Komplette Reiseroute", "details": "Details", "download_share": "Herunterladen & Teilen", "save_itinerary": "Reiseroute speichern", "plan_another_trip": "🔄 Plane eine weitere Reise", "about": "Über", "how_it_works": "Wie es funktioniert", "travel_agents": "Reiseassistenten", "share_itinerary": "Reiseroute teilen", "save_for_mobile": "Für Mobilgeräte speichern", "built_with": "Mit ❤️ für Sie gebaut", # 출력 관련 추가 텍스트 "itinerary_ready": "Ihre Reiseroute ist fertig! 🎉", "personalized_experience": "Wir haben eine personalisierte Reiseerfahrung nur für Sie erstellt. Entdecken Sie Ihre Reiseroute unten.", "agent_activity": "Agentenaktivität", "error_origin_destination": "Bitte geben Sie sowohl den Abfahrtsort als auch das Ziel ein.", "your_itinerary_file": "Ihre Reise-Datei", "text_format": "Textformat – Kann in jedem Texteditor geöffnet werden." }, "ar": { "page_title": " وكيل السفر الذكي الخاص بك", "header": " وكيل السفر الذكي الخاص بك", "create_itinerary": "إنشاء خط سير الرحلة", "trip_details": "تفاصيل الرحلة", "origin": "المغادرة من", "destination": "الوجهة", "travel_dates": "تواريخ السفر", "duration": "المدة (بالأيام)", "preferences": "التفضيلات", "additional_preferences": "تفضيلات إضافية", "interests": "الاهتمامات", "special_requirements": "المتطلبات الخاصة", "submit": "🚀 إنشاء خط سير الرحلة الشخصي", "request_details": "طلب السفر الخاص بك", "from": "من", "when": "متى", "budget": "الميزانية", "travel_style": "أسلوب السفر", "live_agent_outputs": "مخرجات الوكيل المباشرة", "full_itinerary": "خط سير الرحلة الكامل", "details": "التفاصيل", "download_share": "تنزيل ومشاركة", "save_itinerary": "حفظ خط سير الرحلة", "plan_another_trip": "🔄 خطط لرحلة أخرى", "about": "حول", "how_it_works": "كيف يعمل", "travel_agents": "وكلاء السفر", "share_itinerary": "شارك خط سير الرحلة", "save_for_mobile": "حفظ للهاتف المحمول", "built_with": "مصنوع بحب من أجلك", # 출력 관련 추가 텍스트 "itinerary_ready": "تم تجهيز خط سير رحلتك! 🎉", "personalized_experience": "لقد أنشأنا تجربة سفر مخصصة لك. استعرض خط سير رحلتك أدناه.", "agent_activity": "نشاط الوكيل", "error_origin_destination": "يرجى إدخال نقطة الانطلاق والوجهة.", "your_itinerary_file": "ملف خط سير رحلتك", "text_format": "تنسيق نصي - يمكن فتحه في أي محرر نصوص." } } def t(key): lang = st.session_state.get("selected_language", "en") return translations[lang].get(key, key) # --------------------------- # 세션 초기화 # --------------------------- if 'selected_language' not in st.session_state: st.session_state.selected_language = "en" # 기본은 영어 # ------------------------------------------ # 사이드바에 언어 선택 위젯 추가 # ------------------------------------------ with st.sidebar: language = st.selectbox( "Language / 언어 / 言語 / 语言 / Idioma / Langue / Sprache / اللغة", ["English", "한국어", "日本語", "中文", "Español", "Français", "Deutsch", "العربية"] ) lang_map = { "English": "en", "한국어": "ko", "日本語": "ja", "中文": "zh", "Español": "es", "Français": "fr", "Deutsch": "de", "العربية": "ar" } st.session_state.selected_language = lang_map.get(language, "en") # ------------------------------------------ # 이후 Streamlit UI 코드 시작 # ------------------------------------------ # Modern CSS with refined color scheme and sleek animations st.markdown(""" """, unsafe_allow_html=True) # Helper function to download HTML file def get_download_link(text_content, filename): b64 = base64.b64encode(text_content.encode()).decode() href = f'📥 {t("save_itinerary")}' return href # Updated helper function to display modern progress with a single UI element def display_modern_progress(current_step, total_steps=6): if 'progress_steps' not in st.session_state: st.session_state.progress_steps = { 0: {'status': 'pending', 'name': t("trip_details")}, 1: {'status': 'pending', 'name': t("about")}, 2: {'status': 'pending', 'name': t("travel_style")}, 3: {'status': 'pending', 'name': t("live_agent_outputs")}, 4: {'status': 'pending', 'name': t("download_share")}, 5: {'status': 'pending', 'name': t("full_itinerary")} } for i in range(total_steps): if i < current_step: st.session_state.progress_steps[i]['status'] = 'complete' elif i == current_step: st.session_state.progress_steps[i]['status'] = 'active' else: st.session_state.progress_steps[i]['status'] = 'pending' progress_percentage = (current_step / total_steps) * 100 st.progress(progress_percentage / 100) st.markdown("""
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) for i, step_info in st.session_state.progress_steps.items(): status = step_info['status'] name = step_info['name'] if status == 'complete': icon = "✅" status_class = "complete" elif status == 'active': icon = "🔄" status_class = "active" else: icon = "⭕" status_class = "pending" st.markdown(f"""
{icon} {name}
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) return progress_percentage def update_step_status(step_index, status): if 'progress_steps' in st.session_state and step_index in st.session_state.progress_steps: st.session_state.progress_steps[step_index]['status'] = status def run_task_with_logs(task, input_text, log_container, output_container, results_key=None): log_message = f"🤖 Starting {task.agent.role}..." st.session_state.log_messages.append(log_message) with log_container: st.markdown("### " + t("agent_activity")) for msg in st.session_state.log_messages: st.markdown(msg) result = run_task(task, input_text) if results_key: st.session_state.results[results_key] = result log_message = f"✅ {task.agent.role} completed!" st.session_state.log_messages.append(log_message) with log_container: st.markdown("### " + t("agent_activity")) for msg in st.session_state.log_messages: st.markdown(msg) with output_container: st.markdown(f"### {task.agent.role} Output") st.markdown("
" + result + "
", unsafe_allow_html=True) return result # ------------------------------------------ # Session state 초기화 # ------------------------------------------ if 'generated_itinerary' not in st.session_state: st.session_state.generated_itinerary = None if 'generation_complete' not in st.session_state: st.session_state.generation_complete = False if 'current_step' not in st.session_state: st.session_state.current_step = 0 if 'results' not in st.session_state: st.session_state.results = { "destination_info": "", "accommodation_info": "", "transportation_info": "", "activities_info": "", "dining_info": "", "itinerary": "", "final_itinerary": "" } if 'log_messages' not in st.session_state: st.session_state.log_messages = [] if 'current_output' not in st.session_state: st.session_state.current_output = None if 'form_submitted' not in st.session_state: st.session_state.form_submitted = False # Modern animated header st.markdown(f"""

{t("header")}

✨ Create your personalized AI-powered travel itinerary in minutes! ✨

""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) with st.sidebar: st.markdown("""

AI Agent X: Travelling

AI-Powered Travel Planning

""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) st.markdown("### 🌟 " + t("about")) st.info("This AI-powered tool creates a personalized travel itinerary based on your preferences. Fill in the form and let our specialized travel agents plan your perfect trip!") st.markdown('
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) st.markdown("### 🔍 " + t("how_it_works")) st.markdown("""
  1. 🖊️ Enter your travel details
  2. 🧠 AI analysis of your preferences
  3. 📋 Generate comprehensive itinerary
  4. 📥 Download and enjoy your trip!
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) st.markdown("### 🤖 Travel Agents") agents = [ ("🔭 Research Specialist", "Finds the best destinations based on your preferences"), ("🏨 Accommodation Expert", "Suggests suitable hotels and stays"), ("🚆 Transportation Planner", "Plans efficient travel routes"), ("🎯 Activities Curator", "Recommends activities tailored to your interests"), ("🍽️ Dining Connoisseur", "Finds the best dining experiences"), ("📅 Itinerary Creator", "Puts everything together in a daily plan") ] for name, desc in agents: st.markdown("**" + name + "**") st.markdown("" + desc + "", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) if not st.session_state.generation_complete: st.markdown('
', unsafe_allow_html=True) st.markdown("

✈️ " + t("create_itinerary") + "

", unsafe_allow_html=True) st.markdown("""

Complete the form below for a personalized travel plan.

""", unsafe_allow_html=True) with st.form("travel_form"): col1, col2 = st.columns(2) with col1: st.markdown('

Trip Details

', unsafe_allow_html=True) origin = st.text_input(t("origin"), placeholder="e.g., New York, USA") destination = st.text_input(t("destination"), placeholder="e.g., Paris, France") st.markdown('

Travel Dates

', unsafe_allow_html=True) start_date = st.date_input("Start Date", min_value=datetime.now(), label_visibility="collapsed") duration = st.slider(t("duration"), min_value=1, max_value=30, value=7) end_date = start_date + timedelta(days=duration-1) st.markdown('

' + start_date.strftime("%b %d") + " - " + end_date.strftime("%b %d, %Y") + '

', unsafe_allow_html=True) with col2: st.markdown('

Preferences

', unsafe_allow_html=True) travelers = st.number_input("Travelers", min_value=1, max_value=15, value=2) budget_options = ["Budget", "Moderate", "Luxury"] budget = st.selectbox("Budget", budget_options, help="Budget: Economy options | Moderate: Mid-range | Luxury: High-end experiences") travel_style = st.multiselect("🌈 Travel Style", options=["Culture", "Adventure", "Relaxation", "Food & Dining", "Nature", "Shopping", "Nightlife", "Family-friendly"], default=["Culture", "Food & Dining"]) with st.expander("Additional Preferences", expanded=False): preferences = st.text_area("Interests", placeholder="History museums, local cuisine, hiking, art...") special_requirements = st.text_area("Special Requirements", placeholder="Dietary restrictions, accessibility needs...") submit_button = st.form_submit_button(t("submit")) st.markdown('
', unsafe_allow_html=True) if submit_button: if not origin or not destination: st.error(t("error_origin_destination")) else: st.session_state.form_submitted = True st.session_state.destination = destination # 목적지를 session_state에 저장 user_input = { "origin": origin, "destination": destination, "duration": str(duration), "travel_dates": f"{start_date.strftime('%Y-%m-%d')} to {end_date.strftime('%Y-%m-%d')}", "travelers": str(travelers), "budget": budget.lower(), "travel_style": ", ".join(travel_style), "preferences": preferences, "special_requirements": special_requirements } st.session_state.user_input = user_input # 저장하여 이후 지도에 활용 # 기존의 여행 요청 프롬프트 input_context = f"""Travel Request Details: Origin: {user_input['origin']} Destination: {user_input['destination']} Duration: {user_input['duration']} days Travel Dates: {user_input['travel_dates']} Travelers: {user_input['travelers']} Budget Level: {user_input['budget']} Travel Style: {user_input['travel_style']} Preferences/Interests: {user_input['preferences']} Special Requirements: {user_input['special_requirements']} """ # LLM에 전달할 프롬프트에 언어 지시문 추가 llm_language_instructions = { "en": "Please output the response in English.", "ko": "한국어로 출력해 주세요.", "ja": "日本語で出力してください。", "zh": "请用中文输出。", "es": "Por favor, responda en español.", "fr": "Veuillez répondre en français.", "de": "Bitte antworten Sie auf Deutsch.", "ar": "يرجى الرد باللغة العربية." } selected_lang = st.session_state.get("selected_language", "en") language_instruction = llm_language_instructions.get(selected_lang, "Please output the response in English.") modified_input_context = language_instruction + "\n" + input_context st.markdown("""
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) progress_tab, logs_tab, details_tab = st.tabs(["📊 Progress", "🔄 Live Activity", "📋 " + t("request_details")]) with details_tab: st.markdown("#### " + t("request_details")) st.markdown("**" + t("destination") + ":** " + user_input['destination']) st.markdown("**" + t("from") + ":** " + user_input['origin']) st.markdown("**" + t("when") + ":** " + user_input['travel_dates'] + " (" + user_input['duration'] + " days)") st.markdown("**" + t("budget") + ":** " + user_input['budget'].title()) st.markdown("**" + t("travel_style") + ":** " + user_input['travel_style']) if user_input['preferences']: st.markdown("**Interests:** " + user_input['preferences']) if user_input['special_requirements']: st.markdown("**Special Requirements:** " + user_input['special_requirements']) with progress_tab: if 'progress_placeholder' not in st.session_state: st.session_state.progress_placeholder = st.empty() with st.session_state.progress_placeholder.container(): display_modern_progress(st.session_state.current_step) with logs_tab: log_container = st.container() st.session_state.log_messages = [] st.markdown('
', unsafe_allow_html=True) output_container = st.container() with output_container: st.markdown('
', unsafe_allow_html=True) st.markdown("### 🌟 " + t("live_agent_outputs")) st.info("Our AI agents will show their work here as they create your itinerary") st.markdown('
', unsafe_allow_html=True) st.session_state.current_step = 0 update_step_status(0, 'active') with st.session_state.progress_placeholder.container(): display_modern_progress(st.session_state.current_step) destination_info = run_task_with_logs( destination_research_task, modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']), log_container, output_container, "destination_info" ) update_step_status(0, 'complete') st.session_state.current_step = 1 update_step_status(1, 'active') with st.session_state.progress_placeholder.container(): display_modern_progress(st.session_state.current_step) accommodation_info = run_task_with_logs( accommodation_task, modified_input_context.format(destination=user_input['destination'], budget=user_input['budget'], preferences=user_input['preferences']), log_container, output_container, "accommodation_info" ) update_step_status(1, 'complete') st.session_state.current_step = 2 update_step_status(2, 'active') with st.session_state.progress_placeholder.container(): display_modern_progress(st.session_state.current_step) transportation_info = run_task_with_logs( transportation_task, modified_input_context.format(origin=user_input['origin'], destination=user_input['destination']), log_container, output_container, "transportation_info" ) update_step_status(2, 'complete') st.session_state.current_step = 3 update_step_status(3, 'active') with st.session_state.progress_placeholder.container(): display_modern_progress(st.session_state.current_step) activities_info = run_task_with_logs( activities_task, modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']), log_container, output_container, "activities_info" ) update_step_status(3, 'complete') st.session_state.current_step = 4 update_step_status(4, 'active') with st.session_state.progress_placeholder.container(): display_modern_progress(st.session_state.current_step) dining_info = run_task_with_logs( dining_task, modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']), log_container, output_container, "dining_info" ) update_step_status(4, 'complete') st.session_state.current_step = 5 update_step_status(5, 'active') with st.session_state.progress_placeholder.container(): display_modern_progress(st.session_state.current_step) combined_info = f"""{input_context} Destination Information: {destination_info} Accommodation Options: {accommodation_info} Transportation Plan: {transportation_info} Recommended Activities: {activities_info} Dining Recommendations: {dining_info} """ itinerary = run_task_with_logs( itinerary_task, combined_info.format(duration=user_input['duration'], origin=user_input['origin'], destination=user_input['destination']), log_container, output_container, "itinerary" ) update_step_status(5, 'complete') st.session_state.current_step = 6 with st.session_state.progress_placeholder.container(): display_modern_progress(st.session_state.current_step) st.session_state.generated_itinerary = itinerary st.session_state.generation_complete = True date_str = datetime.now().strftime("%Y-%m-%d") st.session_state.filename = f"{user_input['destination'].replace(' ', '_')}_{date_str}_itinerary.txt" if st.session_state.generation_complete: st.markdown("""

""" + t("itinerary_ready") + """

""" + t("personalized_experience") + """

""", unsafe_allow_html=True) # 탭 생성 (챗봇 탭 포함) itinerary_tab, details_tab, download_tab, map_tab, chatbot_tab = st.tabs([ "🗒️ " + t("full_itinerary"), "💼 " + t("details"), "💾 " + t("download_share"), "🗺️ 지도 및 시각화", "🤖 챗봇 인터페이스" ]) # 일정 탭 with itinerary_tab: st.text_area("Your Itinerary", st.session_state.generated_itinerary, height=600) # 상세 정보 탭 with details_tab: agent_tabs = st.tabs(["🌎 Destination", "🏨 Accommodation", "🚗 Transportation", "🎭 Activities", "🍽️ Dining"]) with agent_tabs[0]: st.markdown("### 🌎 Destination Research") st.markdown(st.session_state.results["destination_info"]) with agent_tabs[1]: st.markdown("### 🏨 Accommodation Options") st.markdown(st.session_state.results["accommodation_info"]) with agent_tabs[2]: st.markdown("### 🚗 Transportation Plan") st.markdown(st.session_state.results["transportation_info"]) with agent_tabs[3]: st.markdown("### 🎭 Recommended Activities") st.markdown(st.session_state.results["activities_info"]) with agent_tabs[4]: st.markdown("### 🍽️ Dining Recommendations") st.markdown(st.session_state.results["dining_info"]) # 다운로드 및 공유 탭 with download_tab: col1, col2 = st.columns([2, 1]) with col1: st.markdown("### " + t("save_itinerary")) st.markdown("Download your personalized travel plan to access it offline or share with your travel companions.") st.markdown("""

""" + t("your_itinerary_file") + """

""" + t("text_format") + """

""", unsafe_allow_html=True) st.markdown("
" + get_download_link(st.session_state.generated_itinerary, st.session_state.filename) + "
", unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) st.markdown("### " + t("share_itinerary")) st.markdown("*Coming soon: Email your itinerary or share via social media.*") with col2: st.markdown("### " + t("save_for_mobile")) st.markdown("*Coming soon: QR code for easy access on your phone*") # 지도 및 시각화 탭 with map_tab: st.markdown("### 목적지 지도") # session_state에서 목적지 값을 가져옵니다. (없을 경우 기본값 "Paris") dest = st.session_state.get("destination", "Paris") # 지오코딩을 통해 위도, 경도 구하기 try: geolocator = Nominatim(user_agent="travel_app") location = geolocator.geocode(dest) if location: lat, lon = location.latitude, location.longitude else: st.error("입력하신 목적지를 찾을 수 없습니다. 기본 좌표를 사용합니다.") lat, lon = 48.8566, 2.3522 # Paris 기본값 except Exception as e: st.error("지오코딩 오류 발생: " + str(e)) lat, lon = 48.8566, 2.3522 # 지도 데이터 생성 (필요시 목적지 주변 명소 데이터를 동적으로 생성 가능) map_data = pd.DataFrame({ "lat": [lat], "lon": [lon], "name": [dest] }) st.map(map_data) st.markdown("#### Pydeck을 활용한 인터랙티브 지도 예시") layer = pdk.Layer( "ScatterplotLayer", data=map_data, get_position='[lon, lat]', get_color='[200, 30, 0, 160]', get_radius=200, ) view_state = pdk.ViewState( latitude=lat, longitude=lon, zoom=12, pitch=50, ) deck_chart = pdk.Deck(layers=[layer], initial_view_state=view_state) st.pydeck_chart(deck_chart) # 챗봇 인터페이스 탭 (Clear 버튼 제거됨) with chatbot_tab: st.markdown("### AI 챗봇 인터페이스") # 대화 기록을 세션 상태에 저장 (메시지, 발신자, 타임스탬프) if "chat_history" not in st.session_state: st.session_state.chat_history = [] # 사용자 입력창 및 전송 버튼 user_message = st.text_input("메시지를 입력하세요:", key="chat_input") if st.button("전송", key="send_button"): if user_message: # 제미나이 기반 챗봇 응답: run_task()를 활용하여 chatbot_task에 질의 response = run_task(chatbot_task, user_message) st.session_state.chat_history.append({ "speaker": "사용자", "message": user_message, "time": datetime.now() }) st.session_state.chat_history.append({ "speaker": "AI", "message": response, "time": datetime.now() }) # 대화 기록 출력 (타임스탬프 포함, 스크롤 가능한 영역) st.markdown("
", unsafe_allow_html=True) for chat in st.session_state.chat_history: time_str = chat["time"].strftime("%H:%M:%S") st.markdown(f"**{chat['speaker']}** ({time_str}): {chat['message']}") st.markdown("
", unsafe_allow_html=True) st.markdown("""

""" + t("built_with") + """

""", unsafe_allow_html=True)