Chat Suggestions
Version: 1.0.0 Last Updated: 2025-01-04 Status: Implemented
1. Overview
Chat Suggestions는 채팅 응답 완료 후 사용자에게 후속 액션을 제안하는 인터랙티브 버튼 시스템입니다. SSE(Server-Sent Events)를 통해 백엔드에서 전송된 suggestion 데이터를 기반으로 렌더링됩니다.
1.1 Purpose
- 사용자의 다음 행동을 자연스럽게 유도
- 설문조사(Questionnaire) 시작을 쉽게 제안
- LLM이 생성한 후속 질문으로 대화 흐름 확장
- Conversational Action Catalog의 액션 실행 지원
1.2 Key Features
| Feature | Description |
|---|---|
| 3가지 Suggestion 타입 | Exploration, Questionnaire, Action |
| 애니메이션 효과 | Framer Motion 기반 fade-in, scale 애니메이션 |
| 타입별 스타일링 | 아이콘 및 색상으로 타입 구분 |
| SSE 이벤트 연동 | 실시간 suggestion 수신 및 렌더링 |
2. Type Definitions
2.1 Suggestion Types
// lib/chat/types.ts
/**
* Questionnaire Type Enum
* Matches backend QuestionnaireType enum
*/
export type QuestionnaireType = 'ISI' | 'DBAS16' | 'PHQ9' | 'GAD7' | 'PSS' | 'WIS';
/**
* Exploration Suggestion
* Follow-up questions or topics generated by LLM
*/
export interface ExplorationSuggestion {
type: 'exploration';
text: string;
}
/**
* Questionnaire Suggestion
* Suggestion to start a questionnaire
*/
export interface QuestionnaireSuggestion {
type: 'questionnaire';
questionnaireType: QuestionnaireType;
text: string;
actionId?: string;
}
/**
* Action Suggestion (generic)
* Actions from the Conversational Action Catalog
*/
export interface ActionSuggestion {
type: 'action';
actionId: string;
text: string;
actionTypeId: string;
payload: Record<string, unknown>;
confidence: number;
}
/**
* Combined Suggestion Type
*/
export type Suggestion = ExplorationSuggestion | QuestionnaireSuggestion | ActionSuggestion;
2.2 SSE Event Structure
// lib/chat/chat-api.ts
export interface SSEEvent {
type: 'agent_switch' | 'content' | 'control' | 'error' | 'suggestions';
// ... other fields
// Suggestions event data
suggestions?: Suggestion[];
suggestionsMetadata?: {
explorationCount: number;
actionCount: number;
totalGenerated: number;
};
}
3. Component Architecture
3.1 Component Hierarchy
Chat (chat.tsx)
├── NativeMessages (native-messages.tsx)
│ └── SuggestionButtons (suggestion-buttons.tsx)
│ └── SuggestionButton (internal)
├── NativeChatInput
└── QuestionnaireModal
3.2 SuggestionButtons Component
Location: components/chat/suggestion-buttons.tsx
interface SuggestionButtonsProps {
suggestions: Suggestion[];
onSelect: (suggestion: Suggestion) => void;
disabled?: boolean;
}
export function SuggestionButtons({
suggestions,
onSelect,
disabled = false,
}: SuggestionButtonsProps) {
if (!suggestions || suggestions.length === 0) {
return null;
}
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="flex flex-wrap gap-2 py-3"
>
{suggestions.map((suggestion, index) => (
<SuggestionButton
key={`${suggestion.type}-${index}`}
suggestion={suggestion}
onSelect={onSelect}
disabled={disabled}
index={index}
/>
))}
</motion.div>
);
}
3.3 Type-specific Icons
| Type | Icon | Visual |
|---|---|---|
questionnaire | Checkmark with box | Survey/form indicator |
exploration | Magnifying glass | Search/discover indicator |
action | Arrow right | Action/proceed indicator |
3.4 Styling by Type
| Type | Background | Text Color | Shadow |
|---|---|---|---|
questionnaire | #3651B2 (Primary Blue) | White | rgba(54, 81, 178, 0.3) |
exploration | #F3F4F6 (Light Gray) | #1A1B1E (Dark) | rgba(0, 0, 0, 0.1) |
action | #F3F4F6 (Light Gray) | #1A1B1E (Dark) | rgba(0, 0, 0, 0.1) |
4. Data Flow
4.1 SSE Event Flow
┌─────────────────┐
│ Backend SSE │
│ (suggestions) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ chat-api.ts │
│ (SSE parsing) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ useChatStream │
│ setSuggestions()│
└────────┬────────┘
│
▼
┌─────────────────┐
│ NativeMessages │
│ (render if │
│ !isStreaming) │
└────────┬────────┘
│
▼
┌─────────────────┐
│SuggestionButtons│
│ (UI render) │
└─────────────────┘
4.2 State Management
// hooks/chat/use-chat-stream.ts
export function useChatStream(options: UseChatStreamOptions): UseChatStreamReturn {
const [suggestions, setSuggestions] = useState<Suggestion[]>([]);
// SSE event handling
case 'suggestions': {
console.log('[useChatStream] suggestions event:', event.suggestions);
if (event.suggestions && event.suggestions.length > 0) {
setSuggestions(event.suggestions);
}
break;
}
// Clear suggestions when sending new message
const sendMessage = useCallback((content: string) => {
setSuggestions([]); // Clear previous suggestions
// ... send message logic
}, []);
const clearSuggestions = useCallback(() => {
setSuggestions([]);
}, []);
return {
suggestions,
clearSuggestions,
// ... other returns
};
}
5. Event Handling
5.1 Selection Handler
// components/chat/chat.tsx
const handleSelectSuggestion = useCallback((suggestion: Suggestion) => {
console.log('[Chat] Suggestion selected:', suggestion);
if (suggestion.type === 'questionnaire') {
// Open questionnaire modal
const qnSuggestion = suggestion as QuestionnaireSuggestion;
setActiveQuestionnaireType(qnSuggestion.questionnaireType as QuestionnaireType);
setIsQuestionnaireOpen(true);
clearSuggestions();
} else if (suggestion.type === 'exploration') {
// Send the suggestion text as a message
sendMessage(suggestion.text);
clearSuggestions();
} else if (suggestion.type === 'action') {
// Handle action suggestions (future implementation)
console.log('[Chat] Action suggestion not implemented yet:', suggestion);
}
}, [clearSuggestions, sendMessage]);
5.2 Behavior by Type
| Type | Click Behavior |
|---|---|
questionnaire | Opens QuestionnaireModal with the specified type |
exploration | Sends the suggestion text as a new user message |
action | (Not implemented) Logs to console |
6. Rendering Conditions
Suggestions are only rendered when ALL conditions are met:
// components/chat/native-messages.tsx
{!isStreaming && suggestions.length > 0 && onSelectSuggestion && (
<div className="px-1">
<SuggestionButtons
suggestions={suggestions}
onSelect={onSelectSuggestion}
disabled={isStreaming}
/>
</div>
)}
| Condition | Purpose |
|---|---|
!isStreaming | Don't show during response generation |
suggestions.length > 0 | Only show when suggestions exist |
onSelectSuggestion | Handler must be provided |
7. Animation Specs
7.1 Container Animation
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="flex flex-wrap gap-2 py-3"
>
7.2 Button Animation
<motion.button
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.1, duration: 0.2 }}
className="... hover:scale-[1.02] active:scale-[0.98]"
>
| Property | Value | Description |
|---|---|---|
| Initial opacity | 0 | Fade in from invisible |
| Initial y | 10px | Slide up from below |
| Stagger delay | index * 0.1s | Sequential appearance |
| Duration | 0.2s | Quick, snappy animation |
| Hover scale | 1.02 | Subtle grow on hover |
| Active scale | 0.98 | Subtle shrink on press |
8. Backend Integration
8.1 Expected SSE Event Format
{
"type": "suggestions",
"suggestions": [
{
"type": "exploration",
"text": "Tell me more about your sleep patterns"
},
{
"type": "questionnaire",
"questionnaireType": "ISI",
"text": "Complete sleep quality assessment"
},
{
"type": "action",
"actionId": "set-bedtime-goal",
"text": "Set a bedtime goal",
"actionTypeId": "sleep.goal.set",
"payload": { "suggestedTime": "23:00" },
"confidence": 0.85
}
],
"suggestionsMetadata": {
"explorationCount": 1,
"actionCount": 1,
"totalGenerated": 3
}
}
8.2 Timing
- Suggestions event is sent after the
control(done) event - Suggestions appear only after streaming completes
9. Future Improvements
9.1 Action Suggestion Implementation
Currently, ActionSuggestion type selection only logs to console. Full implementation requires:
- Action execution service integration
- Conversational Action Catalog lookup
- Payload validation and processing
- Result feedback to chat
9.2 Potential Enhancements
- Suggestion analytics tracking
- A/B testing for suggestion ordering
- Personalized suggestion ranking
- Suggestion expiration/timeout
- Multi-language support for suggestion text
10. File References
| File | Purpose |
|---|---|
lib/chat/types.ts | Type definitions |
lib/chat/chat-api.ts | SSE event interface |
hooks/chat/use-chat-stream.ts | State management |
components/chat/suggestion-buttons.tsx | UI component |
components/chat/native-messages.tsx | Rendering logic |
components/chat/chat.tsx | Event handling |
11. Change History
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0.0 | 2025-01-04 | bok@weltcorp.com | Initial documentation |