tutor wait: the thinking bubble moves through stages instead of one fixed line

The model provider holds the whole answer and sends it at once; a full
answer with a diagram took about 30 s on 2026-09-29. A fixed 'thinking'
line for that long looked stuck. The stage times are approximate and not
tied to what the server is actually doing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-29 22:05:33 +03:30
parent 0957ef476b
commit db6d694ab0

View File

@@ -212,6 +212,42 @@ function Bubble({ role, children, extra }: { role: 'user' | 'assistant'; childre
); );
} }
/**
* منتظرِ جوابِ دستیار. سرویسِ مدل کلِ جواب را نگه می‌دارد و یک‌جا می‌فرستد؛ جوابِ
* کامل با شکل در ۲۰۲۶-۰۹-۲۹ حدودِ ۳۰ ثانیه طول کشید. پیامِ ثابت در آن مدت شبیهِ
* گیر کردن بود، پس متن با زمان جلو می‌رود. زمان‌ها تقریبی‌اند و به مرحله‌ی واقعیِ
* سرور وصل نیستند.
*/
const THINKING_STEPS: [number, string][] = [
[0, 'پی داره تو کتابت می‌گرده'],
[4, 'پی داره حلش می‌کنه'],
[15, 'داره قدم‌ها رو مرتب می‌نویسه'],
[28, 'جوابِ کامل یه کم طول می‌کشه، الان می‌رسه'],
];
function Thinking() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const started = Date.now();
const timer = setInterval(() => setSeconds((Date.now() - started) / 1000), 1000);
return () => clearInterval(timer);
}, []);
const text = [...THINKING_STEPS].reverse().find(([at]) => seconds >= at)![1];
return (
<div className="flex items-center gap-2">
<span className="flex h-8 w-8 flex-shrink-0 items-center justify-center overflow-hidden rounded-full bg-[#f5f1ff]">
<SeyarMascot char="pi" mood="idle" size={32} />
</span>
<div className="flex items-center gap-2 rounded-2xl border border-line bg-white px-4 py-3 text-xs text-muted" aria-live="polite">
{text}
{[0, 1, 2].map((i) => (
<motion.span key={i} className="h-1.5 w-1.5 rounded-full bg-violet/60" animate={{ y: [0, -4, 0] }} transition={{ duration: 0.6, repeat: Infinity, delay: i * 0.15 }} />
))}
</div>
</div>
);
}
function Message({ function Message({
message, last, busy, onRetry, onFollowUp, message, last, busy, onRetry, onFollowUp,
}: { }: {
@@ -225,21 +261,7 @@ function Message({
if (message.role === 'user') return <Bubble role="user"><MathText text={message.text} /></Bubble>; if (message.role === 'user') return <Bubble role="user"><MathText text={message.text} /></Bubble>;
if (!message.text) { if (!message.text) return <Thinking />;
return (
<div className="flex items-center gap-2">
<span className="flex h-8 w-8 flex-shrink-0 items-center justify-center overflow-hidden rounded-full bg-[#f5f1ff]">
<SeyarMascot char="pi" mood="idle" size={32} />
</span>
<div className="flex items-center gap-2 rounded-2xl border border-line bg-white px-4 py-3 text-xs text-muted">
پی داره فکر می‌کنه
{[0, 1, 2].map((i) => (
<motion.span key={i} className="h-1.5 w-1.5 rounded-full bg-violet/60" animate={{ y: [0, -4, 0] }} transition={{ duration: 0.6, repeat: Infinity, delay: i * 0.15 }} />
))}
</div>
</div>
);
}
async function rate(helpful: boolean) { async function rate(helpful: boolean) {
if (!message.messageId || message.feedback) return; if (!message.messageId || message.feedback) return;