diff --git a/agent/src/index.ts b/agent/src/index.ts index eb696999c3c..cb4ad207c61 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -56,6 +56,7 @@ import { autonomePlugin } from "@elizaos/plugin-autonome"; import { availPlugin } from "@elizaos/plugin-avail"; import { avalanchePlugin } from "@elizaos/plugin-avalanche"; import { b2Plugin } from "@elizaos/plugin-b2"; +import { beatsfoundationPlugin } from "@elizaos/plugin-beatsfoundation"; import { binancePlugin } from "@elizaos/plugin-binance"; import { birdeyePlugin } from "@elizaos/plugin-birdeye"; import { @@ -1003,6 +1004,7 @@ export async function createAgent( ? abstractPlugin : null, getSecret(character, "B2_PRIVATE_KEY") ? b2Plugin : null, + getSecret(character, "BEATSFOUNDATION_API_KEY") ? beatsfoundationPlugin : null, getSecret(character, "BINANCE_API_KEY") && getSecret(character, "BINANCE_SECRET_KEY") ? binancePlugin diff --git a/packages/plugin-beatsfoundation/README.md b/packages/plugin-beatsfoundation/README.md new file mode 100644 index 00000000000..cfc6b979336 --- /dev/null +++ b/packages/plugin-beatsfoundation/README.md @@ -0,0 +1,118 @@ +# @elizaos/plugin-beatsfoundation + +A plugin for Eliza that enables AI music generation using the Beats Foundation API. + +## Features +- AI-powered music generation from text prompts +- Support for multiple genres and moods +- Optional lyrics input +- Instrumental track generation +- Natural language processing for music generation requests +- Access to the Beats Foundation song library + +## Installation +```bash +npm install @elizaos/plugin-beatsfoundation +``` + +## Configuration +1. Get your API key from [Beats Foundation](https://www.beatsfoundation.com) +2. Set up your environment variables: +```bash +BEATS_FOUNDATION_API_KEY=your_api_key +``` +3. Register the plugin in your Eliza configuration: +```typescript +import { BeatsFoundationPlugin } from "@elizaos/plugin-beatsfoundation"; +// In your Eliza configuration +plugins: [ + new BeatsFoundationPlugin(), + // ... other plugins +]; +``` + +## Usage +The plugin responds to natural language queries for music generation. Here are some examples: +```plaintext +"Generate a happy pop song about summer" +"Create an instrumental jazz track" +"Make me a rock song with these lyrics: [lyrics]" +"List recent AI-generated songs" +``` + +### Supported Parameters +The plugin supports various music generation parameters including: +- Genre (pop, rock, jazz, etc.) +- Mood (happy, sad, energetic, etc.) +- Lyrics (optional) +- Instrumental toggle (boolean, will generate instrumental track or with vocals) +- Custom prompts (up to 200 characters) + +### Available Actions +#### GENERATE_SONG +Generates a new AI song based on provided parameters. +```typescript +// Example response format +{ + id: "song_123", + title: "Summer Vibes", + audio_url: "https://...", + streams: 0, + upvote_count: 0, + song_url: "https://...", + username: "user123" +} +``` + +#### LIST_SONGS +Retrieves a paginated list of generated songs. + +## API Reference +For detailed API documentation, visit [docs.beatsfoundation.com](https://docs.beatsfoundation.com) + +### Environment Variables +| Variable | Description | Required | +| -------- | ----------- | -------- | +| BEATS_FOUNDATION_API_KEY | Your Beats Foundation API key | Yes | + +### Types +```typescript +interface GenerateSongRequest { + prompt: string; + lyrics?: string; + genre?: string; + mood?: string; + isInstrumental?: boolean; +} + +interface Song { + id: string; + title: string; + audio_url: string; + streams: number; + upvote_count: number; + song_url: string; + username: string; +} +``` + +## Error Handling +The plugin includes comprehensive error handling for: +- Invalid API keys +- Rate limiting (2 generations per hour) +- Network timeouts +- Invalid generation parameters +- Server errors + +## Rate Limits +The Beats Foundation API is currently free to use and has a rate limit of 2 song generations per hour per API key. Public endpoints like song listing and retrieval are not rate limited. + +## Support +For support, please: +- Visit [docs.beatsfoundation.com](https://docs.beatsfoundation.com) +- Open an issue in the repository +- Join our Discord community + +## Links +- [Beats Foundation API Documentation](https://docs.beatsfoundation.com) +- [GitHub Repository](https://github.com/elizaos/eliza/tree/main/packages/plugin-beatsfoundation) diff --git a/packages/plugin-beatsfoundation/package.json b/packages/plugin-beatsfoundation/package.json new file mode 100644 index 00000000000..c4bad16a881 --- /dev/null +++ b/packages/plugin-beatsfoundation/package.json @@ -0,0 +1,25 @@ +{ + "name": "@elizaos/plugin-beatsfoundation", + "version": "0.0.1", + "description": "Beats Foundation plugin for ElizaOS", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "clean": "rimraf dist", + "dev": "tsc -w", + "lint": "eslint src --ext .ts", + "test": "jest" + }, + "dependencies": { + "@elizaos/core": "workspace:*", + "axios": "^1.6.7" + }, + "devDependencies": { + "@types/node": "^20.11.19", + "typescript": "^5.3.3" + }, + "peerDependencies": { + "@elizaos/core": "workspace:*" + } +} \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/CreateSong/examples.ts b/packages/plugin-beatsfoundation/src/actions/CreateSong/examples.ts new file mode 100644 index 00000000000..2d30a7fc76f --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/CreateSong/examples.ts @@ -0,0 +1,27 @@ +export const createSongExamples = [ + { + input: "Create a happy pop song about summer", + output: { + prompt: "Create a happy pop song about summer", + genre: "pop", + mood: "happy" + } + }, + { + input: "Generate an instrumental jazz piece with a relaxing vibe", + output: { + prompt: "Generate an instrumental jazz piece with a relaxing vibe", + genre: "jazz", + mood: "relaxing", + isInstrumental: true + } + }, + { + input: "Make a rock song with these lyrics: Life is a highway, I wanna ride it all night long", + output: { + prompt: "Make a rock song", + genre: "rock", + lyrics: "Life is a highway, I wanna ride it all night long" + } + } +]; \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/CreateSong/index.ts b/packages/plugin-beatsfoundation/src/actions/CreateSong/index.ts new file mode 100644 index 00000000000..7d7378a6fdd --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/CreateSong/index.ts @@ -0,0 +1,104 @@ +import { + composeContext, + elizaLogger, + generateObjectDeprecated, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, + type Action, +} from "@elizaos/core"; +import { validateBeatsFoundationConfig } from "../../environment"; +import { createSongExamples } from "./examples"; +import { createSongService } from "./service"; +import { createSongTemplate } from "./template"; +import { CreateSongContent } from "./types"; +import { isCreateSongContent } from "./validation"; + +export default { + name: "CREATE_SONG", + similes: ["GENERATE_SONG", "MAKE_SONG", "COMPOSE_SONG"], + validate: async (runtime: IAgentRuntime, _message: Memory) => { + await validateBeatsFoundationConfig(runtime); + return true; + }, + description: "Create a new song using Beats Foundation", + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + _options: { [key: string]: unknown }, + callback?: HandlerCallback + ): Promise => { + elizaLogger.log("Starting Beats Foundation CREATE_SONG handler..."); + + // Initialize or update state + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + try { + // Compose and generate content + const context = composeContext({ + state, + template: createSongTemplate, + }); + + const content = (await generateObjectDeprecated({ + runtime, + context, + modelClass: ModelClass.SMALL, + })) as unknown as CreateSongContent; + + // Validate content + if (!isCreateSongContent(content)) { + throw new Error("Invalid song creation content"); + } + + // Get config with validation + const config = await validateBeatsFoundationConfig(runtime); + const songService = createSongService(config.BEATSFOUNDATION_API_KEY); + + try { + const song = await songService.createSong(content); + elizaLogger.success( + `Song created successfully! Title: ${song.title}` + ); + + if (callback) { + callback({ + text: `Created new song: ${song.title}`, + content: { + song, + request: content + }, + }); + } + + return true; + } catch (error: any) { + elizaLogger.error("Error in CREATE_SONG handler:", error); + if (callback) { + callback({ + text: `Error creating song: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + } catch (error: any) { + elizaLogger.error("Error in CREATE_SONG handler:", error); + if (callback) { + callback({ + text: `Error creating song: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + }, + examples: createSongExamples, +} as Action; \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/CreateSong/service.ts b/packages/plugin-beatsfoundation/src/actions/CreateSong/service.ts new file mode 100644 index 00000000000..f6718a07f64 --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/CreateSong/service.ts @@ -0,0 +1,29 @@ +import axios from 'axios'; +import { Song } from '../../types'; +import { CreateSongContent } from './types'; + +export function createSongService(apiKey: string) { + return { + createSong: async (content: CreateSongContent): Promise => { + try { + const response = await axios.post( + 'https://www.beatsfoundation.com/api/songs', + content, + { + headers: { + Authorization: `Bearer ${apiKey}`, + 'Content-Type': 'application/json', + }, + timeout: 300000, // 5 minutes timeout for song generation + } + ); + return response.data.song; + } catch (error: any) { + if (error.response) { + throw new Error(`Beats Foundation API Error: ${error.response.data.error || error.response.status}`); + } + throw error; + } + } + }; +} \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/CreateSong/template.ts b/packages/plugin-beatsfoundation/src/actions/CreateSong/template.ts new file mode 100644 index 00000000000..fa06c8f69d0 --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/CreateSong/template.ts @@ -0,0 +1,11 @@ +export const createSongTemplate = ` +Given the conversation context, extract the song creation parameters. +Return a JSON object with the following structure: +{ + "prompt": string (required), + "lyrics": string (optional), + "genre": string (optional), + "mood": string (optional), + "isInstrumental": boolean (optional) +} +`; \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/CreateSong/types.ts b/packages/plugin-beatsfoundation/src/actions/CreateSong/types.ts new file mode 100644 index 00000000000..2fa33fda631 --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/CreateSong/types.ts @@ -0,0 +1,9 @@ +import { Content } from "@elizaos/core"; + +export interface CreateSongContent extends Content { + prompt: string; + lyrics?: string; + genre?: string; + mood?: string; + isInstrumental?: boolean; +} \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/CreateSong/validation.ts b/packages/plugin-beatsfoundation/src/actions/CreateSong/validation.ts new file mode 100644 index 00000000000..49db51db53b --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/CreateSong/validation.ts @@ -0,0 +1,14 @@ +import { CreateSongContent } from "./types"; + +export function isCreateSongContent(content: unknown): content is CreateSongContent { + if (!content || typeof content !== "object") return false; + const c = content as CreateSongContent; + + if (typeof c.prompt !== "string" || c.prompt.length === 0) return false; + if (c.lyrics !== undefined && typeof c.lyrics !== "string") return false; + if (c.genre !== undefined && typeof c.genre !== "string") return false; + if (c.mood !== undefined && typeof c.mood !== "string") return false; + if (c.isInstrumental !== undefined && typeof c.isInstrumental !== "boolean") return false; + + return true; +} \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongById/examples.ts b/packages/plugin-beatsfoundation/src/actions/GetSongById/examples.ts new file mode 100644 index 00000000000..0519ecba6ea --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongById/examples.ts @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongById/index.ts b/packages/plugin-beatsfoundation/src/actions/GetSongById/index.ts new file mode 100644 index 00000000000..852d63a00d9 --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongById/index.ts @@ -0,0 +1,101 @@ +import { + composeContext, + elizaLogger, + generateObjectDeprecated, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, + type Action, +} from "@elizaos/core"; +import { validateBeatsFoundationConfig } from "../../environment"; +import { getSongByIdExamples } from "./examples"; +import { createSongService } from "./service"; +import { getSongByIdTemplate } from "./template"; +import { GetSongByIdContent } from "./types"; +import { isGetSongByIdContent } from "./validation"; + +export default { + name: "GET_SONG_BY_ID", + similes: ["FETCH_SONG", "GET_SONG", "RETRIEVE_SONG"], + validate: async (runtime: IAgentRuntime, _message: Memory) => { + await validateBeatsFoundationConfig(runtime); + return true; + }, + description: "Get a song by its ID from Beats Foundation", + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + _options: { [key: string]: unknown }, + callback?: HandlerCallback + ): Promise => { + elizaLogger.log("Starting Beats Foundation GET_SONG_BY_ID handler..."); + + // Initialize or update state + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + try { + // Compose and generate content + const context = composeContext({ + state, + template: getSongByIdTemplate, + }); + + const content = (await generateObjectDeprecated({ + runtime, + context, + modelClass: ModelClass.SMALL, + })) as unknown as GetSongByIdContent; + + // Validate content + if (!isGetSongByIdContent(content)) { + throw new Error("Invalid song ID content"); + } + + // Get config with validation + const config = await validateBeatsFoundationConfig(runtime); + const songService = createSongService(config.BEATSFOUNDATION_API_KEY); + + try { + const song = await songService.getSongById(content.songId); + elizaLogger.success( + `Song retrieved successfully! ID: ${content.songId}, Title: ${song.title}` + ); + + if (callback) { + callback({ + text: `Retrieved song: ${song.title}`, + content: song, + }); + } + + return true; + } catch (error: any) { + elizaLogger.error("Error in GET_SONG_BY_ID handler:", error); + if (callback) { + callback({ + text: `Error fetching song: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + } catch (error: any) { + elizaLogger.error("Error in GET_SONG_BY_ID handler:", error); + if (callback) { + callback({ + text: `Error fetching song: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + }, + examples: getSongByIdExamples, +} as Action; \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongById/service.ts b/packages/plugin-beatsfoundation/src/actions/GetSongById/service.ts new file mode 100644 index 00000000000..0519ecba6ea --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongById/service.ts @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongById/template.ts b/packages/plugin-beatsfoundation/src/actions/GetSongById/template.ts new file mode 100644 index 00000000000..0519ecba6ea --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongById/template.ts @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongById/types.ts b/packages/plugin-beatsfoundation/src/actions/GetSongById/types.ts new file mode 100644 index 00000000000..0519ecba6ea --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongById/types.ts @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongById/validation.ts b/packages/plugin-beatsfoundation/src/actions/GetSongById/validation.ts new file mode 100644 index 00000000000..0519ecba6ea --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongById/validation.ts @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongs/examples.ts b/packages/plugin-beatsfoundation/src/actions/GetSongs/examples.ts new file mode 100644 index 00000000000..ac7da8cbf40 --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongs/examples.ts @@ -0,0 +1,19 @@ +export const getSongsExamples = [ + { + input: "Show me all songs", + output: {} + }, + { + input: "Get the first 10 songs", + output: { + limit: 10 + } + }, + { + input: "Show me the next 20 songs starting from position 40", + output: { + limit: 20, + offset: 40 + } + } +]; \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongs/index.ts b/packages/plugin-beatsfoundation/src/actions/GetSongs/index.ts new file mode 100644 index 00000000000..dba62b6be05 --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongs/index.ts @@ -0,0 +1,107 @@ +import { + composeContext, + elizaLogger, + generateObjectDeprecated, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, + type Action, +} from "@elizaos/core"; +import { validateBeatsFoundationConfig } from "../../environment"; +import { getSongsExamples } from "./examples"; +import { createSongsService } from "./service"; +import { getSongsTemplate } from "./template"; +import { GetSongsContent } from "./types"; +import { isGetSongsContent } from "./validation"; + +export default { + name: "GET_SONGS", + similes: ["LIST_SONGS", "FETCH_SONGS", "SHOW_SONGS"], + validate: async (runtime: IAgentRuntime, _message: Memory) => { + await validateBeatsFoundationConfig(runtime); + return true; + }, + description: "Get a list of songs from Beats Foundation", + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + _options: { [key: string]: unknown }, + callback?: HandlerCallback + ): Promise => { + elizaLogger.log("Starting Beats Foundation GET_SONGS handler..."); + + // Initialize or update state + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + try { + // Compose and generate content + const context = composeContext({ + state, + template: getSongsTemplate, + }); + + const content = (await generateObjectDeprecated({ + runtime, + context, + modelClass: ModelClass.SMALL, + })) as unknown as GetSongsContent; + + // Validate content + if (!isGetSongsContent(content)) { + throw new Error("Invalid songs content"); + } + + // Get config with validation + const config = await validateBeatsFoundationConfig(runtime); + const songsService = createSongsService(config.BEATSFOUNDATION_API_KEY); + + try { + const songs = await songsService.getSongs(content.limit, content.offset); + elizaLogger.success( + `Songs retrieved successfully! Count: ${songs.length}` + ); + + if (callback) { + callback({ + text: `Retrieved ${songs.length} songs`, + content: { + songs, + pagination: { + limit: content.limit, + offset: content.offset + } + }, + }); + } + + return true; + } catch (error: any) { + elizaLogger.error("Error in GET_SONGS handler:", error); + if (callback) { + callback({ + text: `Error fetching songs: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + } catch (error: any) { + elizaLogger.error("Error in GET_SONGS handler:", error); + if (callback) { + callback({ + text: `Error fetching songs: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + }, + examples: getSongsExamples, +} as Action; \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongs/service.ts b/packages/plugin-beatsfoundation/src/actions/GetSongs/service.ts new file mode 100644 index 00000000000..ec739b0baef --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongs/service.ts @@ -0,0 +1,31 @@ +import axios from 'axios'; +import { Song } from '../../types'; + +export function createSongsService(apiKey: string) { + return { + getSongs: async (limit?: number, offset?: number): Promise => { + try { + const params: Record = {}; + if (limit !== undefined) params.limit = limit; + if (offset !== undefined) params.offset = offset; + + const response = await axios.get( + 'https://www.beatsfoundation.com/api/songs', + { + params, + headers: { + Authorization: `Bearer ${apiKey}`, + 'Content-Type': 'application/json', + }, + } + ); + return response.data.songs; + } catch (error: any) { + if (error.response) { + throw new Error(`Beats Foundation API Error: ${error.response.data.error || error.response.status}`); + } + throw error; + } + } + }; +} \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongs/template.ts b/packages/plugin-beatsfoundation/src/actions/GetSongs/template.ts new file mode 100644 index 00000000000..fdad32eaaf8 --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongs/template.ts @@ -0,0 +1,8 @@ +export const getSongsTemplate = ` +Given the conversation context, extract any pagination parameters for retrieving songs. +Return a JSON object with the following optional structure: +{ + "limit": number (optional), + "offset": number (optional) +} +`; \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongs/types.ts b/packages/plugin-beatsfoundation/src/actions/GetSongs/types.ts new file mode 100644 index 00000000000..d522c519804 --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongs/types.ts @@ -0,0 +1,6 @@ +import { Content } from "@elizaos/core"; + +export interface GetSongsContent extends Content { + limit?: number; + offset?: number; +} \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/actions/GetSongs/validation.ts b/packages/plugin-beatsfoundation/src/actions/GetSongs/validation.ts new file mode 100644 index 00000000000..f65ad552c9d --- /dev/null +++ b/packages/plugin-beatsfoundation/src/actions/GetSongs/validation.ts @@ -0,0 +1,11 @@ +import { GetSongsContent } from "./types"; + +export function isGetSongsContent(content: unknown): content is GetSongsContent { + if (!content || typeof content !== "object") return false; + const c = content as GetSongsContent; + + if (c.limit !== undefined && (typeof c.limit !== "number" || c.limit < 0)) return false; + if (c.offset !== undefined && (typeof c.offset !== "number" || c.offset < 0)) return false; + + return true; +} \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/environment.ts b/packages/plugin-beatsfoundation/src/environment.ts new file mode 100644 index 00000000000..7197778c2f6 --- /dev/null +++ b/packages/plugin-beatsfoundation/src/environment.ts @@ -0,0 +1,33 @@ +import { IAgentRuntime } from "@elizaos/core"; +import { z } from "zod"; + +export const beatsFoundationEnvSchema = z.object({ + BEATSFOUNDATION_API_KEY: z + .string() + .min(1, "BeatsFoundation API key is required"), +}); + +export type BeatsFoundationConfig = z.infer; + +export async function validateBeatsFoundationConfig( + runtime: IAgentRuntime +): Promise { + try { + const config = { + BEATSFOUNDATION_API_KEY: runtime.getSetting("BEATSFOUNDATION_API_KEY"), + }; + + return beatsFoundationEnvSchema.parse(config); + } catch (error) { + if (error instanceof z.ZodError) { + const errorMessages = error.errors + .map((err) => `${err.path.join(".")}: ${err.message}`) + .join("\n"); + throw new Error( + `Beats Foundation configuration validation failed:\n${errorMessages}` + ); + } + throw error; + } +} + diff --git a/packages/plugin-beatsfoundation/src/index.ts b/packages/plugin-beatsfoundation/src/index.ts new file mode 100644 index 00000000000..46157f262af --- /dev/null +++ b/packages/plugin-beatsfoundation/src/index.ts @@ -0,0 +1,15 @@ +import { Plugin } from "@elizaos/core"; +import GetSongById from './actions/GetSongById'; +import GetSongs from './actions/GetSongs'; +import CreateSong from './actions/CreateSong'; + +export const beatsfoundationPlugin: Plugin = { + name: 'beatsfoundation', + description: 'Beats Foundation plugin for ElizaOS', + clients: [], + actions: [GetSongById, GetSongs, CreateSong], + services: [], + providers: [], +}; + +export default beatsfoundationPlugin; \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/src/types.ts b/packages/plugin-beatsfoundation/src/types.ts new file mode 100644 index 00000000000..34b6827cb5f --- /dev/null +++ b/packages/plugin-beatsfoundation/src/types.ts @@ -0,0 +1,17 @@ +export interface GenerateSongRequest { + prompt: string; + lyrics?: string; + genre?: string; + mood?: string; + isInstrumental?: boolean; +} + +export interface Song { + id: string; + title: string; + audio_url: string; + streams: number; + upvote_count: number; + song_url: string; + username: string; +} \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/tsconfig.json b/packages/plugin-beatsfoundation/tsconfig.json new file mode 100644 index 00000000000..73993deaaf7 --- /dev/null +++ b/packages/plugin-beatsfoundation/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": [ + "src/**/*.ts" + ] +} \ No newline at end of file diff --git a/packages/plugin-beatsfoundation/tsup.config.ts b/packages/plugin-beatsfoundation/tsup.config.ts new file mode 100644 index 00000000000..ba44a7c49cf --- /dev/null +++ b/packages/plugin-beatsfoundation/tsup.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], + external: [ + "dotenv", + "fs", + "path", + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + ], +}); +