elder_menu.html에서 음성인식 버튼을 누르면 각각 음성만으로 "메뉴 재추천", "결제하기"로 넘어가는 것은 이미 구현이 끝났다. 문제는 "장바구니"기능과 관련해서 발생했었는데, 이를 해결하기 위해 장바구니 기능에 대해서 Redis를 적용하기로 한 것이었다.
장바구니 기능을 Redis로 저장하고 관리하게끔 세팅했으니, 이제 다시 본궤도로 돌아와서 음성인식으로 "장바구니"기능을 사용할 수 있도록 해볼 차례다.
애초에 장바구니 기능과 관련해서 Redis가 필요하겠다 생각하게 되었던 배경은 다음과 같다.
- cart_ai()를 테스트하다 보니 전반적으로는 response의 결과값이 생각보다 정확했는데, delete action에 있어서는 확실히 정확도가 떨어지는 이슈가 있었음_ ex. "아메리카노 1잔으로 줄여줘", "아메리카노 1잔만 줄여줘"의 구분
- delete에 대한 response의 정확도를 높이기 위해서는 "현재 장바구니 상태"를 gpt에게 매개변수로 넘겨줘야 한다고 판단함
- 당시 상황은 js내의 로직으로만 장바구니가 구현된 상태였으므로, 장바구니 기능에만 한정해서 Redis를 사용하기로 함 (DB에 저장하는 방식을 선택하지 않은 이유는 앞선 포스팅에서 설명한 바 있음)
따라서 이제는 Redis에 저장된 "현재 장바구니 상태"정보를 cart_ai()에서 사용할 수 있도록 해당 코드를 수정해줄 차례다.
html에서 "음성인식 재시작"버튼을 누르는 것부터 진행되어야 할 흐름을 정리해보면 다음과 같다.
- "음성인식 재시작" 버튼을 클릭하고, 장바구니 메뉴에 대한 추가, 수정, 삭제 요청(=inputText)을 음성으로 한다
- request_type()를 실행하고, 결과로 types가 "cart"로 반환한다 (인자로 받은 recommended_menu도 반환함)
- cart_ai()를 실행하고, 결과로 "calculate", "menu", "recommended_menu"를 반환한다
- cart_ai()의 반환값을 사용해서, current_cart_get의 "name"과 "quantity"를 update해준다
- update해준 장바구니 현황을 다시 Redis에 저장해준다 (-> Redis에는 항상 최신의 장바구니 상황만이 담기며, 전체적인 value값을 update마다 hset해주는 것으로 로직을 구성함 = Cart객체를 만들고 add_to_cart() 호출)
- html상에서 해당 장바구니 update내용이 반영되도록 axios get요청으로 Redis에서 저장정보를 받아오고, 이를 response로 돌려줌 (선: get_cart(), 후: view_cart())
- updateCartDisplay()를 통해 받아온 장바구니 정보를 html상에 반영해줌
이 과정에서 6+7 과정이 removeItem()시에도 이미 똑같이 쓰인 바가 있고, 다른 api들에서도 자주 사용될 것아서 해당 과정들을 묶어서 별도로 "refreshCart()"라는 함수를 만들어줬다.
즉, updateCartDisplay()는 "currentTotal"을 포함해서, html상의 row를 붙여주는 역할을 하므로, elder_menu.html이 로드되거나 새로고침될 때 사용된다. 반면에 refreshCart()는 장바구니 상태를 저장하는 Redis의 상태가 변경될 때마다 이를 즉각적으로 "새로고침 없이" 반영될 수 있도록 axios get요청을 포함하는 함수이다.
그리고 수많은 print문과 console.log를 찍어가며 코드를 작성하고, 들어오는 data형식들을 확인한 끝에 음성인식으로 장바구니를 udpate하는 기능을 구현하는 것에 성공했다..ㅎㅎ!!
사실 위의 과정에서 가장 까다로웠던 것은 cart_ai()의 프롬프트를 적절하게 수정해서 우리가 원하는 형태로 답변을 받아오는 동시에 대답의 정확도를 올리는 것이었다.
프롬프트에 적어준다고 하여 항상 그에 맞는 gpt의 response가 반환되는 것이 아니므로, 어떻게 하면 3번 날 오류를 1번 정도까지 줄일 수 있을지에 대한 다양한 시도가 있었다.
원래 처음 cart_ai()를 작성할 때는 response로 "mene", "quantity", "action"의 세 가지 항목을 받아오도록 했었다.
하지만 아무리 action을 "add"와 "delete"로만 프롬프트에 지정해줘도 inputText의 표현에 "action"항목의 response가 너무 많은 영향을 받아 정확도가 떨어지는 문제가 심각했다..
그래서 다음에 시도한 방식은 response를 "calculate", "menu" 두 가지로 수정하는 것이었다.
특히, calculate는 add나 delete를 포함하지 않고, +와 -의 기호를 포함해서 response를 반환하도록 프롬프트를 작성했다.
이렇게 수정하자 action이 inputText에 지대한 영향을 받던 것은 수정되고, 이전보다는 정확도가 개선되었다.
하지만 그럼에도 "~로 바꿔줘"와 같은 inputText(=음성인식)에 대해서는 +와 -와 뒤에 붙는 quantity까지 정확하지는 못함을 발견했다. (부호와 quantity는 공백으로 split해서 사용했다_프롬프트 자체에 둘 사이에 공백을 넣어서 결과값을 반환해달라고 직접적으로 글로 적는 것보다 -> 프롬프트에 제시해준 예시에서 부호와 quantity사이에 공백이 있도록 작성하는 것이 더 잘 반영됨)
와중에 cart_ai()에 매개변수로 전해주고 있는 current_cart_get의 type을 print문으로 찍어봤다가 해당 데이터가 객체(obj)로 넘어가고 있음을 발견했다. 그래서 gpt가 해당 장바구니 상황을 정확히 반영하지 못한 것인가 해서 이를 str형식으로 바꿔서 전달하는 동시에 프롬프트를 수정해서 해당 current_cart_get을 고려해서 calculate항목에 대해서 나름의 결과값을 반환하도록 했다.
다시 말해 이전에는 현재 장바구니에 아이스 아메리카노가 1잔 담겨있는 상태에서 "아이스 아메리카노 3잔으로 늘려줘"에 대한 response에서 calculate의 값으로 "+ 2"을 기대했다면, 이제 수정된 프롬프트에서는 calculate값으로 "3"을 기대하는 것이다.
이렇게 calculate에 대한 반환값을 action(=+,-)와 quantity로 구분해서 지시하는 것보다 gpt에 판단을 일임하는 것이 오히려 정확도가 높았다. 물론 gpt에 대한 의존도가 더 높아진다는 문제점이 있기는 하나, 정확도 면에서 보자면 확실히 좋은 선택이었다.
실제로 "아이스 아메리카노를 3잔으로 늘려줘"나 "아이스 아메리카노를 3잔 줄여줘"에 대한 calculate값이 각기 다르게 잘 구분되어서 반환되는 것을 여러 번의 test로 확인할 수 있었다.
'TIL' 카테고리의 다른 글
[TIL 2024. 06. 12] 배포 후 오류 수정 (0) | 2024.06.12 |
---|---|
[TIL 2024. 06. 07] elder관련 오류 수정 (1) | 2024.06.10 |
[TIL 2024. 06. 04] axios post | updateCartDisplay() 오류 (0) | 2024.06.05 |
[TIL 2024. 06. 03] Redis로 장바구니 update (0) | 2024.06.04 |
[TIL 2024. 05. 31] 장바구니 기능: Redis (0) | 2024.06.03 |