diff --git a/backend-ai/app/clients/llm_client.py b/backend-ai/app/clients/llm_client.py index 59cdccc..d8b0603 100644 --- a/backend-ai/app/clients/llm_client.py +++ b/backend-ai/app/clients/llm_client.py @@ -224,10 +224,8 @@ def generate_answer(self, state: AgentState) -> str: ) else: live = self._generate_live_property_search_answer(state) - if live: - parts.append(live) - else: - parts.append(f"조건에 맞는 매물 {count}개를 찾았습니다.") + base = live if live else f"조건에 맞는 매물 {count}개를 찾았습니다." + parts.append(base + "\n아래 매물 중 하나를 선택하면 시세·안전 분석을 해 드릴게요.") if parts: return "\n\n".join(parts) @@ -371,7 +369,6 @@ def _generate_live_property_search_answer(self, state: AgentState) -> str | None except (httpx.HTTPError, KeyError, TypeError, ValueError): return None - def _generate_live_analysis_answer(self, state: AgentState) -> str | None: analysis_cards = state.get("analysis_cards", []) tool_results = state.get("tool_results", {}) diff --git a/backend-ai/app/graph/nodes/price_analysis.py b/backend-ai/app/graph/nodes/price_analysis.py index e0a316f..077232c 100644 --- a/backend-ai/app/graph/nodes/price_analysis.py +++ b/backend-ai/app/graph/nodes/price_analysis.py @@ -16,6 +16,7 @@ def price_analysis(state: AgentState) -> AgentState: if result.get("requiresSelection"): result = _regional_price_analysis(state["message"]) + updated_tool_results = { **state.get("tool_results", {}), "priceAnalysis": result, diff --git a/backend-ai/app/graph/nodes/safety_analysis.py b/backend-ai/app/graph/nodes/safety_analysis.py index cea7b5d..1d3e4fe 100644 --- a/backend-ai/app/graph/nodes/safety_analysis.py +++ b/backend-ai/app/graph/nodes/safety_analysis.py @@ -8,6 +8,18 @@ def safety_analysis(state: AgentState) -> AgentState: message=state["message"], context=state.get("context", {}), ) + + updated_tool_results = { + **state.get("tool_results", {}), + "safetyAnalysis": result, + } + + if result.get("requiresSelection"): + return { + **state, + "tool_results": updated_tool_results, + } + metrics = { "selectedPropertyId": result.get("selectedPropertyId"), "stub": result.get("stub", False), @@ -26,8 +38,5 @@ def safety_analysis(state: AgentState) -> AgentState: return { **state, "analysis_cards": [*state.get("analysis_cards", []), analysis_card], - "tool_results": { - **state.get("tool_results", {}), - "safetyAnalysis": result, - }, + "tool_results": updated_tool_results, } diff --git a/backend/src/main/java/com/ssafy/salmanhae/model/dto/chat/ChatResponse.java b/backend/src/main/java/com/ssafy/salmanhae/model/dto/chat/ChatResponse.java index b4ab43d..f312bc6 100644 --- a/backend/src/main/java/com/ssafy/salmanhae/model/dto/chat/ChatResponse.java +++ b/backend/src/main/java/com/ssafy/salmanhae/model/dto/chat/ChatResponse.java @@ -1,5 +1,6 @@ package com.ssafy.salmanhae.model.dto.chat; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -13,7 +14,7 @@ public record ChatResponse( ) { public ChatResponse { properties = properties == null ? List.of() : properties.stream() - .map(Map::copyOf) + .>map(HashMap::new) .toList(); legalCards = legalCards == null ? List.of() : List.copyOf(legalCards); analysisCards = analysisCards == null ? List.of() : List.copyOf(analysisCards); diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index aa44f3d..64d635d 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -7,6 +7,9 @@ spring.datasource.url=${SUPABASE_DB_URL} spring.datasource.username=${SUPABASE_DB_USERNAME} spring.datasource.password=${SUPABASE_DB_PASSWORD} +# HikariCP - disable server-side prepared statements to prevent "prepared statement already exists" errors on connection reuse +spring.datasource.hikari.data-source-properties.prepareThreshold=0 + # MyBatis mybatis.mapper-locations=classpath:mappers/**/*.xml mybatis.type-aliases-package=com.ssafy.salmanhae.model.dto diff --git a/frontend/src/store/chatSessionStore.js b/frontend/src/store/chatSessionStore.js index a16e0d9..906279c 100644 --- a/frontend/src/store/chatSessionStore.js +++ b/frontend/src/store/chatSessionStore.js @@ -28,7 +28,9 @@ export const useChatSessionStore = defineStore('chatSession', { chatMessages: (state) => state.sessions.find((s) => s.id === state.currentSessionId)?.messages ?? [], sessionList: (state) => - [...state.sessions].sort((a, b) => b.createdAt.localeCompare(a.createdAt)), + [...state.sessions] + .filter((s) => s.messages.length > 0) + .sort((a, b) => b.createdAt.localeCompare(a.createdAt)), }, actions: { @@ -54,11 +56,14 @@ export const useChatSessionStore = defineStore('chatSession', { } }, - createSession() { + newChat() { + this.currentSessionId = null + }, + + _createSession() { const session = makeSession() this.sessions.unshift(session) this.currentSessionId = session.id - this._persist() return session }, @@ -70,7 +75,7 @@ export const useChatSessionStore = defineStore('chatSession', { _ensureSession() { if (!this.currentSessionId || !this.sessions.some((s) => s.id === this.currentSessionId)) { - this.createSession() + this._createSession() } }, diff --git a/frontend/src/views/Chatbot.vue b/frontend/src/views/Chatbot.vue index c756aab..41fd23d 100644 --- a/frontend/src/views/Chatbot.vue +++ b/frontend/src/views/Chatbot.vue @@ -1,6 +1,27 @@