Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,222 +1,88 @@
|
|
1 |
import os
|
2 |
-
import asyncio
|
3 |
-
from typing import List, Dict
|
4 |
-
|
5 |
-
# ChromaDB ๊ฒฝ๋ก ์ค์
|
6 |
-
db_dir = os.path.join(os.getcwd(), "chromadb_KH_media")
|
7 |
-
os.environ["CHROMA_DB_DIR"] = db_dir
|
8 |
-
|
9 |
-
# === ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ํฌํธ ===
|
10 |
import chromadb
|
11 |
-
import gradio as gr
|
12 |
from sentence_transformers import SentenceTransformer
|
13 |
from google import genai
|
|
|
14 |
|
15 |
-
#
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
"์ด์์", "์ดํ", "์ต์์ง", "์ต๋ฏผ์", "๊น๊ดํธ"
|
20 |
-
]
|
21 |
|
22 |
-
#
|
23 |
class SimpleRAGSystem:
|
24 |
-
def __init__(self, db_path
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
except Exception:
|
33 |
-
self.available = False
|
34 |
-
|
35 |
-
def search_similar_docs(self, query: str, top_k: int = 10) -> List[str]:
|
36 |
if not self.available:
|
37 |
return []
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
#
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
# ๋ต๋ณ ์คํ์ผ:
|
66 |
-
- ์์ธํ๊ณ ํ๋ถํ ์ค๋ช
์ ํฌํจํ์ฌ ์์ธํ๊ณ ๊ธธ๊ฒ ๋ต๋ณ ์ ๊ณต
|
67 |
-
- ์น๊ทผํ๊ณ ๋์์ด ๋๋ ์๋ด์ฌ ํค
|
68 |
-
- ํต์ฌ ์ ๋ณด๋ฅผ ๋ช
ํํ๊ฒ ์ ๋ฌ
|
69 |
-
- ์ถ๊ฐ ๊ถ๊ธํ ์ ์ด ์์ผ๋ฉด ์ธ์ ๋ ๋ฌผ์ด๋ณด๋ผ๊ณ ์๋ด
|
70 |
-
|
71 |
-
# ์ฐธ๊ณ ๋ฌธ์ ํ์ฉ:
|
72 |
-
- ๋ฌธ์ ๋ด์ฉ์ด ์์ผ๋ฉด ๊ตฌ์ฒด์ ์ผ๋ก ์ธ์ฉ
|
73 |
-
- ์ฌ๋ฌ ๋ฌธ์์ ์ ๋ณด๋ฅผ ์ข
ํฉํ์ฌ ๋ต๋ณ ์์ฑ
|
74 |
-
- ์ ํํ์ง ์์ ์ ๋ณด๋ ์ถ์ธกํ์ง ๋ง๊ณ ์์งํ๊ฒ ๋ชจ๋ฅธ๋ค๊ณ ๋ต๋ณ
|
75 |
-
|
76 |
-
# ํ์ฌ ๊ฒฝํฌ๋ํ๊ต ๋ฏธ๋์ดํ๊ณผ ๊ต์์ง:
|
77 |
-
์ด์ธํฌ, ๊นํ์ฉ, ๋ฐ์ข
๋ฏผ, ํ์ง์, ์ด์ ๊ต, ์ด๊ธฐํ, ์ด์ ์, ์กฐ์์, ์ด์ข
ํ, ์ด๋ํฉ, ์ด์์, ์ดํ, ์ต์์ง, ์ต๋ฏผ์, ๊น๊ดํธ
|
78 |
-
|
79 |
-
ํ๊ตญ์ด๋ก ์์ฐ์ค๋ฝ๊ฒ ๋ต๋ณํด์ฃผ์ธ์."""
|
80 |
-
|
81 |
-
def respond(
|
82 |
-
message,
|
83 |
-
history: list[tuple[str, str]],
|
84 |
-
system_message,
|
85 |
-
max_tokens,
|
86 |
-
temperature,
|
87 |
-
top_p,
|
88 |
-
model_name,
|
89 |
-
):
|
90 |
-
# RAG ์ปจํ
์คํธ ์ถ๊ฐ
|
91 |
-
context_docs = []
|
92 |
-
if rag_system and rag_system.available:
|
93 |
-
try:
|
94 |
-
context_docs = rag_system.search_similar_docs(message, top_k=8)
|
95 |
-
except Exception:
|
96 |
-
pass
|
97 |
-
|
98 |
-
# ์์คํ
๋ฉ์์ง์ ์ปจํ
์คํธ ์ถ๊ฐ
|
99 |
-
enhanced_system_message = system_message
|
100 |
-
if context_docs:
|
101 |
-
context_text = "\n".join([f"์ฐธ๊ณ ๋ฌธ์ {i+1}: {doc}" for i, doc in enumerate(context_docs)])
|
102 |
-
enhanced_system_message += f"\n\n# ์ฐธ๊ณ ๋ฌธ์:\n{context_text}"
|
103 |
-
|
104 |
-
# ๋ํ ํ์คํ ๋ฆฌ๋ฅผ ํฌํจํ ์ ์ฒด ์ปจํ
์คํธ ๊ตฌ์ฑ
|
105 |
-
full_context = enhanced_system_message + "\n\n"
|
106 |
-
|
107 |
-
# ์ด์ ๋ํ ํ์คํ ๋ฆฌ ์ถ๊ฐ
|
108 |
-
for val in history:
|
109 |
-
if val[0]:
|
110 |
-
full_context += f"์ฌ์ฉ์: {val[0]}\n"
|
111 |
-
if val[1]:
|
112 |
-
full_context += f"AI ์๋ด์ฌ: {val[1]}\n"
|
113 |
-
|
114 |
-
# ํ์ฌ ์ฌ์ฉ์ ๋ฉ์์ง ์ถ๊ฐ
|
115 |
-
full_context += f"์ฌ์ฉ์: {message}\nAI ์๋ด์ฌ: "
|
116 |
-
|
117 |
try:
|
118 |
-
|
119 |
-
api_response = client.models.generate_content(
|
120 |
model=model_name,
|
121 |
-
contents=
|
122 |
-
config={
|
123 |
-
"temperature": temperature,
|
124 |
-
"top_p": top_p,
|
125 |
-
"max_output_tokens": max_tokens,
|
126 |
-
}
|
127 |
)
|
128 |
-
|
129 |
-
if hasattr(api_response, 'text') and api_response.text:
|
130 |
-
yield api_response.text
|
131 |
-
else:
|
132 |
-
yield "์๋ต์ด ๋น์ด์์ต๋๋ค. ๋ค๋ฅธ ๋ชจ๋ธ์ ์๋ํด๋ณด์ธ์."
|
133 |
-
|
134 |
except Exception as e:
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
yield error_msg
|
145 |
-
|
146 |
-
# === Gradio ์ธํฐํ์ด์ค ===
|
147 |
demo = gr.ChatInterface(
|
148 |
-
respond,
|
149 |
title="๐ฌ ๊ฒฝํฌ๋ํ๊ต ๋ฏธ๋์ดํ๊ณผ AI ์๋ด์ฌ",
|
150 |
-
description=""
|
151 |
-
๊ฒฝํฌ๋ํ๊ต ๋ฏธ๋์ดํ๊ณผ์ ๋ํ ๋ชจ๋ ๊ถ๊ธํ ์ ์ ๋ฌผ์ด๋ณด์ธ์!
|
152 |
-
""",
|
153 |
additional_inputs=[
|
154 |
-
gr.Slider(
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
minimum=0.1,
|
163 |
-
maximum=1.0,
|
164 |
-
value=0.7,
|
165 |
-
step=0.1,
|
166 |
-
label="Temperature (์ฐฝ์์ฑ)"
|
167 |
-
),
|
168 |
-
gr.Slider(
|
169 |
-
minimum=0.1,
|
170 |
-
maximum=1.0,
|
171 |
-
value=0.9,
|
172 |
-
step=0.05,
|
173 |
-
label="Top-p (๋ค์์ฑ)"
|
174 |
-
),
|
175 |
-
gr.Dropdown(
|
176 |
-
choices=[
|
177 |
-
"gemini-2.0-flash",
|
178 |
-
"gemini-2.0-flash-lite",
|
179 |
-
"gemini-1.5-flash",
|
180 |
-
"gemini-1.5-pro",
|
181 |
-
"gemma-3-27b-it",
|
182 |
-
"gemma-3-12b-it",
|
183 |
-
"gemma-3-4b-it"
|
184 |
-
],
|
185 |
-
value="gemini-2.0-flash",
|
186 |
-
label="๋ชจ๋ธ ์ ํ"
|
187 |
-
),
|
188 |
-
],
|
189 |
-
additional_inputs_accordion="๐ง ๊ณ ๊ธ ์ค์ ",
|
190 |
-
examples=[
|
191 |
-
["๋ฏธ๋์ดํ๊ณผ์์ ๋ฐฐ์ฐ๋ ์ฃผ์ ๊ณผ๋ชฉ๋ค์ ๋ฌด์์ธ๊ฐ์?"],
|
192 |
-
["๋ฏธ๋์ดํ๊ณผ ๊ต์์ง์ ์๊ฐํด์ฃผ์ธ์."],
|
193 |
-
["๋ฏธ๋์ดํ๊ณผ ์กธ์
ํ ์ง๋ก๋ ์ด๋ป๊ฒ ๋๋์?"],
|
194 |
-
["๋ฏธ๋์ดํ๊ณผ ์
ํ ์ ํ์ ๋ํด ์๋ ค์ฃผ์ธ์."],
|
195 |
-
["๋ฏธ๋์ดํ๊ณผ ๋์๋ฆฌ๋ ํ์ ํ๋์ ์ด๋ค ๊ฒ๋ค์ด ์๋์?"]
|
196 |
],
|
197 |
theme="soft",
|
198 |
analytics_enabled=False,
|
199 |
)
|
200 |
|
201 |
-
|
202 |
-
|
203 |
-
with gr.Row():
|
204 |
-
with gr.Column():
|
205 |
-
gr.Markdown(f"""
|
206 |
-
---
|
207 |
-
### โ๏ธ ์์คํ
์ ๋ณด
|
208 |
-
**์ธ์ด ๋ชจ๋ธ**: Google Gemini 2.0 Flash + Gemma 3 (4B/12B/27B) ์ ํ ๊ฐ๋ฅ
|
209 |
-
**์๋ฒ ๋ฉ ๋ชจ๋ธ**: snunlp/KR-SBERT-V40K-klueNLI-augSTS (ํ๊ตญ์ด ํนํ)
|
210 |
-
**RAG ์๏ฟฝ๏ฟฝ๏ฟฝ**: {"โ
ํ์ฑํ" if rag_system and rag_system.available else "โ ๋นํ์ฑํ"}
|
211 |
-
**๋ฌธ์ ์**: {rag_system.collection.count() if rag_system and rag_system.available else "0"}๊ฐ
|
212 |
-
|
213 |
-
๐ก **์ฌ์ฉ ํ**: ๊ตฌ์ฒด์ ์ธ ์ง๋ฌธ์ผ์๋ก ๋ ์ ํํ ๋ต๋ณ์ ๋ฐ์ ์ ์์ต๋๋ค!
|
214 |
-
""")
|
215 |
|
216 |
if __name__ == "__main__":
|
217 |
-
|
218 |
-
server_name="0.0.0.0",
|
219 |
-
server_port=int(os.environ.get("PORT", 7860)),
|
220 |
-
share=False,
|
221 |
-
show_api=False
|
222 |
-
)
|
|
|
1 |
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
import chromadb
|
|
|
3 |
from sentence_transformers import SentenceTransformer
|
4 |
from google import genai
|
5 |
+
import gradio as gr
|
6 |
|
7 |
+
# ํ๊ฒฝ ์ค์
|
8 |
+
DB_DIR = os.getenv("CHROMA_DB_DIR", os.path.join(os.getcwd(), "chromadb_KH_media"))
|
9 |
+
os.environ["CHROMA_DB_DIR"] = DB_DIR
|
10 |
+
API_KEY = os.getenv("GOOGLE_API_KEY", "AIzaSyBuBsC5k9yw2JwUfVFn1Zu1qM_ifwGx6cM")
|
|
|
|
|
11 |
|
12 |
+
# RAG ์์คํ
|
13 |
class SimpleRAGSystem:
|
14 |
+
def __init__(self, db_path=None, collection_name="KH_media_docs"):
|
15 |
+
path = db_path or DB_DIR
|
16 |
+
self.encoder = SentenceTransformer("snunlp/KR-SBERT-V40K-klueNLI-augSTS")
|
17 |
+
self.client = chromadb.PersistentClient(path=path)
|
18 |
+
self.collection = self.client.get_collection(name=collection_name)
|
19 |
+
self.available = self.collection.count() > 0
|
20 |
+
|
21 |
+
def search(self, query, top_k=8):
|
|
|
|
|
|
|
|
|
22 |
if not self.available:
|
23 |
return []
|
24 |
+
emb = self.encoder.encode(query).tolist()
|
25 |
+
docs = self.collection.query(
|
26 |
+
query_embeddings=[emb], n_results=top_k,
|
27 |
+
include=["documents"]
|
28 |
+
)
|
29 |
+
return docs["documents"][0] if docs.get("documents") else []
|
30 |
+
|
31 |
+
rag = SimpleRAGSystem()
|
32 |
+
|
33 |
+
# Google GenAI ํด๋ผ์ด์ธํธ
|
34 |
+
client = genai.Client(api_key=API_KEY)
|
35 |
+
|
36 |
+
# Gradio ์๋ต ํจ์
|
37 |
+
SYSTEM_MSG = f"""
|
38 |
+
๋น์ ์ ๊ฒฝํฌ๋ํ๊ต ๋ฏธ๋์ดํ๊ณผ ์ ๋ฌธ ์๋ด AI์
๋๋ค.
|
39 |
+
"""
|
40 |
+
|
41 |
+
def respond(message, history, system_message, max_tokens, temperature, top_p, model_name):
|
42 |
+
# RAG ์ปจํ
์คํธ
|
43 |
+
docs = rag.search(message) if rag.available else []
|
44 |
+
ctx = "\n".join(f"์ฐธ๊ณ ๋ฌธ์{i+1}: {d}" for i, d in enumerate(docs))
|
45 |
+
sys = system_message + ("\n# ์ฐธ๊ณ ๋ฌธ์:\n" + ctx if ctx else "")
|
46 |
+
# ๋ํ ์ปจํ
์คํธ
|
47 |
+
convo = "".join(f"์ฌ์ฉ์: {u}\nAI: {a}\n" for u, a in history)
|
48 |
+
prompt = f"{sys}\n{convo}์ฌ์ฉ์: {message}\nAI:"
|
49 |
+
# API ํธ์ถ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
try:
|
51 |
+
res = client.models.generate_content(
|
|
|
52 |
model=model_name,
|
53 |
+
contents=prompt,
|
54 |
+
config={"max_output_tokens": max_tokens, "temperature": temperature, "top_p": top_p}
|
|
|
|
|
|
|
|
|
55 |
)
|
56 |
+
return res.text or "์๋ต์ด ์์ต๋๋ค."
|
|
|
|
|
|
|
|
|
|
|
57 |
except Exception as e:
|
58 |
+
err = str(e).lower()
|
59 |
+
if "quota" in err:
|
60 |
+
return "API ํ ๋น๋์ ์ด๊ณผํ์ต๋๋ค. ๋์ค์ ์๋ํด์ฃผ์ธ์."
|
61 |
+
if "authentication" in err:
|
62 |
+
return "์ธ์ฆ ์ค๋ฅ: API ํค๋ฅผ ํ์ธํ์ธ์."
|
63 |
+
return f"์ค๋ฅ ๋ฐ์: {e}"
|
64 |
+
|
65 |
+
# Gradio ์ธํฐํ์ด์ค
|
|
|
|
|
|
|
|
|
66 |
demo = gr.ChatInterface(
|
67 |
+
fn=respond,
|
68 |
title="๐ฌ ๊ฒฝํฌ๋ํ๊ต ๋ฏธ๋์ดํ๊ณผ AI ์๋ด์ฌ",
|
69 |
+
description="๊ฒฝํฌ๋ํ๊ต ๋ฏธ๋์ดํ๊ณผ์ ๋ํด ๋ฌผ์ด๋ณด์ธ์!",
|
|
|
|
|
70 |
additional_inputs=[
|
71 |
+
gr.Slider(128, 2048, 1024, step=64, label="์ต๋ ํ ํฐ"),
|
72 |
+
gr.Slider(0.1, 1.0, 0.7, step=0.1, label="Temperature"),
|
73 |
+
gr.Slider(0.1, 1.0, 0.9, step=0.05, label="Top-p"),
|
74 |
+
gr.Dropdown([
|
75 |
+
"gemini-2.0-flash", "gemini-2.0-flash-lite",
|
76 |
+
"gemini-1.5-flash", "gemini-1.5-pro",
|
77 |
+
"gemma-3-27b-it", "gemma-3-12b-it", "gemma-3-4b-it"
|
78 |
+
], value="gemini-2.0-flash", label="๋ชจ๋ธ ์ ํ")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
],
|
80 |
theme="soft",
|
81 |
analytics_enabled=False,
|
82 |
)
|
83 |
|
84 |
+
def main():
|
85 |
+
demo.launch(server_name="0.0.0.0", server_port=int(os.getenv("PORT", 7860)), share=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
|
87 |
if __name__ == "__main__":
|
88 |
+
main()
|
|
|
|
|
|
|
|
|
|