프로젝트 '재움' 개발과정(5)
chatGPT api를 이용하여 GPT에게 정보를 주고 수면 피드백을 받아보겠습니다!
먼저 open api key를 이용해 사용하여야 하는데요 gpt 3.5 turbo를 사용하였습니다.
서버에서 전달받은 데이터를 토대로(chatGPT를 이용할 때 직접 쓰는 질문이랑 같습니다.)
답변을 해줄겁니다.
gpt에게 어떤 데이터를 넘겨줄 것인지 정하겠습니다.
start_sleep : 수면 시작 시간
total_sleep : 총 수면 시간
sleep_event : 수면 자세
bad_position_time : 바르지 않은 수면 자세 시간
을 넘겨주도록 하겠습니다.
촬영 종료 버튼을 누르면 바로 피드백을 받을 것이기 때문에 버튼을 눌렀을 때 gpt에게 질문을 던져줘야 합니다.
아래 엔드포인트를 통해 닉네임과 수면정보아이디를 넘겨줍니다.
const sleepInfoId = document.getElementById("sleep_info_id").value;
const requestData = {
nickname: nickname,
sleep_info_id: sleepInfoId,
};
return fetch("/record/info_and_event", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(requestData),
});
보내준 정보와 받을 정보를 schemas.py에 작성합니다.
# Pydantic 모델을 사용하여 요청의 body에서 데이터를 추출
class RequestData(BaseModel):
nickname: str
sleep_info_id: int
class SleepInfoGet(BaseModel):
total_sleep: str
start_sleep: str
end_sleep: str
sleep_event: List[str] = []
event_time: List[str] = []
닉네임과 수면정보아이디를 통해 수면정보 테이블과 수면이벤트 테이블의 정보를 join 해서 얻을 겁니다.
def get_sleep_info_with_events_by_nickname_and_id(db: Session, nickname: str, sleep_info_id: int):
return db.query(model.SleepInfo.total_sleep, model.SleepInfo.start_sleep,model.SleepInfo.end_sleep, model.SleepEvent.sleep_event, model.SleepEvent.event_time).\
join(model.SleepEvent).\
filter(model.SleepInfo.nickname == nickname).\
filter(model.SleepInfo.sleep_info_id == sleep_info_id).\
filter(model.SleepEvent.sleep_info_id == model.SleepInfo.sleep_info_id).\
all()
이제 api_record에서 gpt에게 join 해서 얻은 데이터를 넘겨주고 맨 처음 작성한 generate_sleep_feedback 함수를 통해
피드백을 받고 클라이언트에게 보여줍니다.
# 수면 피드백
@router.post("/record/info_and_event")
async def get_info_and_events(request_data: RequestData, db: Session = Depends(get_db) ):
db_info_event_data = get_sleep_info_with_events_by_nickname_and_id(
db, request_data.nickname, request_data.sleep_info_id
)
results = SleepInfoGet(total_sleep='', start_sleep='',end_sleep='', sleep_event=[], event_time=[])
sleep_events = []
event_times = []
for info in db_info_event_data:
results.total_sleep = info.total_sleep
results.start_sleep = info.start_sleep
results.end_sleep = info.end_sleep
sleep_events.append(info.sleep_event)
event_times.append(info.event_time)
results.sleep_event = sleep_events
results.event_time = event_times
bad_position_time = calculate_bad_sleep_without_event(sleep_events, event_times, results.end_sleep, "front standard")
# results 데이터를 JSON 형식으로 변환
results_json = {
"total_sleep": results.total_sleep,
"start_sleep": results.start_sleep,
"sleep_event": results.sleep_event,
"bad_position_time": bad_position_time
}
json_data = json.dumps(results_json)
print("gpt한테 보내주는 값: ", type(json_data))
# generate_sleep_feedback 함수에 results_text를 전달하여 GPT-3.5 모델에 데이터를 제공
response = generate_sleep_feedback(json_data)
# 응답 받은 내용 출력 형식 변경
feedback = response["choices"][0]["message"]["content"].replace("\n", "<br>").replace("{", "").replace("}", "").replace("\"","").replace(",","")
return feedback
피드백 생성 시까지 시간이 3초 정도 걸리기 때문에 생성 중이라는 로딩을 보여주고 피드백을 보여주겠습니다.
record.css
.feedbackcontainer {
display: flex;
align-items: center; /* 요소들을 세로 가운데 정렬 */
justify-content: center;
}
.loader {
display: none;
border: 4px solid rgb(250, 248, 248);
border-top: 4px solid #3498db;
border-radius: 50%;
width: 30px;
height: 30px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
#feedback {
font-family: "Cafe24Oneprettynight";
text-align: center;
color: white;
margin-right: 10px; /* 로더와 간격을 주기 위한 마진 설정 */
margin-top: 15px;
}
record.html
<div class="feedbackcontainer">
<p id="feedback"></p>
<div class="loader"></div>
</div>
record.js 종료버튼 눌렀을 때 첫 부분에 보여줄 메시지를 작성해 줍니다.
const feedbackElement = document.getElementById("feedback");
const loaderElement = document.querySelector(".loader");
feedbackElement.innerHTML = "오늘의 피드백을 생성중입니다.";
loaderElement.style.display = "block";
이어서 피드백을 받게 되면 있던 메시지와 로딩은 사라집니다.
.then((secondResponse) => {
if (secondResponse.ok) {
return secondResponse.json();
} else {
throw new Error("두 번째 요청에 문제가 있습니다.");
}
})
.then((secondData) => {
console.log("두 번째 요청으로 받은 데이터:", secondData);
// 받은 데이터를 처리하거나 표시
console.log("두 번째 요청으로 받은 닉네임:", nickname);
const feedback = secondData;
feedbackElement.innerHTML = feedback;
loaderElement.style.display = "none";
const feedbackData = {
nickname: nickname,
sleep_feedback: secondData,
};
아래는 실제 사용 예시입니다
피드백을 받았으니 바로 수면 정보 테이블을 업데이트시켜주겠습니다.
아래 엔드포인트를 통해 수면정보 테이블에 피드백을 추가할 예정입니다.
return fetch(`/feedback/${nickname}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(feedbackData),
});
})
.then((thirdResponse) => {
if (thirdResponse.ok) {
return thirdResponse.json();
} else {
throw new Error("세 번째 요청에 문제가 있습니다.");
}
})
.then((thirdData) => {
console.log("세 번째 요청으로 받은 데이터:", thirdData);
// Handle the data received from the third request
})
.catch((error) => {
console.error("요청에 문제가 있습니다:", error);
});
schemas.py
class SleepInfoFeedback(BaseModel):
sleep_feedback: str
crud.py
def update_info_feedbeck(db: Session, nickname: str, sleep_feedback: str):
# 가장 마지막 sleep_info_id 가져오기
latest_sleep_info_id = db.query(func.max(model.SleepInfo.sleep_info_id)).filter(model.SleepInfo.nickname == nickname).scalar()
if latest_sleep_info_id is not None:
# 해당 sleep_info_id를 사용하여 업데이트
db_sleep_info = db.query(model.SleepInfo).filter(model.SleepInfo.sleep_info_id == latest_sleep_info_id).first()
if db_sleep_info:
db_sleep_info.sleep_feedback = sleep_feedback
db.commit()
db.refresh(db_sleep_info)
return db_sleep_info
api_record.py
# 수면 피드백 업데이트
@router.put("/feedback/{nickname}")
def update_sleep_info_feedback(nickname: str, sleep_info_feedback: SleepInfoFeedback, db: Session = Depends(get_db)):
update_sleep_feedback = update_info_feedbeck(db, nickname, sleep_info_feedback.sleep_feedback)
return update_sleep_feedback
수면 이벤트 테이블에 추가되는 예시입니다.
prompt가 아직 원하는 대답을 계속 주지 않기 때문에 계속 손보는 중입니다..
사람들이 왜 prompt 할 때 화딱지가 나는지 알 거 같습니다..
얼마나 떠먹여 줘야 알아듣는 거니 ㅠㅠ