Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -15,42 +15,56 @@ from elevenlabs.client import ElevenLabs
|
|
15 |
from elevenlabs import play, save
|
16 |
|
17 |
# Load environment variables
|
|
|
18 |
load_dotenv()
|
|
|
19 |
|
20 |
# Argument parsing
|
21 |
parser = argparse.ArgumentParser()
|
22 |
parser.add_argument("--share", action='store_true', default=False, help="make link public")
|
23 |
args = parser.parse_args()
|
|
|
24 |
|
25 |
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
|
|
|
|
26 |
output_dir = 'outputs'
|
27 |
samples_dir = 'samples'
|
28 |
os.makedirs(output_dir, exist_ok=True)
|
29 |
os.makedirs(samples_dir, exist_ok=True)
|
|
|
30 |
|
31 |
supported_languages = ['zh', 'en']
|
|
|
32 |
|
|
|
33 |
MAILERSEND_API_KEY = os.getenv("MAILERSEND_API_KEY")
|
34 |
MAILERSEND_DOMAIN = os.getenv("MAILERSEND_DOMAIN")
|
35 |
MAILERSEND_SENDER_EMAIL = f"noreply@{MAILERSEND_DOMAIN}"
|
36 |
MAILERSEND_SENDER_NAME = "Voice Clone App"
|
|
|
37 |
|
38 |
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
|
39 |
client = ElevenLabs(api_key=ELEVENLABS_API_KEY)
|
|
|
40 |
|
41 |
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
|
42 |
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
|
43 |
AWS_REGION_NAME = os.getenv('AWS_REGION_NAME')
|
44 |
S3_BUCKET_NAME = os.getenv('S3_BUCKET_NAME')
|
|
|
45 |
|
46 |
# List of blocked words
|
47 |
BLOCKED_WORDS = ['Kill','hurt','shoot','gun','rifle','AR','semi automatic','knife','blade','sword','punch harm','disrupt','blackmail','steal','bitch','cunt','fuck','freaking','nigger','nigga','niggas','cracker','jew','oriental','fag','faggot','account','money','transfer','urgent','help','scared','policy','frightened','accident','fear','scam','address','social security number','assault','injure','maim','destroy','damage','threaten','intimidate','bully','menace','blackmail','extort','exploit','defame','steal','rob','embezzle','defraud Harass','jerk','idiot','stupid','moron','asshole','con','trick','swindle','defraud','payment','credit card','bank account','urgent','immediate','afraid','phone number','email','password']
|
|
|
48 |
|
49 |
def get_blocked_words(text):
|
|
|
50 |
# Split the text into words for accurate matching
|
51 |
words_in_text = text.lower().split()
|
52 |
# Find all blocked words present in the text
|
53 |
blocked_found = [word for word in BLOCKED_WORDS if word.lower() in words_in_text]
|
|
|
54 |
return blocked_found
|
55 |
|
56 |
# Function to check for blocked words
|
@@ -59,6 +73,7 @@ def contains_blocked_words(text):
|
|
59 |
|
60 |
# Function to send email with downloadable file using MailerSend
|
61 |
def send_email_with_file(recipient_email, file_path, subject, body):
|
|
|
62 |
try:
|
63 |
mailer = emails.NewEmail(MAILERSEND_API_KEY)
|
64 |
|
@@ -82,7 +97,7 @@ def send_email_with_file(recipient_email, file_path, subject, body):
|
|
82 |
|
83 |
with open(file_path, "rb") as file:
|
84 |
attachment_content = base64.b64encode(file.read()).decode('utf-8')
|
85 |
-
|
86 |
attachments = [
|
87 |
{
|
88 |
"filename": os.path.basename(file_path),
|
@@ -93,16 +108,21 @@ def send_email_with_file(recipient_email, file_path, subject, body):
|
|
93 |
mailer.set_attachments(attachments, mail_body)
|
94 |
|
95 |
response = mailer.send(mail_body)
|
|
|
96 |
|
97 |
if response[0] == 202:
|
|
|
98 |
return True
|
99 |
else:
|
|
|
100 |
return False
|
101 |
except Exception as e:
|
|
|
102 |
return False
|
103 |
|
104 |
# S3 upload functions
|
105 |
def upload_to_s3(local_file, bucket, s3_file):
|
|
|
106 |
s3 = boto3.client('s3',
|
107 |
aws_access_key_id=AWS_ACCESS_KEY_ID,
|
108 |
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
|
@@ -110,60 +130,79 @@ def upload_to_s3(local_file, bucket, s3_file):
|
|
110 |
|
111 |
try:
|
112 |
s3.upload_file(local_file, bucket, s3_file, ExtraArgs={'ACL': 'public-read'})
|
|
|
113 |
return True
|
114 |
except FileNotFoundError:
|
|
|
115 |
return False
|
116 |
except NoCredentialsError:
|
|
|
|
|
|
|
|
|
117 |
return False
|
118 |
|
119 |
def upload_voice_sample_and_metadata(sample_path, metadata, bucket):
|
|
|
120 |
# Upload the voice sample
|
121 |
sample_filename = os.path.basename(sample_path)
|
122 |
s3_sample_path = f'voice_samples/{sample_filename}'
|
123 |
if not upload_to_s3(sample_path, bucket, s3_sample_path):
|
|
|
124 |
return False
|
125 |
|
126 |
# Create and upload metadata file
|
127 |
metadata['sample_s3_path'] = s3_sample_path
|
128 |
metadata_filename = f"{os.path.splitext(sample_filename)[0]}_metadata.json"
|
129 |
s3_metadata_path = f'voice_metadata/{metadata_filename}'
|
130 |
-
|
131 |
# Save metadata to a temporary file
|
132 |
temp_metadata_path = '/tmp/temp_metadata.json'
|
133 |
-
|
134 |
-
|
135 |
-
|
|
|
|
|
|
|
|
|
|
|
136 |
# Upload metadata file
|
137 |
if not upload_to_s3(temp_metadata_path, bucket, s3_metadata_path):
|
|
|
138 |
return False
|
139 |
-
|
140 |
# Clean up temporary file
|
141 |
-
|
|
|
|
|
|
|
|
|
142 |
|
|
|
143 |
return True
|
144 |
|
145 |
def predict(prompt, style, audio_file_pth, voice_name, customer_email, order_name):
|
|
|
146 |
text_hint = 'Your file will only be saved for 24 hours.\n'
|
147 |
if len(prompt) < 2:
|
148 |
text_hint += "[ERROR] Please provide a longer prompt text.\n"
|
|
|
149 |
return text_hint, None, None
|
150 |
if len(prompt) > 200:
|
151 |
text_hint += "[ERROR] Text length limited to 200 characters. Please try shorter text.\n"
|
|
|
152 |
return text_hint, None, None
|
153 |
|
154 |
blocked_words = get_blocked_words(prompt)
|
155 |
if blocked_words:
|
156 |
text_hint += f"[ERROR] Your text contains blocked words: {', '.join(blocked_words)}. Please remove them and try again.\n"
|
|
|
157 |
return text_hint, None, None
|
158 |
|
159 |
# Check if audio file was uploaded
|
160 |
if audio_file_pth is None:
|
161 |
text_hint += "[ERROR] No audio file was uploaded. Please upload a reference audio file.\n"
|
162 |
-
|
163 |
-
|
164 |
-
# Check if audio file was uploaded
|
165 |
-
if audio_file_pth is None:
|
166 |
-
text_hint += "[ERROR] No audio file was uploaded. Please upload a reference audio file.\n"
|
167 |
return text_hint, None, None
|
168 |
|
169 |
# Copy the sample audio to the samples directory
|
@@ -171,8 +210,10 @@ def predict(prompt, style, audio_file_pth, voice_name, customer_email, order_nam
|
|
171 |
sample_filename = f"{voice_name}_{customer_email}_sample.mp3"
|
172 |
sample_path = os.path.join(samples_dir, sample_filename)
|
173 |
shutil.copy2(audio_file_pth, sample_path)
|
|
|
174 |
except Exception as e:
|
175 |
text_hint += f"[ERROR] Failed to copy audio file: {str(e)}\n"
|
|
|
176 |
return text_hint, None, None
|
177 |
|
178 |
# Prepare metadata
|
@@ -181,27 +222,48 @@ def predict(prompt, style, audio_file_pth, voice_name, customer_email, order_nam
|
|
181 |
'email': customer_email,
|
182 |
'order_name': order_name
|
183 |
}
|
|
|
184 |
|
185 |
# Use ElevenLabs API to clone the voice and generate audio
|
186 |
try:
|
187 |
full_voice_name = f"{voice_name}_{customer_email}"
|
|
|
188 |
voice = client.clone(
|
189 |
name=full_voice_name,
|
190 |
description="A trial voice model for testing",
|
191 |
files=[sample_path],
|
192 |
)
|
|
|
|
|
|
|
193 |
audio = client.generate(text=prompt, voice=voice)
|
194 |
output_audio_path = os.path.join(output_dir, f"{full_voice_name}_output.mp3")
|
195 |
save(audio, output_audio_path)
|
|
|
|
|
196 |
text_hint += "Audio generated successfully using ElevenLabs.\n"
|
197 |
except Exception as e:
|
198 |
text_hint += f"[ERROR] ElevenLabs API error: {e}\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
return text_hint, None, None
|
200 |
|
201 |
# Send email with the generated audio file
|
202 |
email_subject = "Your Voice Clone Audio is Ready"
|
203 |
email_body = f"Hi {voice_name},\n\nYour voice clone audio file is ready. Please find the attached file.\n\nBest regards,\nVoice Clone App"
|
|
|
|
|
|
|
|
|
|
|
|
|
204 |
return text_hint, output_audio_path, sample_path
|
|
|
205 |
with gr.Blocks(gr.themes.Glass()) as demo:
|
206 |
with gr.Row():
|
207 |
with gr.Column():
|
@@ -235,20 +297,30 @@ with gr.Blocks(gr.themes.Glass()) as demo:
|
|
235 |
info="We'll send you a downloadable file to this email address."
|
236 |
)
|
237 |
tts_button = gr.Button("Start", elem_id="send-btn", visible=True)
|
|
|
238 |
|
239 |
with gr.Column():
|
240 |
out_text_gr = gr.Text(label="Info")
|
241 |
audio_gr = gr.Audio(label="Generated Audio", autoplay=True)
|
242 |
ref_audio_gr = gr.Audio(label="Original Audio Used")
|
|
|
243 |
|
244 |
-
tts_button.click(
|
|
|
|
|
|
|
|
|
|
|
245 |
|
246 |
demo.queue()
|
|
|
247 |
demo.launch(debug=True, show_api=False, share=args.share)
|
|
|
248 |
|
249 |
css = """
|
250 |
footer {visibility: hidden}
|
251 |
audio .btn-container {display: none}
|
252 |
"""
|
253 |
|
254 |
-
demo.add_css(css)
|
|
|
|
15 |
from elevenlabs import play, save
|
16 |
|
17 |
# Load environment variables
|
18 |
+
print("Loading environment variables...")
|
19 |
load_dotenv()
|
20 |
+
print("Environment variables loaded.")
|
21 |
|
22 |
# Argument parsing
|
23 |
parser = argparse.ArgumentParser()
|
24 |
parser.add_argument("--share", action='store_true', default=False, help="make link public")
|
25 |
args = parser.parse_args()
|
26 |
+
print(f"Arguments parsed. Share mode is set to: {args.share}")
|
27 |
|
28 |
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
29 |
+
print(f"Using device: {device}")
|
30 |
+
|
31 |
output_dir = 'outputs'
|
32 |
samples_dir = 'samples'
|
33 |
os.makedirs(output_dir, exist_ok=True)
|
34 |
os.makedirs(samples_dir, exist_ok=True)
|
35 |
+
print(f"Directories '{output_dir}' and '{samples_dir}' are ready.")
|
36 |
|
37 |
supported_languages = ['zh', 'en']
|
38 |
+
print(f"Supported languages: {supported_languages}")
|
39 |
|
40 |
+
# Load API keys and configurations
|
41 |
MAILERSEND_API_KEY = os.getenv("MAILERSEND_API_KEY")
|
42 |
MAILERSEND_DOMAIN = os.getenv("MAILERSEND_DOMAIN")
|
43 |
MAILERSEND_SENDER_EMAIL = f"noreply@{MAILERSEND_DOMAIN}"
|
44 |
MAILERSEND_SENDER_NAME = "Voice Clone App"
|
45 |
+
print("MailerSend configuration loaded.")
|
46 |
|
47 |
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
|
48 |
client = ElevenLabs(api_key=ELEVENLABS_API_KEY)
|
49 |
+
print("ElevenLabs client initialized.")
|
50 |
|
51 |
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
|
52 |
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
|
53 |
AWS_REGION_NAME = os.getenv('AWS_REGION_NAME')
|
54 |
S3_BUCKET_NAME = os.getenv('S3_BUCKET_NAME')
|
55 |
+
print("AWS S3 configuration loaded.")
|
56 |
|
57 |
# List of blocked words
|
58 |
BLOCKED_WORDS = ['Kill','hurt','shoot','gun','rifle','AR','semi automatic','knife','blade','sword','punch harm','disrupt','blackmail','steal','bitch','cunt','fuck','freaking','nigger','nigga','niggas','cracker','jew','oriental','fag','faggot','account','money','transfer','urgent','help','scared','policy','frightened','accident','fear','scam','address','social security number','assault','injure','maim','destroy','damage','threaten','intimidate','bully','menace','blackmail','extort','exploit','defame','steal','rob','embezzle','defraud Harass','jerk','idiot','stupid','moron','asshole','con','trick','swindle','defraud','payment','credit card','bank account','urgent','immediate','afraid','phone number','email','password']
|
59 |
+
print(f"Blocked words list loaded with {len(BLOCKED_WORDS)} words.")
|
60 |
|
61 |
def get_blocked_words(text):
|
62 |
+
print("Checking for blocked words in the input text...")
|
63 |
# Split the text into words for accurate matching
|
64 |
words_in_text = text.lower().split()
|
65 |
# Find all blocked words present in the text
|
66 |
blocked_found = [word for word in BLOCKED_WORDS if word.lower() in words_in_text]
|
67 |
+
print(f"Blocked words found: {blocked_found}")
|
68 |
return blocked_found
|
69 |
|
70 |
# Function to check for blocked words
|
|
|
73 |
|
74 |
# Function to send email with downloadable file using MailerSend
|
75 |
def send_email_with_file(recipient_email, file_path, subject, body):
|
76 |
+
print(f"Sending email to {recipient_email} with file {file_path}...")
|
77 |
try:
|
78 |
mailer = emails.NewEmail(MAILERSEND_API_KEY)
|
79 |
|
|
|
97 |
|
98 |
with open(file_path, "rb") as file:
|
99 |
attachment_content = base64.b64encode(file.read()).decode('utf-8')
|
100 |
+
|
101 |
attachments = [
|
102 |
{
|
103 |
"filename": os.path.basename(file_path),
|
|
|
108 |
mailer.set_attachments(attachments, mail_body)
|
109 |
|
110 |
response = mailer.send(mail_body)
|
111 |
+
print(f"MailerSend response: {response}")
|
112 |
|
113 |
if response[0] == 202:
|
114 |
+
print("Email sent successfully.")
|
115 |
return True
|
116 |
else:
|
117 |
+
print("Failed to send email.")
|
118 |
return False
|
119 |
except Exception as e:
|
120 |
+
print(f"Error sending email: {e}")
|
121 |
return False
|
122 |
|
123 |
# S3 upload functions
|
124 |
def upload_to_s3(local_file, bucket, s3_file):
|
125 |
+
print(f"Uploading {local_file} to S3 bucket {bucket} as {s3_file}...")
|
126 |
s3 = boto3.client('s3',
|
127 |
aws_access_key_id=AWS_ACCESS_KEY_ID,
|
128 |
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
|
|
|
130 |
|
131 |
try:
|
132 |
s3.upload_file(local_file, bucket, s3_file, ExtraArgs={'ACL': 'public-read'})
|
133 |
+
print("File uploaded to S3 successfully.")
|
134 |
return True
|
135 |
except FileNotFoundError:
|
136 |
+
print("File not found.")
|
137 |
return False
|
138 |
except NoCredentialsError:
|
139 |
+
print("AWS credentials not available.")
|
140 |
+
return False
|
141 |
+
except Exception as e:
|
142 |
+
print(f"Error uploading to S3: {e}")
|
143 |
return False
|
144 |
|
145 |
def upload_voice_sample_and_metadata(sample_path, metadata, bucket):
|
146 |
+
print("Uploading voice sample and metadata to S3...")
|
147 |
# Upload the voice sample
|
148 |
sample_filename = os.path.basename(sample_path)
|
149 |
s3_sample_path = f'voice_samples/{sample_filename}'
|
150 |
if not upload_to_s3(sample_path, bucket, s3_sample_path):
|
151 |
+
print("Failed to upload voice sample.")
|
152 |
return False
|
153 |
|
154 |
# Create and upload metadata file
|
155 |
metadata['sample_s3_path'] = s3_sample_path
|
156 |
metadata_filename = f"{os.path.splitext(sample_filename)[0]}_metadata.json"
|
157 |
s3_metadata_path = f'voice_metadata/{metadata_filename}'
|
158 |
+
|
159 |
# Save metadata to a temporary file
|
160 |
temp_metadata_path = '/tmp/temp_metadata.json'
|
161 |
+
try:
|
162 |
+
with open(temp_metadata_path, 'w') as f:
|
163 |
+
json.dump(metadata, f)
|
164 |
+
print("Metadata file created.")
|
165 |
+
except Exception as e:
|
166 |
+
print(f"Error creating metadata file: {e}")
|
167 |
+
return False
|
168 |
+
|
169 |
# Upload metadata file
|
170 |
if not upload_to_s3(temp_metadata_path, bucket, s3_metadata_path):
|
171 |
+
print("Failed to upload metadata file.")
|
172 |
return False
|
173 |
+
|
174 |
# Clean up temporary file
|
175 |
+
try:
|
176 |
+
os.remove(temp_metadata_path)
|
177 |
+
print("Temporary metadata file removed.")
|
178 |
+
except Exception as e:
|
179 |
+
print(f"Error removing temporary file: {e}")
|
180 |
|
181 |
+
print("Voice sample and metadata uploaded successfully.")
|
182 |
return True
|
183 |
|
184 |
def predict(prompt, style, audio_file_pth, voice_name, customer_email, order_name):
|
185 |
+
print("Prediction started...")
|
186 |
text_hint = 'Your file will only be saved for 24 hours.\n'
|
187 |
if len(prompt) < 2:
|
188 |
text_hint += "[ERROR] Please provide a longer prompt text.\n"
|
189 |
+
print("Prompt is too short.")
|
190 |
return text_hint, None, None
|
191 |
if len(prompt) > 200:
|
192 |
text_hint += "[ERROR] Text length limited to 200 characters. Please try shorter text.\n"
|
193 |
+
print("Prompt is too long.")
|
194 |
return text_hint, None, None
|
195 |
|
196 |
blocked_words = get_blocked_words(prompt)
|
197 |
if blocked_words:
|
198 |
text_hint += f"[ERROR] Your text contains blocked words: {', '.join(blocked_words)}. Please remove them and try again.\n"
|
199 |
+
print(f"Blocked words detected: {blocked_words}")
|
200 |
return text_hint, None, None
|
201 |
|
202 |
# Check if audio file was uploaded
|
203 |
if audio_file_pth is None:
|
204 |
text_hint += "[ERROR] No audio file was uploaded. Please upload a reference audio file.\n"
|
205 |
+
print("No audio file uploaded.")
|
|
|
|
|
|
|
|
|
206 |
return text_hint, None, None
|
207 |
|
208 |
# Copy the sample audio to the samples directory
|
|
|
210 |
sample_filename = f"{voice_name}_{customer_email}_sample.mp3"
|
211 |
sample_path = os.path.join(samples_dir, sample_filename)
|
212 |
shutil.copy2(audio_file_pth, sample_path)
|
213 |
+
print(f"Audio file copied to {sample_path}.")
|
214 |
except Exception as e:
|
215 |
text_hint += f"[ERROR] Failed to copy audio file: {str(e)}\n"
|
216 |
+
print(f"Error copying audio file: {e}")
|
217 |
return text_hint, None, None
|
218 |
|
219 |
# Prepare metadata
|
|
|
222 |
'email': customer_email,
|
223 |
'order_name': order_name
|
224 |
}
|
225 |
+
print("Metadata prepared:", metadata)
|
226 |
|
227 |
# Use ElevenLabs API to clone the voice and generate audio
|
228 |
try:
|
229 |
full_voice_name = f"{voice_name}_{customer_email}"
|
230 |
+
print(f"Cloning voice with name: {full_voice_name}")
|
231 |
voice = client.clone(
|
232 |
name=full_voice_name,
|
233 |
description="A trial voice model for testing",
|
234 |
files=[sample_path],
|
235 |
)
|
236 |
+
print("Voice cloned successfully.")
|
237 |
+
|
238 |
+
print("Generating audio using the cloned voice...")
|
239 |
audio = client.generate(text=prompt, voice=voice)
|
240 |
output_audio_path = os.path.join(output_dir, f"{full_voice_name}_output.mp3")
|
241 |
save(audio, output_audio_path)
|
242 |
+
print(f"Audio generated and saved to {output_audio_path}.")
|
243 |
+
|
244 |
text_hint += "Audio generated successfully using ElevenLabs.\n"
|
245 |
except Exception as e:
|
246 |
text_hint += f"[ERROR] ElevenLabs API error: {e}\n"
|
247 |
+
print(f"ElevenLabs API error: {e}")
|
248 |
+
return text_hint, None, None
|
249 |
+
|
250 |
+
# Optionally upload to S3 (uncommented)
|
251 |
+
if not upload_voice_sample_and_metadata(sample_path, metadata, S3_BUCKET_NAME):
|
252 |
+
text_hint += "[ERROR] Failed to upload to S3.\n"
|
253 |
+
print("Failed to upload voice sample and metadata to S3.")
|
254 |
return text_hint, None, None
|
255 |
|
256 |
# Send email with the generated audio file
|
257 |
email_subject = "Your Voice Clone Audio is Ready"
|
258 |
email_body = f"Hi {voice_name},\n\nYour voice clone audio file is ready. Please find the attached file.\n\nBest regards,\nVoice Clone App"
|
259 |
+
if send_email_with_file(customer_email, output_audio_path, email_subject, email_body):
|
260 |
+
text_hint += "An email has been sent with your audio file.\n"
|
261 |
+
else:
|
262 |
+
text_hint += "[ERROR] Failed to send email.\n"
|
263 |
+
print("Failed to send email with the audio file.")
|
264 |
+
|
265 |
return text_hint, output_audio_path, sample_path
|
266 |
+
|
267 |
with gr.Blocks(gr.themes.Glass()) as demo:
|
268 |
with gr.Row():
|
269 |
with gr.Column():
|
|
|
297 |
info="We'll send you a downloadable file to this email address."
|
298 |
)
|
299 |
tts_button = gr.Button("Start", elem_id="send-btn", visible=True)
|
300 |
+
print("Gradio input components initialized.")
|
301 |
|
302 |
with gr.Column():
|
303 |
out_text_gr = gr.Text(label="Info")
|
304 |
audio_gr = gr.Audio(label="Generated Audio", autoplay=True)
|
305 |
ref_audio_gr = gr.Audio(label="Original Audio Used")
|
306 |
+
print("Gradio output components initialized.")
|
307 |
|
308 |
+
tts_button.click(
|
309 |
+
predict,
|
310 |
+
[input_text_gr, style_gr, ref_gr, voice_name_gr, customer_email_gr, order_gr],
|
311 |
+
outputs=[out_text_gr, audio_gr, ref_audio_gr]
|
312 |
+
)
|
313 |
+
print("Gradio button click event bound to predict function.")
|
314 |
|
315 |
demo.queue()
|
316 |
+
print("Launching Gradio demo...")
|
317 |
demo.launch(debug=True, show_api=False, share=args.share)
|
318 |
+
print("Gradio demo launched.")
|
319 |
|
320 |
css = """
|
321 |
footer {visibility: hidden}
|
322 |
audio .btn-container {display: none}
|
323 |
"""
|
324 |
|
325 |
+
demo.add_css(css)
|
326 |
+
print("Custom CSS added to Gradio interface.")
|