DEV Community

James Murdza
James Murdza

Posted on • Edited on

Making an Alexa chatbot with Tambo+Deezer ๐ŸŽถ

Today we're going to see how to start with a basic AI chatbot and add in tools and custom UI components. For this tutorial we'll add a "music search tool" and a "music miniplayer" to give a chatbot musical abilities in about ten minutes.

But first, here's quick demo:

(Link to the code: jamesmurdza/my-music-player)

1. Create a New Tambo App

We'll start by creating a new Tambo app (Tambo is an open source generative UI framework):

npx tambo create-app my-music-player
cd my-music-player
npx tambo init
Enter fullscreen mode Exit fullscreen mode

Once you have your Tambo project set up, you can delete a few of the template files from the example:

rm src/components/ui/card-data.tsx src/services/population-stats.ts
Enter fullscreen mode Exit fullscreen mode

2. Define Music Types

We'll be using the Deezer API to search for music, so let's define a few types which we'll use later.

Put these into src/lib/types.ts:

import { z } from "zod";

// This schema is used both the server function output and the props of the music card component:
export const songSchema = z.object({
    artist: z.string().describe("Artist name"),
    title : z.string().describe("Title"),
    album: z.string().describe("Album name"),
    duration: z.number().describe("Duration in seconds"),
    preview: z.string().describe("Preview URL (30 seconds)"),
    link: z.string().describe("Full song link"),
    albumCover: z.string().optional().describe("Album cover URL"),
  });

export type Song = z.infer<typeof songSchema>;

// This schema defines the server function input 
export const searchMusicInputSchema = z.object({
  query: z
    .string()
    .describe("Music search query (song title, artist name, or genre)"),
});
export type SearchMusicInput = z.infer<typeof searchMusicInputSchema>;

// This schema defines the server function input and output
export const searchMusicSchema = z.function().args(searchMusicInputSchema).returns(z.array(songSchema));
Enter fullscreen mode Exit fullscreen mode

3. Create a Music Search Service

Now, let's define a NextJS server function to query the Deezer API. We'll use this later as a tool for the chatbot.

Save this to src/services/music-search.ts:

"use server";

import { SearchMusicInput, Song } from "@/lib/types";

export async function searchMusic({ query }: SearchMusicInput): Promise<Song[]> {
  const response = await fetch(
    `https://api.deezer.com/search?q=${encodeURIComponent(query)}&limit=10`
  );
  const data = await response.json();
  if (data.error) throw new Error(data.error);
  // Map Deezer API results to MusicSearchResult type
  return (data.data || []).map((item: any) => ({
    ...item,
    artist: item.artist?.name || "",
    album: item.album?.title || "",
    albumCover: item.album?.cover || ""
  }));
}
Enter fullscreen mode Exit fullscreen mode

Note that we are using the same types which we defined in step 2.


4. Build the Music Miniplayer Component

For the next step, we'll design a music miniplayer React Component that looks something like this:

Put this in src/components/ui/music-card.tsx:

import { z } from "zod";
import { useState, useEffect, useRef } from "react";

import { songSchema } from "@/lib/types";
export type MusicCardProps = z.infer<typeof songSchema>;

export function MusicCard({
  title,
  artist,
  album,
  preview,
  link,
  albumCover,
}: MusicCardProps) {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

You can find the full code for this component here. Note that again, we are using the types from step 2.


5. Register Tools and Components with Tambo

The final step is to integrate both our music search tool and our miniplayer component into the AI chat template. That can be done simply by registering these elements (and their type definitions) with Tambo.

To do that, replace the entire contents of src/lib/tambo.ts with this code:

"use client";

// Central configuration file for Tambo components and tools
// Read more about Tambo at https://tambo.co/docs

import { TamboComponent, TamboTool } from "@tambo-ai/react";

import { MusicCard } from "@/components/ui/music-card";
import { searchMusic } from "@/services/music-search";
import { songSchema, searchMusicSchema } from "@/lib/types";

// Tambo tools registered for AI use.
export const tools: TamboTool[] = [
  {
    name: "searchMusic",
    description:
      "Searches for music by song title, artist name, or any music-related query.",
    tool: searchMusic,
    toolSchema: searchMusicSchema,
  },
];

// Tambo components registered for AI use.
export const components: TamboComponent[] = [
  {
    name: "MusicCard",
    description: "A component that plays a song from Deezer.",
    component: MusicCard,
    propsSchema: songSchema,
  },
];
Enter fullscreen mode Exit fullscreen mode

Conclusion

That's it! Your app should work now (or let me know ๐Ÿ˜‰). There's a lot more that can be added, such as a loading state for the miniplayer component and any additional tools or components you can think of.

Join the Tambo Discord to see more projects you can build with Tambo!

Top comments (1)

Collapse
 
michaelmagan profile image
michael magan

James, this is such a cool use of tambo! Thanks for sharing it.