과정/2차 AI프로젝트 서비스 개발

프로젝트 '재움' 개발과정(5)

줘요 2023. 11. 7. 20:51

 

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 할 때 화딱지가 나는지 알 거 같습니다..

 

얼마나 떠먹여 줘야 알아듣는 거니 ㅠㅠ