chibi-bot 1.6.0b0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chibi/__init__.py +0 -0
- chibi/__main__.py +343 -0
- chibi/cli.py +90 -0
- chibi/config/__init__.py +6 -0
- chibi/config/app.py +123 -0
- chibi/config/gpt.py +108 -0
- chibi/config/logging.py +15 -0
- chibi/config/telegram.py +43 -0
- chibi/config_generator.py +233 -0
- chibi/constants.py +362 -0
- chibi/exceptions.py +58 -0
- chibi/models.py +496 -0
- chibi/schemas/__init__.py +0 -0
- chibi/schemas/anthropic.py +20 -0
- chibi/schemas/app.py +54 -0
- chibi/schemas/cloudflare.py +65 -0
- chibi/schemas/mistralai.py +56 -0
- chibi/schemas/suno.py +83 -0
- chibi/service.py +135 -0
- chibi/services/bot.py +276 -0
- chibi/services/lock_manager.py +20 -0
- chibi/services/mcp/manager.py +242 -0
- chibi/services/metrics.py +54 -0
- chibi/services/providers/__init__.py +16 -0
- chibi/services/providers/alibaba.py +79 -0
- chibi/services/providers/anthropic.py +40 -0
- chibi/services/providers/cloudflare.py +98 -0
- chibi/services/providers/constants/suno.py +2 -0
- chibi/services/providers/customopenai.py +11 -0
- chibi/services/providers/deepseek.py +15 -0
- chibi/services/providers/eleven_labs.py +85 -0
- chibi/services/providers/gemini_native.py +489 -0
- chibi/services/providers/grok.py +40 -0
- chibi/services/providers/minimax.py +96 -0
- chibi/services/providers/mistralai_native.py +312 -0
- chibi/services/providers/moonshotai.py +20 -0
- chibi/services/providers/openai.py +74 -0
- chibi/services/providers/provider.py +892 -0
- chibi/services/providers/suno.py +130 -0
- chibi/services/providers/tools/__init__.py +23 -0
- chibi/services/providers/tools/cmd.py +132 -0
- chibi/services/providers/tools/common.py +127 -0
- chibi/services/providers/tools/constants.py +78 -0
- chibi/services/providers/tools/exceptions.py +1 -0
- chibi/services/providers/tools/file_editor.py +875 -0
- chibi/services/providers/tools/mcp_management.py +274 -0
- chibi/services/providers/tools/mcp_simple.py +72 -0
- chibi/services/providers/tools/media.py +451 -0
- chibi/services/providers/tools/memory.py +252 -0
- chibi/services/providers/tools/schemas.py +10 -0
- chibi/services/providers/tools/send.py +435 -0
- chibi/services/providers/tools/tool.py +163 -0
- chibi/services/providers/tools/utils.py +146 -0
- chibi/services/providers/tools/web.py +261 -0
- chibi/services/providers/utils.py +182 -0
- chibi/services/task_manager.py +93 -0
- chibi/services/user.py +269 -0
- chibi/storage/abstract.py +54 -0
- chibi/storage/database.py +86 -0
- chibi/storage/dynamodb.py +257 -0
- chibi/storage/local.py +70 -0
- chibi/storage/redis.py +91 -0
- chibi/utils/__init__.py +0 -0
- chibi/utils/app.py +249 -0
- chibi/utils/telegram.py +521 -0
- chibi_bot-1.6.0b0.dist-info/LICENSE +21 -0
- chibi_bot-1.6.0b0.dist-info/METADATA +340 -0
- chibi_bot-1.6.0b0.dist-info/RECORD +70 -0
- chibi_bot-1.6.0b0.dist-info/WHEEL +4 -0
- chibi_bot-1.6.0b0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
from asyncio import sleep
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Optional, Unpack
|
|
3
|
+
|
|
4
|
+
from loguru import logger
|
|
5
|
+
from openai.types.chat import ChatCompletionToolParam
|
|
6
|
+
from openai.types.shared_params import FunctionDefinition
|
|
7
|
+
from telegram import Update
|
|
8
|
+
from telegram.ext import ContextTypes
|
|
9
|
+
|
|
10
|
+
from chibi.config import gpt_settings, telegram_settings
|
|
11
|
+
from chibi.constants import AUDIO_UPLOAD_TIMEOUT
|
|
12
|
+
from chibi.schemas.app import ModelChangeSchema
|
|
13
|
+
from chibi.services.providers.constants.suno import POLLING_ATTEMPTS_WAIT_BETWEEN
|
|
14
|
+
from chibi.services.providers.tools.exceptions import ToolException
|
|
15
|
+
from chibi.services.providers.tools.tool import ChibiTool
|
|
16
|
+
from chibi.services.providers.tools.utils import AdditionalOptions, download
|
|
17
|
+
from chibi.services.user import generate_image, get_chibi_user, user_has_reached_images_generation_limit
|
|
18
|
+
from chibi.utils.telegram import get_telegram_chat
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from chibi.services.providers import Suno
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TextToSpeechTool(ChibiTool):
|
|
25
|
+
register = bool(gpt_settings.openai_key)
|
|
26
|
+
run_in_background_by_default = True
|
|
27
|
+
definition = ChatCompletionToolParam(
|
|
28
|
+
type="function",
|
|
29
|
+
function=FunctionDefinition(
|
|
30
|
+
name="text_to_speech",
|
|
31
|
+
description=(
|
|
32
|
+
"Send an audio file with speech to user. Use it when user ask you or sending you voice messages."
|
|
33
|
+
),
|
|
34
|
+
parameters={
|
|
35
|
+
"type": "object",
|
|
36
|
+
"properties": {
|
|
37
|
+
"text": {"type": "string", "description": "Text to speech"},
|
|
38
|
+
},
|
|
39
|
+
"required": ["text"],
|
|
40
|
+
},
|
|
41
|
+
),
|
|
42
|
+
)
|
|
43
|
+
name = "text_to_speech"
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
async def function(cls, text: str, **kwargs: Unpack[AdditionalOptions]) -> dict[str, str]:
|
|
47
|
+
user_id = kwargs.get("user_id")
|
|
48
|
+
if not user_id:
|
|
49
|
+
raise ToolException("This function requires user_id to be automatically provided.")
|
|
50
|
+
|
|
51
|
+
telegram_context = kwargs.get("telegram_context")
|
|
52
|
+
telegram_update = kwargs.get("telegram_update")
|
|
53
|
+
|
|
54
|
+
if telegram_context is None or telegram_update is None:
|
|
55
|
+
raise ToolException(
|
|
56
|
+
"This function requires telegram context & telegram update to be automatically provided."
|
|
57
|
+
)
|
|
58
|
+
logger.log("TOOL", "Sending voice message to user...")
|
|
59
|
+
|
|
60
|
+
user = await get_chibi_user(user_id=user_id)
|
|
61
|
+
provider = user.tts_provider
|
|
62
|
+
audio_data = await provider.speech(text=text)
|
|
63
|
+
title = f"{text[:15]}..."
|
|
64
|
+
await telegram_context.bot.send_audio(
|
|
65
|
+
chat_id=get_telegram_chat(update=telegram_update).id,
|
|
66
|
+
audio=audio_data,
|
|
67
|
+
title=title,
|
|
68
|
+
performer=f"{telegram_settings.bot_name} AI",
|
|
69
|
+
filename=f"{title.replace(' ', '_')}.mp3",
|
|
70
|
+
parse_mode="HTML",
|
|
71
|
+
read_timeout=AUDIO_UPLOAD_TIMEOUT,
|
|
72
|
+
write_timeout=AUDIO_UPLOAD_TIMEOUT,
|
|
73
|
+
)
|
|
74
|
+
return {"detail": "Audio was successfully sent."}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class GetAvailableImageModelsTool(ChibiTool):
|
|
78
|
+
register = True
|
|
79
|
+
definition = ChatCompletionToolParam(
|
|
80
|
+
type="function",
|
|
81
|
+
function=FunctionDefinition(
|
|
82
|
+
name="get_available_image_generation_models",
|
|
83
|
+
description=("Get models and providers available for user for image generation."),
|
|
84
|
+
parameters={
|
|
85
|
+
"type": "object",
|
|
86
|
+
"properties": {},
|
|
87
|
+
"required": [],
|
|
88
|
+
},
|
|
89
|
+
),
|
|
90
|
+
)
|
|
91
|
+
name = "get_available_image_generation_models"
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
async def function(cls, **kwargs: Unpack[AdditionalOptions]) -> dict[str, Any]:
|
|
95
|
+
user_id = kwargs.get("user_id")
|
|
96
|
+
if not user_id:
|
|
97
|
+
raise ToolException("This function requires user_id to be automatically provided.")
|
|
98
|
+
|
|
99
|
+
logger.log("TOOL", f"Getting available image generation models for user {user_id}...")
|
|
100
|
+
|
|
101
|
+
from chibi.services.user import get_models_available
|
|
102
|
+
|
|
103
|
+
data: list[ModelChangeSchema] = await get_models_available(user_id=user_id, image_generation=True)
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
"available_models": [info.model_dump(include={"provider", "name", "display_name"}) for info in data],
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class GenerateImageTool(ChibiTool):
|
|
111
|
+
register = True
|
|
112
|
+
run_in_background_by_default = True
|
|
113
|
+
allow_model_to_change_background_mode = False
|
|
114
|
+
definition = ChatCompletionToolParam(
|
|
115
|
+
type="function",
|
|
116
|
+
function=FunctionDefinition(
|
|
117
|
+
name="generate_image",
|
|
118
|
+
description=(
|
|
119
|
+
"Generate image using one of the available models. You won’t see the image itself, only a message "
|
|
120
|
+
"about whether the operation was successful or not. Check available providers and models first. "
|
|
121
|
+
"Use your knowledge to adapt the prompt for a specific model to achieve the best result. "
|
|
122
|
+
f"The aspect ratio ({gpt_settings.image_aspect_ratio}), size, and image quality are set globally "
|
|
123
|
+
f"and cannot be changed via the prompt"
|
|
124
|
+
),
|
|
125
|
+
parameters={
|
|
126
|
+
"type": "object",
|
|
127
|
+
"properties": {
|
|
128
|
+
"provider": {"type": "string", "description": "Provider name, i.e. 'Gemini'"},
|
|
129
|
+
"image_model": {"type": "string", "description": "Model name, i.e. 'dall-e-3'"},
|
|
130
|
+
"prompt": {"type": "string", "description": "Image generation prompt. English recommended"},
|
|
131
|
+
},
|
|
132
|
+
"required": ["provider", "image_model", "prompt"],
|
|
133
|
+
},
|
|
134
|
+
),
|
|
135
|
+
)
|
|
136
|
+
name = "generate_image"
|
|
137
|
+
|
|
138
|
+
@classmethod
|
|
139
|
+
async def generate_and_send_image(
|
|
140
|
+
cls,
|
|
141
|
+
user_id: int,
|
|
142
|
+
provider: str,
|
|
143
|
+
model: str,
|
|
144
|
+
prompt: str,
|
|
145
|
+
update: Update,
|
|
146
|
+
context: ContextTypes.DEFAULT_TYPE,
|
|
147
|
+
) -> None:
|
|
148
|
+
from chibi.utils.telegram import send_images
|
|
149
|
+
|
|
150
|
+
images = await generate_image(user_id=user_id, provider_name=provider, model=model, prompt=prompt)
|
|
151
|
+
await send_images(images=images, update=update, context=context)
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
@classmethod
|
|
155
|
+
async def function(
|
|
156
|
+
cls,
|
|
157
|
+
provider: str,
|
|
158
|
+
image_model: str,
|
|
159
|
+
prompt: str,
|
|
160
|
+
**kwargs: Unpack[AdditionalOptions],
|
|
161
|
+
) -> dict[str, str]:
|
|
162
|
+
user_id = kwargs.get("user_id")
|
|
163
|
+
if not user_id:
|
|
164
|
+
raise ToolException("This function requires user_id to be automatically provided.")
|
|
165
|
+
telegram_context = kwargs.get("telegram_context")
|
|
166
|
+
telegram_update = kwargs.get("telegram_update")
|
|
167
|
+
|
|
168
|
+
if telegram_context is None or telegram_update is None:
|
|
169
|
+
raise ToolException(
|
|
170
|
+
"This function requires telegram context & telegram update to be automatically provided."
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
if await user_has_reached_images_generation_limit(user_id=user_id):
|
|
174
|
+
raise ToolException("User has reached image generation monthly limit.")
|
|
175
|
+
|
|
176
|
+
await cls.generate_and_send_image(
|
|
177
|
+
user_id=user_id,
|
|
178
|
+
provider=provider,
|
|
179
|
+
model=image_model,
|
|
180
|
+
prompt=prompt,
|
|
181
|
+
update=telegram_update,
|
|
182
|
+
context=telegram_context,
|
|
183
|
+
)
|
|
184
|
+
return {"detail": "Image was successfully generated and sent."}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class GenerateMusicViaSunoTool(ChibiTool):
|
|
188
|
+
register = bool(gpt_settings.suno_key)
|
|
189
|
+
run_in_background_by_default: bool = True
|
|
190
|
+
allow_model_to_change_background_mode: bool = False
|
|
191
|
+
definition = ChatCompletionToolParam(
|
|
192
|
+
type="function",
|
|
193
|
+
function=FunctionDefinition(
|
|
194
|
+
name="generate_music_via_suno",
|
|
195
|
+
description="Generate music via Suno AI using unofficial API.",
|
|
196
|
+
parameters={
|
|
197
|
+
"type": "object",
|
|
198
|
+
"properties": {
|
|
199
|
+
"prompt": {
|
|
200
|
+
"type": "string",
|
|
201
|
+
"description": "Description of the music with or without lyrics. 500 characters maximum",
|
|
202
|
+
},
|
|
203
|
+
"instrumental": {
|
|
204
|
+
"type": "boolean",
|
|
205
|
+
"description": "Whether to generate instrumental only music.",
|
|
206
|
+
"default": False,
|
|
207
|
+
},
|
|
208
|
+
"suno_model": {
|
|
209
|
+
"type": "string",
|
|
210
|
+
"description": "Model version. Available options: V4, V4_5, V4_5PLUS, V4_5ALL, V5",
|
|
211
|
+
"default": "V5",
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
"required": ["prompt"],
|
|
215
|
+
},
|
|
216
|
+
),
|
|
217
|
+
)
|
|
218
|
+
name = "generate_music_via_suno"
|
|
219
|
+
_provider: Optional["Suno"] = None
|
|
220
|
+
|
|
221
|
+
@classmethod
|
|
222
|
+
async def function(
|
|
223
|
+
cls,
|
|
224
|
+
prompt: str,
|
|
225
|
+
suno_model: str = "V5",
|
|
226
|
+
instrumental: bool = False,
|
|
227
|
+
**kwargs: Unpack[AdditionalOptions],
|
|
228
|
+
) -> dict[str, Any]:
|
|
229
|
+
telegram_context = kwargs.get("telegram_context")
|
|
230
|
+
telegram_update = kwargs.get("telegram_update")
|
|
231
|
+
|
|
232
|
+
if telegram_context is None or telegram_update is None:
|
|
233
|
+
raise ToolException(
|
|
234
|
+
"This function requires telegram context & telegram update to be automatically provided."
|
|
235
|
+
)
|
|
236
|
+
logger.log("TOOL", f"Generating music via Suno. Prompt: {prompt}")
|
|
237
|
+
|
|
238
|
+
task_id = await cls._get_provider().order_music_generation(
|
|
239
|
+
prompt=prompt, instrumental_only=instrumental, model=suno_model
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
logger.log("TOOL", f"[Task #{task_id}] Music generation request accepted by API.")
|
|
243
|
+
|
|
244
|
+
return await cls._poll_and_send_audio(
|
|
245
|
+
task_id=task_id, telegram_context=telegram_context, telegram_update=telegram_update
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
@classmethod
|
|
249
|
+
def _get_provider(cls) -> "Suno":
|
|
250
|
+
from chibi.services.providers import RegisteredProviders, Suno
|
|
251
|
+
|
|
252
|
+
if cls._provider:
|
|
253
|
+
return cls._provider
|
|
254
|
+
provider = RegisteredProviders().get(provider_name="Suno")
|
|
255
|
+
if not isinstance(provider, Suno):
|
|
256
|
+
raise ToolException("This function requires Suno provider to be set.")
|
|
257
|
+
cls._provider = provider
|
|
258
|
+
return provider
|
|
259
|
+
|
|
260
|
+
@classmethod
|
|
261
|
+
async def _poll_and_send_audio(
|
|
262
|
+
cls,
|
|
263
|
+
task_id: int | str,
|
|
264
|
+
telegram_context: ContextTypes.DEFAULT_TYPE,
|
|
265
|
+
telegram_update: Update,
|
|
266
|
+
) -> dict[str, Any]:
|
|
267
|
+
logger.log("TOOL", f"[Task #{task_id}] Polling the generation result...")
|
|
268
|
+
await sleep(POLLING_ATTEMPTS_WAIT_BETWEEN)
|
|
269
|
+
music_generation_result = await cls._get_provider().poll_result(task_id=task_id)
|
|
270
|
+
|
|
271
|
+
if not music_generation_result.data:
|
|
272
|
+
raise ToolException(
|
|
273
|
+
f"SunoGetGenerationDetails does not contain data: {music_generation_result.model_dump()}"
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
if not music_generation_result.data.response:
|
|
277
|
+
raise ToolException(
|
|
278
|
+
f"SunoGetGenerationDetails.data does not contain response: {music_generation_result.model_dump()}"
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
if not music_generation_result.data.response.suno_data:
|
|
282
|
+
raise ToolException(
|
|
283
|
+
f"SunoGetGenerationDetails.data.response does not contain suno_data: "
|
|
284
|
+
f"{music_generation_result.model_dump()}"
|
|
285
|
+
)
|
|
286
|
+
generated_data: dict[str | int, Any] = {"task_id": task_id}
|
|
287
|
+
|
|
288
|
+
for version, suno_data in enumerate(music_generation_result.data.response.suno_data, start=1):
|
|
289
|
+
music_url = (
|
|
290
|
+
suno_data.audio_url
|
|
291
|
+
or suno_data.source_audio_url
|
|
292
|
+
or suno_data.stream_audio_url
|
|
293
|
+
or suno_data.source_stream_audio_url
|
|
294
|
+
)
|
|
295
|
+
if not music_url:
|
|
296
|
+
logger.warning(f"Suno task #{task_id} does not contain audio URL. Suno data ID: {suno_data.id}")
|
|
297
|
+
continue
|
|
298
|
+
|
|
299
|
+
image_url = suno_data.source_image_url or suno_data.image_url
|
|
300
|
+
title = f"{suno_data.title} v{version}"
|
|
301
|
+
chat_id = get_telegram_chat(update=telegram_update).id
|
|
302
|
+
|
|
303
|
+
logger.log("TOOL", f"[Suno] Audio and thumbnail downloaded. Sending it to the chat #{chat_id}...")
|
|
304
|
+
await telegram_context.bot.send_audio(
|
|
305
|
+
chat_id=chat_id,
|
|
306
|
+
audio=await download(str(music_url)) or str(music_url),
|
|
307
|
+
title=title,
|
|
308
|
+
performer=f"{telegram_settings.bot_name} AI via Suno AI",
|
|
309
|
+
duration=int(suno_data.duration) if suno_data.duration else None,
|
|
310
|
+
thumbnail=await download(str(image_url)) if image_url else None,
|
|
311
|
+
filename=f"{title.replace(' ', '_')}.mp3",
|
|
312
|
+
parse_mode="HTML",
|
|
313
|
+
read_timeout=AUDIO_UPLOAD_TIMEOUT,
|
|
314
|
+
write_timeout=AUDIO_UPLOAD_TIMEOUT,
|
|
315
|
+
)
|
|
316
|
+
generated_version_data = {
|
|
317
|
+
"id": suno_data.id,
|
|
318
|
+
"title": title,
|
|
319
|
+
"music_url": str(music_url),
|
|
320
|
+
"image_url": str(image_url),
|
|
321
|
+
}
|
|
322
|
+
generated_data[version] = generated_version_data
|
|
323
|
+
return {
|
|
324
|
+
"detail": "Music was successfully generated and sent to user",
|
|
325
|
+
"suno_task_data": generated_data,
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class GenerateAdvancedMusicViaSunoTool(GenerateMusicViaSunoTool):
|
|
330
|
+
run_in_background_by_default: bool = True
|
|
331
|
+
allow_model_to_change_background_mode: bool = False
|
|
332
|
+
definition = ChatCompletionToolParam(
|
|
333
|
+
type="function",
|
|
334
|
+
function=FunctionDefinition(
|
|
335
|
+
name="generate_music_via_suno_custom_mode",
|
|
336
|
+
description="Generate music via Suno AI using unofficial API. (Custom Mode)",
|
|
337
|
+
parameters={
|
|
338
|
+
"type": "object",
|
|
339
|
+
"properties": {
|
|
340
|
+
"prompt": {
|
|
341
|
+
"type": "string",
|
|
342
|
+
"description": (
|
|
343
|
+
"Description of the music or lyrics. If contains lyrics, must contain"
|
|
344
|
+
"only lyrics. Limits: for V4 model - 3000 chars, for V4_5, V4_5PLUS, "
|
|
345
|
+
"V4_5ALL and V5 - 5000 chars."
|
|
346
|
+
),
|
|
347
|
+
},
|
|
348
|
+
"style": {
|
|
349
|
+
"type": "string",
|
|
350
|
+
"description": (
|
|
351
|
+
"Music style, i.e. 'Uplifting trance, Techno, Eurodance'"
|
|
352
|
+
"Limits: for V4 model - 200 chars, for V4_5, V4_5PLUS, "
|
|
353
|
+
"V4_5ALL and V5 - 1000 chars"
|
|
354
|
+
),
|
|
355
|
+
},
|
|
356
|
+
"title": {
|
|
357
|
+
"type": "string",
|
|
358
|
+
"description": (
|
|
359
|
+
"Music title. Limits: for V4 and V4_5ALL model - 80 chars, "
|
|
360
|
+
"for V4_5, V4_5PLUS and V5 - 100 chars"
|
|
361
|
+
),
|
|
362
|
+
},
|
|
363
|
+
"negative_tags": {
|
|
364
|
+
"type": "string",
|
|
365
|
+
"description": (
|
|
366
|
+
"Music styles or traits to exclude from the generated audio."
|
|
367
|
+
"I.e.: 'Heavy Metal, Upbeat Drums'"
|
|
368
|
+
),
|
|
369
|
+
},
|
|
370
|
+
"vocal_gender": {
|
|
371
|
+
"type": "string",
|
|
372
|
+
"enum": ["m", "f"],
|
|
373
|
+
"description": "Vocal gender for generated vocals. 'm' or 'f'",
|
|
374
|
+
},
|
|
375
|
+
"style_weight": {
|
|
376
|
+
"type": "number",
|
|
377
|
+
"description": "Weight of the provided style guidance. Range 0.00–1.00",
|
|
378
|
+
"default": 0.5,
|
|
379
|
+
},
|
|
380
|
+
"weirdness_constraint": {
|
|
381
|
+
"type": "number",
|
|
382
|
+
"description": "Constraint on creative deviation/novelty. Range 0.00–1.00",
|
|
383
|
+
"default": 0.5,
|
|
384
|
+
},
|
|
385
|
+
"instrumental": {
|
|
386
|
+
"type": "boolean",
|
|
387
|
+
"description": "Whether to generate instrumental only music.",
|
|
388
|
+
"default": False,
|
|
389
|
+
},
|
|
390
|
+
"suno_model": {
|
|
391
|
+
"type": "string",
|
|
392
|
+
"description": "Model version. Available options: V4, V4_5, V4_5PLUS, V4_5ALL, V5",
|
|
393
|
+
"default": "V5",
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
"required": ["prompt", "style", "title"],
|
|
397
|
+
},
|
|
398
|
+
),
|
|
399
|
+
)
|
|
400
|
+
name = "generate_music_via_suno_custom_mode"
|
|
401
|
+
|
|
402
|
+
@classmethod
|
|
403
|
+
async def function( # type: ignore[override]
|
|
404
|
+
cls,
|
|
405
|
+
prompt: str,
|
|
406
|
+
style: str | None = None,
|
|
407
|
+
title: str | None = None,
|
|
408
|
+
suno_model: str = "V5",
|
|
409
|
+
instrumental: bool = False,
|
|
410
|
+
negative_tags: str | None = None,
|
|
411
|
+
vocal_gender: str | None = None,
|
|
412
|
+
style_weight: float = 0.5,
|
|
413
|
+
weirdness_constraint: float = 0.5,
|
|
414
|
+
**kwargs: Unpack[AdditionalOptions],
|
|
415
|
+
) -> dict[str, Any]:
|
|
416
|
+
telegram_context = kwargs.get("telegram_context")
|
|
417
|
+
telegram_update = kwargs.get("telegram_update")
|
|
418
|
+
|
|
419
|
+
if telegram_context is None or telegram_update is None:
|
|
420
|
+
raise ToolException(
|
|
421
|
+
"This function requires telegram context & telegram update to be automatically provided."
|
|
422
|
+
)
|
|
423
|
+
if not style:
|
|
424
|
+
raise ToolException("Style is mandatory in custom mode.")
|
|
425
|
+
|
|
426
|
+
if not title:
|
|
427
|
+
raise ToolException("Title is mandatory in custom mode.")
|
|
428
|
+
|
|
429
|
+
if vocal_gender and vocal_gender not in ("f", "m"):
|
|
430
|
+
raise ToolException("Vocal gender must be 'f' or 'm' if specified.")
|
|
431
|
+
|
|
432
|
+
logger.log("TOOL", f"Generating music via Suno. Custom mode. Prompt: {prompt}. Style: {style}. Title: {title}")
|
|
433
|
+
|
|
434
|
+
task_id = await cls._get_provider().order_music_generation_advanced_mode(
|
|
435
|
+
prompt=prompt,
|
|
436
|
+
instrumental_only=instrumental,
|
|
437
|
+
model=suno_model,
|
|
438
|
+
style=style,
|
|
439
|
+
title=title,
|
|
440
|
+
negative_tags=negative_tags,
|
|
441
|
+
vocal_gender=vocal_gender,
|
|
442
|
+
style_weight=style_weight,
|
|
443
|
+
weirdness_constraint=weirdness_constraint,
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
logger.log("TOOL", f"[Task #{task_id}] Music generation request accepted by API.")
|
|
447
|
+
|
|
448
|
+
result = await cls._poll_and_send_audio(
|
|
449
|
+
task_id=task_id, telegram_context=telegram_context, telegram_update=telegram_update
|
|
450
|
+
)
|
|
451
|
+
return result
|