Spaces:
No application file
No application file
""" | |
RAG ๊ฒ์ ์ฑ๋ด ์น ์ ํ๋ฆฌ์ผ์ด์ (์ธ์ ์ค์ ์์ ์ ์ฉ) | |
""" | |
import os | |
import json | |
import logging | |
import tempfile | |
import threading | |
import datetime | |
from flask import Flask, request, jsonify, render_template, send_from_directory, session, redirect, url_for | |
from werkzeug.utils import secure_filename | |
from dotenv import load_dotenv | |
from functools import wraps | |
# ๋ก๊ฑฐ ์ค์ | |
logging.basicConfig( | |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', | |
level=logging.DEBUG # INFO์์ DEBUG๋ก ๋ณ๊ฒฝํ์ฌ ๋ ์์ธํ ๋ก๊ทธ ํ์ธ | |
) | |
logger = logging.getLogger(__name__) | |
# ํ๊ฒฝ ๋ณ์ ๋ก๋ | |
load_dotenv() | |
# ํ๊ฒฝ ๋ณ์ ๋ก๋ ์ํ ํ์ธ ๋ฐ ๋ก๊น | |
ADMIN_USERNAME = os.getenv('ADMIN_USERNAME') | |
ADMIN_PASSWORD = os.getenv('ADMIN_PASSWORD') | |
DEVICE_SERVER_URL = os.getenv('DEVICE_SERVER_URL', 'http://localhost:5050') | |
logger.info(f"==== ํ๊ฒฝ ๋ณ์ ๋ก๋ ์ํ ====") | |
logger.info(f"ADMIN_USERNAME ์ค์ ์ฌ๋ถ: {ADMIN_USERNAME is not None}") | |
# ๋น๋ฐ๋ฒํธ๋ ๋ก๋ ์ฌ๋ถ๋ง ๊ธฐ๋ก (๋ณด์) | |
logger.info(f"ADMIN_PASSWORD ์ค์ ์ฌ๋ถ: {ADMIN_PASSWORD is not None}") | |
logger.info(f"DEVICE_SERVER_URL: {DEVICE_SERVER_URL}") | |
# ํ๊ฒฝ ๋ณ์๊ฐ ์์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ ์ค์ (๊ฐ๋ฐ์ฉ, ๋ฐฐํฌ ์ ํ๊ฒฝ ๋ณ์ ์ค์ ๊ถ์ฅ) | |
if not ADMIN_USERNAME: | |
ADMIN_USERNAME = 'admin' | |
logger.warning("ADMIN_USERNAME ํ๊ฒฝ๋ณ์๊ฐ ์์ด ๊ธฐ๋ณธ๊ฐ 'admin'์ผ๋ก ์ค์ ํฉ๋๋ค.") | |
if not ADMIN_PASSWORD: | |
ADMIN_PASSWORD = 'rag12345' | |
logger.warning("ADMIN_PASSWORD ํ๊ฒฝ๋ณ์๊ฐ ์์ด ๊ธฐ๋ณธ๊ฐ 'rag12345'๋ก ์ค์ ํฉ๋๋ค.") | |
class MockComponent: pass | |
# --- ๋ก์ปฌ ๋ชจ๋ ์ํฌํธ --- | |
# ์ค์ ๊ฒฝ๋ก์ ๋ง๊ฒ utils, retrieval ํด๋๊ฐ ์กด์ฌํด์ผ ํฉ๋๋ค. | |
try: | |
from utils.vito_stt import VitoSTT | |
from utils.llm_interface import LLMInterface | |
from utils.document_processor import DocumentProcessor | |
from retrieval.vector_retriever import VectorRetriever | |
from retrieval.reranker import ReRanker | |
# ๋ผ์ฐํธ ์ ์ ํ์ผ ์ํฌํธ | |
from app.app_routes import register_routes | |
from app.app_device_routes import register_device_routes | |
except ImportError as e: | |
logger.error(f"๋ก์ปฌ ๋ชจ๋ ์ํฌํธ ์คํจ: {e}. utils ๋ฐ retrieval ํจํค์ง๊ฐ ์ฌ๋ฐ๋ฅธ ๊ฒฝ๋ก์ ์๋์ง ํ์ธํ์ธ์.") | |
# ๊ฐ๋ฐ/ํ ์คํธ๋ฅผ ์ํด ์์ ํด๋์ค ์ ์ (์ค์ ์ฌ์ฉ ์ ์ ๊ฑฐ) | |
VitoSTT = LLMInterface = DocumentProcessor = VectorRetriever = ReRanker = MockComponent | |
# --- ๋ก์ปฌ ๋ชจ๋ ์ํฌํธ ๋ --- | |
# Flask ์ฑ ์ด๊ธฐํ | |
app = Flask(__name__) | |
# ์ธ์ ์ค์ - ๊ณ ์ ๋ ์ํฌ๋ฆฟ ํค ์ฌ์ฉ (์ค์ ๋ฐฐํฌ ์ ํ๊ฒฝ ๋ณ์ ๋ฑ์ผ๋ก ๊ด๋ฆฌ ๊ถ์ฅ) | |
app.secret_key = os.getenv('FLASK_SECRET_KEY', 'rag_chatbot_fixed_secret_key_12345') # ํ๊ฒฝ ๋ณ์ ์ฐ์ ์ฌ์ฉ | |
# --- ์ธ์ ์ฟ ํค ์ค์ ์์ (ํ๊น ํ์ด์ค ํ๊ฒฝ ๊ณ ๋ ค) --- | |
# ํ๊น ํ์ด์ค ์คํ์ด์ค๋ ์ผ๋ฐ์ ์ผ๋ก HTTPS๋ก ์๋น์ค๋๋ฏ๋ก Secure=True ์ค์ | |
app.config['SESSION_COOKIE_SECURE'] = True | |
app.config['SESSION_COOKIE_HTTPONLY'] = True # JavaScript์์ ์ฟ ํค ์ ๊ทผ ๋ฐฉ์ง (๋ณด์ ๊ฐํ) | |
# SameSite='Lax'๊ฐ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ์ ๋ ์์ ํ๊ณ ํธํ์ฑ์ด ์ข์. | |
# ๋ง์ฝ ์ฑ์ด ๋ค๋ฅธ ๋๋ฉ์ธ์ iframe ๋ด์์ ์คํ๋์ด์ผ ํ๋ค๋ฉด 'None'์ผ๋ก ์ค์ ํด์ผ ํจ. | |
# (๋จ, 'None'์ผ๋ก ์ค์ ์ ๋ฐ๋์ Secure=True์ฌ์ผ ํจ) | |
# ๋ก๊ทธ ๋ถ์ ๊ฒฐ๊ณผ iframe ํ๊ฒฝ์ผ๋ก ํ์ธ๋์ด 'None'์ผ๋ก ๋ณ๊ฒฝ | |
app.config['SESSION_COOKIE_SAMESITE'] = 'None' # <--- ์ด๋ ๊ฒ ๋ณ๊ฒฝํฉ๋๋ค. | |
app.config['SESSION_COOKIE_DOMAIN'] = None # ํน์ ๋๋ฉ์ธ ์ ํ ์์ | |
app.config['SESSION_COOKIE_PATH'] = '/' # ์ฑ ์ ์ฒด ๊ฒฝ๋ก์ ์ฟ ํค ์ ์ฉ | |
app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(days=1) # ์ธ์ ์ ํจ ์๊ฐ ์ฆ๊ฐ | |
# --- ์ธ์ ์ฟ ํค ์ค์ ๋ --- | |
# ์ต๋ ํ์ผ ํฌ๊ธฐ ์ค์ (10MB) | |
app.config['MAX_CONTENT_LENGTH'] = 10 * 1024 * 1024 | |
# ์ ํ๋ฆฌ์ผ์ด์ ํ์ผ ๊ธฐ์ค ์๋ ๊ฒฝ๋ก ์ค์ | |
APP_ROOT = os.path.dirname(os.path.abspath(__file__)) | |
app.config['UPLOAD_FOLDER'] = os.path.join(APP_ROOT, 'uploads') | |
app.config['DATA_FOLDER'] = os.path.join(APP_ROOT, '..', 'data') | |
app.config['INDEX_PATH'] = os.path.join(APP_ROOT, '..', 'data', 'index') | |
# ํ์ํ ํด๋ ์์ฑ | |
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) | |
os.makedirs(app.config['DATA_FOLDER'], exist_ok=True) | |
os.makedirs(app.config['INDEX_PATH'], exist_ok=True) | |
# ํ์ฉ๋๋ ์ค๋์ค/๋ฌธ์ ํ์ผ ํ์ฅ์ | |
ALLOWED_AUDIO_EXTENSIONS = {'mp3', 'wav', 'ogg', 'm4a'} | |
ALLOWED_DOC_EXTENSIONS = {'txt', 'md', 'pdf', 'docx', 'csv'} | |
# --- ์ ์ญ ๊ฐ์ฒด ์ด๊ธฐํ --- | |
try: | |
llm_interface = LLMInterface(default_llm="openai") | |
stt_client = VitoSTT() | |
except NameError: | |
logger.warning("LLM ๋๋ STT ์ธํฐํ์ด์ค ์ด๊ธฐํ ์คํจ. Mock ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํฉ๋๋ค.") | |
llm_interface = MockComponent() | |
stt_client = MockComponent() | |
base_retriever = None | |
retriever = None | |
app_ready = False # ์ฑ ์ด๊ธฐํ ์ํ ํ๋๊ทธ | |
# --- ์ ์ญ ๊ฐ์ฒด ์ด๊ธฐํ ๋ --- | |
# --- ์ธ์ฆ ๋ฐ์ฝ๋ ์ดํฐ (์์ ๋จ) --- | |
def login_required(f): | |
def decorated_function(*args, **kwargs): | |
logger.info(f"----------- ์ธ์ฆ ํ์ ํ์ด์ง ์ ๊ทผ ์๋: {request.path} -----------") | |
logger.info(f"ํ์ฌ ํ๋ผ์คํฌ ์ธ์ ๊ฐ์ฒด: {session}") | |
logger.info(f"ํ์ฌ ์ธ์ ์ํ: logged_in={session.get('logged_in', False)}, username={session.get('username', 'None')}") | |
# ๋ธ๋ผ์ฐ์ ๊ฐ ๋ณด๋ธ ์ค์ ์ฟ ํค ํ์ธ (๋๋ฒ๊น ์ฉ) | |
logger.info(f"์์ฒญ์ ์ธ์ ์ฟ ํค ๊ฐ: {request.cookies.get('session', 'None')}") | |
# Flask ์ธ์ ์ 'logged_in' ํค๊ฐ ์๋์ง ์ง์ ํ์ธ | |
if 'logged_in' not in session: | |
logger.warning(f"ํ๋ผ์คํฌ ์ธ์ ์ 'logged_in' ์์. ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋ฆฌ๋๋ ์ .") | |
# ์๋ ์ฟ ํค ํ์ธ ๋ก์ง ์ ๊ฑฐ๋จ | |
return redirect(url_for('login', next=request.url)) # ๋ก๊ทธ์ธ ํ ์๋ ํ์ด์ง๋ก ๋์๊ฐ๋๋ก next ํ๋ผ๋ฏธํฐ ์ถ๊ฐ | |
logger.info(f"์ธ์ฆ ์ฑ๊ณต: {session.get('username', 'unknown')} ์ฌ์ฉ์๊ฐ {request.path} ์ ๊ทผ") | |
return f(*args, **kwargs) | |
return decorated_function | |
# --- ์ธ์ฆ ๋ฐ์ฝ๋ ์ดํฐ ๋ --- | |
# --- ํฌํผ ํจ์ --- | |
def allowed_audio_file(filename): | |
"""ํ์ผ์ด ํ์ฉ๋ ์ค๋์ค ํ์ฅ์๋ฅผ ๊ฐ์ง๋์ง ํ์ธ""" | |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_AUDIO_EXTENSIONS | |
def allowed_doc_file(filename): | |
"""ํ์ผ์ด ํ์ฉ๋ ๋ฌธ์ ํ์ฅ์๋ฅผ ๊ฐ์ง๋์ง ํ์ธ""" | |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_DOC_EXTENSIONS | |
# --- ํฌํผ ํจ์ ๋ --- | |
# init_retriever ํจ์ ๋ด๋ถ์ ๋ก๊น ์ถ๊ฐ ์์ | |
# --- ๊ฒ์๊ธฐ ์ด๊ธฐํ ๊ด๋ จ ํจ์ --- | |
def init_retriever(): | |
"""๊ฒ์๊ธฐ ๊ฐ์ฒด ์ด๊ธฐํ ๋๋ ๋ก๋""" | |
global base_retriever, retriever | |
index_path = app.config['INDEX_PATH'] | |
data_path = app.config['DATA_FOLDER'] # data_path ์ ์ ํ์ธ | |
logger.info("--- init_retriever ์์ ---") | |
# 1. ๊ธฐ๋ณธ ๊ฒ์๊ธฐ ๋ก๋ ๋๋ ์ด๊ธฐํ | |
# ... (VectorRetriever ๋ก๋ ๋๋ ์ด๊ธฐํ ๋ก์ง์ ์ด์ ๊ณผ ๋์ผํ๊ฒ ์ ์ง) ... | |
# VectorRetriever ์ด๊ธฐํ/๋ก๋ ์คํจ ์ base_retriever = None ๋ฐ return None ์ฒ๋ฆฌ ํฌํจ | |
if os.path.exists(os.path.join(index_path, "documents.json")): | |
try: | |
logger.info(f"์ธ๋ฑ์ค ๋ก๋ ์๋: {index_path}") | |
base_retriever = VectorRetriever.load(index_path) | |
logger.info(f"์ธ๋ฑ์ค ๋ก๋ ์ฑ๊ณต. ๋ฌธ์ {len(getattr(base_retriever, 'documents', []))}๊ฐ") | |
except Exception as e: | |
logger.error(f"์ธ๋ฑ์ค ๋ก๋ ์คํจ: {e}", exc_info=True) | |
logger.info("์ VectorRetriever ์ด๊ธฐํ ์๋...") | |
try: | |
base_retriever = VectorRetriever() | |
logger.info("์ VectorRetriever ์ด๊ธฐํ ์ฑ๊ณต.") | |
except Exception as e_init: | |
logger.error(f"์ VectorRetriever ์ด๊ธฐํ ์คํจ: {e_init}", exc_info=True) | |
base_retriever = None | |
else: | |
logger.info("์ธ๋ฑ์ค ํ์ผ ์์. ์ VectorRetriever ์ด๊ธฐํ ์๋...") | |
try: | |
base_retriever = VectorRetriever() | |
logger.info("์ VectorRetriever ์ด๊ธฐํ ์ฑ๊ณต.") | |
except Exception as e_init: | |
logger.error(f"์ VectorRetriever ์ด๊ธฐํ ์คํจ: {e_init}", exc_info=True) | |
base_retriever = None | |
if base_retriever is None: | |
logger.error("base_retriever ์ด๊ธฐํ/๋ก๋์ ์คํจํ์ฌ init_retriever ์ค๋จ.") | |
return None | |
# 2. ๋ฐ์ดํฐ ํด๋ ๋ฌธ์ ๋ก๋ (๊ธฐ๋ณธ ๊ฒ์๊ธฐ๊ฐ ๋น์ด์์ ๋) | |
needs_loading = (not hasattr(base_retriever, 'documents') or not getattr(base_retriever, 'documents', None)) # None ์ฒดํฌ ์ถ๊ฐ | |
if needs_loading and os.path.exists(data_path): | |
logger.info(f"๊ธฐ๋ณธ ๊ฒ์๊ธฐ๊ฐ ๋น์ด์์ด {data_path}์์ ๋ฌธ์ ๋ก๋ ์๋...") | |
try: | |
# ================== ์์ ๋ ๋ถ๋ถ 1 ์์ ================== | |
# DocumentProcessor.load_documents_from_directory ํธ์ถ ์ ์ฌ๋ฐ๋ฅธ ์ธ์ ์ ๋ฌ | |
docs = DocumentProcessor.load_documents_from_directory( | |
directory=data_path, # <-- ๊ฒฝ๋ก ๋ณ์ ์ฌ์ฉ | |
extensions=[".txt", ".md", ".csv"], # <-- ํ์ํ ํ์ฅ์ ์ ๋ฌ | |
recursive=True # <-- ์ฌ๊ท ํ์ ์ฌ๋ถ ์ ๋ฌ | |
) | |
# ================== ์์ ๋ ๋ถ๋ถ 1 ๋ ==================== | |
logger.info(f"{len(docs)}๊ฐ ๋ฌธ์ ๋ก๋ ์ฑ๊ณต.") | |
if docs and hasattr(base_retriever, 'add_documents'): | |
logger.info("๊ฒ์๊ธฐ์ ๋ฌธ์ ์ถ๊ฐ ์๋...") | |
base_retriever.add_documents(docs) | |
logger.info("๋ฌธ์ ์ถ๊ฐ ์๋ฃ.") | |
if hasattr(base_retriever, 'save'): | |
logger.info(f"๊ฒ์๊ธฐ ์ํ ์ ์ฅ ์๋: {index_path}") | |
try: | |
base_retriever.save(index_path) | |
logger.info("์ธ๋ฑ์ค ์ ์ฅ ์๋ฃ.") | |
except Exception as e_save: | |
logger.error(f"์ธ๋ฑ์ค ์ ์ฅ ์คํจ: {e_save}", exc_info=True) | |
except Exception as e_load_add: | |
# load_documents_from_directory ์์ฒด์์ ์ค๋ฅ๊ฐ ๋ ์๋ ์์ (๊ถํ ๋ฑ) | |
logger.error(f"DATA_FOLDER ๋ฌธ์ ๋ก๋/์ถ๊ฐ ์ค ์ค๋ฅ: {e_load_add}", exc_info=True) | |
# 3. ์ฌ์์ํ ๊ฒ์๊ธฐ ์ด๊ธฐํ | |
logger.info("์ฌ์์ํ ๊ฒ์๊ธฐ ์ด๊ธฐํ ์๋...") | |
try: | |
# ================== ์์ ๋ ๋ถ๋ถ 2 ์์ ================== | |
# custom_rerank_fn ํจ์๋ฅผ ReRanker ์ด๊ธฐํ ์ ์ ์ ์ | |
def custom_rerank_fn(query, results): | |
query_terms = set(query.lower().split()) | |
for result in results: | |
if isinstance(result, dict) and "text" in result: | |
text = result["text"].lower() | |
term_freq = sum(1 for term in query_terms if term in text) | |
normalized_score = term_freq / (len(text.split()) + 1) * 10 | |
result["rerank_score"] = result.get("score", 0) * 0.7 + normalized_score * 0.3 | |
elif isinstance(result, dict): | |
result["rerank_score"] = result.get("score", 0) | |
results.sort(key=lambda x: x.get("rerank_score", 0) if isinstance(x, dict) else 0, reverse=True) | |
return results | |
# ================== ์์ ๋ ๋ถ๋ถ 2 ๋ ==================== | |
# ReRanker ํด๋์ค ์ฌ์ฉ | |
retriever = ReRanker( | |
base_retriever=base_retriever, | |
rerank_fn=custom_rerank_fn, # ์ด์ ํจ์๊ฐ ์ ์๋์์ผ๋ฏ๋ก ์ฌ์ฉ ๊ฐ๋ฅ | |
rerank_field="text" | |
) | |
logger.info("์ฌ์์ํ ๊ฒ์๊ธฐ ์ด๊ธฐํ ์๋ฃ.") | |
except Exception as e_rerank: | |
logger.error(f"์ฌ์์ํ ๊ฒ์๊ธฐ ์ด๊ธฐํ ์คํจ: {e_rerank}", exc_info=True) | |
logger.warning("์ฌ์์ํ ์คํจ, ๊ธฐ๋ณธ ๊ฒ์๊ธฐ๋ฅผ retriever๋ก ์ฌ์ฉํฉ๋๋ค.") | |
retriever = base_retriever # fallback | |
logger.info("--- init_retriever ์ข ๋ฃ ---") | |
return retriever | |
def background_init(): | |
"""๋ฐฑ๊ทธ๋ผ์ด๋์์ ๊ฒ์๊ธฐ ์ด๊ธฐํ ์ํ""" | |
global app_ready, retriever, base_retriever, llm_interface, stt_client | |
temp_app_ready = False # ์์ ์ํ ํ๋๊ทธ | |
try: | |
logger.info("๋ฐฑ๊ทธ๋ผ์ด๋ ์ด๊ธฐํ ์์...") | |
# 1. LLM, STT ์ธํฐํ์ด์ค ์ด๊ธฐํ (ํ์ ์) | |
if llm_interface is None or isinstance(llm_interface, MockComponent): | |
if 'LLMInterface' in globals() and LLMInterface != MockComponent: | |
llm_interface = LLMInterface(default_llm="openai") | |
logger.info("LLM ์ธํฐํ์ด์ค ์ด๊ธฐํ ์๋ฃ.") | |
else: | |
logger.warning("LLMInterface ํด๋์ค ์์. Mock ์ฌ์ฉ.") | |
llm_interface = MockComponent() # Mock ๊ฐ์ฒด ๋ณด์ฅ | |
if stt_client is None or isinstance(stt_client, MockComponent): | |
if 'VitoSTT' in globals() and VitoSTT != MockComponent: | |
stt_client = VitoSTT() | |
logger.info("STT ํด๋ผ์ด์ธํธ ์ด๊ธฐํ ์๋ฃ.") | |
else: | |
logger.warning("VitoSTT ํด๋์ค ์์. Mock ์ฌ์ฉ.") | |
stt_client = MockComponent() # Mock ๊ฐ์ฒด ๋ณด์ฅ | |
# 2. ๊ฒ์๊ธฐ ์ด๊ธฐํ | |
if 'VectorRetriever' in globals() and VectorRetriever != MockComponent: | |
logger.info("์ค์ ๊ฒ์๊ธฐ ์ด๊ธฐํ ์๋...") | |
# init_retriever๊ฐ base_retriever์ retriever๋ฅผ ๋ชจ๋ ์ค์ ํ๋ค๊ณ ๊ฐ์ | |
retriever = init_retriever() | |
# init_retriever ๋ด๋ถ์์ base_retriever๊ฐ ์ค์ ๋์ง ์์๋ค๋ฉด ์ฌ๊ธฐ์ ์ค์ | |
if hasattr(retriever, 'base_retriever') and base_retriever is None: | |
base_retriever = retriever.base_retriever | |
elif base_retriever is None: | |
# retriever๊ฐ base_retriever๋ฅผ ํฌํจํ์ง ์๋ ๊ฒฝ์ฐ ๋๋ ReRanker๊ฐ ์๋ ๊ฒฝ์ฐ | |
# init_retriever์์ base_retriever๋ฅผ ์ง์ ์ค์ ํ๋๋ก ํ๊ฑฐ๋, ์ฌ๊ธฐ์ ๋ณ๋ ๋ก์ง ํ์ | |
# ์์: base_retriever = VectorRetriever.load(...) ๋๋ VectorRetriever() | |
logger.warning("init_retriever ํ base_retriever๊ฐ ์ค์ ๋์ง ์์. ํ์ธ ํ์.") | |
# ์์๋ก retriever ์์ฒด๋ฅผ base_retriever๋ก ์ค์ (๋์ผ ๊ฐ์ฒด์ผ ๊ฒฝ์ฐ) | |
if isinstance(retriever, VectorRetriever): | |
base_retriever = retriever | |
# ์ฑ๊ณต์ ์ผ๋ก ์ด๊ธฐํ ๋์๋์ง ํ์ธ (None์ด ์๋์ง) | |
if retriever is not None and base_retriever is not None: | |
logger.info("๊ฒ์๊ธฐ (Retriever, Base Retriever) ์ด๊ธฐํ ์ฑ๊ณต") | |
temp_app_ready = True # ์ด๊ธฐํ ์ฑ๊ณต ์์๋ง True ์ค์ | |
else: | |
logger.error("๊ฒ์๊ธฐ ์ด๊ธฐํ ํ์๋ retriever ๋๋ base_retriever๊ฐ None์ ๋๋ค.") | |
# ์คํจ ์ Mock ๊ฐ์ฒด ํ ๋น (์ต์ํ์ ๋์ ๋ณด์ฅ) | |
if base_retriever is None: base_retriever = MockComponent() | |
if retriever is None: retriever = MockComponent() | |
if not hasattr(retriever, 'search'): retriever.search = lambda query, **kwargs: [] | |
if not hasattr(base_retriever, 'documents'): base_retriever.documents = [] | |
# temp_app_ready = False ๋๋ True (์ ์ฑ ์ ๋ฐ๋ผ ๊ฒฐ์ ) | |
temp_app_ready = True # ์ผ๋จ ์ฑ์ ์คํ๋๋๋ก ์ค์ | |
else: | |
logger.warning("VectorRetriever ํด๋์ค ์์. Mock ๊ฒ์๊ธฐ ์ฌ์ฉ.") | |
base_retriever = MockComponent() | |
retriever = MockComponent() | |
if not hasattr(retriever, 'search'): retriever.search = lambda query, **kwargs: [] | |
if not hasattr(base_retriever, 'documents'): base_retriever.documents = [] | |
temp_app_ready = True # Mock์ด๋ผ๋ ์ค๋น๋ ๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ | |
logger.info(f"๋ฐฑ๊ทธ๋ผ์ด๋ ์ด๊ธฐํ ์๋ฃ. ์ต์ข ์ํ: {'Ready' if temp_app_ready else 'Not Ready (Error during init)'}") | |
except Exception as e: | |
logger.error(f"์ฑ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ด๊ธฐํ ์ค ์ฌ๊ฐํ ์ค๋ฅ ๋ฐ์: {e}", exc_info=True) | |
# ์ค๋ฅ ๋ฐ์ ์์๋ Mock ๊ฐ์ฒด ํ ๋น ์๋ | |
if base_retriever is None: base_retriever = MockComponent() | |
if retriever is None: retriever = MockComponent() | |
if not hasattr(retriever, 'search'): retriever.search = lambda query, **kwargs: [] | |
if not hasattr(base_retriever, 'documents'): base_retriever.documents = [] | |
temp_app_ready = True # ์ค๋ฅ ๋ฐ์ํด๋ ์ฑ์ ์๋ตํ๋๋ก ์ค์ (์ ์ฑ ์ ๋ฐ๋ผ False ๊ฐ๋ฅ) | |
logger.warning("์ด๊ธฐํ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง๋ง Mock ๊ฐ์ฒด๋ก ๋์ฒด ํ ์ฑ ์ฌ์ฉ ๊ฐ๋ฅ ์ํ๋ก ์ค์ .") | |
finally: | |
# ์ต์ข ์ ์ผ๋ก app_ready ์ํ ์ ๋ฐ์ดํธ | |
app_ready = temp_app_ready | |
# ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋ ์์ ๋ถ๋ถ์ ๊ทธ๋๋ก ์ ์ง | |
init_thread = threading.Thread(target=background_init) | |
init_thread.daemon = True | |
init_thread.start() | |
# ๋ผ์ฐํธ ๋ฑ๋ก | |
try: | |
# ๊ธฐ๋ณธ RAG ์ฑ๋ด ๋ผ์ฐํธ ๋ฑ๋ก | |
register_routes( | |
app=app, | |
login_required=login_required, | |
llm_interface=llm_interface, | |
retriever=retriever, | |
stt_client=stt_client, | |
DocumentProcessor=DocumentProcessor, | |
base_retriever=base_retriever, | |
app_ready=app_ready, | |
ADMIN_USERNAME=ADMIN_USERNAME, | |
ADMIN_PASSWORD=ADMIN_PASSWORD, | |
DEVICE_SERVER_URL=DEVICE_SERVER_URL | |
) | |
logger.info("๊ธฐ๋ณธ ์ฑ๋ด ๋ผ์ฐํธ ๋ฑ๋ก ์๋ฃ") | |
# ์ฅ์น ๊ด๋ฆฌ ๋ผ์ฐํธ ๋ฑ๋ก | |
register_device_routes( | |
app=app, | |
login_required=login_required, | |
DEVICE_SERVER_URL=DEVICE_SERVER_URL | |
) | |
logger.info("์ฅ์น ๊ด๋ฆฌ ๋ผ์ฐํธ ๋ฑ๋ก ์๋ฃ") | |
except Exception as e: | |
logger.error(f"๋ผ์ฐํธ ๋ฑ๋ก ์ค ์ค๋ฅ ๋ฐ์: {e}", exc_info=True) | |
# --- ์ ์ ํ์ผ ์๋น --- | |
def send_static(path): | |
return send_from_directory('static', path) | |
# --- ์์ฒญ ์ฒ๋ฆฌ ํ --- | |
def after_request_func(response): | |
"""๋ชจ๋ ์๋ต์ ๋ํด ํ์ฒ๋ฆฌ ์ํ""" | |
return response | |
# ์ฑ ์คํ (๋ก์ปฌ ํ ์คํธ์ฉ) | |
if __name__ == '__main__': | |
logger.info("Flask ์ฑ์ ์ง์ ์คํํฉ๋๋ค (๊ฐ๋ฐ์ฉ ์๋ฒ).") | |
# ๋๋ฒ๊ทธ ๋ชจ๋๋ ์ค์ ๋ฐฐํฌ ์ False๋ก ์ค์ ํด์ผ ํฉ๋๋ค. | |
# port ๋ฒํธ๋ ํ๊ฒฝ ๋ณ์ ๋๋ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ฉํฉ๋๋ค. | |
port = int(os.environ.get("PORT", 7860)) | |
logger.info(f"์๋ฒ๋ฅผ http://0.0.0.0:{port} ์์ ์์ํฉ๋๋ค.") | |
app.run(debug=True, host='0.0.0.0', port=port) |