SOY NV AI commited on
Commit
59f2d9e
·
1 Parent(s): 04600a5

fix: GraphRAG 생성 로직 개선 및 회차 분석 후 자동 Graph Extraction 추가

Browse files

- create_chunks_for_file에서 Graph Extraction이 회차 분석 성공 여부와 관계없이 실행되도록 수정
- 회차 분석 API 성공 후 Graph Extraction 자동 실행 추가
- parent_chunk 변수 스코프 문제 해결
- 로깅 미들웨어 추가 및 개선

EXAONE_설치_가이드.md CHANGED
@@ -164,6 +164,8 @@ tokenizer = AutoTokenizer.from_pretrained("LGAI-EXAONE/EXAONE-3.0-7.8B-Instruct"
164
 
165
 
166
 
 
 
167
 
168
 
169
 
 
164
 
165
 
166
 
167
+
168
+
169
 
170
 
171
 
EXAONE_추가_안내.md CHANGED
@@ -81,6 +81,8 @@ Ollama를 거치지 않고 Python에서 직접 Hugging Face 모델을 사용할
81
 
82
 
83
 
 
 
84
 
85
 
86
 
 
81
 
82
 
83
 
84
+
85
+
86
 
87
 
88
 
add_exaone_model.py CHANGED
@@ -159,6 +159,8 @@ if __name__ == "__main__":
159
 
160
 
161
 
 
 
162
 
163
 
164
 
 
159
 
160
 
161
 
162
+
163
+
164
 
165
 
166
 
app/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
  Flask 애플리케이션 초기화
3
  """
4
 
5
- from flask import Flask
6
  from flask_login import LoginManager
7
  import sqlite3
8
  from pathlib import Path
@@ -69,6 +69,20 @@ def create_app() -> Flask:
69
  from app.routes import main_bp
70
  app.register_blueprint(main_bp)
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  # 데이터베이스 초기화 및 마이그레이션
73
  with app.app_context():
74
  db.create_all()
 
2
  Flask 애플리케이션 초기화
3
  """
4
 
5
+ from flask import Flask, request
6
  from flask_login import LoginManager
7
  import sqlite3
8
  from pathlib import Path
 
69
  from app.routes import main_bp
70
  app.register_blueprint(main_bp)
71
 
72
+ # 요청 로깅 미들웨어 추가
73
+ @app.before_request
74
+ def log_request_info():
75
+ """각 HTTP 요청 정보를 로깅"""
76
+ logger.info(f"[요청] {request.method} {request.path} - IP: {request.remote_addr}")
77
+ if request.args:
78
+ logger.debug(f"[요청 파라미터] {dict(request.args)}")
79
+
80
+ @app.after_request
81
+ def log_response_info(response):
82
+ """각 HTTP 응답 정보를 로깅"""
83
+ logger.info(f"[응답] {request.method} {request.path} - 상태: {response.status_code}")
84
+ return response
85
+
86
  # 데이터베이스 초기화 및 마이그레이션
87
  with app.app_context():
88
  db.create_all()
app/routes.py CHANGED
@@ -1003,36 +1003,44 @@ def create_chunks_for_file(file_id, content, skip_episode_analysis=False, skip_g
1003
  db.session.add(episode_analysis)
1004
  db.session.commit()
1005
  print(f"[회차 분석] 완료: {len(episode_sections)}개 회차 분석 결과를 하나의 텍스트로 저장")
1006
-
1007
- # 회차별 Graph Extraction 실행
1008
- if not skip_graph_extraction:
1009
- print(f"[Graph Extraction] 회차별 Graph Extraction 시작...")
1010
- graph_extraction_success_count = 0
1011
- for section_type, section_title, section_content, section_metadata in episode_sections:
1012
- try:
1013
- print(f"[Graph Extraction] '{section_title}' Graph Extraction 중...")
1014
- success = extract_graph_from_episode(
1015
- episode_content=section_content,
1016
- episode_title=section_title,
1017
- file_id=file_id,
1018
- full_content=content,
1019
- parent_chunk=parent_chunk,
1020
- model_name=model_name
1021
- )
1022
- if success:
1023
- graph_extraction_success_count += 1
1024
- print(f"[Graph Extraction] '{section_title}' Graph Extraction 완료")
1025
- else:
1026
- print(f"[Graph Extraction] '{section_title}' Graph Extraction 실패")
1027
- except Exception as e:
1028
- print(f"[Graph Extraction] '{section_title}' Graph Extraction 중 오류: {str(e)}")
1029
- import traceback
1030
- traceback.print_exc()
1031
- continue
1032
-
1033
- print(f"[Graph Extraction] 완료: {graph_extraction_success_count}/{len(episode_sections)}개 회차 Graph Extraction 성공")
1034
  else:
1035
  print(f"[회차 분석] 경고: 분석 결과가 없습니다.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1036
  else:
1037
  if not model_name:
1038
  print(f"[회차 분석] 모델명이 없어 회차 분석을 건너뜁니다.")
@@ -3734,11 +3742,35 @@ def process_episode_analysis(file_id):
3734
  db.session.add(episode_analysis)
3735
  db.session.commit()
3736
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3737
  return jsonify({
3738
  'file_id': file_id,
3739
  'filename': file.original_filename,
3740
  'episode_count': len(episode_sections),
3741
- 'message': f'{len(episode_sections)}개 회차 분석이 완료되었습니다.',
 
3742
  'step': 'episode-analysis',
3743
  'completed': True
3744
  }), 200
 
1003
  db.session.add(episode_analysis)
1004
  db.session.commit()
1005
  print(f"[회차 분석] 완료: {len(episode_sections)}개 회차 분석 결과를 하나의 텍스트로 저장")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1006
  else:
1007
  print(f"[회차 분석] 경고: 분석 결과가 없습니다.")
1008
+
1009
+ # 회차별 Graph Extraction 실행 (회차 분석 성공 여부와 관계없이 실행)
1010
+ if episode_sections and model_name and not skip_graph_extraction:
1011
+ print(f"[Graph Extraction] 회차별 Graph Extraction 시작...")
1012
+
1013
+ # Parent Chunk 가져오기 (회차 분석 블록 밖에서도 사용 가능하도록)
1014
+ parent_chunk = None
1015
+ try:
1016
+ parent_chunk = ParentChunk.query.filter_by(file_id=file_id).first()
1017
+ except:
1018
+ pass
1019
+
1020
+ graph_extraction_success_count = 0
1021
+ for section_type, section_title, section_content, section_metadata in episode_sections:
1022
+ try:
1023
+ print(f"[Graph Extraction] '{section_title}' Graph Extraction 중...")
1024
+ success = extract_graph_from_episode(
1025
+ episode_content=section_content,
1026
+ episode_title=section_title,
1027
+ file_id=file_id,
1028
+ full_content=content,
1029
+ parent_chunk=parent_chunk,
1030
+ model_name=model_name
1031
+ )
1032
+ if success:
1033
+ graph_extraction_success_count += 1
1034
+ print(f"[Graph Extraction] '{section_title}' Graph Extraction 완료")
1035
+ else:
1036
+ print(f"[Graph Extraction] '{section_title}' Graph Extraction 실패")
1037
+ except Exception as e:
1038
+ print(f"[Graph Extraction] '{section_title}' Graph Extraction 중 오류: {str(e)}")
1039
+ import traceback
1040
+ traceback.print_exc()
1041
+ continue
1042
+
1043
+ print(f"[Graph Extraction] 완료: {graph_extraction_success_count}/{len(episode_sections)}개 회차 Graph Extraction 성공")
1044
  else:
1045
  if not model_name:
1046
  print(f"[회차 분석] 모델명이 없어 회차 분석을 건너뜁니다.")
 
3742
  db.session.add(episode_analysis)
3743
  db.session.commit()
3744
 
3745
+ # 회차 분석 성공 후 Graph Extraction 자동 실행
3746
+ print(f"[단계 3: 회차 분석] Graph Extraction 자동 실행 시작...")
3747
+ graph_success_count = 0
3748
+ for section_type, section_title, section_content, section_metadata in episode_sections:
3749
+ try:
3750
+ print(f"[단계 3: 회차 분석] '{section_title}' Graph Extraction 중...")
3751
+ success = extract_graph_from_episode(
3752
+ episode_content=section_content,
3753
+ episode_title=section_title,
3754
+ file_id=file_id,
3755
+ full_content=content,
3756
+ parent_chunk=parent_chunk,
3757
+ model_name=file.model_name
3758
+ )
3759
+ if success:
3760
+ graph_success_count += 1
3761
+ print(f"[단계 3: 회차 분석] '{section_title}' Graph Extraction 완료")
3762
+ except Exception as e:
3763
+ print(f"[단계 3: 회차 분석] '{section_title}' Graph Extraction 중 오류: {str(e)}")
3764
+ continue
3765
+
3766
+ print(f"[단계 3: 회차 분석] Graph Extraction 완료: {graph_success_count}/{len(episode_sections)}개 회차 성공")
3767
+
3768
  return jsonify({
3769
  'file_id': file_id,
3770
  'filename': file.original_filename,
3771
  'episode_count': len(episode_sections),
3772
+ 'graph_success_count': graph_success_count,
3773
+ 'message': f'{len(episode_sections)}개 회차 분석이 완료되었습니다. (Graph Extraction: {graph_success_count}/{len(episode_sections)}개 성공)',
3774
  'step': 'episode-analysis',
3775
  'completed': True
3776
  }), 200
download_exaone_model.py CHANGED
@@ -87,6 +87,8 @@ if __name__ == "__main__":
87
 
88
 
89
 
 
 
90
 
91
 
92
 
 
87
 
88
 
89
 
90
+
91
+
92
 
93
 
94
 
install_exaone_direct.py CHANGED
@@ -92,6 +92,8 @@ if __name__ == "__main__":
92
 
93
 
94
 
 
 
95
 
96
 
97
 
 
92
 
93
 
94
 
95
+
96
+
97
 
98
 
99
 
install_exaone_simple.py CHANGED
@@ -69,6 +69,8 @@ if __name__ == "__main__":
69
 
70
 
71
 
 
 
72
 
73
 
74
 
 
69
 
70
 
71
 
72
+
73
+
74
 
75
 
76
 
run.py CHANGED
@@ -12,28 +12,46 @@ from app import create_app
12
 
13
  app = create_app()
14
 
15
- # 로깅 설정
16
- if not app.debug:
17
- # 프로덕션 환경에서는 파일로 로깅
18
- if not os.path.exists('logs'):
19
- os.mkdir('logs')
20
- file_handler = RotatingFileHandler('logs/server.log', maxBytes=10240000, backupCount=10)
21
- file_handler.setFormatter(logging.Formatter(
22
- '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
23
- ))
24
- file_handler.setLevel(logging.INFO)
25
- app.logger.addHandler(file_handler)
26
- app.logger.setLevel(logging.INFO)
27
- app.logger.info('서버 시작')
28
-
29
- # 디버그 모드에서도 콘솔에 모든 로그 출력
30
- logging.basicConfig(
31
- level=logging.DEBUG,
32
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
33
- handlers=[
34
- logging.StreamHandler(sys.stdout)
35
- ]
36
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
  if __name__ == '__main__':
39
  try:
 
12
 
13
  app = create_app()
14
 
15
+ # 로깅 설정 - 콘솔과 파일 모두에 출력
16
+ if not os.path.exists('logs'):
17
+ os.mkdir('logs')
18
+
19
+ # 파일 핸들러 설정
20
+ file_handler = RotatingFileHandler('logs/server.log', maxBytes=10240000, backupCount=10)
21
+ file_handler.setFormatter(logging.Formatter(
22
+ '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
23
+ ))
24
+ file_handler.setLevel(logging.INFO)
25
+
26
+ # 콘솔 핸들러 설정
27
+ console_handler = logging.StreamHandler(sys.stdout)
28
+ console_handler.setFormatter(logging.Formatter(
29
+ '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
30
+ ))
31
+ console_handler.setLevel(logging.INFO)
32
+
33
+ # Flask 앱 로거 설정
34
+ app.logger.setLevel(logging.INFO)
35
+ app.logger.addHandler(file_handler)
36
+ app.logger.addHandler(console_handler)
37
+
38
+ # 루트 로거 설정 (모든 로거에 적용)
39
+ root_logger = logging.getLogger()
40
+ root_logger.setLevel(logging.INFO)
41
+ root_logger.addHandler(console_handler)
42
+
43
+ # Werkzeug 로거 설정 (HTTP 요청 로깅)
44
+ werkzeug_logger = logging.getLogger('werkzeug')
45
+ werkzeug_logger.setLevel(logging.INFO)
46
+ # Werkzeug의 기본 핸들러 제거하고 새로 추가
47
+ werkzeug_logger.handlers.clear()
48
+ werkzeug_handler = logging.StreamHandler(sys.stdout)
49
+ werkzeug_handler.setFormatter(logging.Formatter(
50
+ '%(asctime)s - %(levelname)s - %(message)s'
51
+ ))
52
+ werkzeug_logger.addHandler(werkzeug_handler)
53
+
54
+ app.logger.info('서버 시작')
55
 
56
  if __name__ == '__main__':
57
  try: