jonghhhh commited on
Commit
2425d9c
Β·
verified Β·
1 Parent(s): dfe0c2c

Upload app (4).py

Browse files
Files changed (1) hide show
  1. app (4).py +241 -0
app (4).py ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import asyncio
3
+ from typing import List, Dict
4
+
5
+ # .env 파일 및 Space Secrets λ‘œλ“œ
6
+ from dotenv import load_dotenv
7
+ load_dotenv()
8
+
9
+ # Google API Key 검증
10
+ google_api_key = os.getenv("GOOGLE_API_KEY")
11
+ if not google_api_key:
12
+ raise EnvironmentError("GOOGLE_API_KEYλ₯Ό Settingsβ†’Secrets에 μΆ”κ°€ν•΄μ£Όμ„Έμš”.")
13
+
14
+ # ChromaDB 경둜 μ„€μ •
15
+ db_dir = os.path.join(os.getcwd(), "chromadb_KH_media")
16
+ os.environ["CHROMA_DB_DIR"] = db_dir
17
+
18
+ # === 라이브러리 μž„ν¬νŠΈ ===
19
+ import chromadb
20
+ import gradio as gr
21
+ from sentence_transformers import SentenceTransformer
22
+ from google import genai
23
+
24
+ # === ν˜„μž¬ κ΅μˆ˜μ§„ λͺ©λ‘ ===
25
+ PROFESSORS = [
26
+ "이인희", "κΉ€νƒœμš©", "λ°•μ’…λ―Ό", "홍지아", "이정ꡐ",
27
+ "μ΄κΈ°ν˜•", "μ΄μ„ μ˜", "쑰수영", "μ΄μ’…ν˜", "이두황",
28
+ "이상원", "μ΄ν›ˆ", "μ΅œμˆ˜μ§„", "μ΅œλ―Όμ•„", "κΉ€κ΄€ν˜Έ"
29
+ ]
30
+
31
+ # === Simple RAG μ‹œμŠ€ν…œ ===
32
+ class SimpleRAGSystem:
33
+ def __init__(self, db_path: str = None, collection: str = "KH_media_docs"):
34
+ db_path = db_path or os.getenv("CHROMA_DB_DIR")
35
+ try:
36
+ self.embedding_model = SentenceTransformer("snunlp/KR-SBERT-V40K-klueNLI-augSTS")
37
+ self.client = chromadb.PersistentClient(path=db_path)
38
+ self.collection = self.client.get_collection(name=collection)
39
+ count = self.collection.count()
40
+ if count == 0:
41
+ print("κ²½κ³ : ChromaDBκ°€ λΉ„μ–΄μžˆμŠ΅λ‹ˆλ‹€.")
42
+ self.available = False
43
+ else:
44
+ self.available = True
45
+ print(f"ChromaDB λ‘œλ“œ μ™„λ£Œ: {count}개 λ¬Έμ„œ")
46
+ except Exception as e:
47
+ print(f"RAG μ‹œμŠ€ν…œ μ΄ˆκΈ°ν™” μ‹€νŒ¨: {e}")
48
+ self.available = False
49
+
50
+ def search_similar_docs(self, query: str, top_k: int = 10) -> List[str]:
51
+ if not self.available:
52
+ return []
53
+ try:
54
+ emb = self.embedding_model.encode(query).tolist()
55
+ res = self.collection.query(
56
+ query_embeddings=[emb], n_results=top_k,
57
+ include=["documents", "metadatas"]
58
+ )
59
+ return res["documents"][0] if res["documents"] else []
60
+ except Exception as e:
61
+ print(f"RAG 검색 였λ₯˜: {e}")
62
+ return []
63
+
64
+ # RAG μ‹œμŠ€ν…œ μ΄ˆκΈ°ν™”
65
+ try:
66
+ rag_system = SimpleRAGSystem()
67
+ except Exception as e:
68
+ print(f"RAG μ‹œμŠ€ν…œμ„ μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€: {e}")
69
+ rag_system = None
70
+
71
+ # === Google GenAI Client μ„€μ • ===
72
+ client = genai.Client(api_key=google_api_key)
73
+
74
+ # === μ‹œμŠ€ν…œ λ©”μ‹œμ§€ ===
75
+ SYSTEM_MESSAGE = """당신은 κ²½ν¬λŒ€ν•™κ΅ λ―Έλ””μ–΄ν•™κ³Ό μ „λ¬Έ 상담 AIμž…λ‹ˆλ‹€.
76
+
77
+ # μ£Όμš” μ—­ν• :
78
+ - 제곡된 λ¬Έμ„œ 정보λ₯Ό λ°”νƒ•μœΌλ‘œ λ‹΅λ³€ 제곡
79
+ - λ―Έλ””μ–΄ν•™κ³Ό κ΄€λ ¨ μ§ˆλ¬Έμ— μΉœμ ˆν•˜κ³  ꡬ체적으둜 응닡
80
+ - λ¬Έμ„œμ— μ—†λŠ” λ‚΄μš©μ€ 일반 μ§€μ‹μœΌλ‘œ 보완 (단, λͺ…μ‹œ)
81
+
82
+ # λ‹΅λ³€ μŠ€νƒ€μΌ:
83
+ - μžμ„Έν•˜κ³  ν’λΆ€ν•œ μ„€λͺ…을 ν¬ν•¨ν•˜μ—¬ μƒμ„Έν•˜κ³  길게 λ‹΅λ³€ 제곡
84
+ - μΉœκ·Όν•˜κ³  도움이 λ˜λŠ” 상담사 톀
85
+ - 핡심 정보λ₯Ό λͺ…ν™•ν•˜κ²Œ 전달
86
+ - μΆ”κ°€ κΆκΈˆν•œ 점이 있으면 μ–Έμ œλ“  물어보라고 μ•ˆλ‚΄
87
+
88
+ # μ°Έκ³  λ¬Έμ„œ ν™œμš©:
89
+ - λ¬Έμ„œ λ‚΄μš©μ΄ 있으면 ꡬ체적으둜 인용
90
+ - μ—¬λŸ¬ λ¬Έμ„œμ˜ 정보λ₯Ό μ’…ν•©ν•˜μ—¬ λ‹΅λ³€ μž‘μ„±
91
+ - μ •ν™•ν•˜μ§€ μ•Šμ€ μ •λ³΄λŠ” μΆ”μΈ‘ν•˜μ§€ 말고 μ†”μ§ν•˜κ²Œ λͺ¨λ₯Έλ‹€κ³  λ‹΅λ³€
92
+
93
+ # ν˜„μž¬ κ²½ν¬λŒ€ν•™κ΅ λ―Έλ””μ–΄ν•™κ³Ό κ΅μˆ˜μ§„:
94
+ 이인희, κΉ€νƒœμš©, λ°•μ’…λ―Ό, 홍지아, 이정ꡐ, μ΄κΈ°ν˜•, μ΄μ„ μ˜, 쑰수영, μ΄μ’…ν˜, 이두황, 이상원, μ΄ν›ˆ, μ΅œμˆ˜μ§„, μ΅œλ―Όμ•„, κΉ€κ΄€ν˜Έ
95
+
96
+ ν•œκ΅­μ–΄λ‘œ μžμ—°μŠ€λŸ½κ²Œ λ‹΅λ³€ν•΄μ£Όμ„Έμš”."""
97
+
98
+ def respond(
99
+ message,
100
+ history: list[tuple[str, str]],
101
+ system_message,
102
+ max_tokens,
103
+ temperature,
104
+ top_p,
105
+ model_name,
106
+ ):
107
+ # RAG μ»¨ν…μŠ€νŠΈ μΆ”κ°€
108
+ context_docs = []
109
+ if rag_system and rag_system.available:
110
+ try:
111
+ context_docs = rag_system.search_similar_docs(message, top_k=8)
112
+ except Exception as e:
113
+ print(f"RAG 검색 쀑 였λ₯˜: {e}")
114
+
115
+ # μ‹œμŠ€ν…œ λ©”μ‹œμ§€μ— μ»¨ν…μŠ€νŠΈ μΆ”κ°€
116
+ enhanced_system_message = system_message
117
+ if context_docs:
118
+ context_text = "\n".join([f"μ°Έκ³ λ¬Έμ„œ {i+1}: {doc}" for i, doc in enumerate(context_docs)])
119
+ enhanced_system_message += f"\n\n# μ°Έκ³  λ¬Έμ„œ:\n{context_text}"
120
+
121
+ # λŒ€ν™” νžˆμŠ€ν† λ¦¬λ₯Ό ν¬ν•¨ν•œ 전체 μ»¨ν…μŠ€νŠΈ ꡬ성
122
+ full_context = enhanced_system_message + "\n\n"
123
+
124
+ # 이전 λŒ€ν™” νžˆμŠ€ν† λ¦¬ μΆ”κ°€
125
+ for val in history:
126
+ if val[0]:
127
+ full_context += f"μ‚¬μš©μž: {val[0]}\n"
128
+ if val[1]:
129
+ full_context += f"AI 상담사: {val[1]}\n"
130
+
131
+ # ν˜„μž¬ μ‚¬μš©μž λ©”μ‹œμ§€ μΆ”κ°€
132
+ full_context += f"μ‚¬μš©μž: {message}\nAI 상담사: "
133
+
134
+ response = ""
135
+ try:
136
+ # Google GenAI API 호좜
137
+ api_response = client.models.generate_content(
138
+ model=model_name,
139
+ contents=full_context,
140
+ config={
141
+ "temperature": temperature,
142
+ "top_p": top_p,
143
+ "max_output_tokens": max_tokens,
144
+ }
145
+ )
146
+
147
+ response = api_response.text
148
+ yield response
149
+
150
+ except Exception as e:
151
+ error_msg = f"μ£„μ†‘ν•©λ‹ˆλ‹€. 응닡 생성 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {str(e)}"
152
+ yield error_msg
153
+
154
+ # === Gradio μΈν„°νŽ˜μ΄μŠ€ ===
155
+ demo = gr.ChatInterface(
156
+ respond,
157
+ title="🎬 κ²½ν¬λŒ€ν•™κ΅ λ―Έλ””μ–΄ν•™κ³Ό AI 상담사",
158
+ description="""
159
+ κ²½ν¬λŒ€ν•™κ΅ 미디어학과에 λŒ€ν•œ λͺ¨λ“  κΆκΈˆν•œ 점을 λ¬Όμ–΄λ³΄μ„Έμš”!
160
+
161
+ **μ£Όμš” κΈ°λŠ₯:**
162
+ - πŸ“š λ―Έλ””μ–΄ν•™κ³Ό 컀리큘럼 및 κ΅μœ‘κ³Όμ • μ•ˆλ‚΄
163
+ - πŸ‘¨β€πŸ« κ΅μˆ˜μ§„ 및 연ꡬ λΆ„μ•Ό μ†Œκ°œ
164
+ - πŸŽ“ μž…ν•™ 정보 및 μ§„λ‘œ 상담
165
+ - 🏫 ν•™κ³Ό μ‹œμ„€ 및 동아리 ν™œλ™ μ•ˆλ‚΄
166
+ """,
167
+ additional_inputs=[
168
+ gr.Textbox(
169
+ value=SYSTEM_MESSAGE,
170
+ label="μ‹œμŠ€ν…œ λ©”μ‹œμ§€",
171
+ lines=3,
172
+ max_lines=10
173
+ ),
174
+ gr.Slider(
175
+ minimum=128,
176
+ maximum=2048,
177
+ value=1024,
178
+ step=64,
179
+ label="μ΅œλŒ€ 토큰 수"
180
+ ),
181
+ gr.Slider(
182
+ minimum=0.1,
183
+ maximum=1.0,
184
+ value=0.7,
185
+ step=0.1,
186
+ label="Temperature (μ°½μ˜μ„±)"
187
+ ),
188
+ gr.Slider(
189
+ minimum=0.1,
190
+ maximum=1.0,
191
+ value=0.9,
192
+ step=0.05,
193
+ label="Top-p (λ‹€μ–‘μ„±)"
194
+ ),
195
+ gr.Dropdown(
196
+ choices=[
197
+ "gemini-2.0-flash",
198
+ "gemini-2.0-flash-lite",
199
+ "gemini-1.5-flash",
200
+ "gemini-1.5-pro"
201
+ ],
202
+ value="gemini-2.0-flash",
203
+ label="λͺ¨λΈ 선택"
204
+ ),
205
+ ],
206
+ additional_inputs_accordion="πŸ”§ κ³ κΈ‰ μ„€μ •",
207
+ examples=[
208
+ "λ―Έλ””μ–΄ν•™κ³Όμ—μ„œ λ°°μš°λŠ” μ£Όμš” κ³Όλͺ©λ“€μ€ λ¬΄μ—‡μΈκ°€μš”?",
209
+ "λ―Έλ””μ–΄ν•™κ³Ό κ΅μˆ˜μ§„μ„ μ†Œκ°œν•΄μ£Όμ„Έμš”.",
210
+ "λ―Έλ””μ–΄ν•™κ³Ό μ‘Έμ—… ν›„ μ§„λ‘œλŠ” μ–΄λ–»κ²Œ λ˜λ‚˜μš”?",
211
+ "λ―Έλ””μ–΄ν•™κ³Ό μž…ν•™ μ „ν˜•μ— λŒ€ν•΄ μ•Œλ €μ£Όμ„Έμš”.",
212
+ "λ―Έλ””μ–΄ν•™κ³Ό λ™μ•„λ¦¬λ‚˜ 학생 ν™œλ™μ€ μ–΄λ–€ 것듀이 μžˆλ‚˜μš”?"
213
+ ],
214
+ theme="soft",
215
+ analytics_enabled=False,
216
+ )
217
+
218
+ # === μ‹œμŠ€ν…œ 정보 ν‘œμ‹œ ===
219
+ with demo:
220
+ with gr.Row():
221
+ with gr.Column():
222
+ gr.Markdown(f"""
223
+ ---
224
+ ### βš™οΈ μ‹œμŠ€ν…œ 정보
225
+ **μ–Έμ–΄ λͺ¨λΈ**: Google Gemini 2.0 Flash (무료)
226
+ **μž„λ² λ”© λͺ¨λΈ**: snunlp/KR-SBERT-V40K-klueNLI-augSTS (ν•œκ΅­μ–΄ νŠΉν™”)
227
+ **RAG μƒνƒœ**: {"βœ… ν™œμ„±ν™”" if rag_system and rag_system.available else "❌ λΉ„ν™œμ„±ν™”"}
228
+ **λ¬Έμ„œ 수**: {rag_system.collection.count() if rag_system and rag_system.available else "0"}개
229
+
230
+ πŸ’‘ **μ‚¬μš© 팁**: ꡬ체적인 질문일수둝 더 μ •ν™•ν•œ 닡변을 받을 수 μžˆμŠ΅λ‹ˆλ‹€!
231
+
232
+ πŸ”‘ **API μƒνƒœ**: {"βœ… Google API 연결됨" if google_api_key else "❌ API ν‚€ μ—†μŒ"}
233
+ """)
234
+
235
+ if __name__ == "__main__":
236
+ demo.launch(
237
+ server_name="0.0.0.0",
238
+ server_port=int(os.environ.get("PORT", 7860)),
239
+ share=False,
240
+ show_api=False
241
+ )