dev-yuje commited on
Commit
0112759
ยท
1 Parent(s): 5393c73

Fix model load traceability and Chatbot data format

Browse files
Files changed (2) hide show
  1. app.py +45 -43
  2. requirements.txt +2 -1
app.py CHANGED
@@ -18,6 +18,7 @@ import numpy as np
18
  import pandas as pd
19
  import tensorflow as tf
20
  import joblib
 
21
 
22
  # TF ์ตœ์ ํ™” ๊ฒฝ๊ณ  ๋ฐฉ์ง€ ๋ฐ ์•ˆ์ •์„ฑ
23
  os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
@@ -35,48 +36,51 @@ def load_all_models():
35
  self.model_path = "models/telecom_cb_model.keras"
36
  self.preprocessor = None
37
  self.model = None
 
38
  self.load_resources()
39
 
40
  def load_resources(self):
41
  try:
42
  if os.path.exists(self.preprocessor_path):
43
  self.preprocessor = joblib.load(self.preprocessor_path)
 
 
 
44
  if os.path.exists(self.model_path):
45
- # compile=False๊ฐ€ ์ค‘์š”ํ•จ
46
- self.model = tf.keras.models.load_model(self.model_path, compile=False)
 
 
 
 
 
 
47
  except Exception as e:
48
- print(f"Error loading resources: {e}")
49
 
50
  def predict(self, features_dict):
51
  try:
52
  if self.model is None or self.preprocessor is None:
53
- return f"Error: ๋ชจ๋ธ({self.model is not None})/์ „์ฒ˜๋ฆฌ๊ธฐ({self.preprocessor is not None}) ๋กœ๋“œ ์‹คํŒจ"
54
 
55
  ALL_FEATURES = [
56
  'C1Z001386', 'C1M210000', 'C18210000', 'C1L120001', 'C1L120004',
57
  'L10210000', 'L90210100', 'L90210200', 'L10210B00', 'L10216000',
58
  'L10217000', 'D10110000', 'D10133000', 'PERF1'
59
  ]
60
- # ๋ฐ์ดํ„ฐ ์ค€๋น„
61
- input_values = []
62
- for col in ALL_FEATURES:
63
- val = features_dict.get(col, 0.0)
64
- input_values.append(float(val))
65
 
 
66
  df = pd.DataFrame([input_values], columns=ALL_FEATURES)
67
 
68
- # ๋กœ๊ทธ ๋ณ€ํ™˜ (๋…ธํŠธ๋ถ ๋กœ์ง)
69
  log_cols = ['C1Z001386', 'C1L120004', 'D10110000', 'D10133000', 'L90210200',
70
  'L10216000', 'L10210B00', 'L10217000', 'L90210100', 'L10210000']
71
  df[log_cols] = np.log1p(df[log_cols].astype(float).clip(lower=0))
72
 
73
- # ์ „์ฒ˜๋ฆฌ ๋ฐ ์˜ˆ์ธก
74
  scaled_data = self.preprocessor.transform(df)
75
  prediction = self.model.predict(scaled_data, verbose=0)
76
  return float(prediction[0][0])
77
  except Exception as e:
78
- import traceback
79
- return f"Error: {str(e)}\n{traceback.format_exc()[:100]}"
80
 
81
  _models["predictor"] = RobustCreditPredictor()
82
 
@@ -103,7 +107,7 @@ def load_all_models():
103
 
104
  _models["consultant"] = Consultant()
105
  except Exception as e:
106
- print(f"Load Error: {e}")
107
 
108
  FEATURES_DETAIL = {
109
  'C1Z001386': ('1๋…„ ๋‚ด ์นด๋“œ ์ด ์ด์šฉ๊ธˆ์•ก', '๋งŒ์› ๋‹จ์œ„', '0'),
@@ -127,34 +131,35 @@ def handle_predict(*args):
127
  load_all_models()
128
  features_dict = {}
129
  for i, key in enumerate(ALL_KEYS):
130
- val = str(args[i]).strip().replace(",", "")
 
131
  if key == 'PERF1':
132
- features_dict[key] = 1.0 if (val.lower() == 'true' or val == '1' or args[i] is True) else 0.0
133
  else:
134
  try:
135
- features_dict[key] = float(val or 0)
136
  except:
137
- return f"โŒ ์˜ค๋ฅ˜: '{FEATURES_DETAIL[key][0]}' ์ˆซ์ž ์•„๋‹˜", "โŒ"
138
 
139
- # ํ•ฉ์‚ฐ ๋กœ์ง
140
  features_dict['L10210000'] = features_dict['L10216000'] + features_dict['L10217000']
141
 
142
  res = _models["predictor"].predict(features_dict)
143
  if isinstance(res, str) and "Error" in res:
144
- # ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์—๋Ÿฌ ๋‚ด์šฉ ์ผ๋ถ€๋ฅผ UI์— ํ‘œ์‹œ
145
- return f"โŒ ๋ถ„์„ ์‹คํŒจ: {res}", f"โš ๏ธ {res[:20]}..."
 
146
 
147
  score_val = str(int(round(float(res))))
148
  return {"features": features_dict, "score": score_val}, score_val
149
  except Exception as e:
150
- return f"โŒ ์‹œ์Šคํ…œ ์˜ค๋ฅ˜: {str(e)}", "โš ๏ธ ์‹œ์Šคํ…œ ์˜ค๋ฅ˜"
151
 
152
  def generate_response(chatbot, user_message, analysis_report):
153
  if not user_message: yield chatbot, ""; return
154
 
155
- # 1. ์ฑ—๋ด‡ ๊ธฐ๋ก ์—…๋ฐ์ดํŠธ (Gradio 4/5 ํ˜ธํ™˜์„ ์œ„ํ•ด ์ˆ˜๋™ ๊ตฌ์„ฑ)
156
- # ํŠœํ”Œ ๋ฐฉ์‹ ์‚ฌ์šฉ
157
- chatbot.append([user_message, "โšก ์‹œ์Šคํ…œ ๋ถ„์„ ์ค‘..."])
158
  yield chatbot, ""
159
 
160
  try:
@@ -162,38 +167,37 @@ def generate_response(chatbot, user_message, analysis_report):
162
  cons = _models["consultant"]
163
  cons.lazy_load_search()
164
 
165
- # ๋ฌธ์„œ ๊ฒ€์ƒ‰
166
  context = ""
167
  if cons.retriever:
168
- docs = cons.retriever.invoke(user_message)
169
- context = "\n\n".join([d.page_content for d in docs])
 
 
170
 
171
  from llm.prompt import QA_PROMPT
172
  score_val = analysis_report.get("score", "๋ฏธ์ธก์ •") if isinstance(analysis_report, dict) else "๋ฏธ์ธก์ •"
173
  query_text = f"โ–  ๊ณ ๊ฐ ์ ์ˆ˜: {score_val}์ \nโ–  ์งˆ๋ฌธ: {user_message}"
174
-
175
- # LangChain์— ์ „๋‹ฌํ•  ํ”„๋กฌํ”„ํŠธ ๊ตฌ์„ฑ
176
  full_prompt = QA_PROMPT.format(context=context, query=query_text)
177
 
178
- # "Incompatible format" ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ๋ฆฌ์ŠคํŠธ ๋ฉ”์‹œ์ง€ ๋Œ€์‹  ๋ฌธ์ž์—ด๋กœ ์‹œ๋„
179
- # ํ˜น์€ ๋ช…์‹œ์ ์ธ Role ์ง€์ •
180
  from langchain_core.messages import HumanMessage
181
  messages = [HumanMessage(content=full_prompt)]
182
 
183
  answer_buffer = ""
184
  for chunk in cons.llm.stream(messages):
185
  answer_buffer += chunk.content
186
- # ํ˜„์žฌ ๋Œ€ํ™”์˜ ๋งˆ์ง€๋ง‰ ์‘๋‹ต ์—…๋ฐ์ดํŠธ
187
- chatbot[-1][1] = answer_buffer
188
  yield chatbot, ""
189
 
190
  except Exception as e:
191
- chatbot[-1][1] = f"โš ๏ธ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
192
  yield chatbot, ""
193
 
194
- with gr.Blocks(title="KCB AI") as demo:
195
  analysis_report = gr.State(None)
196
- gr.Markdown("# ๐Ÿ›ก๏ธ KCB AI ์‹ ์šฉ ์ƒ๋‹ด ์‹œ์Šคํ…œ (v5.6.0 Stable)")
197
 
198
  with gr.Row():
199
  with gr.Column(scale=1):
@@ -207,18 +211,16 @@ with gr.Blocks(title="KCB AI") as demo:
207
  predict_btn = gr.Button("๐Ÿ“ˆ ์ ์ˆ˜ ๋ถ„์„ํ•˜๊ธฐ", variant="primary")
208
 
209
  with gr.Column(scale=2):
210
- result_display = gr.Text(label="๐ŸŽฏ AI ์˜ˆ์ธก ์‹ ์šฉ ์ ์ˆ˜")
211
- chatbot = gr.Chatbot(label="AI ์ƒ๋‹ด์‚ฌ", height=450)
 
212
  with gr.Row():
213
  msg = gr.Textbox(placeholder="์งˆ๋ฌธ์„ ์ž…๋ ฅํ•˜์„ธ์š”...", show_label=False, scale=8)
214
  submit_btn = gr.Button("์ „์†ก", variant="primary", scale=1)
215
 
216
  predict_btn.click(handle_predict, inputs=input_list, outputs=[analysis_report, result_display])
217
-
218
- # ํ…์ŠคํŠธ ๋ฐ•์Šค ์ž…๋ ฅ ํ›„ ์ „์†ก ์‹œ ๋กœ์ง
219
- # input์„ msg๋กœ, output์„ [chatbot, msg]๋กœ ์„ค์ •ํ•˜์—ฌ ์ž๋™ ๋น„์šฐ๊ธฐ
220
- submit_event = submit_btn.click(generate_response, inputs=[chatbot, msg, analysis_report], outputs=[chatbot, msg])
221
  msg.submit(generate_response, inputs=[chatbot, msg, analysis_report], outputs=[chatbot, msg])
 
222
 
223
  if __name__ == "__main__":
224
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
18
  import pandas as pd
19
  import tensorflow as tf
20
  import joblib
21
+ import traceback
22
 
23
  # TF ์ตœ์ ํ™” ๊ฒฝ๊ณ  ๋ฐฉ์ง€ ๋ฐ ์•ˆ์ •์„ฑ
24
  os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
 
36
  self.model_path = "models/telecom_cb_model.keras"
37
  self.preprocessor = None
38
  self.model = None
39
+ self.load_error = "์ดˆ๊ธฐํ™”๋จ"
40
  self.load_resources()
41
 
42
  def load_resources(self):
43
  try:
44
  if os.path.exists(self.preprocessor_path):
45
  self.preprocessor = joblib.load(self.preprocessor_path)
46
+ else:
47
+ self.load_error = "์ „์ฒ˜๋ฆฌ๊ธฐ ํŒŒ์ผ ๋ถ€์žฌ"
48
+
49
  if os.path.exists(self.model_path):
50
+ # compile=False๊ฐ€ ์ค‘์š”ํ•จ. ์ปค์Šคํ…€ ๋ ˆ์ด์–ด ๋ฌด์‹œ.
51
+ try:
52
+ self.model = tf.keras.models.load_model(self.model_path, compile=False)
53
+ self.load_error = "์„ฑ๊ณต"
54
+ except Exception as model_e:
55
+ self.load_error = f"Keras ๋กœ๋“œ ์—๋Ÿฌ: {str(model_e)}\n{traceback.format_exc()}"
56
+ else:
57
+ self.load_error = "๋ชจ๋ธ ํŒŒ์ผ ๋ถ€์žฌ"
58
  except Exception as e:
59
+ self.load_error = f"ํ†ตํ•ฉ ๋กœ๋“œ ์—๋Ÿฌ: {str(e)}\n{traceback.format_exc()}"
60
 
61
  def predict(self, features_dict):
62
  try:
63
  if self.model is None or self.preprocessor is None:
64
+ return f"Error: ๋กœ๋“œ ์ƒํƒœ ํ™•์ธ ์š”๋ง (๋ชจ๋ธ:{self.model is not None}). ๋กœ๋“œ ์—๋Ÿฌ ์›๋ณธ: {self.load_error[:200]}"
65
 
66
  ALL_FEATURES = [
67
  'C1Z001386', 'C1M210000', 'C18210000', 'C1L120001', 'C1L120004',
68
  'L10210000', 'L90210100', 'L90210200', 'L10210B00', 'L10216000',
69
  'L10217000', 'D10110000', 'D10133000', 'PERF1'
70
  ]
 
 
 
 
 
71
 
72
+ input_values = [float(features_dict.get(col, 0.0)) for col in ALL_FEATURES]
73
  df = pd.DataFrame([input_values], columns=ALL_FEATURES)
74
 
 
75
  log_cols = ['C1Z001386', 'C1L120004', 'D10110000', 'D10133000', 'L90210200',
76
  'L10216000', 'L10210B00', 'L10217000', 'L90210100', 'L10210000']
77
  df[log_cols] = np.log1p(df[log_cols].astype(float).clip(lower=0))
78
 
 
79
  scaled_data = self.preprocessor.transform(df)
80
  prediction = self.model.predict(scaled_data, verbose=0)
81
  return float(prediction[0][0])
82
  except Exception as e:
83
+ return f"Error: ์˜ˆ์ธก ์—ฐ์‚ฐ ์—๋Ÿฌ: {str(e)}\n{traceback.format_exc()[:100]}"
 
84
 
85
  _models["predictor"] = RobustCreditPredictor()
86
 
 
107
 
108
  _models["consultant"] = Consultant()
109
  except Exception as e:
110
+ print(f"Grand Load Error: {e}")
111
 
112
  FEATURES_DETAIL = {
113
  'C1Z001386': ('1๋…„ ๋‚ด ์นด๋“œ ์ด ์ด์šฉ๊ธˆ์•ก', '๋งŒ์› ๋‹จ์œ„', '0'),
 
131
  load_all_models()
132
  features_dict = {}
133
  for i, key in enumerate(ALL_KEYS):
134
+ # ์ „์ฒ˜๋ฆฌ ์ „์˜ ์›๋ณธ ๊ฐ’ ์ •์ œ
135
+ val_raw = str(args[i]).strip().replace(",", "")
136
  if key == 'PERF1':
137
+ features_dict[key] = 1.0 if (val_raw.lower() == 'true' or val_raw == '1' or args[i] is True) else 0.0
138
  else:
139
  try:
140
+ features_dict[key] = float(val_raw or 0)
141
  except:
142
+ return f"โŒ ์˜ค๋ฅ˜: '{FEATURES_DETAIL[key][0]}' ํ•ญ๋ชฉ ์ˆซ์ž ์ž…๋ ฅ ์š”๋ง", "โŒ"
143
 
 
144
  features_dict['L10210000'] = features_dict['L10216000'] + features_dict['L10217000']
145
 
146
  res = _models["predictor"].predict(features_dict)
147
  if isinstance(res, str) and "Error" in res:
148
+ # ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ UI ์ƒ๋‹จ ์ ์ˆ˜์นธ์— ์—๋Ÿฌ ๋‚ด์šฉ ๋…ธ์ถœ (๋””๋ฒ„๊น…์šฉ)
149
+ # res[:50]์œผ๋กœ๋Š” ๋ถ€์กฑํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ตœ๋Œ€ํ•œ ๋ณด์—ฌ์คŒ
150
+ return f"โŒ ๋ถ„์„ ์‹คํŒจ: {res}", f"โš ๏ธ {res[:40]}..."
151
 
152
  score_val = str(int(round(float(res))))
153
  return {"features": features_dict, "score": score_val}, score_val
154
  except Exception as e:
155
+ return f"โŒ ์‹œ์Šคํ…œ ์˜ค๋ฅ˜: {str(e)}", "โš ๏ธ ์‹œ์Šคํ…œ ์—๋Ÿฌ"
156
 
157
  def generate_response(chatbot, user_message, analysis_report):
158
  if not user_message: yield chatbot, ""; return
159
 
160
+ # Gradio 5 Dictionary ๊ทœ๊ฒฉ ๊ฐ•์ œ ์ค€์ˆ˜
161
+ chatbot.append({"role": "user", "content": user_message})
162
+ chatbot.append({"role": "assistant", "content": "โšก ์ƒ๋‹ด์‚ฌ๊ฐ€ ๋ถ„์„ ์ค‘์ž…๋‹ˆ๋‹ค..."})
163
  yield chatbot, ""
164
 
165
  try:
 
167
  cons = _models["consultant"]
168
  cons.lazy_load_search()
169
 
 
170
  context = ""
171
  if cons.retriever:
172
+ try:
173
+ docs = cons.retriever.invoke(user_message)
174
+ context = "\n\n".join([d.page_content for d in docs])
175
+ except: pass
176
 
177
  from llm.prompt import QA_PROMPT
178
  score_val = analysis_report.get("score", "๋ฏธ์ธก์ •") if isinstance(analysis_report, dict) else "๋ฏธ์ธก์ •"
179
  query_text = f"โ–  ๊ณ ๊ฐ ์ ์ˆ˜: {score_val}์ \nโ–  ์งˆ๋ฌธ: {user_message}"
 
 
180
  full_prompt = QA_PROMPT.format(context=context, query=query_text)
181
 
182
+ # LangChain์˜ ๋ฆฌ์ŠคํŠธ ๋ฉ”์‹œ์ง€ ๋Œ€์‹  ๋”•์…”๋„ˆ๋ฆฌ ํฌ๋งท์œผ๋กœ ์ง์ ‘ ์‹œ๋„ (๊ฐ€์žฅ ํ˜ธํ™˜์„ฑ ๋†’์Œ)
183
+ # ํ•˜์ง€๋งŒ ChatGoogleGenerativeAI๋Š” [HumanMessage(...)]๋ฅผ ๊ธฐ๋Œ€ํ•จ
184
  from langchain_core.messages import HumanMessage
185
  messages = [HumanMessage(content=full_prompt)]
186
 
187
  answer_buffer = ""
188
  for chunk in cons.llm.stream(messages):
189
  answer_buffer += chunk.content
190
+ # Gradio 5 Dictionary ํฌ๋งท์œผ๋กœ ๋งˆ์ง€๋ง‰ ๋ฉ”์‹œ์ง€ ์—…๋ฐ์ดํŠธ
191
+ chatbot[-1] = {"role": "assistant", "content": answer_buffer}
192
  yield chatbot, ""
193
 
194
  except Exception as e:
195
+ chatbot[-1] = {"role": "assistant", "content": f"โš ๏ธ ์ƒ๋‹ด ์—๋Ÿฌ: {str(e)}"}
196
  yield chatbot, ""
197
 
198
+ with gr.Blocks(title="KCB AI Consultant") as demo:
199
  analysis_report = gr.State(None)
200
+ gr.Markdown("# ๐Ÿ›ก๏ธ KCB AI ์‹ ์šฉ ์ƒ๋‹ด ์‹œ์Šคํ…œ (v5.7.0 Debug-Pro)")
201
 
202
  with gr.Row():
203
  with gr.Column(scale=1):
 
211
  predict_btn = gr.Button("๐Ÿ“ˆ ์ ์ˆ˜ ๋ถ„์„ํ•˜๊ธฐ", variant="primary")
212
 
213
  with gr.Column(scale=2):
214
+ result_display = gr.Text(label="๐ŸŽฏ AI ์˜ˆ์ธก ์‹ ์šฉ ์ ์ˆ˜ (์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์ด๊ณณ์— ๋‚ด์šฉ ํ‘œ์‹œ)")
215
+ # type="messages"๊ฐ€ Gradio 5์˜ ํ•ต์‹ฌ
216
+ chatbot = gr.Chatbot(label="AI ์ƒ๋‹ด์‚ฌ", height=450, type="messages")
217
  with gr.Row():
218
  msg = gr.Textbox(placeholder="์งˆ๋ฌธ์„ ์ž…๋ ฅํ•˜์„ธ์š”...", show_label=False, scale=8)
219
  submit_btn = gr.Button("์ „์†ก", variant="primary", scale=1)
220
 
221
  predict_btn.click(handle_predict, inputs=input_list, outputs=[analysis_report, result_display])
 
 
 
 
222
  msg.submit(generate_response, inputs=[chatbot, msg, analysis_report], outputs=[chatbot, msg])
223
+ submit_btn.click(generate_response, inputs=[chatbot, msg, analysis_report], outputs=[chatbot, msg])
224
 
225
  if __name__ == "__main__":
226
  demo.launch(server_name="0.0.0.0", server_port=7860)
requirements.txt CHANGED
@@ -4,7 +4,7 @@ numpy<2.0.0
4
  tensorflow-cpu==2.15.1
5
  keras<3.0.0
6
  scikit-learn
7
- langchain
8
  langchain-huggingface
9
  langchain-community
10
  langchain-google-genai
@@ -12,3 +12,4 @@ faiss-cpu
12
  sentence-transformers
13
  pypdf
14
  python-dotenv
 
 
4
  tensorflow-cpu==2.15.1
5
  keras<3.0.0
6
  scikit-learn
7
+ langchain>=0.3.0
8
  langchain-huggingface
9
  langchain-community
10
  langchain-google-genai
 
12
  sentence-transformers
13
  pypdf
14
  python-dotenv
15
+ pydantic>=2.0.0