jaeyong2 commited on
Commit
8721ec5
·
1 Parent(s): 318c946

Add application file

Browse files
Files changed (4) hide show
  1. app.py +287 -0
  2. image.png +0 -0
  3. language_info.py +138 -0
  4. requirements.txt +4 -0
app.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import copy
4
+ from datetime import datetime
5
+ import pandas as pd
6
+ import gradio as gr
7
+ from openai import OpenAI
8
+ from supabase import create_client
9
+ from language_info import *
10
+
11
+ # 시스템 프롬프트 정의
12
+ FIRST_PROMPT = """
13
+ 너는 유저의 질문을 분석하는 AI야! 유저의 질문을 바탕으로 주어진 조건에 맞도록 질문을 분석해줘!
14
+ 조건 1. 아래 Task 리스트 중 1개의 작업 선택!
15
+ Task : ["ReAsk", "FindProduct", "Recommandation", "Etc"]
16
+ 조건 2. 만약, Task가 "FindProduct"라면, 원하는 "Product"를 "Option"으로 정의를 해줘!
17
+ 조건 3. 만약, Task가 "Recommandation"라면, 유저의 조건을 "Condition"이라고 "Option"에 제공해줘!
18
+ 조건 4. 만약, Task가 "ReAsk"라면, 유저의 질문에서 추가적으로 요구되는 조건을 "Condition"이라고 "Option"에 제공해줘!
19
+ ** 조건 5. 화장품 관련 이야기를 제외한 다른 이야기는 답할 수 없다는 내용으로 답변을 해줘! **
20
+ ** 조건 6. 언어가 다르더라도 출력은 전부 "한국어"를 사용해서 출력해! 그리고 유저 입력에 대한 한국어 번역을 "Translation"으로 제공해!**
21
+
22
+ OUTPUT 포맷
23
+ json
24
+ {
25
+ "Task":"...",
26
+ "Option":{"...":"...", ..., key:val},
27
+ "Translation":"..."
28
+ }
29
+ """
30
+
31
+ # Supabase 로깅 함수
32
+ def log_to_supabase(supabase, question, answer, history):
33
+ """Supabase에 채팅 로그를 저장하는 함수"""
34
+ try:
35
+ timestamp = datetime.now().isoformat()
36
+ supabase.table("chat_log").insert({
37
+ "question": question,
38
+ "answer": answer,
39
+ "history": json.dumps(history, ensure_ascii=False),
40
+ "timestamp": timestamp
41
+ }).execute()
42
+ return True
43
+ except Exception as e:
44
+ print(f"Error logging to Supabase: {e}")
45
+ return False
46
+
47
+ def local_RAG(model, message, client, vector_id):
48
+ """로컬 검색 기반 생성 함수"""
49
+ try:
50
+ response = client.responses.create(
51
+ model=model,
52
+ input=message,
53
+ tools=[{
54
+ "type": "file_search",
55
+ "vector_store_ids": [vector_id],
56
+ "max_num_results": 5
57
+ }]
58
+ )
59
+ if response.output[0].results is None:
60
+ return ""
61
+ return response.output[1].content[0].text
62
+ except Exception as e:
63
+ print(f"Error in RAG: {e}")
64
+ return ""
65
+
66
+ def routing(messages, client, language):
67
+ """사용자 질문 분석 및 라우팅 함수"""
68
+ try:
69
+ routing_messages = copy.deepcopy(messages)
70
+ routing_messages[0]['content'] = FIRST_PROMPT
71
+ response = client.chat.completions.create(
72
+ model="gpt-4o",
73
+ messages=routing_messages,
74
+ response_format={"type": "json_object"}
75
+ )
76
+ return json.loads(response.choices[0].message.content)
77
+ except Exception as e:
78
+ print(f"Error in routing: {e}")
79
+ return {"Task": "Etc"}
80
+
81
+ def generate_response(query_parsing, client, vector_id, user_message, chat_history, language):
82
+ """쿼리 분석 결과에 따른 응답 생성 함수"""
83
+
84
+ # 메시지 형식으로 변환
85
+ messages = [{"role": "system", "content": get_system_prompt(language)}]
86
+ for user_msg, bot_msg in chat_history:
87
+ if user_msg:
88
+ messages.append({"role": "user", "content": user_msg})
89
+ if bot_msg:
90
+ messages.append({"role": "assistant", "content": bot_msg})
91
+ if language!="한국어":
92
+ messages.append({"role": "user", "content": user_message})
93
+ else:
94
+ messages.append({"role": "user", "content": query_parsing["Translation"]})
95
+
96
+ # 쿼리 분석 결과가 없는 경우
97
+ if "Task" not in query_parsing:
98
+ return get_text('error_understanding', language)
99
+
100
+ # ReAsk: 추가 정보 요청
101
+ if query_parsing["Task"] == "ReAsk":
102
+ if "Option" in query_parsing and "Condition" in query_parsing["Option"]:
103
+ return f"{get_text('additional_info_needed', language)}{query_parsing['Option']['Condition']}"
104
+ else:
105
+ return get_text('request_more_info', language)
106
+
107
+ # FindProduct: 제품 검색
108
+ if query_parsing["Task"] == "FindProduct":
109
+ if "Option" not in query_parsing:
110
+ return get_text('error_product_not_found', language)
111
+
112
+ product = query_parsing['Option']["Product"]
113
+
114
+ # 수파베이스에서 화장품 데이터 가져오기
115
+ try:
116
+ product_list = supabase.table("cosmetics").select("*").execute().data
117
+ except:
118
+ # 실제 구현 시 데이터베이스 연결 필수
119
+ product_list = [] # 임시 빈 리스트
120
+
121
+ find_data = ""
122
+ for item in product_list:
123
+ if product in item["title"]:
124
+ find_data += f"item : {item['title']}\tbrand : {item['brand']}\tmake : {item['maker']}\tsummary : {item['summary']}\n\n"
125
+
126
+ if len(find_data) > 2:
127
+ # 데이터를 찾았을 때
128
+ messages[-1]['content'] = messages[-1]['content'] + "\n\n<데이터>\n\n" + find_data + "\n\n</데이터>\n\n" + messages[-1]['content']
129
+ response = client.chat.completions.create(
130
+ model="gpt-4o",
131
+ messages=messages
132
+ )
133
+ return response.choices[0].message.content
134
+ else:
135
+ # 데이터를 찾지 못했을 때 RAG 시도
136
+ response = local_RAG("gpt-4o", user_message, client, vector_id)
137
+ if response == "":
138
+ # RAG도 실패했을 때 검색 모델 사용
139
+ response = client.chat.completions.create(
140
+ model="gpt-4o-search-preview",
141
+ messages=messages
142
+ )
143
+ return response.choices[0].message.content
144
+ return response
145
+
146
+ # Recommendation: 제품 추천
147
+ if query_parsing["Task"] == "Recommandation":
148
+ response = local_RAG("gpt-4o", user_message, client, vector_id)
149
+ if response == "":
150
+ # RAG 실패 시 검색 모델 사용
151
+ response = client.chat.completions.create(
152
+ model="gpt-4o-search-preview",
153
+ messages=messages
154
+ )
155
+ return response.choices[0].message.content
156
+ return response
157
+
158
+ # Etc: 일반 응답
159
+ response = client.chat.completions.create(
160
+ model="gpt-4o",
161
+ messages=messages
162
+ )
163
+ return response.choices[0].message.content
164
+
165
+ def get_system_prompt(language):
166
+ """언어에 맞는 시스템 프롬프트 생성"""
167
+ return f"""
168
+ 너는 한국의 화장품을 상담해 주는 AI야!
169
+ 유저의 한국 화장품 관련 질문에 가장 적절한 답변을 해줘!
170
+ 조건1 : 화장품과 관련되지 않은 질문은 대답하지 마.
171
+ 조건2 : 주어진 language에 맞는 언어로 답변해줘!
172
+ 조건3 : 유저가 별도의 데이터를 제공하면 (<데이터>...</데이터> 형식), 제공된 데이터 내에서만 답변해줘.
173
+ language: {language}
174
+ """
175
+
176
+ # 현재 선택된 언어를 저장할 전역 변수
177
+ selected_language = "English"
178
+
179
+ def chatbot(message, history, language_choice=None):
180
+ """챗봇의 메인 함수"""
181
+ global selected_language
182
+
183
+ # language_choice가 제공되었으면 업데이트
184
+ if language_choice is not None:
185
+ selected_language = language_choice
186
+
187
+ # OpenAI API 키 및 환경 변수 설정
188
+ openai_api_key = os.getenv("OPENAI_API_KEY")
189
+ vector_id = os.getenv("vector_id")
190
+
191
+ # Supabase 설정
192
+ supabase_url = os.getenv("SUPABASE_URL")
193
+ supabase_key = os.getenv("SUPABASE_KEY")
194
+ supabase = None
195
+
196
+ client = OpenAI(api_key=openai_api_key)
197
+
198
+ # Supabase 클라이언트 생성 (있을 경우)
199
+ if supabase_url and supabase_key:
200
+ supabase = create_client(supabase_url, supabase_key)
201
+
202
+ # 쿼리 분석 및 응답 생성
203
+ query_parsing = routing([{"role": "system", "content": ""}, {"role": "user", "content": message}], client, selected_language)
204
+ response = generate_response(query_parsing, client, vector_id, message, history, selected_language)
205
+
206
+ # Supabase 로깅 (해당 환경변수가 있을 경우)
207
+ if supabase:
208
+ chat_history = []
209
+ for user_msg, bot_msg in history:
210
+ if user_msg:
211
+ chat_history.append({"role": "user", "content": user_msg})
212
+ if bot_msg:
213
+ chat_history.append({"role": "assistant", "content": bot_msg})
214
+ chat_history.append({"role": "user", "content": message})
215
+ chat_history.append({"role": "assistant", "content": response})
216
+
217
+ log_to_supabase(supabase, message, response, chat_history)
218
+
219
+ return response
220
+
221
+ def change_language(language_choice):
222
+ """언어 변경 함수"""
223
+ global selected_language
224
+ selected_language = language_choice
225
+ return language_choice
226
+
227
+ # 메인 함수
228
+ def main():
229
+ """Gradio 인터페이스 설정 함수"""
230
+ # 언어 설정
231
+ languages = ["English", "한국어", "Español", "中文", "日本語", "ภาษาไทย", "Tiếng Việt", "Bahasa Indonesia"]
232
+ global selected_language
233
+ selected_language = "English"
234
+ current_dir = os.path.dirname(os.path.abspath(__file__))
235
+ image_path = os.path.join(current_dir, "image.png")
236
+ # Gradio 인터페이스 구성
237
+ with gr.Blocks(css="footer {visibility: hidden}") as demo:
238
+
239
+ gr.Markdown(f"# {get_text('title', selected_language)}")
240
+ gr.Markdown(f"(Conversation logs are saved.)")
241
+
242
+ with gr.Row():
243
+ language_dropdown = gr.Dropdown(
244
+ choices=languages,
245
+ value=selected_language,
246
+ label=get_text("language_selector", selected_language)
247
+ )
248
+
249
+ # 언어 상태를 저장할 state 객체 생성
250
+ lang_state = gr.State(value=selected_language)
251
+
252
+ # 언어가 변경될 때 실행되는 함수
253
+ def update_language(new_lang, history):
254
+ global selected_language
255
+ selected_language = new_lang
256
+ return new_lang, history
257
+
258
+ # 챗봇의 메시지 전송 함수를 수정하여 현재 언어 상태를 전달
259
+ def handle_message(message, history, lang):
260
+ return chatbot(message, history, lang)
261
+
262
+ chatbot_interface = gr.ChatInterface(
263
+ fn=handle_message,
264
+ additional_inputs=[language_dropdown],
265
+ title="",
266
+ examples=[
267
+ ["이니스프리 그린티 제품 알려줘", "한국어"],
268
+ ["แนะนำผลิตภัณฑ์ดูแลผิวที่ดีสำหรับผู้หญิง", "ภาษาไทย"],
269
+ ["What products are effective for whitening?", "English"]
270
+ ],
271
+ )
272
+
273
+ # 언어 변경 시 이벤트
274
+ language_dropdown.change(
275
+ fn=update_language,
276
+ inputs=[language_dropdown, chatbot_interface.chatbot],
277
+ outputs=[lang_state, chatbot_interface.chatbot]
278
+ )
279
+ gr.Markdown(f"# Architecture")
280
+
281
+ gr.Image(value=image_path, show_label=False, height=400, width=400)
282
+
283
+ # Gradio 앱 실행
284
+ demo.launch()
285
+
286
+ if __name__ == "__main__":
287
+ main()
image.png ADDED
language_info.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ TRANSLATIONS = {
2
+ "English": {
3
+ "title": "💬 K-Cosmetics Consultation Chatbot",
4
+ "language_selector": "Choose your language:",
5
+ "info_api_key": "Please set your OpenAI API key.",
6
+ "chat_input": "Enter your message:",
7
+ "error_routing": "Routing error: ",
8
+ "error_generation": "Generation error: ",
9
+ "error_logging": "Logging error: ",
10
+ "error_rag": "RAG error: ",
11
+ "error_understanding": "Sorry, I couldn't understand what you're looking for. Could you please be more specific?",
12
+ "error_product_not_found": "Sorry, I couldn't find the product you're looking for. Please provide more specific details about the product.",
13
+ "request_more_info": "Please provide more details about the product you're interested in (e.g. name, brand, maker) or specify your requirements in detail (e.g. for dry skin).",
14
+ "additional_info_needed": "I need the following additional information: ",
15
+ "generating_response": "Generating response...",
16
+ "thinking": "AI is thinking..."
17
+ },
18
+ "한국어": {
19
+ "title": "💬 화장품 상담 챗봇",
20
+ "language_selector": "언어를 선택하세요:",
21
+ "info_api_key": "OpenAI API 키를 설정해주세요.",
22
+ "chat_input": "메시지 입력:",
23
+ "error_routing": "라우팅 오류: ",
24
+ "error_generation": "생성 오류: ",
25
+ "error_logging": "로그 저장 오류: ",
26
+ "error_rag": "RAG 오류: ",
27
+ "error_understanding": "죄송합니다. 원하시는 내용을 제대로 이해하지 못했어요. 조금 더 구체적으로 알려주시면 감사하겠습니다.",
28
+ "error_product_not_found": "죄송합니다. 원하시는 내용을 찾지 못했어요. 찾으시는 제품에 대해서 명확하게 다시 알려주세요.",
29
+ "request_more_info": "관심 있는 제품에 대해서 자세히(ex. 이름, 브랜드, 메이커) 알려주세요. 또는 원하시는 조건에 대해서 자세히(ex. 건성 피부용) 알려주세요.",
30
+ "additional_info_needed": "다음과 같은 정보가 추가적으로 필요합니다: ",
31
+ "generating_response": "답변 생성 중...",
32
+ "thinking": "AI가 생각하는 중입니다..."
33
+ },
34
+ "Español": {
35
+ "title": "💬 Chatbot de Consulta de Cosméticos",
36
+ "language_selector": "Elige tu idioma:",
37
+ "info_api_key": "Por favor, configura tu clave API de OpenAI.",
38
+ "chat_input": "Ingresa tu mensaje:",
39
+ "error_routing": "Error de enrutamiento: ",
40
+ "error_generation": "Error de generación: ",
41
+ "error_logging": "Error de registro: ",
42
+ "error_rag": "Error de RAG: ",
43
+ "error_understanding": "Lo siento, no pude entender lo que estás buscando. ¿Podrías ser más específico?",
44
+ "error_product_not_found": "Lo siento, no pude encontrar el producto que buscas. Por favor, proporciona detalles más específicos sobre el producto.",
45
+ "request_more_info": "Por favor, proporciona más detalles sobre el producto que te interesa (ej. nombre, marca, fabricante) o especifica tus requisitos en detalle (ej. para piel seca).",
46
+ "additional_info_needed": "Necesito la siguiente información adicional: ",
47
+ "generating_response": "Generando respuesta...",
48
+ "thinking": "La IA está pensando..."
49
+ },
50
+ "中文": {
51
+ "title": "💬 化妆品咨询聊天机器人",
52
+ "language_selector": "选择你的语言:",
53
+ "info_api_key": "请设置你的OpenAI API密钥。",
54
+ "chat_input": "输入你的消息:",
55
+ "error_routing": "路由错误: ",
56
+ "error_generation": "生成错误: ",
57
+ "error_logging": "日志错误: ",
58
+ "error_rag": "RAG错误: ",
59
+ "error_understanding": "抱歉,我无法理解您在寻找什么。您能更具体一点吗?",
60
+ "error_product_not_found": "抱歉,我找不到您正在寻找的产品。请提供更具体的产品详情。",
61
+ "request_more_info": "请提供有关您感兴趣的产品的更多详细信息(例如名称,品牌,制造商)或详细说明您的要求(例如适合干性皮肤)。",
62
+ "additional_info_needed": "我需要以下额外信息: ",
63
+ "generating_response": "生成回答中...",
64
+ "thinking": "AI正在思考中..."
65
+ },
66
+ "日本語": {
67
+ "title": "💬 化粧品相談チャットボット",
68
+ "language_selector": "言語を選択してください:",
69
+ "info_api_key": "OpenAI APIキーを設定してください。",
70
+ "chat_input": "メッセージを入力してください:",
71
+ "error_routing": "ルーティングエラー: ",
72
+ "error_generation": "生成エラー: ",
73
+ "error_logging": "ログエラー: ",
74
+ "error_rag": "RAGエラー: ",
75
+ "error_understanding": "申し訳ありませんが、お探しの内容を理解できませんでした。もう少し具体的に教えていただけますか?",
76
+ "error_product_not_found": "申し訳ありませんが、お探しの製品が見つかりませんでした。製品についてより具体的な詳細を提供してください。",
77
+ "request_more_info": "興味のある製品について詳しく(例:名前、ブランド、メーカー)教えてください。または、ご要望を詳しく(例:乾燥肌用)教えてください。",
78
+ "additional_info_needed": "以下の追加情報が必要です: ",
79
+ "generating_response": "応答を生成中...",
80
+ "thinking": "AIが考え中です..."
81
+ },
82
+ "ภาษาไทย": {
83
+ "title": "💬 แชทบอทให้คำปรึกษาด้านเครื่องสำอาง",
84
+ "language_selector": "เลือกภาษาของคุณ:",
85
+ "info_api_key": "โปรดตั้งค่าคีย์ API OpenAI ของคุณ",
86
+ "chat_input": "ป้อนข้อความของคุณ:",
87
+ "error_routing": "ข้อผิดพลาดในการกำหนดเส้นทาง: ",
88
+ "error_generation": "ข้อผิดพลาดในการสร้าง: ",
89
+ "error_logging": "ข้อผิดพลาดในการบันทึก: ",
90
+ "error_rag": "ข้อผิดพลาด RAG: ",
91
+ "error_understanding": "ขออภัย ฉันไม่เข้าใจว่าคุณกำลังมองหาอะไร คุณช่วยระบุให้ชัดเจนได้ไหม?",
92
+ "error_product_not_found": "ขออภัย ฉันไม่พบผลิตภัณฑ์ที่คุณกำลังมองหา โปรดให้รายละเอียดเฉพาะเกี่ยวกับผลิตภัณฑ์เพิ่มเติม",
93
+ "request_more_info": "โปรดให้รายละเอียดเพิ่มเติมเกี่ยวกับผลิตภัณฑ์ที่คุณสนใจ (เช่น ชื่อ, แบรนด์, ผู้ผลิต) หรือระบุความต้องการของคุณโดยละเอียด (เช่น สำหรับผิวแห้ง)",
94
+ "additional_info_needed": "ฉันต้องการข้อมูลเพิ่มเติมต่อไปนี้: ",
95
+ "generating_response": "กำลังสร้างคำตอบ...",
96
+ "thinking": "AI กำลังคิด..."
97
+ },
98
+ "Tiếng Việt": {
99
+ "title": "💬 Chatbot Tư vấn Mỹ phẩm",
100
+ "language_selector": "Chọn ngôn ngữ của bạn:",
101
+ "info_api_key": "Vui lòng thiết lập khóa API OpenAI của bạn.",
102
+ "chat_input": "Nhập tin nhắn của bạn:",
103
+ "error_routing": "Lỗi định tuyến: ",
104
+ "error_generation": "Lỗi tạo: ",
105
+ "error_logging": "Lỗi ghi nhật ký: ",
106
+ "error_rag": "Lỗi RAG: ",
107
+ "error_understanding": "Xin lỗi, tôi không hiểu bạn đang tìm kiếm gì. Bạn có thể cụ thể hơn được không?",
108
+ "error_product_not_found": "Xin lỗi, tôi không thể tìm thấy sản phẩm bạn đang tìm kiếm. Vui lòng cung cấp thêm chi tiết cụ thể về sản phẩm.",
109
+ "request_more_info": "Vui lòng cung cấp thêm chi tiết về sản phẩm bạn quan tâm (ví dụ: tên, thương hiệu, nhà sản xuất) hoặc chỉ rõ yêu cầu của bạn (ví dụ: cho da khô).",
110
+ "additional_info_needed": "Tôi cần thêm thông tin sau: ",
111
+ "generating_response": "Đang tạo phản hồi...",
112
+ "thinking": "AI đang suy nghĩ..."
113
+ },
114
+ "Bahasa Indonesia": {
115
+ "title": "💬 Chatbot Konsultasi Kosmetik",
116
+ "language_selector": "Pilih bahasa Anda:",
117
+ "info_api_key": "Harap atur kunci API OpenAI Anda.",
118
+ "chat_input": "Masukkan pesan Anda:",
119
+ "error_routing": "Kesalahan perutean: ",
120
+ "error_generation": "Kesalahan pembuatan: ",
121
+ "error_logging": "Kesalahan pencatatan: ",
122
+ "error_rag": "Kesalahan RAG: ",
123
+ "error_understanding": "Maaf, saya tidak mengerti apa yang Anda cari. Bisakah Anda lebih spesifik?",
124
+ "error_product_not_found": "Maaf, saya tidak dapat menemukan produk yang Anda cari. Harap berikan detail yang lebih spesifik tentang produk tersebut.",
125
+ "request_more_info": "Harap berikan lebih banyak detail tentang produk yang Anda minati (misalnya nama, merek, pembuat) atau tentukan persyaratan Anda secara detail (misalnya untuk kulit kering).",
126
+ "additional_info_needed": "Saya membutuhkan informasi tambahan berikut: ",
127
+ "generating_response": "Membuat respons...",
128
+ "thinking": "AI sedang berpikir..."
129
+ }
130
+ }
131
+
132
+ # 텍스트 가져오기 함수
133
+ def get_text(key, language):
134
+ """선택한 언어에 맞는 텍스트 반환"""
135
+ if language in TRANSLATIONS and key in TRANSLATIONS[language]:
136
+ return TRANSLATIONS[language][key]
137
+ # 기본값으로 영어 반환
138
+ return TRANSLATIONS["English"][key]
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ streamlit
2
+ openai
3
+ supabase
4
+ gradio