feat: improve chat UI, refine teacher prompt, and add drafting animation

This commit is contained in:
Max
2026-01-27 15:44:51 +07:00
parent 6f365adfd7
commit d4625e0b65
5 changed files with 66 additions and 48 deletions

View File

@@ -4,13 +4,14 @@ import { useEffect, Suspense } from 'react';
import { useSearchParams, useRouter } from 'next/navigation'; import { useSearchParams, useRouter } from 'next/navigation';
import { ChatWindow } from '@/components/features/chat/chat-window'; import { ChatWindow } from '@/components/features/chat/chat-window';
import { ChatInput } from '@/components/features/chat/chat-input'; import { ChatInput } from '@/components/features/chat/chat-input';
import { ThinkingOverlay } from '@/components/features/chat/thinking-overlay';
import { DraftSheet } from '@/components/features/journal/draft-sheet'; import { DraftSheet } from '@/components/features/journal/draft-sheet';
import { useChatStore } from '@/store/use-chat'; import { useChatStore } from '@/store/use-chat';
import { Loader2 } from "lucide-react"; import { Loader2 } from "lucide-react";
import { AppHeader } from '@/components/layout'; import { AppHeader } from '@/components/layout';
function ChatPageContent() { function ChatPageContent() {
const { resetSession } = useChatStore(); const { resetSession, phase } = useChatStore();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const router = useRouter(); const router = useRouter();
@@ -28,6 +29,9 @@ function ChatPageContent() {
{/* Header */} {/* Header */}
<AppHeader /> <AppHeader />
{/* Drafting Overlay */}
{phase === 'drafting' && <ThinkingOverlay />}
{/* Chat Messages - Scrollable Area */} {/* Chat Messages - Scrollable Area */}
<div className="flex-1 flex flex-col min-h-0 overflow-hidden relative"> <div className="flex-1 flex flex-col min-h-0 overflow-hidden relative">
<ChatWindow /> <ChatWindow />

View File

@@ -41,12 +41,11 @@ export function ChatWindow() {
checkConnection(); checkConnection();
}, []); }, []);
// Auto-scroll to bottom only when new messages arrive
useEffect(() => { useEffect(() => {
if (!isUserScrolling) { if (!isUserScrolling) {
bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); bottomRef.current?.scrollIntoView({ behavior: 'smooth', block: 'end' });
} }
}, [messages.length, isUserScrolling]); }, [messages.length, isUserScrolling, isTyping]);
// Detect when user is manually scrolling // Detect when user is manually scrolling
useEffect(() => { useEffect(() => {
@@ -82,8 +81,7 @@ export function ChatWindow() {
<Sparkles className="w-8 h-8 text-amber-400 absolute -top-2 -right-2" aria-hidden="true" /> <Sparkles className="w-8 h-8 text-amber-400 absolute -top-2 -right-2" aria-hidden="true" />
{/* Connection Status Indicator */} {/* Connection Status Indicator */}
<div className={`absolute -bottom-1 -right-1 w-4 h-4 rounded-full border-2 border-white ${ <div className={`absolute -bottom-1 -right-1 w-4 h-4 rounded-full border-2 border-white ${connectionStatus === 'connected' ? 'bg-green-500' :
connectionStatus === 'connected' ? 'bg-green-500' :
connectionStatus === 'checking' ? 'bg-yellow-400 animate-pulse' : 'bg-red-500' connectionStatus === 'checking' ? 'bg-yellow-400 animate-pulse' : 'bg-red-500'
}`} /> }`} />
</div> </div>
@@ -111,7 +109,7 @@ export function ChatWindow() {
} }
return ( return (
<div ref={containerRef} className="h-full flex-1 overflow-y-auto px-4 py-6 scroll-smooth"> <div ref={containerRef} className="w-full h-full flex-1 min-h-0 overflow-y-auto px-4 py-6">
<div className="max-w-3xl mx-auto space-y-4"> <div className="max-w-3xl mx-auto space-y-4">
{messages.map((msg) => ( {messages.map((msg) => (
<ChatBubble key={msg.id} role={msg.role} content={msg.content} /> <ChatBubble key={msg.id} role={msg.role} content={msg.content} />

View File

@@ -0,0 +1,32 @@
"use client";
import { PenTool, Sparkles } from "lucide-react";
export function ThinkingOverlay() {
return (
<div className="absolute inset-0 z-50 flex flex-col items-center justify-center bg-background/60 backdrop-blur-md transition-all duration-500 animate-in fade-in">
<div className="relative">
{/* Pulsing Background Circle */}
<div className="absolute inset-0 bg-indigo-500/20 rounded-full animate-ping [animation-duration:3s]" />
{/* Icon Container */}
<div className="relative bg-card border border-border p-6 rounded-full shadow-lg flex items-center justify-center">
<PenTool className="w-10 h-10 text-indigo-500 animate-bounce [animation-duration:2s]" />
</div>
{/* Sparkles Decoration */}
<Sparkles className="absolute -top-2 -right-2 w-6 h-6 text-amber-400 animate-pulse" />
<Sparkles className="absolute -bottom-1 -left-2 w-4 h-4 text-blue-400 animate-pulse [animation-delay:0.5s]" />
</div>
<div className="mt-8 space-y-2 text-center">
<h3 className="text-xl font-serif font-medium text-foreground">
Crafting your draft
</h3>
<p className="text-sm text-muted-foreground animate-pulse">
Synthesizing insights...
</p>
</div>
</div>
);
}

View File

@@ -1,35 +1,20 @@
export const TEACHER_AGENT_PROMPT = ` export const TEACHER_AGENT_PROMPT = `
ROLE: The Funky Universal Sage (Old, Wise, & Conversational) ROLE: The Wise Socratic Mentor
PERSONA: PERSONA:
You are an "Old, Sage, and Funky Teacher." You speak with a rhythmic, old-school charm. You are a universal mentor who values the "groove" of a real discussion over a dry list of facts. You are patient, slightly eccentric, and want the student to feel the rhythm of the lesson through dialogue. You are a wise, experienced mentor. You value deep understanding over rote memorization. You are patient, direct, and focused. You guide student to the answer rather than giving it.
CORE MISSION: CORE MISSION:
Engage in a deep, fluid discussion on ANY topic. Your goal is to guide the student through Socratic questioning and conversational feedback. You only provide a structured "Resume/Summary" when explicitly asked or when you feel the breakthrough is complete. Guide the student through Socratic questioning. Do not provide answers immediately. Understand their logic first.
OPERATIONAL FLOW: OPERATIONAL FLOW:
1. The Investigation: Ask 3-4 sharp questions to understand the student's thinking. Be concise.
1. The Entry: Acknowledge the vibe. Keep it brief and rhythmic. 2. The Dialogue: Once you understand their level, guide them with hints and corrections.
3. The Summary: Only when asked or when the concept is mastered, provide a clear, concise summary.
2. The Investigation (3-4 Questions): Start by asking exactly 3 to 4 sharp questions to understand the student's logic. Stay conversational—don't just list them.
3. The Fluid Discussion (Teacher Mode):
- Once the investigation is done, stop the heavy questioning.
- Enter a natural dialogue. If the student is wrong, rectify their ideas within the conversation.
- Offer advice, tips, and "Sage Wisdom" as part of the talk.
- Crucial: Do not provide a summary or "key points" list yet. Keep the talk going as long as the student has more to say.
4. The Trigger for Summary:
- If the student says "resume," "summarize," or "capture this."
- OR, if you feel the "Aha!" moment has happened, ask: "The rhythm feels right now. Shall we capture this wisdom for your records?"
5. The Funky Reveal (Final Summary ONLY):
- Provide a Funky Analogy.
- Give Direct Advice: 3-5 punchy, professional tips.
- State the Universal Non-Negotiable rule.
CONVERSATIONAL STYLE: CONVERSATIONAL STYLE:
- No Bullet Points: Until the Final Summary trigger, use only paragraphs and natural dialogue. - Concise: specific and to the point.
- Direct & Sharp: Be clear when correcting the student's mindset. - Socratic: Ask questions that spark realization.
- The Rhythm: Use phrases like "Let's riff on that," "I hear that discord," or "Now you're playing the right chords." - Direct: Correct misconceptions clearly.
- No fluff.
`; `;

View File

@@ -83,26 +83,25 @@ export function generateTeacherPrompt(
const truncatedInput = truncateInput(userInput); const truncatedInput = truncateInput(userInput);
const formattedHistory = formatChatHistory(chatHistory); const formattedHistory = formatChatHistory(chatHistory);
// Unified "Funky Data Sage" Prompt // Unified "Wise Socratic Mentor" Prompt
return `ROLE: The Funky Data Sage (Old, Wise, & Socratic) return `ROLE: The Wise Socratic Mentor
PERSONA: You are an "Old, Sage, and Funky Teacher." Youve been coding since the days of punch cards, but youve got the rhythm of a funk legend. You are wise, slightly eccentric, and speak in a mix of "Ancient Data Wisdom" and colorful, funky metaphors. You are patient but firm—youve seen every mistake in the book and won't let the student take shortcuts.
CORE MISSION: You do not hand out answers; you guide the student to find them in the "Data Mist." You must ask exactly 3 to 4 sharp, investigative questions to map the student's logic before you reveal your wisdom or provide an analogy. PERSONA:
You are a wise, experienced mentor. You value deep understanding over rote memorization. You are patient, direct, and focused. You guide student to the answer rather than giving it.
CORE MISSION:
Guide the student through Socratic questioning. Do not provide answers immediately. Understand their logic first.
OPERATIONAL FLOW: OPERATIONAL FLOW:
1. The Entry (Funky & Direct): Acknowledge the student's mood with a sage-like observation. (e.g., "I feel a disturbance in the Join... the rhythm of your logic is a bit off, man.") 1. The Investigation: Ask 3-4 sharp questions to understand the student's thinking. Be concise.
2. The Investigation (3-4 Questions): Before the "Lesson," you must ask 3 to 4 probing questions. Force the student to explain the root of their logic. Keep your responses short and punchy during this phase. 2. The Dialogue: Once you understand their level, guide them with hints and corrections.
3. The Sage Audit: 3. The Summary: Only when asked or when the concept is mastered, provide a clear, concise summary.
- If they are wrong: Don't scold. Ask a "Zen Trap" question that makes the error obvious to them.
- If they are right: Nod with approval but challenge the "groove" (efficiency) of their solution.
4. The Funky Reveal: Only AFTER the questions are answered, provide:
- A Funky Analogy: (e.g., "Data cleaning is like tuning a bass guitar—if the strings are grimy, the whole song sounds like mud.")
- The Sage Advice: The direct technical fix and the "Clean Data" non-negotiable rule.
CONVERSATIONAL STYLE: CONVERSATIONAL STYLE:
- Tone: Quirky, sage-like, and rhythmic. Use "Old-School" charm. - Concise: specific and to the point.
- Brevity: Be very short at the beginning. Let the questions do the work. - Socratic: Ask questions that spark realization.
- Mantra: "The data never lies, but the mind often dances to the wrong beat." - Direct: Correct misconceptions clearly.
- No fluff.
CONTEXT: CONTEXT:
User Input (${intent}): ${truncatedInput} User Input (${intent}): ${truncatedInput}