Streamlit에서 "가까운 대피소 검색" 버튼을 눌렀을 때, 응답이 바로 출력되지 않고 두 번 눌러야 정상 작동하는 현상이 발생
Streamlit의 상태 관리 문제:
버튼 클릭 이벤트(st.button)가 클릭 순간에만 True를 반환하고, 이후 상태가 초기화.
또한, UI 갱신이 제대로 이루어지지 않았다.
버튼 클릭 후 상태 업데이트와 클릭시 응답 생성이 연속적으로 처리되지 않았다.
해결 방법
# 세션 상태 초기화
if "button_clicked" not in st.session_state:
st.session_state.button_clicked = False
# 위치 기반 대피소 검색 버튼
if latitude and longitude:
if st.button("가까운 대피소 검색"):
# 명시적인 요청 메시지 추가
user_message = "현재 위치에서 가까운 대피소 정보를 알려줘."
st.session_state.messages.append({"role": "user", "content": user_message})
# 모델에 위치 정보 전달하여 응답 생성
response = get_response(user_input=user_message, user_location={"latitude": latitude, "longitude": longitude})
# 챗봇 응답 추가
st.session_state.messages.append({"role": "ai", "content": response["response"]})
# # 함수 호출 결과가 있으면 추가
# if "function_call" in response:
# function_result = response["function_call"]["result"]
# st.session_state.messages.append({"role": "function", "content": function_result})
# 버튼 클릭 상태 초기화
st.rerun() # 즉시 화면 재렌더링
수정
st.session_state
를 활용해 상태 관리:
버튼 클릭 여부를 상태로 저장하고, 클릭 시 동작을 명시적으로 처리.
st.rerun()
으로 즉시 화면 재렌더링:
버튼 클릭 후 새 상태를 반영한 UI를 즉각 업데이트.
결과
버튼을 한 번 클릭하면 즉시 "가까운 대피소" 정보를 기반으로 한 챗봇 응답이 출력됩니다.
두 번 클릭해야 하는 문제가 해결되었고, 버튼 클릭 후 UI가 매끄럽게 동작합니다.
대피소 검색 함수(find_nearest_shelters)가 실행되었지만, OpenAI API가 이 결과를 활용하지 않고 일반적인 메시지만 출력했습니다. 예를 들어:
입력:
"현재 위치에서 가장 가까운 대피소를 알려줘."
출력:
"대피소 정보를 확인 중입니다. 안전에 유의하세요."
이와 같은 응답만 나왔고, 실제 대피소 정보는 포함되지 않았습니다.
def get_response(user_input: str, user_location: dict = None):
"""
사용자 입력을 받아 모델 응답을 처리하고, 함수 호출이 필요한 경우
적절히 실행하여 최종 응답을 반환합니다.
"""
# 1. 사용자 입력 메시지 생성
user_message = chat_template.format_messages(user_input=user_input)
# 2. 위치 정보 추가
if user_location:
location_message = {
"role": "system",
"content": f"현재 사용자의 위도: {user_location['latitude']}, 경도: {user_location['longitude']}입니다."
}
user_message.append(location_message)
# 3. 이전 대화 기록 불러오기
messages = memory.load_memory_variables({})["history"] + user_message
# 4. 모델 호출로 응답 생성
response = model.invoke(messages)
# 5. 대화 기록 저장
memory.save_context({"input": user_input}, {"output": response.content})
# 6. 함수 호출 처리
function_call = response.additional_kwargs.get("function_call")
if function_call:
function_name = function_call.get("name")
function_args = function_call.get("arguments")
# 파라미터 처리
if isinstance(function_args, str):
function_args = json.loads(function_args)
# 위치 정보 병합
if user_location:
function_args['latitude'] = user_location.get("latitude")
function_args['longitude'] = user_location.get("longitude")
if function_name == "find_nearest_shelters":
# 6.1 대피소 검색 함수 실행
function_result = find_nearest_shelters(
latitude=function_args.get("latitude"),
longitude=function_args.get("longitude"),
address=function_args.get("address")
)
# 6.2 함수 결과를 모델 컨텍스트에 추가
function_message = {
"role": "function",
"name": function_name,
"content": function_result
}
messages.append(function_message)
# 6.3 최종 응답 생성
final_response = model.invoke(messages)
# 대화 기록에 최종 응답 저장
memory.save_context({"input": function_result}, {"output": final_response.content})
return {
"function_call": {
"name": function_name,
"arguments": function_args,
"result": function_result
},
"response": final_response.content
}
# 함수 호출이 없는 경우 일반 응답 반환
return {"response": response.content}
수정 포인트
함수 호출 결과를 모델 컨텍스트에 추가:
FunctionMessage
형태로 모델 대화 컨텍스트에 포함하여, 모델이 이를 바탕으로 최종 응답을 생성하도록 수정했습니다.
위치 정보 병합:
사용자 위치 정보를 find_nearest_shelters 호출 시 누락되지 않도록 병합.
최종 응답 생성:
함수 호출 결과를 모델 컨텍스트에 추가한 후, 이를 포함한 최종 응답을 모델에서 생성.
이러게 사용자 위치기반 정보를 streamlit
에서 받아오고 이를 get_response
함수에서 처리를 할 수 있도록 수정해서 해결했다.