Abdullahrasheed45 commited on
Commit
7e7edae
·
verified ·
1 Parent(s): 25e8db0

Create LiveCaption.tsx

Browse files
Files changed (1) hide show
  1. src/components/LiveCaption.tsx +277 -0
src/components/LiveCaption.tsx ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState } from "react";
2
+ import { PROMPTS, THEME } from "../constants";
3
+
4
+ interface LiveCaptionProps {
5
+ caption: string;
6
+ isRunning?: boolean;
7
+ error?: string | null;
8
+ history: HistoryEntry[];
9
+ stats?: { tps?: number; ttft?: number };
10
+ }
11
+
12
+ export interface HistoryEntry {
13
+ timestamp: string;
14
+ text: string;
15
+ }
16
+
17
+ export default function LiveCaption({
18
+ caption,
19
+ isRunning,
20
+ error,
21
+ history,
22
+ stats,
23
+ }: LiveCaptionProps) {
24
+ const [showHistory, setShowHistory] = useState(false);
25
+
26
+ const content = error || caption;
27
+
28
+ const status = error
29
+ ? {
30
+ bg: "bg-[var(--mistral-red)]/10",
31
+ border: "border-[var(--mistral-red)]",
32
+ text: "text-[var(--mistral-red)]",
33
+ dot: "bg-[var(--mistral-red)]",
34
+ label: "SYSTEM ERROR",
35
+ }
36
+ : isRunning
37
+ ? {
38
+ bg: "bg-[var(--mistral-orange)]/5",
39
+ border: "border-[var(--mistral-orange)]",
40
+ text: "text-[var(--mistral-orange)]",
41
+ dot: "bg-[var(--mistral-orange)]",
42
+ label: "LIVE INFERENCE",
43
+ }
44
+ : {
45
+ bg: "bg-gray-50",
46
+ border: "border-[var(--mistral-beige-dark)]",
47
+ text: "text-gray-500",
48
+ dot: "bg-gray-400",
49
+ label: "STANDBY",
50
+ };
51
+
52
+ return (
53
+ <>
54
+ <div className="w-full max-w-3xl relative font-sans">
55
+ <div
56
+ className={`
57
+ relative rounded-lg overflow-hidden transition-all duration-300
58
+ border shadow-lg flex flex-col
59
+ ${isRunning ? "ring-1 ring-[var(--mistral-orange)]/20 shadow-[var(--mistral-orange)]/10" : ""}
60
+ `}
61
+ style={{
62
+ borderColor: error ? THEME.errorRed : THEME.beigeDark,
63
+ backgroundColor: THEME.beigeLight,
64
+ height: "240px",
65
+ }}
66
+ >
67
+ <div
68
+ className="flex items-center justify-between px-4 py-2 border-b bg-white/50 flex-shrink-0"
69
+ style={{ borderColor: THEME.beigeDark }}
70
+ >
71
+ <div className="flex items-center space-x-3">
72
+ <div className="flex items-center space-x-2">
73
+ <svg
74
+ className="w-4 h-4 text-gray-400"
75
+ fill="none"
76
+ viewBox="0 0 24 24"
77
+ stroke="currentColor"
78
+ >
79
+ <path
80
+ strokeLinecap="round"
81
+ strokeLinejoin="round"
82
+ strokeWidth={2}
83
+ d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
84
+ />
85
+ </svg>
86
+ <span className="text-xs font-bold text-gray-500 uppercase tracking-widest hidden sm:inline">
87
+ Output Stream
88
+ </span>
89
+ </div>
90
+ </div>
91
+ <div className="flex items-center space-x-3">
92
+ {/* View History Button */}
93
+ <button
94
+ onClick={() => setShowHistory(!showHistory)}
95
+ className={`
96
+ flex items-center space-x-1.5 px-3 py-1 rounded text-[10px] font-bold uppercase tracking-wider transition-all
97
+ ${
98
+ showHistory
99
+ ? "text-white shadow-md"
100
+ : "bg-white border text-gray-500 hover:text-[var(--mistral-orange)] hover:border-[var(--mistral-orange)]"
101
+ }
102
+ `}
103
+ style={
104
+ showHistory
105
+ ? { backgroundColor: THEME.textBlack }
106
+ : { borderColor: THEME.beigeDark }
107
+ }
108
+ >
109
+ <svg
110
+ className="w-3 h-3"
111
+ fill="none"
112
+ viewBox="0 0 24 24"
113
+ stroke="currentColor"
114
+ >
115
+ <path
116
+ strokeLinecap="round"
117
+ strokeLinejoin="round"
118
+ strokeWidth={2}
119
+ d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
120
+ />
121
+ </svg>
122
+ <span>{showHistory ? "Close History" : "View History"}</span>
123
+ </button>
124
+ {/* Status Badge */}
125
+ <div
126
+ className={`flex items-center space-x-2 px-2 py-1 rounded-sm border ${status.bg} ${status.border} border-opacity-30`}
127
+ >
128
+ <div className="relative flex h-2 w-2">
129
+ {isRunning && (
130
+ <span
131
+ className={`animate-ping absolute inline-flex h-full w-full rounded-full opacity-75 ${status.dot}`}
132
+ ></span>
133
+ )}
134
+ <span
135
+ className={`relative inline-flex rounded-full h-2 w-2 ${status.dot}`}
136
+ ></span>
137
+ </div>
138
+ <span
139
+ className={`text-[10px] font-bold tracking-wider ${status.text}`}
140
+ >
141
+ {status.label}
142
+ </span>
143
+ </div>
144
+ </div>
145
+ </div>
146
+ {/* Main Content Area */}
147
+ <div className="relative flex-1 overflow-hidden">
148
+ {/* Background Grid Pattern */}
149
+ <div
150
+ className="absolute inset-0 opacity-[0.03] pointer-events-none"
151
+ style={{
152
+ backgroundImage: `linear-gradient(${THEME.black} 1px, transparent 1px), linear-gradient(90deg, ${THEME.black} 1px, transparent 1px)`,
153
+ backgroundSize: "20px 20px",
154
+ }}
155
+ />
156
+ {showHistory ? (
157
+ <div className="absolute inset-0 overflow-y-auto p-4 history-scroll bg-white/40">
158
+ {history.length === 0 ? (
159
+ <div className="h-full flex flex-col items-center justify-center text-gray-400 space-y-2">
160
+ <svg
161
+ className="w-8 h-8 opacity-50"
162
+ fill="none"
163
+ viewBox="0 0 24 24"
164
+ stroke="currentColor"
165
+ >
166
+ <path
167
+ strokeLinecap="round"
168
+ strokeLinejoin="round"
169
+ strokeWidth={1.5}
170
+ d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
171
+ />
172
+ </svg>
173
+ <p className="text-xs font-mono">
174
+ No history recorded yet.
175
+ </p>
176
+ </div>
177
+ ) : (
178
+ <div className="space-y-3">
179
+ {history.map((entry, idx) => (
180
+ <div
181
+ key={idx}
182
+ className="group flex items-start space-x-3 text-sm font-mono border-b pb-2 last:border-0"
183
+ style={{ borderColor: `${THEME.beigeDark}4D` }}
184
+ >
185
+ <span
186
+ className="text-xs opacity-60 mt-0.5 whitespace-nowrap font-light"
187
+ style={{ color: THEME.mistralOrange }}
188
+ >
189
+ [{entry.timestamp}]
190
+ </span>
191
+ <span
192
+ className="leading-relaxed group-hover:text-black transition-colors"
193
+ style={{ color: THEME.textBlack }}
194
+ >
195
+ {entry.text}
196
+ </span>
197
+ </div>
198
+ ))}
199
+ </div>
200
+ )}
201
+ </div>
202
+ ) : (
203
+ <div className="p-6 h-full flex flex-col justify-start overflow-y-auto relative z-10">
204
+ {content ? (
205
+ <p
206
+ className={`text-lg md:text-xl font-mono leading-relaxed break-words`}
207
+ style={{ color: error ? THEME.errorRed : THEME.textBlack }}
208
+ >
209
+ <span className="mr-1">{content}</span>
210
+ {/* Blinking Block Cursor */}
211
+ {!error && isRunning && (
212
+ <span
213
+ className="inline-block w-2.5 h-5 align-middle cursor-blink ml-1"
214
+ style={{ backgroundColor: THEME.mistralOrange }}
215
+ ></span>
216
+ )}
217
+ </p>
218
+ ) : (
219
+ <div className="h-full flex flex-col items-center justify-center space-y-3 opacity-60">
220
+ {isRunning ? (
221
+ <>
222
+ <div className="flex space-x-1">
223
+ <div
224
+ className="w-1.5 h-1.5 rounded-full animate-bounce delay-75"
225
+ style={{ backgroundColor: THEME.mistralOrange }}
226
+ ></div>
227
+ <div
228
+ className="w-1.5 h-1.5 rounded-full animate-bounce delay-100"
229
+ style={{ backgroundColor: THEME.mistralOrange }}
230
+ ></div>
231
+ <div
232
+ className="w-1.5 h-1.5 rounded-full animate-bounce delay-150"
233
+ style={{ backgroundColor: THEME.mistralOrange }}
234
+ ></div>
235
+ </div>
236
+ <p className="text-sm text-gray-500 font-mono italic">
237
+ {PROMPTS.processingMessage}
238
+ </p>
239
+ </>
240
+ ) : (
241
+ <p className="text-sm text-gray-400 font-mono text-center">
242
+ // Awaiting visual input...
243
+ <br />
244
+ // Model ready.
245
+ </p>
246
+ )}
247
+ </div>
248
+ )}
249
+ </div>
250
+ )}
251
+ </div>
252
+ {/* Footer Metadata */}
253
+ <div
254
+ className="px-4 py-1.5 bg-gray-50 border-t flex justify-between items-center text-[10px] text-gray-400 font-mono flex-shrink-0"
255
+ style={{ borderColor: THEME.beigeDark }}
256
+ >
257
+ <div className="flex gap-4">
258
+ <span>
259
+ ttft:{" "}
260
+ {stats?.ttft
261
+ ? `${stats.ttft.toFixed(0)}ms`
262
+ : isRunning
263
+ ? "..."
264
+ : "0ms"}
265
+ </span>
266
+ <span>
267
+ tokens/sec:{" "}
268
+ {stats?.tps ? stats.tps.toFixed(2) : isRunning ? "..." : "0"}
269
+ </span>
270
+ </div>
271
+ <span>ctx: 3.3B-Instruct</span>
272
+ </div>
273
+ </div>
274
+ </div>
275
+ </>
276
+ );
277
+ }