scipious commited on
Commit
d2ea144
·
verified ·
1 Parent(s): a9abd1a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +239 -27
app.py CHANGED
@@ -3,8 +3,10 @@ import os
3
  #os.environ["PYDANTIC_SKIP_VALIDATING_CORE_SCHEMAS"] = "1"
4
  # --------------------------------------------------------------------------
5
 
6
- from flask import Flask, render_template, jsonify, request
7
- from flask_socketio import SocketIO
 
 
8
  import threading
9
  import sqlite3
10
  import gc
@@ -58,6 +60,9 @@ region_paths = {
58
  # --- 프롬프트 ---
59
  lexi_prompts = leximind_prompts.PromptLibrary()
60
 
 
 
 
61
  # --- RAG 객체 ---
62
  region_rag_objects = {}
63
 
@@ -124,33 +129,187 @@ def load_rag_objects():
124
  # --- 웹 ---
125
  @app.route('/')
126
  def index():
127
- return render_template('chat.html')
128
 
129
- # --- 메시지 ---
130
- @app.route('/get_message', methods=['POST'])
131
- def get_message():
132
- global Filtered_search, filters
133
- data = request.get_json()
134
- query = data.get('query', '').strip()
135
- regions = data.get('regions', [])
136
- selected_regulations = data.get('selectedRegulations', [])
137
-
138
- logger.info(f"Query: {query}")
139
-
140
- filters = {"regulation_part": []}
141
- Filtered_search = bool(selected_regulations)
142
- if selected_regulations:
143
- for reg in selected_regulations:
144
- title = reg.get('title', '')
145
- if title:
146
- filters["regulation_part"].append(title)
147
-
148
- Rag_Results = search_DB_from_multiple_regions(query, regions, region_rag_objects)
149
- AImessage = RegAI(query, Rag_Results, ResultFile_FolderAddress)
150
 
151
- logger.info(f"Answer: {AImessage}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
- return jsonify(message=AImessage)
154
 
155
  # --- 법규 리스트 ---
156
  @app.route('/get_reg_list', methods=['POST'])
@@ -280,7 +439,6 @@ def Gemma3_AI_Translate(query_txt):
280
  # --- 검색 ---
281
  def search_DB_from_multiple_regions(query, selected_regions, region_rag_objects):
282
  selected_regions = selected_regions or list(region_rag_objects.keys())
283
- query = Gemma3_AI_Translate(query)
284
  logger.info(f"번역된 쿼리: {query}")
285
 
286
  combined_results = []
@@ -336,6 +494,60 @@ def RegAI(query, Rag_Results, ResultFile_FolderAddress):
336
 
337
  return AI_Result
338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
  # --- 실행 ---
340
  if __name__ == '__main__':
341
  # 로컬 개발용
 
3
  #os.environ["PYDANTIC_SKIP_VALIDATING_CORE_SCHEMAS"] = "1"
4
  # --------------------------------------------------------------------------
5
 
6
+ from flask import Flask, render_template, jsonify, request, Response
7
+ from flask_socketio import SocketIO, emit
8
+ import uuid
9
+
10
  import threading
11
  import sqlite3
12
  import gc
 
60
  # --- 프롬프트 ---
61
  lexi_prompts = leximind_prompts.PromptLibrary()
62
 
63
+ # 세션별 요청 추적을 위한 딕셔너리
64
+ active_sessions = {}
65
+
66
  # --- RAG 객체 ---
67
  region_rag_objects = {}
68
 
 
129
  # --- 웹 ---
130
  @app.route('/')
131
  def index():
132
+ return render_template('chat_v02.html')
133
 
134
+ # 전역 변수에 기본값 추가
135
+ Search_each_all_mode = True # 기본값을 클라이언트에서 제어 가능
136
+
137
+ @socketio.on('search_query')
138
+ def handle_search_query(data):
139
+ global Filtered_search
140
+ global filters
141
+ global Search_each_all_mode
142
+
143
+ # 세션 ID 생성
144
+ session_id = str(uuid.uuid4())
145
+ active_sessions[session_id] = True
146
+
147
+ # 클라이언트에 session_id 전달
148
+ emit('search_started', {'session_id': session_id})
 
 
 
 
 
 
149
 
150
+ try:
151
+ # 클라이언트에서 전송된 검색 모드 사용
152
+ Search_each_all_mode = data.get('searchEachMode', True)
153
+
154
+ query = data.get('query', '')
155
+ regions = data.get('regions', [])
156
+ selected_regulations = data.get('selectedRegulations', [])
157
+
158
+ emit('search_status', {'status': 'processing', 'message': '검색 요청을 처리하는 중입니다...'})
159
+
160
+ logger.info(f"선택된 지역 : {regions}")
161
+ logger.info(f"선택된 법규 : {selected_regulations}")
162
+ if Search_each_all_mode:
163
+ logger.info(f"검색 모드 : 각각 검색")
164
+ else:
165
+ logger.info(f"검색 모드 : 통합 검색")
166
+
167
+ # 법규 타입별로 필터 구분
168
+ filters = {
169
+ "regulation_part": [],
170
+ "regulation_section": [],
171
+ "chapter_section": [],
172
+ "jo": []
173
+ }
174
+
175
+ # 번역 진행 상황 알림
176
+ emit('search_status', {'status': 'translating', 'message': '질문을 번역하는 중입니다...'})
177
+
178
+ if session_id not in active_sessions:
179
+ emit('search_cancelled', {'message': '검색이 취소되었습니다.'})
180
+ emit('search_status', {'status': 'processing', 'message': 'Ready to search'})
181
+ return
182
+
183
+ Translated_query = Gemma3_AI_Translate(query)
184
+ emit('search_status', {'status': 'translated', 'message': f'번역 완료: {Translated_query}'})
185
+ logger.info(f"Query: Original query : {query}")
186
+ logger.info(f"Query: Translated_query : {Translated_query}")
187
+
188
+ if selected_regulations:
189
+ Filtered_search = True
190
+ cont_selected_num = 0
191
+
192
+ # 파일로 저장
193
+ output_path = os.path.join(current_dir, "merged_ai_messages.txt")
194
+
195
+ if os.path.exists(output_path):
196
+ os.remove(output_path)
197
+ print(f"기존 파일 삭제 완료: {output_path}")
198
+
199
+ if Search_each_all_mode:
200
+ # 각각 검색 모드
201
+ emit('search_status', {'status': 'searching', 'message': f'선택된 {len(selected_regulations)}개 법규를 각각 검색 중...'})
202
+
203
+ for i, regulation in enumerate(selected_regulations):
204
+ if session_id not in active_sessions:
205
+ emit('search_cancelled', {'message': '검색이 취소되었습니다.'})
206
+ emit('search_status', {'status': 'processing', 'message': 'Ready to search'})
207
+ return
208
+
209
+ regulation_title = regulation.get('title', '')
210
+ regulation_id = regulation.get('id', '')
211
+ regulation_type = regulation.get('type', 'part') # 타입 정보 추출
212
+
213
+ emit('search_status', {
214
+ 'status': 'searching_regulation',
215
+ 'message': f'법규 {i+1}/{len(selected_regulations)}: [{regulation_type.upper()}] {regulation_title} 검색 중...',
216
+ 'progress': (i / len(selected_regulations)) * 100
217
+ })
218
+
219
+ # 법규 타입별 필터 생성
220
+ current_filters = create_filter_by_type(regulation_type, regulation_title)
221
+ print(f"[{regulation_type}] 필터에 추가: {regulation_title}")
222
+ print(f"생성된 필터: {current_filters}")
223
+
224
+ Rag_Results = search_DB_from_multiple_regions(Translated_query, regions, region_rag_objects, current_filters)
225
+
226
+ if session_id not in active_sessions:
227
+ emit('search_cancelled', {'message': '검색이 취소되었습니다.'})
228
+ emit('search_status', {'status': 'processing', 'message': 'Ready to search'})
229
+ return
230
+
231
+ emit('search_status', {
232
+ 'status': 'ai_processing',
233
+ 'message': f'AI가 [{regulation_type.upper()}] {regulation_title}에 대한 답변을 생성 중...'
234
+ })
235
+
236
+ AImessage = RegAI(query, Rag_Results, ResultFile_FolderAddress)
237
+ logger.info(f"Answer: {AImessage}")
238
+
239
+ if session_id not in active_sessions:
240
+ emit('search_cancelled', {'message': '검색이 취소되었습니다.'})
241
+ return
242
+
243
+ # 각 법규별 결과를 실시간으로 전송 (타입 정보 포함)
244
+ emit('regulation_result', {
245
+ 'regulation_title': f"[{regulation_type.upper()}] {regulation_title}",
246
+ 'regulation_index': i + 1,
247
+ 'total_regulations': len(selected_regulations),
248
+ 'regulation_type': regulation_type,
249
+ 'result': AImessage
250
+ })
251
+
252
+ # 파일에 저장
253
+ if isinstance(AImessage, str) and AImessage.strip():
254
+ with open(output_path, "a", encoding="utf-8") as f:
255
+ cont_selected_num += 1
256
+ from datetime import datetime
257
+ stamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
258
+ f.write(f"\n--- [{stamp}] message #{cont_selected_num} --- Regulation Type: {regulation_type} --- Regulation Name : {regulation_title} ---\n {AImessage}")
259
+
260
+ emit('search_complete', {'status': 'completed', 'message': '모든 법규 검색이 완료되었습니다.'})
261
+ else:
262
+ # 통합 검색 모드 - 타입별로 그룹화
263
+ grouped_regulations = group_regulations_by_type(selected_regulations)
264
+ emit('search_status', {'status': 'searching', 'message': f'선택된 {len(selected_regulations)}개 법규를 타입별로 통합하여 검색 중...'})
265
+
266
+ # 타입별로 필터 생성
267
+ combined_filters = create_combined_filters(grouped_regulations)
268
+ logger.info(f"통합 필터: {combined_filters}")
269
+
270
+ Rag_Results = search_DB_from_multiple_regions(Translated_query, regions, region_rag_objects, combined_filters)
271
+
272
+ if session_id in active_sessions:
273
+ emit('search_status', {'status': 'ai_processing', 'message': 'AI가 통합 답변을 생성 중...'})
274
+ AImessage = RegAI(query, Rag_Results, ResultFile_FolderAddress)
275
+ logger.info(f"Answer: {AImessage}")
276
+
277
+ if session_id in active_sessions:
278
+ emit('search_result', {'result': AImessage})
279
+ emit('search_complete', {'status': 'completed', 'message': '통합 검색이 완료되었습니다.'})
280
+
281
+ else:
282
+ Filtered_search = False
283
+ emit('search_status', {'status': 'searching_all', 'message': '전체 법규에서 검색 중...'})
284
+
285
+ # 필터 없이 검색
286
+ Rag_Results = search_DB_from_multiple_regions(Translated_query, regions, region_rag_objects, None)
287
+
288
+ if session_id in active_sessions:
289
+ emit('search_status', {'status': 'ai_processing', 'message': 'AI가 답변을 생성 중...'})
290
+ AImessage = RegAI(query, Rag_Results, ResultFile_FolderAddress)
291
+ logger.info(f"Answer: {AImessage}")
292
+
293
+ if session_id in active_sessions:
294
+ emit('search_result', {'result': AImessage})
295
+ emit('search_complete', {'status': 'completed', 'message': '검색이 완료되었습니다.'})
296
+
297
+ except Exception as e:
298
+ print(f"검색 오류: {e}")
299
+ emit('search_error', {'error': str(e), 'message': '검색 중 오류가 발생했습니다.'})
300
+ finally:
301
+ # 세션 정리
302
+ if session_id in active_sessions:
303
+ del active_sessions[session_id]
304
+
305
+
306
+ @socketio.on('cancel_search')
307
+ def handle_cancel_search(data):
308
+ session_id = data.get('session_id')
309
+ if session_id and session_id in active_sessions:
310
+ del active_sessions[session_id]
311
+ emit('search_cancelled', {'message': '검색이 취소되었습니다.'})
312
 
 
313
 
314
  # --- 법규 리스트 ---
315
  @app.route('/get_reg_list', methods=['POST'])
 
439
  # --- 검색 ---
440
  def search_DB_from_multiple_regions(query, selected_regions, region_rag_objects):
441
  selected_regions = selected_regions or list(region_rag_objects.keys())
 
442
  logger.info(f"번역된 쿼리: {query}")
443
 
444
  combined_results = []
 
494
 
495
  return AI_Result
496
 
497
+ # 법규 타입별 필터 생성 함수
498
+ def create_filter_by_type(regulation_type, regulation_title):
499
+ """법규 타입에 따라 적절한 필터 딕셔너리 생성"""
500
+ filter_dict = {
501
+ "regulation_part": [],
502
+ "regulation_section": [],
503
+ "chapter_section": [],
504
+ "jo": []
505
+ }
506
+
507
+ # 타입별 매핑
508
+ type_mapping = {
509
+ "part": "regulation_part",
510
+ "section": "regulation_section",
511
+ "chapter": "chapter_section",
512
+ "jo": "jo"
513
+ }
514
+
515
+ filter_key = type_mapping.get(regulation_type, "regulation_part")
516
+ filter_dict[filter_key].append(regulation_title)
517
+
518
+ return filter_dict
519
+
520
+ # 법규들을 타입별로 그룹화하는 함수
521
+ def group_regulations_by_type(selected_regulations):
522
+ """선택된 법규들을 타입별로 그룹화"""
523
+ grouped = {
524
+ "part": [],
525
+ "section": [],
526
+ "chapter": [],
527
+ "jo": []
528
+ }
529
+
530
+ for regulation in selected_regulations:
531
+ regulation_type = regulation.get('type', 'part')
532
+ regulation_title = regulation.get('title', '')
533
+
534
+ if regulation_title and regulation_type in grouped:
535
+ grouped[regulation_type].append(regulation_title)
536
+
537
+ return grouped
538
+
539
+ # 통합 필터 생성 함수
540
+ def create_combined_filters(grouped_regulations):
541
+ """그룹화된 법규들로부터 통합 필터 생성"""
542
+ filters = {
543
+ "regulation_part": grouped_regulations["part"],
544
+ "regulation_section": grouped_regulations["section"],
545
+ "chapter_section": grouped_regulations["chapter"],
546
+ "jo": grouped_regulations["jo"]
547
+ }
548
+
549
+ return filters
550
+
551
  # --- 실행 ---
552
  if __name__ == '__main__':
553
  # 로컬 개발용