Skip to content

Commit

Permalink
Merge pull request #34 from kakaotech-bootcamp-11/develop
Browse files Browse the repository at this point in the history
feat: app.py 에서 db 히스토리 만들도록 구현 #29
  • Loading branch information
jieun-lim authored Sep 3, 2024
2 parents 7af4e02 + 71c3322 commit 3f63372
Showing 1 changed file with 46 additions and 22 deletions.
68 changes: 46 additions & 22 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
from error_handler import register_error_handlers
from openai import OpenAIError
from werkzeug.exceptions import BadRequest
#from conversation_history import save_conversation, history
from conversation_history import save_conversation, history
from konlpy.tag import Okt
from pymongo import MongoClient
from datetime import datetime
import pytz

# 플라스크 앱 정의
app = Flask(__name__)
Expand All @@ -29,6 +33,12 @@
)


# MongoDB 연결 설정
client = MongoClient('mongodb://localhost:27017/')
db = client['chatbot_db'] # 데이터베이스 이름 설정
collection = db['chat_history'] # 콜렉션 이름 설정


# API 키 로드하기
print("환경변수 로드 ")
load_dotenv() # # .env 파일에서 환경 변수를 로드합니다
Expand All @@ -40,7 +50,7 @@
# LLM 변수 정의
STREAM_TOKEN_SIZE = 30
MODEL_VERSION = "gpt-4o-mini" # "gpt-3.5-turbo"
MAX_TOKENS_OUTPUT = 500
MAX_TOKENS_OUTPUT = 250


# 검색할 문서 로드
Expand All @@ -59,16 +69,24 @@ def stream_message(text, max_tokens=STREAM_TOKEN_SIZE, delay=1): # 데이터가
yield f"data: {chunk}\n\n"


def stream_chatgpt(system_prompt, user_prompt):
# eunma: db 에서 데이터 조회해서,
def stream_chatgpt(system_prompt, user_prompt, user_id, chat_id):
print("stream_chatgpt()")
# 기존 N개 데이터 히스토리 가져오기
messages = [{"role": "system", "content": system_prompt + "\n 정보를 일반 텍스트로 작성해 주세요. 굵게 표시하지 말고, 특수 형식 없이 일반 텍스트로만 작성해 주세요."},
{"role": "user", "content": user_prompt} ]
if user_id is not None and chat_id is not None:
conv_history = history(user_id, chat_id, limit=2)
for conv in conv_history:
role = conv.get('role') # 'user' or 'system'
content = conv.get('text')
messages.append({"role": role, "content": content})

print('history:', messages)
client = openai.OpenAI(api_key=OPENAI_API_KEY)
try:
response = client.chat.completions.create(
model=MODEL_VERSION,
messages=[ # 여기에 히스토리 넣기
{"role": "system", "content": system_prompt + "\n 정보를 일반 텍스트로 작성해 주세요. 굵게 표시하지 말고, 특수 형식 없이 일반 텍스트로만 작성해 주세요."},
{"role": "user", "content": user_prompt}
],
messages= messages,
temperature=0.0, # 출력의 다양성 조절 (0~1), 높을 수록 창의적인 대답
max_tokens= MAX_TOKENS_OUTPUT, # 최대 출력 토큰 개수
n = 1, # 생성 답변 개수,
Expand All @@ -85,7 +103,7 @@ def event_stream(): #stream generator
yield f"data: {text}\n\n"
print("답변 결과:\n", result_txt)
# 답변 결과 DB 에 저장
#save_conversation("user123", "thread456", "user", result_txt)
save_conversation(user_id, chat_id, "system", result_txt)


return Response(event_stream(), mimetype='text/event-stream')
Expand Down Expand Up @@ -139,27 +157,27 @@ def extract_arrv_dest(user_input): #user input 에서 출발지와 도착지 출
"""
return text_chatgpt(system_prompt =system_prompt, user_prompt= user_input )

def handle_weather_topic(user_input):
def handle_weather_topic(user_input, user_id, chat_id):
weather_info = get_weather_info()
system_prompt = (f"You are a helpful assistant, and you will kindly answer questions about current weather. "
f"한국어로 대답해야해. 현재 날씨 정보는 다음과 같아. {weather_info}, "
"이 날씨 정보를 다 출력할 필요는 없고, 주어진 질문인 '{user_input}'에 필요한 답만 해줘 ")
result = stream_chatgpt(system_prompt, user_input)
result = stream_chatgpt(system_prompt, user_input, user_id, chat_id)
return result
"""if result is not None: return result # 비동기식 response 형식
else:
result = "죄송해요. 챗 지피티가 답변을 가져오지 못했어요."
return Response(stream_message(result), content_type='text/plain')"""

def handle_trans_topic(user_input):
def handle_trans_topic(user_input, user_id, chat_id):
dict_string = extract_arrv_dest(user_input)
from_to_dict = json.loads(dict_string)
result_txt = get_route_description(from_to_dict, TMAP_API_KEY, KAKAO_MAP_API_KEY)
system_prompt = f"너는 출발지에서 목적지까지 경로를 안내하는 역할이고, 한국어로 대답해야해."\
f"사용자는 경로에 대해 요약된 텍스트를 줄거야. 너는 그걸 자연스럽게 만들어주면 돼. "\
f"출발지는 ```{from_to_dict['from']}```이고 목적지는 ```{from_to_dict['to']}```임. "
user_prompt = f"다음을 자연스럽게 다시 말해줘:\n```{result_txt}``` "
return stream_chatgpt(user_prompt)
return stream_chatgpt(system_prompt, user_prompt, user_id, chat_id)
"""if dict_string:
from_to_dict = json.loads(dict_string)
result = get_route_description(from_to_dict, TMAP_API_KEY, KAKAO_MAP_API_KEY)
Expand All @@ -169,10 +187,10 @@ def handle_trans_topic(user_input):
return Response(stream_message(result), content_type='text/plain')"""

def handle_else_topic(user_input):
def handle_else_topic(user_input, user_id, chat_id):
system_prompt = ("You are a helpful assistant."
"사용자들은 한국어로 질문할 거고, 너도 한국어로 대답해야돼")
result = stream_chatgpt(system_prompt, user_input)
result = stream_chatgpt(system_prompt, user_input, user_id, chat_id)
return result
"""if result is not None:
return result # 비동기식 response 형식
Expand Down Expand Up @@ -205,15 +223,21 @@ def llm():
user_input, user_id, chat_id = params['content'], params['user_id'], params['chat_id']
print("user_input, user_id, chat_id:", user_input, user_id, chat_id)

save_conversation(user_id, chat_id, "user", user_input)
print("save_conversation")



# 동기식으로 RAG 기법 적용한 QA 체인 생성
response = retriever.invoke(user_input)
#print("response type:", type(response))
print('RAG response:', response)
#if response['result'] and not any(phrase in response['result'] for phrase in ["죄송", "모르겠습니다", "알 수 없습니다", "확인할 수 없습니다", "없습니다"]) : # 만약
if response and response != "해당 정보는 제공된 문서들에 포함되어 있지 않습니다.":
if response and "해당 정보는 제공된 문서들에 포함되어 있지 않습니다." not in response:
logging.info( f"RAG - user input: {user_input}")
print("response:", response)
# 답변 결과 DB 에 저장
#save_conversation("user123", "thread456", "user", response)
save_conversation(user_input, chat_id, "system", response)
print("logging: RAG 답변")
return Response(stream_message(response), mimetype='text/event-stream')
elif not response: # # RAG를 수행하지 못했을 때 - 예외 처리 추가하기
Expand All @@ -225,11 +249,11 @@ def llm():
topic = topic_classification(user_input)
print("topic:", topic)
if topic == "WEATHER":
return handle_weather_topic(user_input)
return handle_weather_topic(user_input,user_id, chat_id)
elif topic == "TRANS":
return handle_trans_topic(user_input)
return handle_trans_topic(user_input, user_id, chat_id)
elif topic == "ELSE":
return handle_else_topic(user_input)
return handle_else_topic(user_input, user_id, chat_id)
"""else:
logging.error("chat gpt failed to classify: result is None")
return jsonify({"error": "Topic classification failed"}), 500"""
Expand All @@ -250,11 +274,11 @@ def test(): # whole text 만든 다음, 청크 단위로 나눠 스트림 형식
def stream_output(): # chatGPT API 에서 실시간으로 청크 단위로 답변을 받아옴.
#user_input, user_id, chat_id = get_request_data() # 공통
params = get_request_data(title=True) # request body 를 가져옴
user_input = params['content']
user_input, user_id, chat_id = params['content'], params['user_id'], params['chat_id']

# 답변 가져오기
system_prompt = "You are a helpful assistant"
result = stream_chatgpt(system_prompt, user_input) #
result = stream_chatgpt(system_prompt, user_input, user_id, chat_id) #
return result

# test function for error handling
Expand Down

0 comments on commit 3f63372

Please sign in to comment.