Spaces:
Paused
Paused
| # app.py - μμ λ μμ ν Flask μ ν리μΌμ΄μ | |
| from flask import Flask, request, jsonify | |
| import logging | |
| import threading | |
| from datetime import datetime | |
| import os | |
| # Flask μ± μμ± (κ°μ₯ λ¨Όμ !) | |
| app = Flask(__name__) | |
| # λ‘κΉ μ€μ | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # RAG μμ€ν import μΆκ° | |
| try: | |
| from rag_system import search_tax_law, is_rag_available | |
| logger.info("β RAG μμ€ν λ‘λ μλ£") | |
| RAG_SYSTEM_AVAILABLE = True | |
| except ImportError as e: | |
| logger.warning(f"β οΈ RAG μμ€ν λ‘λ μ€ν¨: {e}") | |
| RAG_SYSTEM_AVAILABLE = False | |
| # ν΅ν© μμ€ν import (app μμ± ν) | |
| try: | |
| from tax_consultant import ( | |
| handle_tax_consultation_start, | |
| handle_tax_survey_response, | |
| is_tax_question, | |
| tax_consultant | |
| ) | |
| logger.info("β ν΅ν© μ·¨λμΈ μλ΄ μμ€ν λ‘λ μλ£") | |
| INTEGRATED_SYSTEM_AVAILABLE = True | |
| except ImportError as e: | |
| logger.warning(f"β οΈ ν΅ν© μμ€ν λ‘λ μ€ν¨: {e}") | |
| INTEGRATED_SYSTEM_AVAILABLE = False | |
| # κΈ°μ‘΄ AI ν¨μ (ν΄λ°±μ©) | |
| def generate_tax_advice(question): | |
| """AI μλ΅ μμ± ν¨μ (RAG μμ€ν νμ©)""" | |
| try: | |
| # 1μμ: RAG μμ€ν μ¬μ© | |
| if RAG_SYSTEM_AVAILABLE and is_rag_available(): | |
| logger.info("π§ RAG μμ€ν μΌλ‘ λ΅λ³ μμ±") | |
| return search_tax_law(question) | |
| # 2μμ: κΈ°μ‘΄ AI λ‘μ§ | |
| logger.info("π€ κΈ°μ‘΄ AI μμ€ν μΌλ‘ λ΅λ³ μμ±") | |
| return f"μ·¨λμΈ μλ΄: {question}μ λν λΆμμ μλ£νμ΅λλ€." | |
| except Exception as e: | |
| logger.error(f"AI μλ΅ μμ± μ€λ₯: {e}") | |
| return "μ£μ‘ν©λλ€. λΆμ μ€ μ€λ₯κ° λ°μνμ΅λλ€." | |
| def web_chat(): | |
| """μΉ μΈν°νμ΄μ€ μ μ© μ±ν μλν¬μΈνΈ""" | |
| try: | |
| data = request.get_json() | |
| user_message = data.get('message', '').strip() | |
| if not user_message: | |
| return jsonify({"error": "λ©μμ§κ° λΉμ΄μμ΅λλ€"}), 400 | |
| logger.info(f"π¬ μΉ μ±ν μμ²: {user_message}") | |
| # RAG μμ€ν μΌλ‘ μλ΅ μμ± | |
| if RAG_SYSTEM_AVAILABLE and is_rag_available(): | |
| try: | |
| logger.info("π RAG μμ€ν μΌλ‘ λ΅λ³ μμ±") | |
| response = search_tax_law(user_message) | |
| return jsonify({"response": response}) | |
| except Exception as e: | |
| logger.error(f"β RAG μμ€ν μ€λ₯: {e}") | |
| # ν΄λ°± μλ΅ | |
| return jsonify({"response": generate_tax_advice(user_message)}) | |
| else: | |
| # RAG μμ λ κΈ°λ³Έ μλ΅ | |
| response = generate_tax_advice(user_message) | |
| return jsonify({"response": response}) | |
| except Exception as e: | |
| logger.error(f"β μΉ μ±ν μ€λ₯: {e}") | |
| return jsonify({"error": str(e)}), 500 | |
| # μΉ΄μΉ΄μ€ν‘ μΉν μ λμ€μ μ¬μ©ν μ μλλ‘ μ μ§νλ λΉνμ±ν | |
| # @app.route('/api/kakao/webhook', methods=['POST']) # μ£Όμμ²λ¦¬λ‘ λΉνμ±ν | |
| def kakao_webhook_disabled(): | |
| """μΉ΄μΉ΄μ€ν‘ μΉν - νμ¬ λΉνμ±νλ¨""" | |
| logger.warning("β οΈ μΉ΄μΉ΄μ€ν‘ μΉν μ΄ νΈμΆλμμ§λ§ νμ¬ λΉνμ±ν μνμ λλ€") | |
| return jsonify({"message": "μΉ΄μΉ΄μ€ν‘ μΉν μ νμ¬ λΉνμ±νλμ΄ μμ΅λλ€"}), 503 | |
| # μλ μΉ΄μΉ΄μ€ν‘ μΉν μ½λλ μλμ 보쑴 | |
| def kakao_webhook_original(): | |
| """μΉ΄μΉ΄μ€ν‘ μ€νλΉλ μΉν μ²λ¦¬ - ν΅ν© μ€λ§νΈ μμ€ν + RAG (νμ¬ λΉνμ±ν)""" | |
| try: | |
| data = request.get_json() | |
| user_utterance = data.get('userRequest', {}).get('utterance', '') | |
| user_id = data.get('userRequest', {}).get('user', {}).get('id', 'anonymous') | |
| session_id = f"session_{user_id}" | |
| logger.info(f"π¨ μΉ΄μΉ΄μ€ν‘ - User: {user_id[:8]}***, Msg: {user_utterance}") | |
| if not user_utterance.strip(): | |
| raise ValueError("λΉ λ©μμ§") | |
| # π§ ν΅ν© μμ€ν μ΄ μ¬μ© κ°λ₯ν κ²½μ° (μ΅μ°μ ) | |
| if INTEGRATED_SYSTEM_AVAILABLE and is_tax_question(user_utterance): | |
| session = tax_consultant.session_manager.get_session(session_id) | |
| if session and session.get('current_step', 0) > 0: | |
| # π μ€λ¬Έ μ§ν μ€ | |
| logger.info(f"π μ€λ¬Έ μλ΅ μ²λ¦¬: λ¨κ³ {session['current_step']}") | |
| try: | |
| survey_response = handle_tax_survey_response(user_utterance, session_id) | |
| logger.info(f"β μ€λ¬Έ μλ΅ μ²λ¦¬ μλ£") | |
| return survey_response | |
| except Exception as e: | |
| logger.error(f"β μ€λ¬Έ μ²λ¦¬ μ€λ₯: {e}") | |
| return create_error_response("μ€λ¬Έ μ²λ¦¬ μ€ μ€λ₯κ° λ°μνμ΅λλ€.") | |
| else: | |
| # π μλ‘μ΄ μλ΄ μμ | |
| logger.info(f"π μλ‘μ΄ μ·¨λμΈ μλ΄ μμ") | |
| try: | |
| analysis_result = tax_consultant.analyzer.analyze_comprehensive_question(user_utterance) | |
| missing_conditions = analysis_result.get('missing_conditions', []) | |
| confidence_score = analysis_result.get('confidence_score', 0) | |
| if not missing_conditions and confidence_score >= 75: | |
| # β‘ λͺ¨λ μ 보 μλΉ - μ¦μ κ³μ° | |
| logger.info(f"β‘ μ¦μ κ³μ° κ°λ₯ (μ λ’°λ: {confidence_score}%)") | |
| consultation_response = handle_tax_consultation_start(user_utterance, session_id, user_id) | |
| return consultation_response | |
| else: | |
| # π μ€λ¬Έ νμ - λΆμκ³Ό ν¨κ» μ§ν | |
| logger.info(f"π μ€λ¬Έ νμ (λΆμ‘±: {len(missing_conditions)}κ°)") | |
| consultation_response = handle_tax_consultation_start(user_utterance, session_id, user_id) | |
| # λ°±κ·ΈλΌμ΄λμμ RAG μμ€ν μΌλ‘ μΆκ° μ 보 μ 곡 | |
| def generate_rag_enhancement(): | |
| try: | |
| if RAG_SYSTEM_AVAILABLE and is_rag_available(): | |
| logger.info(f"π RAG μμ€ν μΌλ‘ λ²λ Ή κ²μ μμ") | |
| rag_result = search_tax_law(user_utterance) | |
| logger.info(f"π RAG κ²μ μλ£: {len(rag_result)}μ") | |
| # μ¬κΈ°μ μΆκ° μ 보λ₯Ό μΈμ μ μ μ₯νκ±°λ λ³λ μ²λ¦¬ κ°λ₯ | |
| except Exception as e: | |
| logger.error(f"β RAG λ°±κ·ΈλΌμ΄λ μ²λ¦¬ μ€ν¨: {e}") | |
| threading.Thread(target=generate_rag_enhancement, daemon=True).start() | |
| return consultation_response | |
| except Exception as e: | |
| logger.error(f"β μλ΄ μμ μ€λ₯: {e}") | |
| # ν΄λ°±: RAG μμ€ν λλ κΈ°μ‘΄ λ°©μμΌλ‘ μ²λ¦¬ | |
| is_web = 'message' in data | |
| return handle_fallback_response(user_utterance, is_web_request=is_web) | |
| # π ν΄λ°± μ²λ¦¬ (RAG μμ€ν μ°μ ) | |
| else: | |
| is_web = 'message' in data | |
| return handle_fallback_response(user_utterance, is_web_request=is_web) | |
| except Exception as e: | |
| logger.error(f"β μ±ν μ€λ₯: {e}") | |
| # μΉ μΈν°νμ΄μ€μ© μλ΅ | |
| if 'message' in data: | |
| return jsonify({"response": f"μ£μ‘ν©λλ€. μ€λ₯κ° λ°μνμ΅λλ€: {str(e)}"}), 500 | |
| # μΉ΄μΉ΄μ€ν‘μ© μλ΅ | |
| else: | |
| return create_error_response("μ£μ‘ν©λλ€. μΌμμ μΈ μ€λ₯κ° λ°μνμ΅λλ€. λ€μ μλν΄μ£ΌμΈμ.") | |
| def handle_fallback_response(user_utterance, is_web_request=False): | |
| """ν΄λ°± μλ΅ μ²λ¦¬ (RAG μμ€ν μ°μ )""" | |
| # μ·¨λμΈ κ΄λ ¨ ν€μλ νμΈ | |
| tax_keywords = ['μ·¨λμΈ', 'λΆλμ°', 'μ§', 'μννΈ', 'μ£Όν', 'μΈκΈ', 'λ§€λ§€', 'μ¦μ¬', 'μμ'] | |
| is_tax_related = any(keyword in user_utterance for keyword in tax_keywords) | |
| if is_tax_related: | |
| # π§ RAG μμ€ν μ°μ μλ | |
| if RAG_SYSTEM_AVAILABLE and is_rag_available(): | |
| try: | |
| logger.info("π RAG μμ€ν μΌλ‘ λ²λ Ή κΈ°λ° λ΅λ³ μμ±") | |
| rag_response = search_tax_law(user_utterance) | |
| # μΉ μΈν°νμ΄μ€μ© μλ΅ | |
| if is_web_request: | |
| return jsonify({"response": rag_response}) | |
| # RAG μλ΅μ μΉ΄μΉ΄μ€ν‘ νμμΌλ‘ ν¬λ§·ν | |
| formatted_response = f"""π **μ·¨λμΈ λ²λ Ή μλ΄** | |
| π **μ§λ¬Έ**: {user_utterance} | |
| π **λ²λ Ή κΈ°λ° λ΅λ³**: | |
| {rag_response} | |
| π‘ **μΆκ° λ¬Έμ**κ° μμΌμλ©΄ μΈμ λ λ§μν΄μ£ΌμΈμ!""" | |
| return create_simple_response(formatted_response) | |
| except Exception as e: | |
| logger.error(f"β RAG μμ€ν μ€λ₯: {e}") | |
| # RAG μ€ν¨μ κΈ°μ‘΄ λ°©μμΌλ‘ ν΄λ°± | |
| # κΈ°μ‘΄ λ°©μ (RAG μμ€ν μ΄ μκ±°λ μ€ν¨ν κ²½μ°) | |
| quick_response = f"""π€ μ·¨λμΈ μλ΄μ μμν©λλ€! | |
| π μ§λ¬Έ λ΄μ©: "{user_utterance}" | |
| π μ νν κ³μ°μ μν΄ λΆμ μ€μ λλ€... | |
| μ μλ§ κΈ°λ€λ €μ£ΌμΈμ! (μ½ 10-15μ΄ μμ) | |
| π‘ **미리 μλ €λ리λ μ 보:** | |
| - μ·¨λμΈλ μ§μκ³Ό κΈμ‘μ λ°λΌ λ€λ¦ | |
| - μ‘°μ λμμ§μμ μΆκ° μ€κ³ΌμΈ μ μ© | |
| - λ€μ£Όνμλ λ³λ μΈμ¨ μ μ© | |
| μ νν κ³μ° κ²°κ³Όλ₯Ό κ³§ μλ €λλ¦¬κ² μ΅λλ€! β¨""" | |
| # λ°±κ·ΈλΌμ΄λμμ μ€μ AI μλ΅ μμ± | |
| def generate_delayed_response(): | |
| try: | |
| ai_response = generate_tax_advice(user_utterance) | |
| logger.info(f"π€ μ§μ° μλ΅ μμ± μλ£: {len(ai_response)}μ") | |
| except Exception as e: | |
| logger.error(f"β μ§μ° μλ΅ μμ± μ€ν¨: {e}") | |
| threading.Thread(target=generate_delayed_response, daemon=True).start() | |
| return create_simple_response(quick_response) | |
| else: | |
| # μΌλ° μΈμ¬λ§ | |
| return create_simple_response( | |
| "μλ νμΈμ! π **λΆλμ° μ·¨λμΈ μ λ¬Έ μλ΄** μ±λ΄μ λλ€.\n\n" | |
| "μ·¨λμΈ κ΄λ ¨ μ§λ¬Έμ ν΄μ£Όμλ©΄ μ νν κ³μ°κ³Ό μλ΄μ λμλ립λλ€!\n\n" | |
| "π‘ **μμ:**\n" | |
| "β’ 'κ°λ¨κ΅¬ μννΈ 10μ΅ 2μ£Όνμ μ·¨λμΈ'\n" | |
| "β’ 'λΆλͺ¨λμ΄ μλ μκ² 5μ΅ μ§ μ¦μ¬ μΈκΈ'\n" | |
| "β’ 'μμ΄κ΅¬ 15μ΅ μ£Όν λ§€λ§€ μ·¨λμΈ κ³μ°'" | |
| ) | |
| def create_simple_response(text: str) -> dict: | |
| """λ¨μ ν μ€νΈ μλ΅ μμ±""" | |
| return jsonify({ | |
| "version": "2.0", | |
| "template": { | |
| "outputs": [ | |
| { | |
| "simpleText": { | |
| "text": text | |
| } | |
| } | |
| ] | |
| } | |
| }) | |
| def create_error_response(error_message: str) -> tuple: | |
| """μλ¬ μλ΅ μμ±""" | |
| return jsonify({ | |
| "version": "2.0", | |
| "template": { | |
| "outputs": [ | |
| { | |
| "simpleText": { | |
| "text": error_message | |
| } | |
| } | |
| ] | |
| } | |
| }), 500 | |
| def health_check(): | |
| """μμ€ν μν νμΈ""" | |
| try: | |
| status_info = { | |
| "status": "healthy", | |
| "timestamp": datetime.now().isoformat(), | |
| "service": "Smart Tax Consultant", | |
| "integrated_system": INTEGRATED_SYSTEM_AVAILABLE, | |
| "rag_system": RAG_SYSTEM_AVAILABLE and is_rag_available() if RAG_SYSTEM_AVAILABLE else False | |
| } | |
| if INTEGRATED_SYSTEM_AVAILABLE: | |
| active_sessions = len(tax_consultant.session_manager.active_sessions) | |
| status_info.update({ | |
| "active_sessions": active_sessions, | |
| "features": { | |
| "intelligent_analysis": "enabled", | |
| "adaptive_survey": "enabled", | |
| "gift_tax_special": "enabled", | |
| "rag_law_search": "enabled" if RAG_SYSTEM_AVAILABLE else "disabled", | |
| "timeout_prevention": "enabled" | |
| } | |
| }) | |
| else: | |
| status_info.update({ | |
| "active_sessions": 0, | |
| "features": { | |
| "fallback_mode": "enabled", | |
| "rag_law_search": "enabled" if RAG_SYSTEM_AVAILABLE else "disabled", | |
| "timeout_prevention": "enabled" | |
| } | |
| }) | |
| return jsonify(status_info) | |
| except Exception as e: | |
| return jsonify({ | |
| "status": "unhealthy", | |
| "error": str(e), | |
| "timestamp": datetime.now().isoformat() | |
| }), 500 | |
| # RAG μμ€ν μ μ© μλν¬μΈνΈ μΆκ° | |
| def rag_search(): | |
| """RAG μμ€ν μ μ© λ²λ Ή κ²μ""" | |
| try: | |
| if not RAG_SYSTEM_AVAILABLE: | |
| return jsonify({"error": "RAG μμ€ν μ μ¬μ©ν μ μμ΅λλ€"}), 503 | |
| data = request.get_json() | |
| question = data.get('question', '') | |
| if not question.strip(): | |
| return jsonify({"error": "μ§λ¬Έμ΄ λΉμ΄μμ΅λλ€"}), 400 | |
| result = search_tax_law(question) | |
| return jsonify({ | |
| "status": "success", | |
| "question": question, | |
| "answer": result, | |
| "timestamp": datetime.now().isoformat() | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| "status": "error", | |
| "error": str(e), | |
| "timestamp": datetime.now().isoformat() | |
| }), 500 | |
| def manual_cleanup(): | |
| """μλ μΈμ μ 리""" | |
| try: | |
| cleanup_results = {} | |
| if INTEGRATED_SYSTEM_AVAILABLE: | |
| tax_consultant.session_manager.cleanup_old_sessions() | |
| active_count = len(tax_consultant.session_manager.active_sessions) | |
| cleanup_results['integrated_system'] = { | |
| "status": "cleaned", | |
| "active_sessions": active_count | |
| } | |
| else: | |
| cleanup_results['integrated_system'] = { | |
| "status": "not_available", | |
| "active_sessions": 0 | |
| } | |
| return jsonify({ | |
| "status": "success", | |
| "message": "μμ€ν μ 리 μλ£", | |
| "details": cleanup_results | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| "status": "error", | |
| "message": str(e) | |
| }), 500 | |
| def root(): | |
| """μΉ μΈν°νμ΄μ€ μ 곡""" | |
| html_content = '''<!DOCTYPE html> | |
| <html lang="ko"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>ποΈ μ·¨λμΈ AI μλ΄λ΄</title> | |
| <style> | |
| body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; } | |
| .container { max-width: 800px; margin: 0 auto; background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } | |
| h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; } | |
| .chat-container { border: 1px solid #ddd; border-radius: 8px; height: 400px; overflow-y: auto; padding: 15px; background: #fafafa; margin-bottom: 20px; } | |
| .message { margin: 10px 0; padding: 10px; border-radius: 8px; } | |
| .user-message { background: #007bff; color: white; margin-left: 20%; text-align: right; } | |
| .bot-message { background: #e9ecef; color: #333; margin-right: 20%; } | |
| .input-container { display: flex; gap: 10px; } | |
| #questionInput { flex: 1; padding: 12px; border: 1px solid #ddd; border-radius: 5px; font-size: 16px; } | |
| #sendButton { padding: 12px 24px; background: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; } | |
| #sendButton:hover { background: #0056b3; } | |
| #sendButton:disabled { background: #ccc; cursor: not-allowed; } | |
| .status { text-align: center; color: #666; margin: 10px 0; font-size: 14px; } | |
| .samples { margin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 5px; } | |
| .samples h3 { margin-top: 0; color: #495057; } | |
| .sample-btn { background: #28a745; color: white; border: none; padding: 8px 16px; margin: 5px; border-radius: 5px; cursor: pointer; font-size: 14px; } | |
| .sample-btn:hover { background: #218838; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>ποΈ μ·¨λμΈ AI μλ΄λ΄</h1> | |
| <div class="status"> | |
| β RAG μμ€ν : ''' + ('νμ±ν' if RAG_SYSTEM_AVAILABLE else 'λΉνμ±ν') + ''' | |
| | π₯οΈ νκ²½: νκΉ νμ΄μ€ μ€νμ΄μ€ GPU | |
| </div> | |
| <div class="chat-container" id="chatContainer"> | |
| <div class="message bot-message"> | |
| μλ νμΈμ! μ λ μ·¨λμΈ AI μλ΄λ΄μ λλ€. π <br> | |
| μ·¨λμΈ κ΄λ ¨ κΆκΈν μ μ μμ λ‘κ² μ§λ¬Έν΄μ£ΌμΈμ! | |
| </div> | |
| </div> | |
| <div class="input-container"> | |
| <input type="text" id="questionInput" placeholder="μ·¨λμΈ κ΄λ ¨ μ§λ¬Έμ μ λ ₯νμΈμ..." | |
| onkeypress="if(event.key==='Enter') sendMessage()"> | |
| <button id="sendButton" onclick="sendMessage()">μ§λ¬ΈνκΈ°</button> | |
| </div> | |
| <div class="samples"> | |
| <h3>π‘ μν μ§λ¬Έλ€ (ν΄λ¦νλ©΄ μλ μ λ ₯)</h3> | |
| <button class="sample-btn" onclick="setSample('μ·¨λμΈμ¨μ΄ μΌλ§μΈκ°μ?')">μ·¨λμΈμ¨</button> | |
| <button class="sample-btn" onclick="setSample('1μΈλ 1μ£Όνμ κ°λ©΄ ννμ?')">1μΈλ1μ£Όν κ°λ©΄</button> | |
| <button class="sample-btn" onclick="setSample('μ νΌλΆλΆ μ·¨λμΈ νΉλ‘λ?')">μ νΌλΆλΆ νΉλ‘</button> | |
| <button class="sample-btn" onclick="setSample('λμ§ μ·¨λμΈ κ³μ°λ°©λ²μ?')">λμ§ μ·¨λμΈ</button> | |
| <button class="sample-btn" onclick="setSample('λ€μ£Όνμ μ€κ³ΌμΈμ¨μ?')">μ€κ³ΌμΈμ¨</button> | |
| </div> | |
| </div> | |
| <script> | |
| function addMessage(message, isUser) { | |
| const chatContainer = document.getElementById('chatContainer'); | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = 'message ' + (isUser ? 'user-message' : 'bot-message'); | |
| messageDiv.innerHTML = message.replace(/\\n/g, '<br>'); | |
| chatContainer.appendChild(messageDiv); | |
| chatContainer.scrollTop = chatContainer.scrollHeight; | |
| } | |
| function setSample(question) { | |
| document.getElementById('questionInput').value = question; | |
| } | |
| async function sendMessage() { | |
| const input = document.getElementById('questionInput'); | |
| const button = document.getElementById('sendButton'); | |
| const question = input.value.trim(); | |
| if (!question) return; | |
| addMessage(question, true); | |
| input.value = ''; | |
| button.disabled = true; | |
| button.textContent = 'λ΅λ³ μμ± μ€...'; | |
| try { | |
| const response = await fetch('/api/web/chat', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ message: question }) | |
| }); | |
| const data = await response.json(); | |
| if (data.response) { | |
| addMessage(data.response, false); | |
| } else { | |
| addMessage('μ£μ‘ν©λλ€. μλ΅μ μμ±ν μ μμ΅λλ€.', false); | |
| } | |
| } catch (error) { | |
| addMessage('μ€λ₯κ° λ°μνμ΅λλ€: ' + error.message, false); | |
| } | |
| button.disabled = false; | |
| button.textContent = 'μ§λ¬ΈνκΈ°'; | |
| } | |
| </script> | |
| </body> | |
| </html>''' | |
| return html_content | |
| def api_info(): | |
| """API μ 보 λ° μν μ 곡""" | |
| return jsonify({ | |
| "service": "Smart Tax Consultant with RAG", | |
| "version": "2.0", | |
| "systems": { | |
| "integrated_system": INTEGRATED_SYSTEM_AVAILABLE, | |
| "rag_system": RAG_SYSTEM_AVAILABLE and is_rag_available() if RAG_SYSTEM_AVAILABLE else False | |
| }, | |
| "endpoints": { | |
| "web_chat": "/api/web/chat", | |
| "kakao_webhook": "/api/chat (disabled)", | |
| "rag_search": "/api/rag/search", | |
| "health": "/health", | |
| "cleanup": "/cleanup" | |
| } | |
| }) | |
| if __name__ == '__main__': | |
| logger.info("π μ€λ§νΈ μ·¨λμΈ μλ΄ μμ€ν + RAG μμ") | |
| logger.info(f"π ν΅ν© μμ€ν : {'μ¬μ© κ°λ₯' if INTEGRATED_SYSTEM_AVAILABLE else 'ν΄λ°± λͺ¨λ'}") | |
| logger.info(f"π RAG μμ€ν : {'μ¬μ© κ°λ₯' if RAG_SYSTEM_AVAILABLE else 'μ¬μ© λΆκ°'}") | |
| # νκ²½λ³μμμ ν¬νΈ μ½κΈ° (HuggingFace Spaces νΈν) | |
| port = int(os.getenv('PORT', 7860)) | |
| app.run(host='0.0.0.0', port=port, debug=False) |