Spaces:
Runtime error
Runtime error
Download src/components/ThinkingBox.tsx from ihatebaselines/purcar-chat-api: direct link, hf CLI and curl.
- Browser
- Download file 4.62 kB
-
https://huggingface.co/spaces/ihatebaselines/purcar-chat-api/resolve/main/src/components/ThinkingBox.tsx
- Command line
-
hf download hf://spaces/ihatebaselines/purcar-chat-api/src/components/ThinkingBox.tsx
-
curl -L -o ThinkingBox.tsx https://huggingface.co/spaces/ihatebaselines/purcar-chat-api/resolve/main/src/components/ThinkingBox.tsx
4.62 kB
| "use client"; | |
| import React, { useState, useEffect } from "react"; | |
| import { Brain, ChevronDown, ChevronRight, Sparkles, Clock, CheckCircle2 } from "lucide-react"; | |
| interface ThinkingBoxProps { | |
| thinking: string; | |
| isStreaming?: boolean; | |
| thinkingTimeSeconds?: number; | |
| defaultExpanded?: boolean; | |
| } | |
| export const ThinkingBox: React.FC<ThinkingBoxProps> = ({ | |
| thinking, | |
| isStreaming = false, | |
| thinkingTimeSeconds, | |
| defaultExpanded = true, | |
| }) => { | |
| const [isExpanded, setIsExpanded] = useState(defaultExpanded); | |
| const [elapsedSeconds, setElapsedSeconds] = useState(thinkingTimeSeconds || 0); | |
| useEffect(() => { | |
| let timer: NodeJS.Timeout; | |
| if (isStreaming) { | |
| const startTime = Date.now() - (elapsedSeconds * 1000); | |
| timer = setInterval(() => { | |
| setElapsedSeconds(Number(((Date.now() - startTime) / 1000).toFixed(1))); | |
| }, 100); | |
| } else if (thinkingTimeSeconds) { | |
| setElapsedSeconds(thinkingTimeSeconds); | |
| } | |
| return () => clearInterval(timer); | |
| }, [isStreaming, thinkingTimeSeconds]); | |
| if (!thinking && !isStreaming) return null; | |
| return ( | |
| <div className="mb-4 rounded-xl border border-white/[0.08] bg-black/40 overflow-hidden backdrop-blur-md transition-all duration-300"> | |
| {/* Header Button */} | |
| <button | |
| onClick={() => setIsExpanded(!isExpanded)} | |
| className="w-full flex items-center justify-between px-3.5 py-2.5 bg-white/[0.02] hover:bg-white/[0.05] transition-colors text-left group" | |
| > | |
| <div className="flex items-center gap-2.5"> | |
| <div className="relative"> | |
| <Brain | |
| className={`w-4 h-4 transition-colors ${ | |
| isStreaming ? "text-cyan-400 animate-pulse" : "text-zinc-400 group-hover:text-zinc-200" | |
| }`} | |
| /> | |
| {isStreaming && ( | |
| <span className="absolute -top-0.5 -right-0.5 w-1.5 h-1.5 rounded-full bg-cyan-400 animate-ping" /> | |
| )} | |
| </div> | |
| <div className="flex items-center gap-2"> | |
| <span className="text-xs font-mono font-medium text-zinc-300 group-hover:text-white transition-colors"> | |
| {isStreaming ? "Thinking Process" : "Thought Process"} | |
| </span> | |
| <span className="text-[11px] font-mono text-zinc-500 flex items-center gap-1"> | |
| <Clock className="w-3 h-3" /> | |
| {elapsedSeconds > 0 ? `${elapsedSeconds.toFixed(1)}s` : "0.8s"} | |
| </span> | |
| </div> | |
| </div> | |
| <div className="flex items-center gap-2"> | |
| {isStreaming ? ( | |
| <span className="inline-flex items-center gap-1.5 text-[10px] font-mono uppercase px-2 py-0.5 rounded-full bg-cyan-500/10 text-cyan-400 border border-cyan-500/20"> | |
| <Sparkles className="w-2.5 h-2.5 animate-spin" /> | |
| Reasoning | |
| </span> | |
| ) : ( | |
| <span className="inline-flex items-center gap-1 text-[10px] font-mono uppercase px-2 py-0.5 rounded-full bg-emerald-500/10 text-emerald-400 border border-emerald-500/20"> | |
| <CheckCircle2 className="w-2.5 h-2.5" /> | |
| Verified | |
| </span> | |
| )} | |
| {isExpanded ? ( | |
| <ChevronDown className="w-3.5 h-3.5 text-zinc-500 group-hover:text-zinc-300 transition-transform" /> | |
| ) : ( | |
| <ChevronRight className="w-3.5 h-3.5 text-zinc-500 group-hover:text-zinc-300 transition-transform" /> | |
| )} | |
| </div> | |
| </button> | |
| {/* Collapsible Content */} | |
| {isExpanded && ( | |
| <div className="px-4 py-3 border-t border-white/[0.04] bg-black/60 text-xs font-mono text-zinc-400 leading-relaxed space-y-1.5 overflow-x-auto"> | |
| {thinking.split("\n").map((line, idx) => { | |
| if (!line.trim()) return <div key={idx} className="h-1" />; | |
| const isStepHeader = line.match(/^(\d+\.|\[.*?\])/); | |
| return ( | |
| <div | |
| key={idx} | |
| className={`flex gap-2 ${ | |
| isStepHeader ? "text-zinc-200 font-semibold pt-1 border-t border-white/[0.03] first:border-0 first:pt-0" : "text-zinc-400 pl-4" | |
| }`} | |
| > | |
| <span>{line}</span> | |
| </div> | |
| ); | |
| })} | |
| {isStreaming && ( | |
| <div className="flex items-center gap-1.5 text-cyan-400 text-[11px] pt-1"> | |
| <span className="w-1.5 h-1.5 rounded-full bg-cyan-400 animate-ping" /> | |
| <span className="italic">Evaluating transformer self-attention states...</span> | |
| </div> | |
| )} | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| }; | |