Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:[BE] agentPersona featuring #48

Merged
merged 15 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 0 additions & 6 deletions .idea/modules/server.iml

This file was deleted.

223 changes: 208 additions & 15 deletions agentPersona/app3.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,223 @@
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.llms import OpenAI
from flask import Flask, request, jsonify, session, Response
from flask_cors import CORS
import json

import os
from dotenv import load_dotenv

from template import greeting_template, plan_template, modify_template, final_template
from openAi import call_openai_gpt

from datetime import timedelta

# env 변수 불러오기
load_dotenv()
openai_api_key = os.getenv("OPENAI_API_KEY")
secret_key = os.getenv("SECRET_KEY")
# env 변수 확인
print("Loaded SECRET_KEY:", secret_key) # SECRET_KEY 출력
pinecone_api_key = os.getenv("PINECONE_API_KEY")

# Flask 앱 설정
app = Flask(__name__)
CORS(app)
app.secret_key = secret_key

# 프롬프트 템플릿
# 여행 에이전트 페르소나 role template
role_template = PromptTemplate(
input_variables=["user_input"],
template=(
"너의 이름은 탐탐이, 영어로 tamtam 이야."
"너는 제주도 여행 계획을 추천하는 여행 에이전트야."
"너는 사용자와의 대화를 통해 수집한 정보들을 기반으로 여행 계획을 추천하는 역할을 해."
"사용자는 너에게 여행 기간, 여행 날짜, 여행 테마(컨셉), 여행을 함께하는 인원 정보를 제공할거야."
"이를 토대로 제주도 여행 계획을 추천해주는 역할을 해."
)
app.permanent_session_lifetime = timedelta(hours=1) # 세션 지속 시간 1시간
@app.before_request
def make_session_permanent():
session.permanent = True
app.config.update(
SESSION_COOKIE_SECURE=False, # HTTPS가 아닌 환경에서도 쿠키 허용
SESSION_COOKIE_HTTPONLY=True, # 클라이언트 측 스크립트에서 쿠키 접근 불가
SESSION_COOKIE_SAMESITE='Lax' # 크로스 사이트 요청 제한 (Strict, Lax, None 중 선택)
)

# OpenAI API 설정
llm = OpenAI(api_key=openai_api_key, max_tokens=3000)

# 체인 생성
greeting_chain = LLMChain(llm=llm, prompt=greeting_template)
plan_chain = LLMChain(llm=llm, prompt=plan_template)
modify_chain = LLMChain(llm=llm, prompt=modify_template)
final_chain = LLMChain(llm=llm, prompt=final_template)


@app.route("/greeting", methods=["POST"])
def greeting():
'''에이전트가 인사말을 건넴'''
data = request.json
front_input = data.get("front_input")

generate_response = greeting_chain.run(
front_input=front_input
)

print(f"LangChain Output: {generate_response}") # LangChain 응답 파이썬에서 출력(한글 깨지는지 확인)
# return jsonify({"generate_response": generate_response})
generate_response_data = {"generate_response": generate_response}

return Response(
json.dumps(generate_response_data, ensure_ascii=False), # ensure_ascii=False로 설정(한글 안깨지게 하기 위해)
content_type="application/json; charset=utf-8"
)

@app.route("/plan", methods=["POST"])
def plan():
'''사용자 입력을 받아 여행 계획을 생성'''
data = request.json
travel_date = data.get("travel_date")
travel_days = data.get("travel_days")
travel_mate = data.get("travel_mate")
travel_theme = data.get("travel_theme")

final_prompt = plan_template.format(
travel_date=travel_date,
travel_days=travel_days,
travel_mate=travel_mate,
travel_theme=travel_theme
)
print(f"Generated Prompt:\n{final_prompt}")

plan_response = plan_chain.run(
travel_date=travel_date,
travel_days=travel_days,
travel_mate=travel_mate,
travel_theme=travel_theme
)
session["current_plan"] = plan_response
print(f"DEBUG: Saved to session: {session.get('current_plan')}")

follow_up_message = "여행 계획이 생성되었습니다. 수정하고 싶은 부분이 있으면 말씀해주세요! 😊"

# return jsonify({"response": plan_response, "follow_up": follow_up_message})

plan_response_data = {"response": plan_response, "follow_up": follow_up_message}
return Response(
json.dumps(plan_response_data, ensure_ascii=False),
content_type="application/json; charset=utf-8"
)

@app.route("/modify", methods=["POST"])
def modify():
'''사용자 입력을 받아 여행 계획을 수정'''
data = request.json
modification_request = data.get("modify_request")
current_plan = session.get("current_plan")

# 수정 요청과 현재 계획 데이터 있는지 확인
if not modification_request:
return jsonify({"error": "Missing 'modify_request' in the request data"}), 401

if not current_plan:
return jsonify({"error": "No current plan found in the session"}), 403

# 사용자 의도 판단 프롬프트
intent_prompt = f"""
사용자가 다음과 같은 요청을 보냈습니다: "{modification_request}".
이 요청이 여행 계획 수정을 끝내겠다는 의도인지 판단해 주세요.
응답은 "수정 종료", "수정 계속" 중 하나로만 작성해주세요.
"""
# 사용자 의도 판단
intent = call_openai_gpt([
{"role": "system", "content": "You analyze user modification intent."},
{"role": "user", "content": intent_prompt}
])

# 수정 종료 하기
if intent == "수정 종료":
return jsonify({"response": "여행 계획에 만족하셨다니 다행입니다! 계획을 확정합니다. 😊"})

# 수정 작업 하기
modification_response = modify_chain.run(
current_plan=current_plan,
modification_request=modification_request
)
session["current_plan"] = modification_response

follow_up_message = "수정이 완료되었습니다. 추가 수정이 필요하면 말씀해주세요! 😊"

# return jsonify({"response": modification_response, "follow_up": follow_up_message})

modify_response_data = {
"response": modification_response,
"follow_up": follow_up_message
}
return Response(
json.dumps(modify_response_data, ensure_ascii=False),
content_type="application/json; charset=utf-8"
)

@app.route("/modify2", methods=["POST"])
def modify2():
'''사용자 입력을 받아 여행 계획을 수정'''
data = request.json
current_plan = data.get("current_plan")
modify_request = data.get("modify_request")

'''방식 1'''
response = modify_chain.run(
current_plan=current_plan,
modify_request=modify_request
)
# '''방식 2''' 디테일 수정을 원할 때 갈구기
# modify_prompt = modify_template.format(
# current_plan=current_plan,
# modify_request=modify_request
# )

# response = openai.ChatCompletion.create(
# model="gpt-4",
# messages=[{"role": "user", "content": modify_prompt}]
# )
# return jsonify({"modified_itinerary": response["choices"][0]["message"]["content"].strip()})
return jsonify({"response": response})

@app.route("/final", methods=["POST"])
def final():
'''여행 계획을 최종 확정'''
data = request.json
user_input = data.get("user_input")
final_plan = session.get("current_plan")

final_response = final_chain.run(user_input=user_input)
session.clear()

return jsonify({"response": final_response, "final_plan": final_plan})

# 세션 데이터 디버깅(세션 데이터 확인용)
@app.route("/debug_session", methods=["GET"])
def debug_session():
"""현재 세션 데이터 디버깅"""
print("Current Session Data:", dict(session))
return jsonify({"session_data": dict(session)})


# GPT 호출
user_input = "여행 계획을 도와주세요"
@app.route("/set_session", methods=["POST"])
def set_session():
# 요청 데이터에서 세션에 저장할 값 가져오기
data = request.json
session["test_key"] = data.get("value", "default_value") # 세션에 저장
session.permanent = True # 세션 지속 설정
print("DEBUG: Session after setting:", dict(session)) # 세션 데이터 출력
return jsonify({"message": "Session set", "session_data": dict(session)})


@app.route("/get_session", methods=["GET"])
def get_session():
data = session.get('current_plan')
print(data)
print("DEBUG: Current session:", dict(session)) # 현재 세션 데이터 출력
return jsonify({"session_data": dict(session)})

@app.route("/clear_session", methods=["GET"])
def clear_session():
"""세션 데이터를 완전히 삭제"""
session.clear() # 세션 데이터 삭제
print("DEBUG: Session cleared.")
return jsonify({"message": "Session cleared successfully"})

# 단계별 질문 흐름 기능
if __name__ == "__main__":
app.run(port=5000, debug=True)
15 changes: 15 additions & 0 deletions agentPersona/openAi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from openai import OpenAI
import os
from dotenv import load_dotenv

load_dotenv()
openai_api_key = os.getenv("OPENAI_API_KEY")

client = OpenAI(api_key=openai_api_key)

def call_openai_gpt(messages):
response = client.chat.completions.create(
model="gpt-4",
messages=messages
)
return response.choices[0].message.content.strip()
59 changes: 59 additions & 0 deletions agentPersona/template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from langchain.prompts import PromptTemplate

#1 프롬프트 템플릿( sequence 로 만들었음 )
#1) 여행 에이전트 페르소나 role template
role_description = PromptTemplate(
template=(
"너의 이름은 탐탐이, 영어로 tamtam 이야."
"너는 제주도 여행 계획을 추천하는 여행 에이전트야."
"너는 사용자와의 대화를 통해 수집한 정보들을 기반으로 여행 계획을 추천하는 역할을 해."
"사용자는 너에게 여행 기간, 여행 날짜, 여행 테마(컨셉), 여행을 함께하는 인원 정보를 제공할거야."
"이를 토대로 제주도 여행 계획을 추천해주는 역할을 해."
)
)
role_description_text = role_description.format()

#2) 인사말 template
greeting_template = PromptTemplate(
input_variables=["front_input"],
template=(
f"{role_description_text}\n\n"
"{front_input} 은 그냥 무시해도 돼"
"사용자에게 인사하며 여행 계획을 도와주겠다는 메세지를 전달해."
"제주도 여행계획을 짜주는 거니 귤 이모티콘과 함께 인사해"
)
)

#3) 여행 계획 템플릿 - 여행 계획 추천 틀을 조정
plan_template = PromptTemplate(
input_variables=["travel_date", "travel_days", "travel_mate", "travel_theme"],
template=(
f"{role_description_text}\n\n"
"여행 정보: 여행날짜: {travel_date}, 여행기간: {travel_days}, "
"여행동반자: {travel_mate}, 여행테마: {travel_theme}."
"이 정보를 기반으로 제주도 여행 일정을 작성해줘. 각 날짜별 추천 활동을 포함해야 해."
"여행 계획을 추천하고, 추천한 계획에서 수정하고 싶은 부분이 있으면 말해달라고 사용자에게 말해."
)
)

#4) 여행 계획 수정 템플릿
modify_template = PromptTemplate(
input_variables=["current_plan", "modify_request"],
template=(
f"{role_description_text}\n\n"
"현재 여행 계획: {current_plan}.\n\n"
"사용자가 요청한 변경사항: {modify_request}.\n"
"이 정보를 기반으로 여행 계획을 수정해주고, 수정된 계획을 사용자에게 제시해."
"기존의 여행 계획틀은 그대로 유지하되, 사용자가 요청한 변경사항을 반영해야 해."
)
)

final_template = PromptTemplate(
input_variables=["user_input"],
template=(
f"{role_description_text}\n\n"
"사용자에게 최종 여행 계획을 보여주고, 즐거운 여행이 되길 바라는 말을 해."
"그리고 지금까지 OOO님의 행복한 제주도 여행을 위해 함께한 탐탐이라는 말을 하면서 마쳐."
"오른쪽의 상세 일정 보기 버튼을 누르면 상세한 일정을 확인할 수 있다고 말을 해."
)
)
2 changes: 2 additions & 0 deletions frontend/src/components/Calendar.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
background-color: #FDE56B;
color:black;
}


.react-calendar__tile--active:enabled:hover,
.react-calendar__tile--active:enabled:focus {
background: #FDE56B;
Expand Down
10 changes: 7 additions & 3 deletions frontend/src/pages/KakaoLoginPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ function KakaoLoginPage() {
const Rest_api_key='19bd1cef6d04beb937c1f7a84130fc11' //REST API KEY
const redirect_uri = 'http://localhost:3000/kakaoauth' //Redirect URI
// oauth 요청 URL
const url = 'http://localhost:8080/login/oauth2/code/kakao'
const kakaoURL = `https://kauth.kakao.com/oauth/authorize?client_id=${Rest_api_key}&redirect_uri=${redirect_uri}&response_type=code`
const kakaoLogin = ()=>{
window.location.href = kakaoURL
}

const onClick =() =>{
window.location.href = url
}
return(
<div className = {styles.background}>
<div className = {styles.title}>
Expand All @@ -22,10 +25,11 @@ function KakaoLoginPage() {
<div className = {styles.screen}>
<span className = {styles.description}> 간편하게 로그인하고 <br/>다양한 서비스를 이용해보세요</span>
<span className={styles.kakaoLoginButton}
onClick={kakaoLogin}
onClick={onClick}
>
<img src = {kakaoIcon} alt="kakaoIcon" className = {styles.kakaoIcon}></img>
<span className = {styles.kakaoText}>
<span className = {styles.kakaoText}
>
카카오 로그인
</span>
</span>
Expand Down
Loading