Skip to content

Commit 388abc9

Browse files
2 parents 676e7e5 + 9e76c2e commit 388abc9

File tree

4 files changed

+308
-266
lines changed

4 files changed

+308
-266
lines changed

src/app.tsx

Lines changed: 137 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import {
2626
// List of tools that require human confirmation
2727
// NOTE: this should match the tools that don't have execute functions in tools.ts
2828
const toolsRequiringConfirmation: (keyof typeof tools)[] = [
29-
"getWeatherInformation",
3029
"searchSpotifyArtist"
3130
];
3231

@@ -157,15 +156,24 @@ export default function Chat() {
157156
};
158157

159158
return (
160-
<div className="h-[100vh] w-full p-4 flex justify-center items-center bg-fixed overflow-hidden" style={{ background: "var(--gradient-bg)" }}>
159+
<div
160+
className="h-[100vh] w-full p-4 flex justify-center items-center bg-fixed overflow-hidden"
161+
style={{ background: "var(--gradient-bg)" }}
162+
>
161163
{/* Animated Background Elements */}
162164
<div className="fixed top-20 left-20 w-64 h-64 bg-blue-400/20 rounded-full blur-3xl animate-float pointer-events-none" />
163-
<div className="fixed bottom-20 right-20 w-80 h-80 bg-purple-400/20 rounded-full blur-3xl animate-float pointer-events-none" style={{ animationDelay: "-3s" }} />
165+
<div
166+
className="fixed bottom-20 right-20 w-80 h-80 bg-purple-400/20 rounded-full blur-3xl animate-float pointer-events-none"
167+
style={{ animationDelay: "-3s" }}
168+
/>
164169

165170
<HasOpenAIKey />
166171
<div className="h-[calc(100vh-2rem)] w-full mx-auto max-w-lg flex flex-col rounded-2xl overflow-hidden relative glass-panel">
167172
{/* Header */}
168-
<div className="px-5 py-4 flex items-center gap-3 sticky top-0 z-10 backdrop-blur-md border-b border-white/20" style={{ background: "var(--gradient-primary)" }}>
173+
<div
174+
className="px-5 py-4 flex items-center gap-3 sticky top-0 z-10 backdrop-blur-md border-b border-white/20"
175+
style={{ background: "var(--gradient-primary)" }}
176+
>
169177
<div className="flex items-center justify-center h-10 w-10 bg-white/20 rounded-full backdrop-blur-sm shadow-sm">
170178
<svg
171179
width="24px"
@@ -198,7 +206,11 @@ export default function Chat() {
198206
className="btn-liquid h-10 w-10 text-white rounded-full flex items-center justify-center backdrop-blur-md bg-white/20 border border-white/30 shadow-lg hover:bg-white/30 hover:scale-105 transition-all duration-300"
199207
onClick={toggleTheme}
200208
>
201-
{theme === "dark" ? <Sun size={20} weight="fill" /> : <Moon size={20} weight="fill" />}
209+
{theme === "dark" ? (
210+
<Sun size={20} weight="fill" />
211+
) : (
212+
<Moon size={20} weight="fill" />
213+
)}
202214
</Button>
203215
</div>
204216

@@ -218,22 +230,104 @@ export default function Chat() {
218230
{/* Messages */}
219231
<div className="flex-1 overflow-y-auto p-4 space-y-6 pb-28 max-h-[calc(100vh-10rem)] scrollbar-hide">
220232
{agentMessages.length === 0 && (
221-
<div className="h-full flex items-center justify-center">
222-
<div className="p-8 max-w-md mx-auto glass-bubble-ai rounded-2xl text-center space-y-4">
233+
<div className="min-h-full flex items-start justify-center py-8">
234+
<div className="p-8 max-w-2xl mx-auto glass-bubble-ai rounded-2xl text-center space-y-4">
223235
<div className="bg-blue-100 text-blue-600 rounded-full p-4 inline-flex shadow-sm">
224236
<Robot size={32} />
225237
</div>
226-
<h3 className="font-bold text-xl text-neutral-800">Welcome to AI Chat</h3>
227-
<p className="text-neutral-600">
228-
I'm your personal assistant. Ask me anything!
238+
<h3 className="font-bold text-xl text-neutral-700 dark:text-neutral-300">
239+
Welcome to Beatsmith AI
240+
</h3>
241+
242+
{/* Deprecation Notice */}
243+
<div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-3 text-sm text-yellow-800 dark:text-yellow-200">
244+
<p className="font-semibold">
245+
Spotify Login System Deprecated
246+
</p>
247+
<p className="mt-1">
248+
The Spotify login system has been deprecated. User-specific
249+
features requiring login are no longer available.
250+
</p>
251+
</div>
252+
253+
<p className="text-neutral-600 dark:text-neutral-400">
254+
I can help you discover music, find similar songs, and explore
255+
artists. Here's what I can do:
229256
</p>
230-
<div className="grid grid-cols-1 gap-2 mt-4">
231-
<button onClick={() => setAgentInput("What's the weather in Tokyo?")} className="text-sm p-3 bg-white/50 hover:bg-white/80 rounded-xl text-left transition-colors flex items-center gap-2 text-neutral-700">
232-
<span>🌤️</span> Weather in Tokyo
233-
</button>
234-
<button onClick={() => setAgentInput("Find songs similar to Blinding Lights")} className="text-sm p-3 bg-white/50 hover:bg-white/80 rounded-xl text-left transition-colors flex items-center gap-2 text-neutral-700">
235-
<span>🎵</span> Music recommendations
236-
</button>
257+
258+
<div className="space-y-4 mt-6">
259+
{/* No Login Required Section */}
260+
<div>
261+
<h4 className="text-sm font-semibold text-neutral-700 dark:text-neutral-300 mb-2 text-left">
262+
Available Functions (No Login Required):
263+
</h4>
264+
<div className="grid grid-cols-1 gap-2">
265+
<button
266+
type="button"
267+
onClick={() =>
268+
setAgentInput("Find songs similar to cruel summer")
269+
}
270+
className="text-sm p-3 bg-white/50 hover:bg-white/80 dark:bg-neutral-800/50 dark:hover:bg-neutral-800/80 rounded-xl text-left flex items-center gap-2 text-neutral-700 dark:text-neutral-300"
271+
>
272+
Find songs similar to "Cruel Summer"
273+
</button>
274+
<button
275+
type="button"
276+
onClick={() =>
277+
setAgentInput("Find artists similar to the weeknd")
278+
}
279+
className="text-sm p-3 bg-white/50 hover:bg-white/80 dark:bg-neutral-800/50 dark:hover:bg-neutral-800/80 rounded-xl text-left flex items-center gap-2 text-neutral-700 dark:text-neutral-300"
280+
>
281+
Find artists similar to The Weeknd
282+
</button>
283+
<button
284+
type="button"
285+
onClick={() =>
286+
setAgentInput("Search for Taylor Swift on Spotify")
287+
}
288+
className="text-sm p-3 bg-white/50 hover:bg-white/80 dark:bg-neutral-800/50 dark:hover:bg-neutral-800/80 rounded-xl text-left flex items-center gap-2 text-neutral-700 dark:text-neutral-300"
289+
>
290+
Search for tracks and artists
291+
</button>
292+
<button
293+
type="button"
294+
onClick={() =>
295+
setAgentInput("Get track information for a song")
296+
}
297+
className="text-sm p-3 bg-white/50 hover:bg-white/80 dark:bg-neutral-800/50 dark:hover:bg-neutral-800/80 rounded-xl text-left flex items-center gap-2 text-neutral-700 dark:text-neutral-300"
298+
>
299+
Get detailed track information
300+
</button>
301+
</div>
302+
</div>
303+
304+
{/* Login Required Section */}
305+
<div>
306+
<h4 className="text-sm font-semibold text-neutral-700 dark:text-neutral-300 mb-2 text-left">
307+
Deprecated Functions (Login Required - No Longer
308+
Available):
309+
</h4>
310+
<div className="grid grid-cols-1 gap-2">
311+
<div className="text-sm p-3 bg-white/50 dark:bg-neutral-800/50 rounded-xl text-left flex items-center gap-2 text-neutral-500 dark:text-neutral-500 opacity-60">
312+
Get your top artists and tracks
313+
</div>
314+
<div className="text-sm p-3 bg-white/50 dark:bg-neutral-800/50 rounded-xl text-left flex items-center gap-2 text-neutral-500 dark:text-neutral-500 opacity-60">
315+
Get your recently played songs
316+
</div>
317+
<div className="text-sm p-3 bg-white/50 dark:bg-neutral-800/50 rounded-xl text-left flex items-center gap-2 text-neutral-500 dark:text-neutral-500 opacity-60">
318+
Access your playlists and liked songs
319+
</div>
320+
<div className="text-sm p-3 bg-white/50 dark:bg-neutral-800/50 rounded-xl text-left flex items-center gap-2 text-neutral-500 dark:text-neutral-500 opacity-60">
321+
Create and manage playlists
322+
</div>
323+
<div className="text-sm p-3 bg-white/50 dark:bg-neutral-800/50 rounded-xl text-left flex items-center gap-2 text-neutral-500 dark:text-neutral-500 opacity-60">
324+
Generate mood-based playlists
325+
</div>
326+
<div className="text-sm p-3 bg-white/50 dark:bg-neutral-800/50 rounded-xl text-left flex items-center gap-2 text-neutral-500 dark:text-neutral-500 opacity-60">
327+
Analyze your music taste
328+
</div>
329+
</div>
330+
</div>
237331
</div>
238332
</div>
239333
</div>
@@ -245,10 +339,14 @@ export default function Chat() {
245339
index === 0 || agentMessages[index - 1]?.role !== m.role;
246340

247341
return (
248-
<div key={m.id} className={`flex ${isUser ? "justify-end" : "justify-start"} animate-in fade-in slide-in-from-bottom-2 duration-300`}>
342+
<div
343+
key={m.id}
344+
className={`flex ${isUser ? "justify-end" : "justify-start"} animate-in fade-in slide-in-from-bottom-2 duration-300`}
345+
>
249346
<div
250-
className={`flex gap-3 max-w-[85%] ${isUser ? "flex-row-reverse" : "flex-row"
251-
}`}
347+
className={`flex gap-3 max-w-[85%] ${
348+
isUser ? "flex-row-reverse" : "flex-row"
349+
}`}
252350
>
253351
{showAvatar && !isUser ? (
254352
<Avatar username={"AI"} />
@@ -263,21 +361,21 @@ export default function Chat() {
263361
// biome-ignore lint/suspicious/noArrayIndexKey: immutable index
264362
<div key={i} className="group relative">
265363
<div
266-
className={`p-4 rounded-2xl shadow-sm ${isUser
267-
? "glass-bubble-user rounded-tr-sm"
268-
: "glass-bubble-ai rounded-tl-sm"
269-
} ${part.text.startsWith("scheduled message")
364+
className={`p-4 rounded-2xl shadow-sm ${
365+
isUser
366+
? "glass-bubble-user rounded-tr-sm"
367+
: "glass-bubble-ai rounded-tl-sm"
368+
} ${
369+
part.text.startsWith("scheduled message")
270370
? "border-accent/50"
271371
: ""
272-
}`}
372+
}`}
273373
>
274-
{part.text.startsWith(
275-
"scheduled message"
276-
) && (
277-
<span className="absolute -top-3 -left-2 text-base">
278-
🕒
279-
</span>
280-
)}
374+
{part.text.startsWith("scheduled message") && (
375+
<span className="absolute -top-3 -left-2 text-base">
376+
🕒
377+
</span>
378+
)}
281379
<MemoizedMarkdown
282380
id={`${m.id}-${i}`}
283381
content={part.text.replace(
@@ -287,8 +385,9 @@ export default function Chat() {
287385
/>
288386
</div>
289387
<p
290-
className={`text-[10px] text-neutral-400 mt-1 opacity-0 group-hover:opacity-100 transition-opacity ${isUser ? "text-right" : "text-left"
291-
}`}
388+
className={`text-[10px] text-neutral-400 mt-1 opacity-0 group-hover:opacity-100 transition-opacity ${
389+
isUser ? "text-right" : "text-left"
390+
}`}
292391
>
293392
{formatTime(
294393
m.metadata?.createdAt
@@ -309,7 +408,10 @@ export default function Chat() {
309408
);
310409

311410
return (
312-
<div key={`${toolCallId}-${i}`} className="glass-bubble-ai p-2 rounded-xl">
411+
<div
412+
key={toolCallId}
413+
className="glass-bubble-ai p-2 rounded-xl"
414+
>
313415
<ToolInvocationCard
314416
toolUIPart={part}
315417
toolCallId={toolCallId}

src/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ When adding tracks to a playlist, you need to convert track IDs to URIs in the f
173173
>,
174174
stopWhen: stepCountIs(15), // Increased to allow multi-step workflows to complete (was 10)
175175
maxSteps: 15 // Enable multi-step calls so model generates text after tool execution
176+
// biome-ignore lint/suspicious/noExplicitAny: complex type inference required for streamText
176177
} as any);
177178

178179
writer.merge(result.toUIMessageStream());

src/styles.css

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@
4343

4444
/* Easings & transitions */
4545
--ease-bounce: cubic-bezier(0.2, 0, 0, 1.5);
46-
--default-transition-duration: 100ms
47-
/* snappier than default 150ms */
48-
;
46+
--default-transition-duration: 100ms /* snappier than default 150ms */;
4947

5048
/* Animation */
5149
--animate-refresh: refresh 0.5s ease-in-out infinite;
@@ -56,32 +54,20 @@
5654

5755
--color-neutral-50: oklch(0.985 0 0);
5856
--color-neutral-100: oklch(0.97 0 0);
59-
--color-neutral-150: oklch(0.96 0 0)
60-
/*new */
61-
;
57+
--color-neutral-150: oklch(0.96 0 0) /*new */;
6258
--color-neutral-200: oklch(0.922 0 0);
63-
--color-neutral-250: oklch(0.9 0 0)
64-
/* new */
65-
;
59+
--color-neutral-250: oklch(0.9 0 0) /* new */;
6660
--color-neutral-300: oklch(0.87 0 0);
6761
--color-neutral-400: oklch(0.708 0 0);
68-
--color-neutral-450: oklch(0.62 0 0)
69-
/* new */
70-
;
62+
--color-neutral-450: oklch(0.62 0 0) /* new */;
7163
--color-neutral-500: oklch(0.556 0 0);
7264
--color-neutral-600: oklch(0.439 0 0);
7365
--color-neutral-700: oklch(0.371 0 0);
74-
--color-neutral-750: oklch(0.31 0 0)
75-
/* new */
76-
;
66+
--color-neutral-750: oklch(0.31 0 0) /* new */;
7767
--color-neutral-800: oklch(0.269 0 0);
78-
--color-neutral-850: oklch(0.23 0 0)
79-
/* new */
80-
;
68+
--color-neutral-850: oklch(0.23 0 0) /* new */;
8169
--color-neutral-900: oklch(0.205 0 0);
82-
--color-neutral-925: oklch(0.175 0 0)
83-
/* new */
84-
;
70+
--color-neutral-925: oklch(0.175 0 0) /* new */;
8571
--color-neutral-950: oklch(0.145 0 0);
8672

8773
--color-red-650: oklch(0.55 0.238 27.4);
@@ -201,7 +187,6 @@
201187

202188
/* Animations */
203189
@keyframes float-slow {
204-
205190
0%,
206191
100% {
207192
transform: translateY(0px);
@@ -247,4 +232,4 @@
247232
.btn-liquid:hover {
248233
background: rgba(255, 255, 255, 0.15);
249234
}
250-
}
235+
}

0 commit comments

Comments
 (0)