kimrang commited on
Commit
3e228de
·
verified ·
1 Parent(s): c428f9f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +190 -41
app.py CHANGED
@@ -55,18 +55,31 @@ def debug_file_system():
55
  debug_file_system()
56
 
57
  def find_vectorstore_folders():
58
- """현재 디렉토리에서 벡터스토어 폴더들을 찾는 함수"""
59
  current_dir = os.getcwd()
60
  print(f"현재 디렉토리: {current_dir}")
61
 
62
  # 모든 파일과 폴더 확인
63
- all_items = os.listdir(current_dir)
64
- print(f"현재 디렉토리 내 모든 항목들: {all_items}")
 
 
 
 
65
 
66
  # 예상되는 벡터스토어 폴더들
67
  expected_folders = ['vectorstore1', 'vectorstore2', 'vectorstore3']
68
  vectorstore_folders = []
69
 
 
 
 
 
 
 
 
 
 
70
  for folder_name in expected_folders:
71
  folder_path = os.path.join(current_dir, folder_name)
72
  if os.path.exists(folder_path) and os.path.isdir(folder_path):
@@ -74,16 +87,19 @@ def find_vectorstore_folders():
74
  folder_contents = os.listdir(folder_path)
75
  print(f"📁 {folder_name} 폴더 내용: {folder_contents}")
76
 
77
- # 필수 파일들 확인
78
- required_files = ['index.faiss', 'index.pkl']
79
- has_all_files = all(file in folder_contents for file in required_files)
80
 
81
- if has_all_files:
 
 
 
 
 
82
  vectorstore_folders.append(folder_name)
83
- print(f"✅ {folder_name} - 모든 필수 파일 존재")
84
  else:
85
- missing_files = [f for f in required_files if f not in folder_contents]
86
- print(f"❌ {folder_name} - 누락된 파일: {missing_files}")
87
 
88
  except Exception as e:
89
  print(f"❌ {folder_name} 폴더 확인 중 오류: {e}")
@@ -92,52 +108,137 @@ def find_vectorstore_folders():
92
 
93
  if not vectorstore_folders:
94
  print("❌ 사용 가능한 벡터스토어 폴더를 찾을 수 없습니다")
 
 
 
 
 
95
  else:
96
  print(f"✅ 총 {len(vectorstore_folders)}개의 벡터스토어 폴더를 찾았습니다: {vectorstore_folders}")
97
 
98
  return vectorstore_folders
99
 
100
  def load_all_vectorstores():
101
- """모든 벡터스토어를 로드하고 통합하는 함수"""
102
  global vectorstores, embeddings, combined_vectorstore
103
 
 
 
 
104
  if not embeddings:
105
- embeddings = HuggingFaceEmbeddings(
106
- model_name="sentence-transformers/all-MiniLM-L6-v2"
107
- )
 
 
 
 
 
 
108
 
109
  # 벡터스토어 폴더들 찾기
110
  folders = find_vectorstore_folders()
111
 
 
 
 
 
112
  loaded_vectorstores = []
113
 
114
  for folder_name in folders:
 
115
  try:
116
- vectorstore = FAISS.load_local(
117
- f"./{folder_name}",
118
- embeddings,
119
- allow_dangerous_deserialization=True
120
- )
121
- vectorstores[folder_name] = vectorstore
122
- loaded_vectorstores.append(vectorstore)
123
- print(f"✅ {folder_name} 로드 완료")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  except Exception as e:
125
- print(f"❌ {folder_name} 로드 실패: {e}")
 
 
126
 
127
- # 벡터스토어들을 통합 (첫 번째를 기본으로 하고 나머지를 merge)
128
  if loaded_vectorstores:
129
- combined_vectorstore = loaded_vectorstores[0]
130
- for vs in loaded_vectorstores[1:]:
131
- try:
132
- combined_vectorstore.merge_from(vs)
133
- print(f"✅ 벡터스토어 통합 완료")
134
- except Exception as e:
135
- print(f"❌ 벡터스토어 통합 실패: {e}")
136
- print(f"🎉 {len(loaded_vectorstores)}개의 벡터스토어가 통합되었습니다")
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
- return len(loaded_vectorstores) > 0
 
139
 
140
- # 질문 리스트 (기존과 동일)
141
  suggested_questions = [
142
  '교원 신규 임용은 어떻게 하나요?',
143
  '교원 연구년 기간은 어떻게 되나요?',
@@ -161,7 +262,7 @@ suggested_questions = [
161
  '안전사고예방계획은 어디에 제출해야 하나요?'
162
  ]
163
 
164
- # 프롬프트 템플릿 (기존과 동일)
165
  prompt_template = """당신은 한남대학교 규정집 도우미입니다.
166
  반드시 한국어로만 답변해주세요. 영어나 다른 언어는 절대 사용하지 마세요.
167
  주어진 문서 내용을 바탕으로 질문에 대해 정확하고 친절하게 한국어로 답변해주세요.
@@ -182,7 +283,7 @@ prompt = PromptTemplate(
182
  )
183
 
184
  def respond_with_groq(question, selected_q, model):
185
- """질문에 대한 답변을 생성하는 함수"""
186
 
187
  # 선택된 질문이 있으면 그것을 사용
188
  if selected_q != "직접 입력":
@@ -192,13 +293,29 @@ def respond_with_groq(question, selected_q, model):
192
  return "질문을 입력해주세요."
193
 
194
  if not GROQ_API_KEY:
195
- return "❌ API 키가 설정되지 않았습니다. 관리자에게 문의하세요."
196
 
197
- # 통합된 벡터스토어가 로드되지 않은 경우
198
  if not combined_vectorstore:
199
- return " 사용 가능한 벡터스토어가 없습니다. 관리자에게 문의하세요."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
 
201
  try:
 
202
  print(f"✅ 통합된 벡터스토어를 사용하여 검색 중...")
203
 
204
  # LLM 설정
@@ -209,6 +326,15 @@ def respond_with_groq(question, selected_q, model):
209
  max_tokens=1000
210
  )
211
 
 
 
 
 
 
 
 
 
 
212
  # QA 체인 생성
213
  qa_chain = RetrievalQA.from_chain_type(
214
  llm=llm,
@@ -226,7 +352,14 @@ def respond_with_groq(question, selected_q, model):
226
  import traceback
227
  error_details = traceback.format_exc()
228
  print(f"❌ 상세 오류 정보:\n{error_details}")
229
- return f"❌ 오류가 발생했습니다: {str(e)}"
 
 
 
 
 
 
 
230
 
231
  def update_question(selected):
232
  """드롭다운 선택 시 질문을 업데이트하는 함수"""
@@ -235,16 +368,32 @@ def update_question(selected):
235
  return ""
236
 
237
  # 앱 시작시 벡터스토어들 로드
 
238
  vectorstores_loaded = load_all_vectorstores()
239
 
 
 
 
 
 
 
 
 
240
  # Gradio 인터페이스 생성
241
  with gr.Blocks(title="한남대학교 Q&A") as interface:
242
- gr.HTML("""
243
  <div style="text-align: center; padding: 20px; background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px; margin-bottom: 20px;">
244
  <h1>🏫 한남대학교 규정집 Q&A</h1>
245
  <p>한남대학교 규정집에 대한 질문에 답변해드립니다.</p>
246
  </div>
247
  """)
 
 
 
 
 
 
 
248
 
249
  with gr.Row():
250
  with gr.Column(scale=1):
 
55
  debug_file_system()
56
 
57
  def find_vectorstore_folders():
58
+ """현재 디렉토리에서 벡터스토어 폴더들을 찾는 함수 - 개선 버전"""
59
  current_dir = os.getcwd()
60
  print(f"현재 디렉토리: {current_dir}")
61
 
62
  # 모든 파일과 폴더 확인
63
+ try:
64
+ all_items = os.listdir(current_dir)
65
+ print(f"현재 디렉토리 내 모든 항목들: {all_items}")
66
+ except Exception as e:
67
+ print(f"디렉토리 읽기 오류: {e}")
68
+ return []
69
 
70
  # 예상되는 벡터스토어 폴더들
71
  expected_folders = ['vectorstore1', 'vectorstore2', 'vectorstore3']
72
  vectorstore_folders = []
73
 
74
+ # 실제로 존재하는 벡터스토어 관련 폴더들도 찾기
75
+ for item in all_items:
76
+ if os.path.isdir(item) and ('vectorstore' in item.lower() or 'vector' in item.lower()):
77
+ expected_folders.append(item)
78
+
79
+ # 중복 제거
80
+ expected_folders = list(set(expected_folders))
81
+ print(f"확인할 폴더들: {expected_folders}")
82
+
83
  for folder_name in expected_folders:
84
  folder_path = os.path.join(current_dir, folder_name)
85
  if os.path.exists(folder_path) and os.path.isdir(folder_path):
 
87
  folder_contents = os.listdir(folder_path)
88
  print(f"📁 {folder_name} 폴더 내용: {folder_contents}")
89
 
90
+ # FAISS 파일들 확인 (더 유연하게)
91
+ has_faiss = any('.faiss' in file for file in folder_contents)
92
+ has_pkl = any('.pkl' in file for file in folder_contents)
93
 
94
+ if has_faiss and has_pkl:
95
+ vectorstore_folders.append(folder_name)
96
+ print(f"✅ {folder_name} - FAISS 파일들 존재")
97
+ elif has_faiss or has_pkl:
98
+ print(f"⚠️ {folder_name} - 일부 파일만 존재 (faiss: {has_faiss}, pkl: {has_pkl})")
99
+ # 일부만 있어도 시도해보기
100
  vectorstore_folders.append(folder_name)
 
101
  else:
102
+ print(f"❌ {folder_name} - FAISS 파일들 없음")
 
103
 
104
  except Exception as e:
105
  print(f"❌ {folder_name} 폴더 확인 중 오류: {e}")
 
108
 
109
  if not vectorstore_folders:
110
  print("❌ 사용 가능한 벡터스토어 폴더를 찾을 수 없습니다")
111
+ # 디버깅을 위해 현재 디렉토리의 모든 하위 폴더 출력
112
+ print("📋 현재 디렉토리의 모든 폴더들:")
113
+ for item in all_items:
114
+ if os.path.isdir(item):
115
+ print(f" 📁 {item}")
116
  else:
117
  print(f"✅ 총 {len(vectorstore_folders)}개의 벡터스토어 폴더를 찾았습니다: {vectorstore_folders}")
118
 
119
  return vectorstore_folders
120
 
121
  def load_all_vectorstores():
122
+ """모든 벡터스토어를 로드하고 통합하는 함수 - 개선 버전"""
123
  global vectorstores, embeddings, combined_vectorstore
124
 
125
+ print("🔄 벡터스토어 로딩 시작...")
126
+
127
+ # 임베딩 모델 초기화
128
  if not embeddings:
129
+ try:
130
+ print("🤖 임베딩 모델 로딩 중...")
131
+ embeddings = HuggingFaceEmbeddings(
132
+ model_name="sentence-transformers/all-MiniLM-L6-v2"
133
+ )
134
+ print("✅ 임베딩 모델 로딩 완료")
135
+ except Exception as e:
136
+ print(f"❌ 임베딩 모델 로딩 실패: {e}")
137
+ return False
138
 
139
  # 벡터스토어 폴더들 찾기
140
  folders = find_vectorstore_folders()
141
 
142
+ if not folders:
143
+ print("❌ 벡터스토어 폴더를 찾을 수 없습니다")
144
+ return False
145
+
146
  loaded_vectorstores = []
147
 
148
  for folder_name in folders:
149
+ folder_path = f"./{folder_name}"
150
  try:
151
+ print(f"📂 {folder_name} 로딩 시도 중...")
152
+
153
+ # 다양한 방법으로 로딩 시도
154
+ vectorstore = None
155
+
156
+ # 방법 1: 기본 로딩
157
+ try:
158
+ vectorstore = FAISS.load_local(
159
+ folder_path,
160
+ embeddings,
161
+ allow_dangerous_deserialization=True
162
+ )
163
+ print(f"✅ {folder_name} 로드 완료 (방법 1)")
164
+ except Exception as e1:
165
+ print(f"⚠️ 방법 1 실패: {e1}")
166
+
167
+ # 방법 2: 절대 경로로 시도
168
+ try:
169
+ abs_path = os.path.abspath(folder_name)
170
+ vectorstore = FAISS.load_local(
171
+ abs_path,
172
+ embeddings,
173
+ allow_dangerous_deserialization=True
174
+ )
175
+ print(f"✅ {folder_name} 로드 완료 (방법 2)")
176
+ except Exception as e2:
177
+ print(f"⚠️ 방법 2 실패: {e2}")
178
+
179
+ # 방법 3: 직접 파일 지정
180
+ try:
181
+ index_file = os.path.join(folder_name, "index.faiss")
182
+ pkl_file = os.path.join(folder_name, "index.pkl")
183
+
184
+ if os.path.exists(index_file) and os.path.exists(pkl_file):
185
+ vectorstore = FAISS.load_local(
186
+ folder_name,
187
+ embeddings,
188
+ allow_dangerous_deserialization=True
189
+ )
190
+ print(f"✅ {folder_name} 로드 완료 (방법 3)")
191
+ else:
192
+ print(f"❌ 필수 파일 없음: {index_file}, {pkl_file}")
193
+ except Exception as e3:
194
+ print(f"❌ 방법 3 실패: {e3}")
195
+
196
+ if vectorstore:
197
+ vectorstores[folder_name] = vectorstore
198
+ loaded_vectorstores.append(vectorstore)
199
+
200
+ # 벡터스토어 정보 출력
201
+ try:
202
+ doc_count = vectorstore.index.ntotal
203
+ print(f"📊 {folder_name}: {doc_count}개 문서")
204
+ except:
205
+ print(f"📊 {folder_name}: 문서 수 확인 불가")
206
+ else:
207
+ print(f"❌ {folder_name} 로드 실패")
208
+
209
  except Exception as e:
210
+ print(f"❌ {folder_name} 로드 예외 발생: {e}")
211
+ import traceback
212
+ traceback.print_exc()
213
 
214
+ # 벡터스토어들을 통합
215
  if loaded_vectorstores:
216
+ try:
217
+ print("🔗 벡터스토어 통합 시작...")
218
+ combined_vectorstore = loaded_vectorstores[0]
219
+
220
+ for i, vs in enumerate(loaded_vectorstores[1:], 1):
221
+ try:
222
+ combined_vectorstore.merge_from(vs)
223
+ print(f" 벡터스토어 {i+1} 통합 완료")
224
+ except Exception as e:
225
+ print(f"❌ 벡터스토어 {i+1} 통합 실패: {e}")
226
+
227
+ print(f"🎉 총 {len(loaded_vectorstores)}개의 벡터스토어가 로드되고 통합되었습니다")
228
+ return True
229
+
230
+ except Exception as e:
231
+ print(f"❌ 벡터스토어 통합 중 오류: {e}")
232
+ # 통합 실패시 첫 번째 것만 사용
233
+ if loaded_vectorstores:
234
+ combined_vectorstore = loaded_vectorstores[0]
235
+ print("⚠️ 첫 번째 벡터스토어만 사용합니다")
236
+ return True
237
 
238
+ print("❌ 사용 가능한 벡터스토어가 없습니다")
239
+ return False
240
 
241
+ # 질문 리스트
242
  suggested_questions = [
243
  '교원 신규 임용은 어떻게 하나요?',
244
  '교원 연구년 기간은 어떻게 되나요?',
 
262
  '안전사고예방계획은 어디에 제출해야 하나요?'
263
  ]
264
 
265
+ # 프롬프트 템플릿
266
  prompt_template = """당신은 한남대학교 규정집 도우미입니다.
267
  반드시 한국어로만 답변해주세요. 영어나 다른 언어는 절대 사용하지 마세요.
268
  주어진 문서 내용을 바탕으로 질문에 대해 정확하고 친절하게 한국어로 답변해주세요.
 
283
  )
284
 
285
  def respond_with_groq(question, selected_q, model):
286
+ """질문에 대한 답변을 생성하는 함수 - 개선 버전"""
287
 
288
  # 선택된 질문이 있으면 그것을 사용
289
  if selected_q != "직접 입력":
 
293
  return "질문을 입력해주세요."
294
 
295
  if not GROQ_API_KEY:
296
+ return "❌ GROQ API 키가 설정되지 않았습니다. Hugging Face Spaces의 Settings에서 GROQ_API_KEY를 설정해주세요."
297
 
298
+ # 통합된 벡터스토어가 로드되지 않은 경우 재시도
299
  if not combined_vectorstore:
300
+ print("⚠️ 벡터스토어가 로드되지 않음. 재로딩 시도...")
301
+ success = load_all_vectorstores()
302
+ if not success:
303
+ # 디버깅 정보 출력
304
+ debug_file_system()
305
+ return """❌ 벡터스토어를 로드할 수 없습니다.
306
+
307
+ 가능한 원인:
308
+ 1. 벡터스토어 파일이 올바르게 업로드되지 않음
309
+ 2. 파일 권한 문제
310
+ 3. Git LFS 설정 필요 (큰 파일의 경우)
311
+
312
+ 해결 방법:
313
+ 1. vectorstore 폴더들이 제대로 업로드되었는지 확인
314
+ 2. 각 폴더에 index.faiss와 index.pkl 파일이 있는지 확인
315
+ 3. Git LFS를 사용해 큰 파일들을 관리해보세요"""
316
 
317
  try:
318
+ print(f"🔍 질문: {question}")
319
  print(f"✅ 통합된 벡터스토어를 사용하여 검색 중...")
320
 
321
  # LLM 설정
 
326
  max_tokens=1000
327
  )
328
 
329
+ # 검색 테스트
330
+ try:
331
+ retriever = combined_vectorstore.as_retriever(search_kwargs={"k": 5})
332
+ docs = retriever.get_relevant_documents(question)
333
+ print(f"🔍 검색된 문서 수: {len(docs)}")
334
+ except Exception as e:
335
+ print(f"❌ 검색 오류: {e}")
336
+ return f"❌ 문서 검색 중 오류가 발생했습니다: {str(e)}"
337
+
338
  # QA 체인 생성
339
  qa_chain = RetrievalQA.from_chain_type(
340
  llm=llm,
 
352
  import traceback
353
  error_details = traceback.format_exc()
354
  print(f"❌ 상세 오류 정보:\n{error_details}")
355
+ return f"""답변 생성 중 오류가 발생했습니다: {str(e)}
356
+
357
+ 디버깅 정보:
358
+ - 벡터스토어 로드됨: {combined_vectorstore is not None}
359
+ - API 키 설정됨: {GROQ_API_KEY is not None}
360
+ - 모델: {model}
361
+
362
+ 관리자에게 위 정보와 함께 문의해주세요."""
363
 
364
  def update_question(selected):
365
  """드롭다운 선택 시 질문을 업데이트하는 함수"""
 
368
  return ""
369
 
370
  # 앱 시작시 벡터스토어들 로드
371
+ print("🚀 앱 시작 - 벡터스토어 로딩 중...")
372
  vectorstores_loaded = load_all_vectorstores()
373
 
374
+ # 상태 메시지 생성
375
+ if vectorstores_loaded:
376
+ status_message = "✅ 벡터스토어가 성공적으로 로드되었습니다!"
377
+ status_color = "green"
378
+ else:
379
+ status_message = "❌ 벡터스토어 로딩에 실패했습니다. 관리자에게 문의하세요."
380
+ status_color = "red"
381
+
382
  # Gradio 인터페이스 생성
383
  with gr.Blocks(title="한남대학교 Q&A") as interface:
384
+ gr.HTML(f"""
385
  <div style="text-align: center; padding: 20px; background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px; margin-bottom: 20px;">
386
  <h1>🏫 한남대학교 규정집 Q&A</h1>
387
  <p>한남대학교 규정집에 대한 질문에 답변해드립니다.</p>
388
  </div>
389
  """)
390
+
391
+ # 상태 표시 추가
392
+ gr.HTML(f"""
393
+ <div style="text-align: center; padding: 10px; background-color: {status_color}; color: white; border-radius: 5px; margin-bottom: 10px;">
394
+ <strong>{status_message}</strong>
395
+ </div>
396
+ """)
397
 
398
  with gr.Row():
399
  with gr.Column(scale=1):