Skip to content

Commit a5cc630

Browse files
add media creation engine
1 parent 94ee57b commit a5cc630

26 files changed

+722
-0
lines changed

agent/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import { autonomePlugin } from "@elizaos/plugin-autonome";
5252
import { availPlugin } from "@elizaos/plugin-avail";
5353
import { avalanchePlugin } from "@elizaos/plugin-avalanche";
5454
import { b2Plugin } from "@elizaos/plugin-b2";
55+
import { beatsfoundationPlugin } from "@elizaos/plugin-beatsfoundation";
5556
import { binancePlugin } from "@elizaos/plugin-binance";
5657
import { birdeyePlugin } from "@elizaos/plugin-birdeye";
5758
import {
@@ -945,6 +946,7 @@ export async function createAgent(
945946
? abstractPlugin
946947
: null,
947948
getSecret(character, "B2_PRIVATE_KEY") ? b2Plugin : null,
949+
getSecret(character, "BEATSFOUNDATION_API_KEY") ? beatsfoundationPlugin : null,
948950
getSecret(character, "BINANCE_API_KEY") &&
949951
getSecret(character, "BINANCE_SECRET_KEY")
950952
? binancePlugin
+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# @elizaos/plugin-beatsfoundation
2+
3+
A plugin for Eliza that enables AI music generation using the Beats Foundation API.
4+
5+
## Features
6+
- AI-powered music generation from text prompts
7+
- Support for multiple genres and moods
8+
- Optional lyrics input
9+
- Instrumental track generation
10+
- Natural language processing for music generation requests
11+
- Access to the Beats Foundation song library
12+
13+
## Installation
14+
```bash
15+
npm install @elizaos/plugin-beatsfoundation
16+
```
17+
18+
## Configuration
19+
1. Get your API key from [Beats Foundation](https://www.beatsfoundation.com)
20+
2. Set up your environment variables:
21+
```bash
22+
BEATS_FOUNDATION_API_KEY=your_api_key
23+
```
24+
3. Register the plugin in your Eliza configuration:
25+
```typescript
26+
import { BeatsFoundationPlugin } from "@elizaos/plugin-beatsfoundation";
27+
// In your Eliza configuration
28+
plugins: [
29+
new BeatsFoundationPlugin(),
30+
// ... other plugins
31+
];
32+
```
33+
34+
## Usage
35+
The plugin responds to natural language queries for music generation. Here are some examples:
36+
```plaintext
37+
"Generate a happy pop song about summer"
38+
"Create an instrumental jazz track"
39+
"Make me a rock song with these lyrics: [lyrics]"
40+
"List recent AI-generated songs"
41+
```
42+
43+
### Supported Parameters
44+
The plugin supports various music generation parameters including:
45+
- Genre (pop, rock, jazz, etc.)
46+
- Mood (happy, sad, energetic, etc.)
47+
- Lyrics (optional)
48+
- Instrumental toggle (boolean, will generate instrumental track or with vocals)
49+
- Custom prompts (up to 200 characters)
50+
51+
### Available Actions
52+
#### GENERATE_SONG
53+
Generates a new AI song based on provided parameters.
54+
```typescript
55+
// Example response format
56+
{
57+
id: "song_123",
58+
title: "Summer Vibes",
59+
audio_url: "https://...",
60+
streams: 0,
61+
upvote_count: 0,
62+
song_url: "https://...",
63+
username: "user123"
64+
}
65+
```
66+
67+
#### LIST_SONGS
68+
Retrieves a paginated list of generated songs.
69+
70+
## API Reference
71+
For detailed API documentation, visit [docs.beatsfoundation.com](https://docs.beatsfoundation.com)
72+
73+
### Environment Variables
74+
| Variable | Description | Required |
75+
| -------- | ----------- | -------- |
76+
| BEATS_FOUNDATION_API_KEY | Your Beats Foundation API key | Yes |
77+
78+
### Types
79+
```typescript
80+
interface GenerateSongRequest {
81+
prompt: string;
82+
lyrics?: string;
83+
genre?: string;
84+
mood?: string;
85+
isInstrumental?: boolean;
86+
}
87+
88+
interface Song {
89+
id: string;
90+
title: string;
91+
audio_url: string;
92+
streams: number;
93+
upvote_count: number;
94+
song_url: string;
95+
username: string;
96+
}
97+
```
98+
99+
## Error Handling
100+
The plugin includes comprehensive error handling for:
101+
- Invalid API keys
102+
- Rate limiting (2 generations per hour)
103+
- Network timeouts
104+
- Invalid generation parameters
105+
- Server errors
106+
107+
## Rate Limits
108+
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.
109+
110+
## Support
111+
For support, please:
112+
- Visit [docs.beatsfoundation.com](https://docs.beatsfoundation.com)
113+
- Open an issue in the repository
114+
- Join our Discord community
115+
116+
## Links
117+
- [Beats Foundation API Documentation](https://docs.beatsfoundation.com)
118+
- [GitHub Repository](https://github.com/elizaos/eliza/tree/main/packages/plugin-beatsfoundation)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "@elizaos/plugin-beatsfoundation",
3+
"version": "0.0.1",
4+
"description": "Beats Foundation plugin for ElizaOS",
5+
"main": "dist/index.js",
6+
"types": "dist/index.d.ts",
7+
"scripts": {
8+
"build": "tsc",
9+
"clean": "rimraf dist",
10+
"dev": "tsc -w",
11+
"lint": "eslint src --ext .ts",
12+
"test": "jest"
13+
},
14+
"dependencies": {
15+
"@elizaos/core": "workspace:*",
16+
"axios": "^1.6.7"
17+
},
18+
"devDependencies": {
19+
"@types/node": "^20.11.19",
20+
"typescript": "^5.3.3"
21+
},
22+
"peerDependencies": {
23+
"@elizaos/core": "workspace:*"
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export const createSongExamples = [
2+
{
3+
input: "Create a happy pop song about summer",
4+
output: {
5+
prompt: "Create a happy pop song about summer",
6+
genre: "pop",
7+
mood: "happy"
8+
}
9+
},
10+
{
11+
input: "Generate an instrumental jazz piece with a relaxing vibe",
12+
output: {
13+
prompt: "Generate an instrumental jazz piece with a relaxing vibe",
14+
genre: "jazz",
15+
mood: "relaxing",
16+
isInstrumental: true
17+
}
18+
},
19+
{
20+
input: "Make a rock song with these lyrics: Life is a highway, I wanna ride it all night long",
21+
output: {
22+
prompt: "Make a rock song",
23+
genre: "rock",
24+
lyrics: "Life is a highway, I wanna ride it all night long"
25+
}
26+
}
27+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import {
2+
composeContext,
3+
elizaLogger,
4+
generateObjectDeprecated,
5+
HandlerCallback,
6+
IAgentRuntime,
7+
Memory,
8+
ModelClass,
9+
State,
10+
type Action,
11+
} from "@elizaos/core";
12+
import { validateBeatsFoundationConfig } from "../../environment";
13+
import { createSongExamples } from "./examples";
14+
import { createSongService } from "./service";
15+
import { createSongTemplate } from "./template";
16+
import { CreateSongContent } from "./types";
17+
import { isCreateSongContent } from "./validation";
18+
19+
export default {
20+
name: "CREATE_SONG",
21+
similes: ["GENERATE_SONG", "MAKE_SONG", "COMPOSE_SONG"],
22+
validate: async (runtime: IAgentRuntime, _message: Memory) => {
23+
await validateBeatsFoundationConfig(runtime);
24+
return true;
25+
},
26+
description: "Create a new song using Beats Foundation",
27+
handler: async (
28+
runtime: IAgentRuntime,
29+
message: Memory,
30+
state: State,
31+
_options: { [key: string]: unknown },
32+
callback?: HandlerCallback
33+
): Promise<boolean> => {
34+
elizaLogger.log("Starting Beats Foundation CREATE_SONG handler...");
35+
36+
// Initialize or update state
37+
if (!state) {
38+
state = (await runtime.composeState(message)) as State;
39+
} else {
40+
state = await runtime.updateRecentMessageState(state);
41+
}
42+
43+
try {
44+
// Compose and generate content
45+
const context = composeContext({
46+
state,
47+
template: createSongTemplate,
48+
});
49+
50+
const content = (await generateObjectDeprecated({
51+
runtime,
52+
context,
53+
modelClass: ModelClass.SMALL,
54+
})) as unknown as CreateSongContent;
55+
56+
// Validate content
57+
if (!isCreateSongContent(content)) {
58+
throw new Error("Invalid song creation content");
59+
}
60+
61+
// Get config with validation
62+
const config = await validateBeatsFoundationConfig(runtime);
63+
const songService = createSongService(config.BEATSFOUNDATION_API_KEY);
64+
65+
try {
66+
const song = await songService.createSong(content);
67+
elizaLogger.success(
68+
`Song created successfully! Title: ${song.title}`
69+
);
70+
71+
if (callback) {
72+
callback({
73+
text: `Created new song: ${song.title}`,
74+
content: {
75+
song,
76+
request: content
77+
},
78+
});
79+
}
80+
81+
return true;
82+
} catch (error: any) {
83+
elizaLogger.error("Error in CREATE_SONG handler:", error);
84+
if (callback) {
85+
callback({
86+
text: `Error creating song: ${error.message}`,
87+
content: { error: error.message },
88+
});
89+
}
90+
return false;
91+
}
92+
} catch (error: any) {
93+
elizaLogger.error("Error in CREATE_SONG handler:", error);
94+
if (callback) {
95+
callback({
96+
text: `Error creating song: ${error.message}`,
97+
content: { error: error.message },
98+
});
99+
}
100+
return false;
101+
}
102+
},
103+
examples: createSongExamples,
104+
} as Action;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import axios from 'axios';
2+
import { Song } from '../../types';
3+
import { CreateSongContent } from './types';
4+
5+
export function createSongService(apiKey: string) {
6+
return {
7+
createSong: async (content: CreateSongContent): Promise<Song> => {
8+
try {
9+
const response = await axios.post(
10+
'https://www.beatsfoundation.com/api/songs',
11+
content,
12+
{
13+
headers: {
14+
Authorization: `Bearer ${apiKey}`,
15+
'Content-Type': 'application/json',
16+
},
17+
timeout: 300000, // 5 minutes timeout for song generation
18+
}
19+
);
20+
return response.data.song;
21+
} catch (error: any) {
22+
if (error.response) {
23+
throw new Error(`Beats Foundation API Error: ${error.response.data.error || error.response.status}`);
24+
}
25+
throw error;
26+
}
27+
}
28+
};
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export const createSongTemplate = `
2+
Given the conversation context, extract the song creation parameters.
3+
Return a JSON object with the following structure:
4+
{
5+
"prompt": string (required),
6+
"lyrics": string (optional),
7+
"genre": string (optional),
8+
"mood": string (optional),
9+
"isInstrumental": boolean (optional)
10+
}
11+
`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Content } from "@elizaos/core";
2+
3+
export interface CreateSongContent extends Content {
4+
prompt: string;
5+
lyrics?: string;
6+
genre?: string;
7+
mood?: string;
8+
isInstrumental?: boolean;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { CreateSongContent } from "./types";
2+
3+
export function isCreateSongContent(content: unknown): content is CreateSongContent {
4+
if (!content || typeof content !== "object") return false;
5+
const c = content as CreateSongContent;
6+
7+
if (typeof c.prompt !== "string" || c.prompt.length === 0) return false;
8+
if (c.lyrics !== undefined && typeof c.lyrics !== "string") return false;
9+
if (c.genre !== undefined && typeof c.genre !== "string") return false;
10+
if (c.mood !== undefined && typeof c.mood !== "string") return false;
11+
if (c.isInstrumental !== undefined && typeof c.isInstrumental !== "boolean") return false;
12+
13+
return true;
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

0 commit comments

Comments
 (0)