Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
import os
|
| 2 |
-
os.environ["PYDANTIC_V1_STYLE"] = "1"
|
| 3 |
-
os.environ["PYDANTIC_SKIP_VALIDATING_CORE_SCHEMAS"] = "1"
|
| 4 |
# --------------------------------------------------------------------------
|
| 5 |
|
| 6 |
from flask import Flask, render_template, jsonify, request
|
|
@@ -24,9 +24,16 @@ eventlet.monkey_patch()
|
|
| 24 |
app = Flask(__name__)
|
| 25 |
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='eventlet')
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
# --- 외부 모듈 임포트 ---
|
| 28 |
-
# 🚨🚨🚨 2단계: Pydantic 환경 설정이 완료된 후 LangChain을 포함하는 모듈 임포트 🚨🚨🚨
|
| 29 |
-
# 이 위치가 가장 안전합니다.
|
| 30 |
import reg_embedding_system
|
| 31 |
import leximind_prompts
|
| 32 |
|
|
@@ -65,13 +72,13 @@ def load_rag_objects():
|
|
| 65 |
global region_rag_objects
|
| 66 |
|
| 67 |
# 📢 [수정]: 로딩 스레드 시작 로그를 추가하여 Gunicorn 로그에서 확인 가능하게 함
|
| 68 |
-
|
| 69 |
|
| 70 |
for region, path in region_paths.items():
|
| 71 |
if not os.path.exists(path):
|
| 72 |
msg = f"[{region}] 경로 없음: {path}"
|
| 73 |
socketio.emit('message', {'message': msg})
|
| 74 |
-
|
| 75 |
continue
|
| 76 |
|
| 77 |
try:
|
|
@@ -89,17 +96,17 @@ def load_rag_objects():
|
|
| 89 |
"sqlite_conn": new_conn
|
| 90 |
}
|
| 91 |
socketio.emit('message', {'message': f"[{region}] 로딩 완료"})
|
| 92 |
-
|
| 93 |
|
| 94 |
except Exception as e:
|
| 95 |
error_msg = f"[{region}] 로딩 실패: {str(e)}"
|
| 96 |
-
|
| 97 |
# 📢 [수정]: 상세한 에러 추적을 위해 traceback 추가
|
| 98 |
-
traceback.
|
| 99 |
socketio.emit('message', {'message': error_msg})
|
| 100 |
|
| 101 |
socketio.emit('message', {'message': "Ready to Search"})
|
| 102 |
-
|
| 103 |
|
| 104 |
# --- 웹 ---
|
| 105 |
@app.route('/')
|
|
@@ -144,7 +151,7 @@ def get_reg_list():
|
|
| 144 |
parts = reg_embedding_system.get_unique_metadata_values(conn, "regulation_part")
|
| 145 |
all_reg_list_part.extend(parts)
|
| 146 |
except Exception as e:
|
| 147 |
-
|
| 148 |
|
| 149 |
unique_parts = sorted(set(all_reg_list_part), key=reg_embedding_system.natural_sort_key)
|
| 150 |
return jsonify(reg_list_part="\n".join(unique_parts))
|
|
@@ -154,23 +161,23 @@ def get_reg_list():
|
|
| 154 |
def handle_connect():
|
| 155 |
global connected_clients
|
| 156 |
connected_clients += 1
|
| 157 |
-
|
| 158 |
|
| 159 |
@socketio.on('disconnect')
|
| 160 |
def handle_disconnect():
|
| 161 |
global connected_clients
|
| 162 |
connected_clients -= 1
|
| 163 |
-
|
| 164 |
if connected_clients <= 0:
|
| 165 |
cleanup_connections()
|
| 166 |
-
|
| 167 |
os._exit(0)
|
| 168 |
|
| 169 |
def cleanup_connections():
|
| 170 |
for region, rag in region_rag_objects.items():
|
| 171 |
try:
|
| 172 |
rag["sqlite_conn"].close()
|
| 173 |
-
|
| 174 |
except:
|
| 175 |
pass
|
| 176 |
|
|
@@ -198,8 +205,8 @@ def Gemma3_AI_analysis(query_txt, content_txt):
|
|
| 198 |
data = response.json()
|
| 199 |
return data["choices"][0]["message"]["content"]
|
| 200 |
except requests.exceptions.RequestException as e:
|
| 201 |
-
|
| 202 |
-
traceback.
|
| 203 |
return f"AI 분석 중 오류가 발생했습니다: {e}"
|
| 204 |
|
| 205 |
# --- Together AI 번역 (SDK -> requests 직접 호출로 변경) ---
|
|
@@ -225,15 +232,15 @@ def Gemma3_AI_Translate(query_txt):
|
|
| 225 |
data = response.json()
|
| 226 |
return data["choices"][0]["message"]["content"]
|
| 227 |
except requests.exceptions.RequestException as e:
|
| 228 |
-
|
| 229 |
-
traceback.
|
| 230 |
return query_txt # 번역 실패 시 원래 쿼리를 사용 (최소한의 기능 유지)
|
| 231 |
|
| 232 |
# --- 검색 ---
|
| 233 |
def search_DB_from_multiple_regions(query, selected_regions, region_rag_objects):
|
| 234 |
selected_regions = selected_regions or list(region_rag_objects.keys())
|
| 235 |
query = Gemma3_AI_Translate(query)
|
| 236 |
-
|
| 237 |
|
| 238 |
combined_results = []
|
| 239 |
for region in selected_regions:
|
|
@@ -263,7 +270,7 @@ def search_DB_from_multiple_regions(query, selected_regions, region_rag_objects)
|
|
| 263 |
sqlite_conn=sqlite_conn,
|
| 264 |
enable_detailed_search=True
|
| 265 |
)
|
| 266 |
-
|
| 267 |
combined_results.extend(results)
|
| 268 |
|
| 269 |
return combined_results
|
|
@@ -274,11 +281,11 @@ def RegAI(query, Rag_Results, ResultFile_FolderAddress):
|
|
| 274 |
AI_Result = "검색 결과가 없습니다." if not Rag_Results else Gemma3_AI_analysis(query, Rag_Results)
|
| 275 |
|
| 276 |
with open(ResultFile_FolderAddress, 'w', encoding='utf-8') as f:
|
| 277 |
-
|
| 278 |
for i, doc in enumerate(Rag_Results):
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
|
| 283 |
return AI_Result
|
| 284 |
|
|
|
|
| 1 |
import os
|
| 2 |
+
#os.environ["PYDANTIC_V1_STYLE"] = "1"
|
| 3 |
+
#os.environ["PYDANTIC_SKIP_VALIDATING_CORE_SCHEMAS"] = "1"
|
| 4 |
# --------------------------------------------------------------------------
|
| 5 |
|
| 6 |
from flask import Flask, render_template, jsonify, request
|
|
|
|
| 24 |
app = Flask(__name__)
|
| 25 |
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='eventlet')
|
| 26 |
|
| 27 |
+
import logging
|
| 28 |
+
|
| 29 |
+
# 로거 설정: 레벨을 INFO로 설정하고, 포맷을 지정합니다.
|
| 30 |
+
logging.basicConfig(
|
| 31 |
+
level=logging.INFO,
|
| 32 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
| 33 |
+
)
|
| 34 |
+
logger = logging.getLogger(__name__)
|
| 35 |
+
|
| 36 |
# --- 외부 모듈 임포트 ---
|
|
|
|
|
|
|
| 37 |
import reg_embedding_system
|
| 38 |
import leximind_prompts
|
| 39 |
|
|
|
|
| 72 |
global region_rag_objects
|
| 73 |
|
| 74 |
# 📢 [수정]: 로딩 스레드 시작 로그를 추가하여 Gunicorn 로그에서 확인 가능하게 함
|
| 75 |
+
logger.info(">>> [RAG_LOADER] RAG 로딩 스레드 시작 <<<")
|
| 76 |
|
| 77 |
for region, path in region_paths.items():
|
| 78 |
if not os.path.exists(path):
|
| 79 |
msg = f"[{region}] 경로 없음: {path}"
|
| 80 |
socketio.emit('message', {'message': msg})
|
| 81 |
+
logger.info(msg)
|
| 82 |
continue
|
| 83 |
|
| 84 |
try:
|
|
|
|
| 96 |
"sqlite_conn": new_conn
|
| 97 |
}
|
| 98 |
socketio.emit('message', {'message': f"[{region}] 로딩 완료"})
|
| 99 |
+
logger.info(f"[{region}] RAG 로딩 완료")
|
| 100 |
|
| 101 |
except Exception as e:
|
| 102 |
error_msg = f"[{region}] 로딩 실패: {str(e)}"
|
| 103 |
+
logger.info(error_msg)
|
| 104 |
# 📢 [수정]: 상세한 에러 추적을 위해 traceback 추가
|
| 105 |
+
traceback.logger.info_exc()
|
| 106 |
socketio.emit('message', {'message': error_msg})
|
| 107 |
|
| 108 |
socketio.emit('message', {'message': "Ready to Search"})
|
| 109 |
+
logger.info("Ready to Search")
|
| 110 |
|
| 111 |
# --- 웹 ---
|
| 112 |
@app.route('/')
|
|
|
|
| 151 |
parts = reg_embedding_system.get_unique_metadata_values(conn, "regulation_part")
|
| 152 |
all_reg_list_part.extend(parts)
|
| 153 |
except Exception as e:
|
| 154 |
+
logger.info(f"[{region}] 법규 로드 실패: {e}")
|
| 155 |
|
| 156 |
unique_parts = sorted(set(all_reg_list_part), key=reg_embedding_system.natural_sort_key)
|
| 157 |
return jsonify(reg_list_part="\n".join(unique_parts))
|
|
|
|
| 161 |
def handle_connect():
|
| 162 |
global connected_clients
|
| 163 |
connected_clients += 1
|
| 164 |
+
logger.info(f"클라이언트 연결: {connected_clients}명")
|
| 165 |
|
| 166 |
@socketio.on('disconnect')
|
| 167 |
def handle_disconnect():
|
| 168 |
global connected_clients
|
| 169 |
connected_clients -= 1
|
| 170 |
+
logger.info(f"연결 해제: {connected_clients}명")
|
| 171 |
if connected_clients <= 0:
|
| 172 |
cleanup_connections()
|
| 173 |
+
logger.info("서버 종료")
|
| 174 |
os._exit(0)
|
| 175 |
|
| 176 |
def cleanup_connections():
|
| 177 |
for region, rag in region_rag_objects.items():
|
| 178 |
try:
|
| 179 |
rag["sqlite_conn"].close()
|
| 180 |
+
logger.info(f"[{region}] DB 연결 종료")
|
| 181 |
except:
|
| 182 |
pass
|
| 183 |
|
|
|
|
| 205 |
data = response.json()
|
| 206 |
return data["choices"][0]["message"]["content"]
|
| 207 |
except requests.exceptions.RequestException as e:
|
| 208 |
+
logger.info(f"Together AI 분석 API 호출 실패: {e}")
|
| 209 |
+
traceback.logger.info_exc()
|
| 210 |
return f"AI 분석 중 오류가 발생했습니다: {e}"
|
| 211 |
|
| 212 |
# --- Together AI 번역 (SDK -> requests 직접 호출로 변경) ---
|
|
|
|
| 232 |
data = response.json()
|
| 233 |
return data["choices"][0]["message"]["content"]
|
| 234 |
except requests.exceptions.RequestException as e:
|
| 235 |
+
logger.info(f"Together AI 번역 API 호출 실패: {e}")
|
| 236 |
+
traceback.logger.info_exc()
|
| 237 |
return query_txt # 번역 실패 시 원래 쿼리를 사용 (최소한의 기능 유지)
|
| 238 |
|
| 239 |
# --- 검색 ---
|
| 240 |
def search_DB_from_multiple_regions(query, selected_regions, region_rag_objects):
|
| 241 |
selected_regions = selected_regions or list(region_rag_objects.keys())
|
| 242 |
query = Gemma3_AI_Translate(query)
|
| 243 |
+
logger.info(f"번역된 쿼리: {query}")
|
| 244 |
|
| 245 |
combined_results = []
|
| 246 |
for region in selected_regions:
|
|
|
|
| 270 |
sqlite_conn=sqlite_conn,
|
| 271 |
enable_detailed_search=True
|
| 272 |
)
|
| 273 |
+
logger.info(f"[{region}] 검색: {len(results)}건")
|
| 274 |
combined_results.extend(results)
|
| 275 |
|
| 276 |
return combined_results
|
|
|
|
| 281 |
AI_Result = "검색 결과가 없습니다." if not Rag_Results else Gemma3_AI_analysis(query, Rag_Results)
|
| 282 |
|
| 283 |
with open(ResultFile_FolderAddress, 'w', encoding='utf-8') as f:
|
| 284 |
+
logger.info("검색된 문서:", file=f)
|
| 285 |
for i, doc in enumerate(Rag_Results):
|
| 286 |
+
logger.info(f"문서 {i+1}: {doc.page_content[:200]}... (메타: {doc.metadata})", file=f)
|
| 287 |
+
logger.info("\n답변:", file=f)
|
| 288 |
+
logger.info(AI_Result, file=f)
|
| 289 |
|
| 290 |
return AI_Result
|
| 291 |
|