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

Stabilize: Downgrade to Gradio 4.44.1 and implement Lazy Loading to fix 500 error

Browse files
Files changed (3) hide show
  1. README.md +3 -3
  2. app.py +76 -68
  3. requirements.txt +1 -1
README.md CHANGED
@@ -4,11 +4,11 @@ emoji: πŸ›‘οΈ
4
  colorFrom: blue
5
  colorTo: indigo
6
  sdk: gradio
7
- sdk_version: 5.4.0
8
  python_version: "3.10"
9
  app_file: app.py
10
  pinned: false
11
  ---
12
 
13
- # πŸ›‘οΈ KCB AI μ‹ μš© 점수 뢄석 μ„œλΉ„μŠ€
14
- KCB κ°€μ΄λ“œλΌμΈ 기반의 μ‹ μš© 상담 AIμž…λ‹ˆλ‹€.
 
4
  colorFrom: blue
5
  colorTo: indigo
6
  sdk: gradio
7
+ sdk_version: 4.44.1
8
  python_version: "3.10"
9
  app_file: app.py
10
  pinned: false
11
  ---
12
 
13
+ # πŸ›‘οΈ KCB AI μ‹ μš© 점수 상담 μ„œλΉ„μŠ€
14
+ κ°€μž₯ μ•ˆμ •μ μΈ μ΅œμ‹  배포 λ²„μ „μž…λ‹ˆλ‹€.
app.py CHANGED
@@ -13,21 +13,35 @@ import gradio as gr
13
  import pandas as pd
14
  import numpy as np
15
  import os
16
- import json
17
  import time
18
 
19
- from langchain_google_genai import ChatGoogleGenerativeAI
20
- from langchain_huggingface import HuggingFaceEmbeddings
21
- from langchain_community.vectorstores import FAISS
22
 
23
- from config import EMBEDDING_MODEL, FAISS_PATH, RETRIEVER_K, GEMINI_API_KEY
24
- from llm.prompt import QA_PROMPT
25
- from predictors.score_prediction import predictor
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
- # API ν‚€ μ„€μ •
28
- os.environ["GOOGLE_API_KEY"] = os.getenv("GOOGLE_API_KEY", GEMINI_API_KEY)
29
 
30
- # 14개 ν”Όμ²˜μ— λŒ€ν•œ 상세 μ„€λͺ… λ§€ν•‘
31
  FEATURES_MAP = {
32
  'C1Z001386': '1λ…„λ‚΄ μΉ΄λ“œ 총 μ΄μš©κΈˆμ•‘ (λ§Œμ›)',
33
  'C1M210000': 'μ‹ μš©μΉ΄λ“œ 건수',
@@ -45,37 +59,35 @@ FEATURES_MAP = {
45
  'PERF1': '90일 연체 μ—¬λΆ€'
46
  }
47
 
48
- # λͺ¨λΈμ΄ μš”κ΅¬ν•˜λŠ” μ •ν™•ν•œ μˆœμ„œ
49
  ALL_FEATURES_KEYS = [
50
  'C1Z001386', 'C1M210000', 'C18210000', 'C1L120001', 'C1L120004',
51
  'L10210000', 'L90210100', 'L90210200', 'L10210B00', 'L10216000',
52
  'L10217000', 'D10110000', 'D10133000', 'PERF1'
53
  ]
54
 
55
- class CreditRAGConsultant:
56
- def __init__(self):
57
- self.embedding_model = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL)
58
- if os.path.exists(FAISS_PATH):
59
- self.vectorstore = FAISS.load_local(FAISS_PATH, self.embedding_model, allow_dangerous_deserialization=True)
60
- self.retriever = self.vectorstore.as_retriever(search_kwargs={"k": RETRIEVER_K})
61
- else:
62
- self.vectorstore = self.retriever = None
63
-
64
- self.llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", temperature=0.7)
65
-
66
- def generate_response(self, history, user_message, analysis_report):
67
- if not user_message: yield history, ""; return
68
- if history and history[-1].get("content") == "생각 쀑...": history = history[:-1]
69
-
70
- history = history + [{"role": "assistant", "content": ""}]
71
- t0 = time.time()
72
 
73
  # R
74
- docs = self.retriever.invoke(user_message) if self.retriever else []
 
 
75
  t_retrieve = time.time() - t0
76
  context = "\n\n".join([doc.page_content for doc in docs])
77
 
78
  # A
 
79
  if analysis_report:
80
  score_val = int(analysis_report["score"])
81
  features_text = "\n".join([f"- {FEATURES_MAP.get(k, k)}: {v}" for k, v in analysis_report['features'].items()])
@@ -88,29 +100,40 @@ class CreditRAGConsultant:
88
 
89
  # G
90
  answer_buffer = ""
91
- try:
92
- for chunk in self.llm.stream(prompt_text):
93
- answer_buffer += chunk.content
94
- history[-1]["content"] = (
95
- f"πŸ“‚ **[R] μ™„λ£Œ** ({t_retrieve:.1f}s) | πŸ”— **[A] μ™„λ£Œ** ({t_augment-t_retrieve:.2f}s)\n\n"
96
- f"{answer_buffer}"
97
- )
98
- yield history, ""
99
- except Exception as e:
100
- history[-1]["content"] = f"⚠️ μ—λŸ¬: {str(e)}"
101
  yield history, ""
 
 
 
 
102
 
103
- consultant = CreditRAGConsultant()
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
105
- with gr.Blocks(title="KCB Credit AI", theme=gr.themes.Soft()) as demo:
106
  analysis_report = gr.State(None)
107
- pending_msg = gr.State("")
108
-
109
- gr.Markdown("# πŸ›‘οΈ KCB AI μ‹ μš© 점수 뢄석 μ‹œμŠ€ν…œ")
110
 
111
  with gr.Row():
112
  with gr.Column(scale=1):
113
- gr.Markdown("### πŸ“Š 금육 μ§€ν‘œ μž…λ ₯")
114
  input_list = []
115
  for key in ALL_FEATURES_KEYS:
116
  if key == 'PERF1':
@@ -121,37 +144,22 @@ with gr.Blocks(title="KCB Credit AI", theme=gr.themes.Soft()) as demo:
121
 
122
  with gr.Column(scale=2):
123
  result_display = gr.Label(label="예츑 μ‹ μš© 점수")
124
- chatbot = gr.Chatbot(label="μ‹€μ‹œκ°„ 상담", height=550, type="messages")
125
 
126
  with gr.Row():
127
  msg = gr.Textbox(placeholder="μ§ˆλ¬Έμ„ μž…λ ₯ν•˜μ„Έμš”...", scale=8, container=False)
128
  submit_btn = gr.Button("μƒλ‹΄ν•˜κΈ°", variant="primary", scale=1)
129
 
130
- def handle_predict(*args):
131
- features_dict = {}
132
- # μž…λ ₯ λ¦¬μŠ€νŠΈμ™€ ν‚€ μˆœμ„œκ°€ 동일함
133
- for i, key in enumerate(ALL_FEATURES_KEYS):
134
- if key == 'PERF1':
135
- features_dict[key] = int(args[i])
136
- else:
137
- val = args[i] if args[i] else "0"
138
- features_dict[key] = float(val)
139
-
140
- score = predictor.predict(features_dict)
141
- display_score = int(min(max(round(score), 0), 1000))
142
- return {"features": features_dict, "score": display_score}, display_score
143
-
144
- def user_msg(user_message, history):
145
- if not user_message: return history, "", ""
146
- return history + [{"role": "user", "content": user_message}, {"role": "assistant", "content": "생각 쀑..."}], "", user_message
147
-
148
  predict_btn.click(handle_predict, inputs=input_list, outputs=[analysis_report, result_display])
149
 
150
- msg.submit(user_msg, [msg, chatbot], [chatbot, msg, pending_msg]).then(
151
- consultant.generate_response, [chatbot, pending_msg, analysis_report], [chatbot, msg]
 
 
 
152
  )
153
- submit_btn.click(user_msg, [msg, chatbot], [chatbot, msg, pending_msg]).then(
154
- consultant.generate_response, [chatbot, pending_msg, analysis_report], [chatbot, msg]
155
  )
156
 
157
  if __name__ == "__main__":
 
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)
32
+ self.embedding_model = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL)
33
+ if os.path.exists(FAISS_PATH):
34
+ self.vectorstore = FAISS.load_local(FAISS_PATH, self.embedding_model, allow_dangerous_deserialization=True)
35
+ self.retriever = self.vectorstore.as_retriever(search_kwargs={"k": RETRIEVER_K})
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': 'μ‹ μš©μΉ΄λ“œ 건수',
 
59
  'PERF1': '90일 연체 μ—¬λΆ€'
60
  }
61
 
 
62
  ALL_FEATURES_KEYS = [
63
  'C1Z001386', 'C1M210000', 'C18210000', 'C1L120001', 'C1L120004',
64
  'L10210000', 'L90210100', 'L90210200', 'L10210B00', 'L10216000',
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()])
 
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':
 
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__":
requirements.txt CHANGED
@@ -1,4 +1,4 @@
1
- gradio==5.4.0
2
  pandas
3
  numpy<2.0.0
4
  tensorflow-cpu==2.15.0
 
1
+ gradio==4.44.1
2
  pandas
3
  numpy<2.0.0
4
  tensorflow-cpu==2.15.0