Spaces:
Paused
Paused
Upload app.py
Browse files
app.py
CHANGED
@@ -22,6 +22,7 @@ intents = discord.Intents.default()
|
|
22 |
intents.message_content = True
|
23 |
client = discord.Client(intents=intents)
|
24 |
tree = app_commands.CommandTree(client)
|
|
|
25 |
|
26 |
def get_available_voices():
|
27 |
"""Fetch only custom voices from ElevenLabs account"""
|
@@ -39,63 +40,129 @@ def get_remaining_credits():
|
|
39 |
|
40 |
def format_credits_message(credits_info):
|
41 |
"""Format credits information into a readable message"""
|
42 |
-
|
43 |
-
total = credits_info["character_limit"]
|
44 |
-
return f"Credits: {credits_info['character_count']} / {total} characters remaining ({used} used)"
|
45 |
|
46 |
# Discord bot commands
|
47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
@app_commands.describe(
|
49 |
-
|
50 |
-
|
51 |
-
voice_name="Choose which voice to use~",
|
52 |
stability="Voice stability (0-1)",
|
53 |
clarity="Voice clarity (0-1)",
|
54 |
style="Speaking style (0-1)"
|
55 |
)
|
56 |
-
|
57 |
-
app_commands.Choice(name="list", value="list"),
|
58 |
-
app_commands.Choice(name="create", value="create")
|
59 |
-
])
|
60 |
-
async def voice(
|
61 |
interaction: discord.Interaction,
|
62 |
-
|
63 |
-
|
64 |
-
voice_name: str = None,
|
65 |
stability: float = 0.5,
|
66 |
clarity: float = 0.75,
|
67 |
style: float = 0.5
|
68 |
):
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
logger.info(f"Received voice command: action={action}, voice_name={voice_name}")
|
78 |
await interaction.response.defer()
|
79 |
|
80 |
if action.lower() == "list":
|
81 |
available_voices = get_available_voices()
|
82 |
-
voice_list = "\n".join([f"
|
83 |
credits_info = get_remaining_credits()
|
84 |
-
credits_msg = f"\n\
|
85 |
|
86 |
embed = discord.Embed(
|
87 |
-
title="
|
88 |
description=f"{voice_list}\n{credits_msg}",
|
89 |
-
color=
|
90 |
)
|
91 |
await interaction.followup.send(embed=embed)
|
92 |
|
93 |
elif action.lower() == "create":
|
94 |
if not all([text, voice_name]):
|
95 |
embed = discord.Embed(
|
96 |
-
title="
|
97 |
-
description="Please provide both text and voice name
|
98 |
-
color=
|
99 |
)
|
100 |
await interaction.followup.send(embed=embed)
|
101 |
return
|
@@ -103,9 +170,9 @@ async def voice(
|
|
103 |
available_voices = get_available_voices()
|
104 |
if voice_name not in available_voices:
|
105 |
embed = discord.Embed(
|
106 |
-
title="
|
107 |
-
description=f"
|
108 |
-
color=
|
109 |
)
|
110 |
await interaction.followup.send(embed=embed)
|
111 |
return
|
@@ -135,9 +202,9 @@ async def voice(
|
|
135 |
credits_msg = f"Credits remaining: {credits_info['character_count']} / {credits_info['character_limit']}"
|
136 |
|
137 |
embed = discord.Embed(
|
138 |
-
title="
|
139 |
-
description=f"
|
140 |
-
color=
|
141 |
)
|
142 |
await interaction.followup.send(
|
143 |
embed=embed,
|
|
|
22 |
intents.message_content = True
|
23 |
client = discord.Client(intents=intents)
|
24 |
tree = app_commands.CommandTree(client)
|
25 |
+
tree.add_command(voice_group)
|
26 |
|
27 |
def get_available_voices():
|
28 |
"""Fetch only custom voices from ElevenLabs account"""
|
|
|
40 |
|
41 |
def format_credits_message(credits_info):
|
42 |
"""Format credits information into a readable message"""
|
43 |
+
return f"Credits Remaining: {credits_info['character_count']}"
|
|
|
|
|
44 |
|
45 |
# Discord bot commands
|
46 |
+
# Command group for voice commands
|
47 |
+
voice_group = app_commands.Group(name="voice", description="Voice generation commands")
|
48 |
+
|
49 |
+
@voice_group.command(name="list", description="List all available voices")
|
50 |
+
async def voice_list(interaction: discord.Interaction):
|
51 |
+
await interaction.response.defer()
|
52 |
+
available_voices = get_available_voices()
|
53 |
+
voice_list = "\n".join([f"β’ {name}" for name in available_voices.keys()])
|
54 |
+
credits_info = get_remaining_credits()
|
55 |
+
credits_msg = format_credits_message(credits_info)
|
56 |
+
|
57 |
+
embed = discord.Embed(
|
58 |
+
title="Available Voices",
|
59 |
+
description=f"{voice_list}\n\n{credits_msg}",
|
60 |
+
color=0x2B2D31
|
61 |
+
)
|
62 |
+
await interaction.followup.send(embed=embed)
|
63 |
+
|
64 |
+
@voice_group.command(name="create", description="Create a voice message")
|
65 |
@app_commands.describe(
|
66 |
+
text="Text to convert to speech",
|
67 |
+
voice_name="Select a voice to use",
|
|
|
68 |
stability="Voice stability (0-1)",
|
69 |
clarity="Voice clarity (0-1)",
|
70 |
style="Speaking style (0-1)"
|
71 |
)
|
72 |
+
async def voice_create(
|
|
|
|
|
|
|
|
|
73 |
interaction: discord.Interaction,
|
74 |
+
text: str,
|
75 |
+
voice_name: str,
|
|
|
76 |
stability: float = 0.5,
|
77 |
clarity: float = 0.75,
|
78 |
style: float = 0.5
|
79 |
):
|
80 |
+
await interaction.response.defer()
|
81 |
+
|
82 |
+
available_voices = get_available_voices()
|
83 |
+
if voice_name not in available_voices:
|
84 |
+
embed = discord.Embed(
|
85 |
+
title="Voice Not Found",
|
86 |
+
description=f"The voice '{voice_name}' was not found. Use `/voice list` to see available voices.",
|
87 |
+
color=0x2B2D31
|
88 |
+
)
|
89 |
+
await interaction.followup.send(embed=embed)
|
90 |
+
return
|
91 |
+
|
92 |
+
try:
|
93 |
+
voice_settings = VoiceSettings(
|
94 |
+
stability=stability,
|
95 |
+
similarity_boost=clarity,
|
96 |
+
style=style,
|
97 |
+
use_speaker_boost=True
|
98 |
+
)
|
99 |
+
|
100 |
+
audio = generate(
|
101 |
+
text=text,
|
102 |
+
voice=Voice(
|
103 |
+
voice_id=available_voices[voice_name],
|
104 |
+
settings=voice_settings
|
105 |
+
)
|
106 |
+
)
|
107 |
+
|
108 |
+
# Save audio to temporary file
|
109 |
+
with open("temp.mp3", "wb") as f:
|
110 |
+
f.write(audio)
|
111 |
+
|
112 |
+
# Get updated credits
|
113 |
+
credits_info = get_remaining_credits()
|
114 |
+
credits_msg = format_credits_message(credits_info)
|
115 |
+
|
116 |
+
embed = discord.Embed(
|
117 |
+
title="Voice Generated",
|
118 |
+
description=f"Voice: {voice_name}\n{credits_msg}",
|
119 |
+
color=0x2B2D31
|
120 |
+
)
|
121 |
+
await interaction.followup.send(
|
122 |
+
embed=embed,
|
123 |
+
file=discord.File("temp.mp3")
|
124 |
+
)
|
125 |
+
|
126 |
+
# Clean up
|
127 |
+
os.remove("temp.mp3")
|
128 |
+
|
129 |
+
except Exception as e:
|
130 |
+
logger.error(f"Error generating audio: {str(e)}", exc_info=True)
|
131 |
+
await interaction.followup.send(f"Error generating audio: {str(e)}")
|
132 |
+
|
133 |
+
# Add autocomplete for voice names
|
134 |
+
@voice_create.autocomplete('voice_name')
|
135 |
+
async def voice_name_autocomplete(
|
136 |
+
interaction: discord.Interaction,
|
137 |
+
current: str,
|
138 |
+
) -> List[app_commands.Choice[str]]:
|
139 |
+
voices = list(get_available_voices().keys())
|
140 |
+
return [
|
141 |
+
app_commands.Choice(name=voice, value=voice)
|
142 |
+
for voice in voices if current.lower() in voice.lower()
|
143 |
+
][:25]
|
144 |
logger.info(f"Received voice command: action={action}, voice_name={voice_name}")
|
145 |
await interaction.response.defer()
|
146 |
|
147 |
if action.lower() == "list":
|
148 |
available_voices = get_available_voices()
|
149 |
+
voice_list = "\n".join([f"β’ {name}" for name in available_voices.keys()])
|
150 |
credits_info = get_remaining_credits()
|
151 |
+
credits_msg = f"\n\nCredits remaining: {credits_info['character_count']} / {credits_info['character_limit']}"
|
152 |
|
153 |
embed = discord.Embed(
|
154 |
+
title="Available Voices",
|
155 |
description=f"{voice_list}\n{credits_msg}",
|
156 |
+
color=0x2B2D31 # Discord dark theme color
|
157 |
)
|
158 |
await interaction.followup.send(embed=embed)
|
159 |
|
160 |
elif action.lower() == "create":
|
161 |
if not all([text, voice_name]):
|
162 |
embed = discord.Embed(
|
163 |
+
title="Missing Information",
|
164 |
+
description="Please provide both text and voice name. Use `/voice list` to see available voices.",
|
165 |
+
color=0x2B2D31
|
166 |
)
|
167 |
await interaction.followup.send(embed=embed)
|
168 |
return
|
|
|
170 |
available_voices = get_available_voices()
|
171 |
if voice_name not in available_voices:
|
172 |
embed = discord.Embed(
|
173 |
+
title="Voice Not Found",
|
174 |
+
description=f"The voice '{voice_name}' was not found. Use `/voice list` to see available voices.",
|
175 |
+
color=0x2B2D31
|
176 |
)
|
177 |
await interaction.followup.send(embed=embed)
|
178 |
return
|
|
|
202 |
credits_msg = f"Credits remaining: {credits_info['character_count']} / {credits_info['character_limit']}"
|
203 |
|
204 |
embed = discord.Embed(
|
205 |
+
title="Voice Generated",
|
206 |
+
description=f"Voice: {voice_name}\n{credits_msg}",
|
207 |
+
color=0x2B2D31
|
208 |
)
|
209 |
await interaction.followup.send(
|
210 |
embed=embed,
|