dev-yuje commited on
Commit
dfd1ae6
Β·
1 Parent(s): 1d4b2ed

Ultra-Stable: Defer ALL heavy imports to function call to prevent boot crash (500 error)

Browse files
Files changed (1) hide show
  1. app.py +61 -83
app.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import huggingface_hub
2
  if not hasattr(huggingface_hub, "HfFolder"):
3
  class MockHfFolder:
@@ -10,22 +11,31 @@ if not hasattr(huggingface_hub, "HfFolder"):
10
  huggingface_hub.HfFolder = MockHfFolder
11
 
12
  import gradio as gr
13
- import pandas as pd
14
- import numpy as np
15
  import os
16
  import time
17
 
18
- # μ§€μ—° λ‘œλ”©μ„ μœ„ν•΄ μ „μ—­ λ³€μˆ˜λ‘œ μ„ μ–Έ
19
- _consultant = None
 
 
 
20
 
21
- def get_consultant():
22
- global _consultant
23
- if _consultant is None:
 
 
 
 
24
  from langchain_google_genai import ChatGoogleGenerativeAI
25
  from langchain_huggingface import HuggingFaceEmbeddings
26
  from langchain_community.vectorstores import FAISS
27
  from config import EMBEDDING_MODEL, FAISS_PATH, RETRIEVER_K, GEMINI_API_KEY
28
 
 
 
 
 
29
  class Consultant:
30
  def __init__(self):
31
  os.environ["GOOGLE_API_KEY"] = os.getenv("GOOGLE_API_KEY", GEMINI_API_KEY)
@@ -36,27 +46,16 @@ def get_consultant():
36
  else:
37
  self.retriever = None
38
  self.llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", temperature=0.7)
39
- _consultant = Consultant()
40
- return _consultant
41
-
42
- # 예츑기 λ‘œλ“œ
43
- from predictors.score_prediction import predictor
44
 
45
  FEATURES_MAP = {
46
- 'C1Z001386': '1λ…„λ‚΄ μΉ΄λ“œ 총 μ΄μš©κΈˆμ•‘ (λ§Œμ›)',
47
- 'C1M210000': 'μ‹ μš©μΉ΄λ“œ 건수',
48
- 'C18210000': 'μ²΄ν¬μΉ΄λ“œ 건수',
49
- 'C1L120001': 'μΉ΄λ“œ 총 ν•œλ„κΈˆμ•‘ (λ§Œμ›)',
50
- 'C1L120004': 'μΉ΄λ“œ κ°œμ„€μΌμˆ˜',
51
- 'L10210000': '은행업쒅 λŒ€μΆœ 건수',
52
- 'L90210100': 'λŒ€λΆ€μ—…μ’… λŒ€μΆœ 건수',
53
- 'L90210200': '저좕은행 λŒ€μΆœ 건수',
54
- 'L10210B00': '주택담보 λŒ€μΆœ 건수',
55
- 'L10216000': 'μ‹ μš©λŒ€μΆœ 총 μž”μ•‘ (λ§Œμ›)',
56
- 'L10217000': 'λ‹΄λ³΄λŒ€μΆœ 총 μž”μ•‘ (λ§Œμ›)',
57
- 'D10110000': '연체 건수',
58
- 'D10133000': '연체 μž”μ•‘ (λ§Œμ›)',
59
- 'PERF1': '90일 연체 μ—¬λΆ€'
60
  }
61
 
62
  ALL_FEATURES_KEYS = [
@@ -65,102 +64,81 @@ ALL_FEATURES_KEYS = [
65
  'L10217000', 'D10110000', 'D10133000', 'PERF1'
66
  ]
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  def generate_response(history, user_message, analysis_report):
69
  if not user_message: yield history, ""; return
70
- if history and isinstance(history[-1], tuple) and history[-1][1] == "생각 쀑...": history = history[:-1]
71
-
72
- # μ±— μƒνƒœ μ΄ˆκΈ°ν™”
73
- history = history + [[user_message, ""]]
74
- t0 = time.time()
75
 
76
  try:
77
- # μ§€μ—° λ‘œλ”© μ‹€ν–‰
78
- history[-1][1] = "⚑ **μ‹œμŠ€ν…œ μ΄ˆκΈ°ν™” 쀑...**"
79
- yield history, ""
80
- cons = get_consultant()
81
 
82
- # R
83
- history[-1][1] = "πŸ“‚ **[R] 뢄석 λ¬Έμ„œ 검색 쀑...**"
84
  yield history, ""
85
  docs = cons.retriever.invoke(user_message) if cons.retriever else []
86
- t_retrieve = time.time() - t0
87
  context = "\n\n".join([doc.page_content for doc in docs])
88
 
89
- # A
90
  from llm.prompt import QA_PROMPT
91
  if analysis_report:
92
  score_val = int(analysis_report["score"])
93
  features_text = "\n".join([f"- {FEATURES_MAP.get(k, k)}: {v}" for k, v in analysis_report['features'].items()])
94
- query_text = f"β–  고객 뢄석 κ²°κ³Ό: {score_val}점\n{features_text}\n\nβ–  질문: {user_message}"
95
  else:
96
  query_text = f"β–  질문: {user_message}"
97
 
98
- prompt_text = QA_PROMPT.format(context=context, query=query_text)
99
- t_augment = time.time() - t0
100
-
101
- # G
102
  answer_buffer = ""
103
- for chunk in cons.llm.stream(prompt_text):
104
  answer_buffer += chunk.content
105
- history[-1][1] = (
106
- f"πŸ“‚ **[R] μ™„λ£Œ** ({t_retrieve:.1f}s) | πŸ”— **[A] μ™„λ£Œ** ({t_augment-t_retrieve:.2f}s)\n\n"
107
- f"{answer_buffer}"
108
- )
109
  yield history, ""
110
 
111
  except Exception as e:
112
- history[-1][1] = f"⚠️ μ„œλ²„ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {str(e)}"
113
  yield history, ""
114
 
115
- def handle_predict(*args):
116
- try:
117
- features_dict = {}
118
- for i, key in enumerate(ALL_FEATURES_KEYS):
119
- if key == 'PERF1': features_dict[key] = int(args[i])
120
- else:
121
- val = str(args[i]).strip() if args[i] else "0"
122
- features_dict[key] = float(val) if val else 0.0
123
-
124
- score = predictor.predict(features_dict)
125
- display_score = int(min(max(round(score), 0), 1000)) if not np.isnan(score) else 0
126
- return {"features": features_dict, "score": display_score}, display_score
127
- except Exception as e:
128
- return {"error": str(e)}, 0
129
-
130
  with gr.Blocks(title="KCB AI Consultant") as demo:
131
  analysis_report = gr.State(None)
132
-
133
- gr.Markdown("# πŸ›‘οΈ KCB AI μ‹ μš© 점수 뢄석 μ‹œμŠ€ν…œ (LTS)")
134
 
135
  with gr.Row():
136
  with gr.Column(scale=1):
137
- input_list = []
138
- for key in ALL_FEATURES_KEYS:
139
- if key == 'PERF1':
140
- input_list.append(gr.Checkbox(label=FEATURES_MAP[key], value=False))
141
- else:
142
- input_list.append(gr.Textbox(label=FEATURES_MAP[key], placeholder="0"))
143
  predict_btn = gr.Button("πŸ“ˆ 점수 λΆ„μ„ν•˜κΈ°", variant="primary")
144
 
145
  with gr.Column(scale=2):
146
  result_display = gr.Label(label="예츑 μ‹ μš© 점수")
147
  chatbot = gr.Chatbot(label="μ‹€μ‹œκ°„ 상담", height=500)
148
-
149
  with gr.Row():
150
  msg = gr.Textbox(placeholder="μ§ˆλ¬Έμ„ μž…λ ₯ν•˜μ„Έμš”...", scale=8, container=False)
151
  submit_btn = gr.Button("μƒλ‹΄ν•˜κΈ°", variant="primary", scale=1)
152
 
153
  predict_btn.click(handle_predict, inputs=input_list, outputs=[analysis_report, result_display])
154
 
155
- def process_chat(message, history):
156
- return "", history + [[message, "생각 쀑..."]]
157
-
158
- msg.submit(process_chat, [msg, chatbot], [msg, chatbot]).then(
159
- generate_response, [chatbot, msg, analysis_report], [chatbot, msg]
160
- )
161
- submit_btn.click(process_chat, [msg, chatbot], [msg, chatbot]).then(
162
- generate_response, [chatbot, msg, analysis_report], [chatbot, msg]
163
- )
164
 
165
  if __name__ == "__main__":
166
  demo.launch()
 
1
+ # 1. μ΅œμƒλ‹¨μ—μ„œλŠ” 였직 κ°€λ²Όμš΄ 라이브러리만 λ‘œλ“œ
2
  import huggingface_hub
3
  if not hasattr(huggingface_hub, "HfFolder"):
4
  class MockHfFolder:
 
11
  huggingface_hub.HfFolder = MockHfFolder
12
 
13
  import gradio as gr
 
 
14
  import os
15
  import time
16
 
17
+ # μ „μ—­ μƒνƒœ 관리 (μ§€μ—° λ‘œλ”© 용)
18
+ _models = {
19
+ "predictor": None,
20
+ "consultant": None
21
+ }
22
 
23
+ def load_all_models():
24
+ """μ‚¬μš©μžκ°€ λ²„νŠΌμ„ 처음 λˆ„λ₯Ό λ•Œλ§Œ 무거운 λͺ¨λΈλ“€μ„ λ‘œλ“œν•©λ‹ˆλ‹€."""
25
+ global _models
26
+ if _models["predictor"] is None:
27
+ print("Loading heavy models...")
28
+ # ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ μž„ν¬νŠΈν•˜μ—¬ λΆ€νŒ… μ‹œ λΆ€ν•˜ λ°©μ§€
29
+ from predictors.score_prediction import CreditPredictor
30
  from langchain_google_genai import ChatGoogleGenerativeAI
31
  from langchain_huggingface import HuggingFaceEmbeddings
32
  from langchain_community.vectorstores import FAISS
33
  from config import EMBEDDING_MODEL, FAISS_PATH, RETRIEVER_K, GEMINI_API_KEY
34
 
35
+ # 1. 예츑기 λ‘œλ“œ
36
+ _models["predictor"] = CreditPredictor()
37
+
38
+ # 2. RAG 상담원 λ‘œλ“œ
39
  class Consultant:
40
  def __init__(self):
41
  os.environ["GOOGLE_API_KEY"] = os.getenv("GOOGLE_API_KEY", GEMINI_API_KEY)
 
46
  else:
47
  self.retriever = None
48
  self.llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", temperature=0.7)
49
+
50
+ _models["consultant"] = Consultant()
51
+ print("Models loaded successfully!")
 
 
52
 
53
  FEATURES_MAP = {
54
+ 'C1Z001386': '1λ…„λ‚΄ μΉ΄λ“œ 총 μ΄μš©κΈˆμ•‘ (λ§Œμ›)', 'C1M210000': 'μ‹ μš©μΉ΄λ“œ 건수', 'C18210000': 'μ²΄ν¬μΉ΄λ“œ 건수',
55
+ 'C1L120001': 'μΉ΄λ“œ 총 ν•œλ„κΈˆμ•‘ (λ§Œμ›)', 'C1L120004': 'μΉ΄λ“œ κ°œμ„€μΌμˆ˜', 'L10210000': '은행업쒅 λŒ€μΆœ 건수',
56
+ 'L90210100': 'λŒ€λΆ€μ—…μ’… λŒ€μΆœ 건수', 'L90210200': '저좕은행 λŒ€μΆœ 건수', 'L10210B00': '주택담보 λŒ€μΆœ 건수',
57
+ 'L10216000': 'μ‹ μš©λŒ€μΆœ 총 μž”μ•‘ (λ§Œμ›)', 'L10217000': 'λ‹΄λ³΄λŒ€μΆœ 총 μž”μ•‘ (λ§Œμ›)', 'D10110000': '연체 건수',
58
+ 'D10133000': '연체 μž”μ•‘ (λ§Œμ›)', 'PERF1': '90일 연체 μ—¬λΆ€'
 
 
 
 
 
 
 
 
 
59
  }
60
 
61
  ALL_FEATURES_KEYS = [
 
64
  'L10217000', 'D10110000', 'D10133000', 'PERF1'
65
  ]
66
 
67
+ def handle_predict(*args):
68
+ try:
69
+ load_all_models()
70
+ features_dict = {}
71
+ for i, key in enumerate(ALL_FEATURES_KEYS):
72
+ if key == 'PERF1': features_dict[key] = int(args[i])
73
+ else:
74
+ val = str(args[i]).strip() if args[i] else "0"
75
+ features_dict[key] = float(val) if val else 0.0
76
+
77
+ score = _models["predictor"].predict(features_dict)
78
+ display_score = int(round(score)) if score is not None else 0
79
+ return {"features": features_dict, "score": display_score}, display_score
80
+ except Exception as e:
81
+ return {"error": str(e)}, 0
82
+
83
  def generate_response(history, user_message, analysis_report):
84
  if not user_message: yield history, ""; return
85
+ history = history + [[user_message, "⚑ **μ‹œμŠ€ν…œ μ€€λΉ„ 쀑... (μ΅œλŒ€ 30초 μ†Œμš”)**"]]
86
+ yield history, ""
 
 
 
87
 
88
  try:
89
+ load_all_models()
90
+ cons = _models["consultant"]
 
 
91
 
92
+ # R (Retrieval)
93
+ history[-1][1] = "πŸ“‚ **뢄석 λ¬Έμ„œ 검색 쀑...**"
94
  yield history, ""
95
  docs = cons.retriever.invoke(user_message) if cons.retriever else []
 
96
  context = "\n\n".join([doc.page_content for doc in docs])
97
 
98
+ # A (Augmentation)
99
  from llm.prompt import QA_PROMPT
100
  if analysis_report:
101
  score_val = int(analysis_report["score"])
102
  features_text = "\n".join([f"- {FEATURES_MAP.get(k, k)}: {v}" for k, v in analysis_report['features'].items()])
103
+ query_text = f"β–  고객 정보: {score_val}점\n{features_text}\n\nβ–  질문: {user_message}"
104
  else:
105
  query_text = f"β–  질문: {user_message}"
106
 
107
+ # G (Generation)
108
+ history[-1][1] = "πŸ’¬ **λ‹΅λ³€ 생성 쀑...**"
109
+ yield history, ""
110
+
111
  answer_buffer = ""
112
+ for chunk in cons.llm.stream(QA_PROMPT.format(context=context, query=query_text)):
113
  answer_buffer += chunk.content
114
+ history[-1][1] = answer_buffer
 
 
 
115
  yield history, ""
116
 
117
  except Exception as e:
118
+ history[-1][1] = f"⚠️ 였λ₯˜ λ°œμƒ: {str(e)}"
119
  yield history, ""
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  with gr.Blocks(title="KCB AI Consultant") as demo:
122
  analysis_report = gr.State(None)
123
+ gr.Markdown("# πŸ›‘οΈ KCB AI μ‹ μš© 상담 μ‹œμŠ€ν…œ (Ultra-Stable)")
 
124
 
125
  with gr.Row():
126
  with gr.Column(scale=1):
127
+ input_list = [gr.Checkbox(label=FEATURES_MAP[k]) if k == 'PERF1' else gr.Textbox(label=FEATURES_MAP[k], placeholder="0") for k in ALL_FEATURES_KEYS]
 
 
 
 
 
128
  predict_btn = gr.Button("πŸ“ˆ 점수 λΆ„μ„ν•˜κΈ°", variant="primary")
129
 
130
  with gr.Column(scale=2):
131
  result_display = gr.Label(label="예츑 μ‹ μš© 점수")
132
  chatbot = gr.Chatbot(label="μ‹€μ‹œκ°„ 상담", height=500)
 
133
  with gr.Row():
134
  msg = gr.Textbox(placeholder="μ§ˆλ¬Έμ„ μž…λ ₯ν•˜μ„Έμš”...", scale=8, container=False)
135
  submit_btn = gr.Button("μƒλ‹΄ν•˜κΈ°", variant="primary", scale=1)
136
 
137
  predict_btn.click(handle_predict, inputs=input_list, outputs=[analysis_report, result_display])
138
 
139
+ def clear_msg(m, h): return "", h + [[m, "생각 쀑..."]]
140
+ msg.submit(clear_msg, [msg, chatbot], [msg, chatbot]).then(generate_response, [chatbot, msg, analysis_report], [chatbot, msg])
141
+ submit_btn.click(clear_msg, [msg, chatbot], [msg, chatbot]).then(generate_response, [chatbot, msg, analysis_report], [chatbot, msg])
 
 
 
 
 
 
142
 
143
  if __name__ == "__main__":
144
  demo.launch()