Spaces:
Sleeping
Sleeping
import os | |
import json | |
import copy | |
from datetime import datetime | |
import pandas as pd | |
import gradio as gr | |
from openai import OpenAI | |
from supabase import create_client | |
from language_info import * | |
# 시스템 프롬프트 정의 | |
FIRST_PROMPT = """ | |
너는 유저의 질문을 분석하는 AI야! 유저의 질문을 바탕으로 주어진 조건에 맞도록 질문을 분석해줘! | |
조건 1. 아래 Task 리스트 중 1개의 작업 선택! | |
Task : ["ReAsk", "FindProduct", "Recommandation", "Etc"] | |
조건 2. 만약, Task가 "FindProduct"라면, 원하는 "Product"를 "Option"으로 정의를 해줘! | |
조건 3. 만약, Task가 "Recommandation"라면, 유저의 조건을 "Condition"이라고 "Option"에 제공해줘! | |
조건 4. 만약, Task가 "ReAsk"라면, 유저의 질문에서 추가적으로 요구되는 조건을 "Condition"이라고 "Option"에 제공해줘! | |
** 조건 5. 화장품 관련 이야기를 제외한 다른 이야기는 답할 수 없다는 내용으로 답변을 해줘! ** | |
** 조건 6. 언어가 다르더라도 출력은 전부 "한국어"를 사용해서 출력해! 그리고 유저 입력에 대한 한국어 번역을 "Translation"으로 제공해!** | |
OUTPUT 포맷 | |
json | |
{ | |
"Task":"...", | |
"Option":{"...":"...", ..., key:val}, | |
"Translation":"..." | |
} | |
""" | |
# Supabase 로깅 함수 | |
def log_to_supabase(supabase, question, answer, history): | |
"""Supabase에 채팅 로그를 저장하는 함수""" | |
try: | |
timestamp = datetime.now().isoformat() | |
supabase.table("chat_log").insert({ | |
"question": question, | |
"answer": answer, | |
"history": json.dumps(history, ensure_ascii=False), | |
"timestamp": timestamp | |
}).execute() | |
return True | |
except Exception as e: | |
print(f"Error logging to Supabase: {e}") | |
return False | |
def local_RAG(model, message, client, vector_id): | |
"""로컬 검색 기반 생성 함수""" | |
try: | |
response = client.responses.create( | |
model=model, | |
input=message, | |
tools=[{ | |
"type": "file_search", | |
"vector_store_ids": [vector_id], | |
"max_num_results": 5 | |
}] | |
) | |
if len(response.output)==0: | |
return "" | |
if not response.output[1].content[0].annotations: | |
return "" | |
return response.output[1].content[0].text | |
except Exception as e: | |
print(f"Error in RAG: {e}") | |
return "" | |
def routing(messages, client, language): | |
"""사용자 질문 분석 및 라우팅 함수""" | |
try: | |
routing_messages = copy.deepcopy(messages) | |
routing_messages[0]['content'] = FIRST_PROMPT | |
response = client.chat.completions.create( | |
model="gpt-4o", | |
messages=routing_messages, | |
response_format={"type": "json_object"} | |
) | |
return json.loads(response.choices[0].message.content) | |
except Exception as e: | |
print(f"Error in routing: {e}") | |
return {"Task": "Etc"} | |
def generate_response(query_parsing, client, vector_id, user_message, chat_history, language): | |
"""쿼리 분석 결과에 따른 응답 생성 함수""" | |
# 메시지 형식으로 변환 | |
messages = [{"role": "system", "content": get_system_prompt(language)}] | |
for user_msg, bot_msg in chat_history: | |
if user_msg: | |
messages.append({"role": "user", "content": user_msg}) | |
if bot_msg: | |
messages.append({"role": "assistant", "content": bot_msg}) | |
if language!="한국어": | |
messages.append({"role": "user", "content": user_message}) | |
else: | |
messages.append({"role": "user", "content": query_parsing["Translation"]}) | |
# 쿼리 분석 결과가 없는 경우 | |
if "Task" not in query_parsing: | |
return get_text('error_understanding', language) | |
# ReAsk: 추가 정보 요청 | |
if query_parsing["Task"] == "ReAsk": | |
if "Option" in query_parsing and "Condition" in query_parsing["Option"]: | |
return f"{get_text('additional_info_needed', language)}{query_parsing['Option']['Condition']}" | |
else: | |
return get_text('request_more_info', language) | |
# FindProduct: 제품 검색 | |
if query_parsing["Task"] == "FindProduct": | |
if "Option" not in query_parsing: | |
return get_text('error_product_not_found', language) | |
product = query_parsing['Option']["Product"] | |
# 수파베이스에서 화장품 데이터 가져오기 | |
try: | |
product_list = supabase.table("cosmetics").select("*").execute().data | |
except: | |
# 실제 구현 시 데이터베이스 연결 필수 | |
product_list = [] # 임시 빈 리스트 | |
find_data = "" | |
for item in product_list: | |
if product in item["title"]: | |
find_data += f"item : {item['title']}\tbrand : {item['brand']}\tmake : {item['maker']}\tsummary : {item['summary']}\n\n" | |
if len(find_data) > 2: | |
# 데이터를 찾았을 때 | |
messages[-1]['content'] = messages[-1]['content'] + "\n\n<데이터>\n\n" + find_data + "\n\n</데이터>\n\n" + messages[-1]['content'] | |
response = client.chat.completions.create( | |
model="gpt-4o", | |
messages=messages | |
) | |
return response.choices[0].message.content | |
else: | |
# 데이터를 찾지 못했을 때 RAG 시도 | |
response = local_RAG("gpt-4o", user_message, client, vector_id) | |
if response == "": | |
# RAG도 실패했을 때 검색 모델 사용 | |
response = client.chat.completions.create( | |
model="gpt-4o-search-preview", | |
messages=messages | |
) | |
return response.choices[0].message.content | |
return response | |
# Recommendation: 제품 추천 | |
if query_parsing["Task"] == "Recommandation": | |
response = local_RAG("gpt-4o", user_message, client, vector_id) | |
if response == "": | |
# RAG 실패 시 검색 모델 사용 | |
response = client.chat.completions.create( | |
model="gpt-4o-search-preview", | |
messages=messages | |
) | |
return response.choices[0].message.content | |
return response | |
# Etc: 일반 응답 | |
response = client.chat.completions.create( | |
model="gpt-4o", | |
messages=messages | |
) | |
return response.choices[0].message.content | |
def get_system_prompt(language): | |
"""언어에 맞는 시스템 프롬프트 생성""" | |
return f""" | |
너는 한국의 화장품을 상담해 주는 AI야! | |
유저의 한국 화장품 관련 질문에 가장 적절한 답변을 해줘! | |
조건1 : 화장품과 관련되지 않은 질문은 대답하지 마. | |
조건2 : 주어진 language에 맞는 언어로 답변해줘! | |
조건3 : 유저가 별도의 데이터를 제공하면 (<데이터>...</데이터> 형식), 제공된 데이터 내에서만 답변해줘. | |
language: {language} | |
""" | |
# 현재 선택된 언어를 저장할 전역 변수 | |
selected_language = "English" | |
def chatbot(message, history, language_choice=None): | |
"""챗봇의 메인 함수""" | |
global selected_language | |
# language_choice가 제공되었으면 업데이트 | |
if language_choice is not None: | |
selected_language = language_choice | |
# OpenAI API 키 및 환경 변수 설정 | |
openai_api_key = os.getenv("OPENAI_API_KEY") | |
vector_id = os.getenv("vector_id") | |
# Supabase 설정 | |
supabase_url = os.getenv("SUPABASE_URL") | |
supabase_key = os.getenv("SUPABASE_KEY") | |
supabase = None | |
client = OpenAI(api_key=openai_api_key) | |
# Supabase 클라이언트 생성 (있을 경우) | |
if supabase_url and supabase_key: | |
supabase = create_client(supabase_url, supabase_key) | |
# 쿼리 분석 및 응답 생성 | |
query_parsing = routing([{"role": "system", "content": ""}, {"role": "user", "content": message}], client, selected_language) | |
response = generate_response(query_parsing, client, vector_id, message, history, selected_language) | |
# Supabase 로깅 (해당 환경변수가 있을 경우) | |
if supabase: | |
chat_history = [] | |
for user_msg, bot_msg in history: | |
if user_msg: | |
chat_history.append({"role": "user", "content": user_msg}) | |
if bot_msg: | |
chat_history.append({"role": "assistant", "content": bot_msg}) | |
chat_history.append({"role": "user", "content": message}) | |
chat_history.append({"role": "assistant", "content": response}) | |
log_to_supabase(supabase, message, response, chat_history) | |
return response | |
def change_language(language_choice): | |
"""언어 변경 함수""" | |
global selected_language | |
selected_language = language_choice | |
return language_choice | |
# 메인 함수 | |
def main(): | |
"""Gradio 인터페이스 설정 함수""" | |
# 언어 설정 | |
languages = ["English", "한국어", "Español", "中文", "日本語", "ภาษาไทย", "Tiếng Việt", "Bahasa Indonesia"] | |
global selected_language | |
selected_language = "English" | |
current_dir = os.path.dirname(os.path.abspath(__file__)) | |
image_path = os.path.join(current_dir, "image.png") | |
# Gradio 인터페이스 구성 | |
with gr.Blocks(css="footer {visibility: hidden}") as demo: | |
gr.Markdown(f"# {get_text('title', selected_language)}") | |
gr.Markdown(f"(Conversation logs are saved.)") | |
with gr.Row(): | |
language_dropdown = gr.Dropdown( | |
choices=languages, | |
value=selected_language, | |
label=get_text("language_selector", selected_language) | |
) | |
# 언어 상태를 저장할 state 객체 생성 | |
lang_state = gr.State(value=selected_language) | |
# 언어가 변경될 때 실행되는 함수 | |
def update_language(new_lang, history): | |
global selected_language | |
selected_language = new_lang | |
return new_lang, history | |
# 챗봇의 메시지 전송 함수를 수정하여 현재 언어 상태를 전달 | |
def handle_message(message, history, lang): | |
return chatbot(message, history, lang) | |
chatbot_interface = gr.ChatInterface( | |
fn=handle_message, | |
additional_inputs=[language_dropdown], | |
title="", | |
examples=[ | |
["이니스프리 그린티 제품 알려줘", "한국어"], | |
["แนะนำผลิตภัณฑ์ดูแลผิวที่ดีสำหรับผู้หญิง", "ภาษาไทย"], | |
["What products are effective for whitening?", "English"] | |
], | |
) | |
# 언어 변경 시 이벤트 | |
language_dropdown.change( | |
fn=update_language, | |
inputs=[language_dropdown, chatbot_interface.chatbot], | |
outputs=[lang_state, chatbot_interface.chatbot] | |
) | |
gr.Markdown(f"# Architecture") | |
gr.Image(value=image_path, show_label=False, height=400, width=400) | |
# Gradio 앱 실행 | |
demo.launch() | |
if __name__ == "__main__": | |
main() |