Spaces:
Running
Running
Upload 2 files
Browse files- app.py +80 -0
- requirements.txt +7 -0
app.py
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import pyttsx3
|
3 |
+
from gtts import gTTS
|
4 |
+
import os
|
5 |
+
import librosa
|
6 |
+
import soundfile as sf
|
7 |
+
import time
|
8 |
+
import numpy as np
|
9 |
+
from io import BytesIO
|
10 |
+
|
11 |
+
# Function to Convert Text to Speech
|
12 |
+
def text_to_speech(text, engine='offline', gender='male'):
|
13 |
+
filename = f"audio_{int(time.time())}.wav"
|
14 |
+
if engine == 'offline':
|
15 |
+
tts_engine = pyttsx3.init()
|
16 |
+
tts_engine.setProperty('rate', 160) # Adjust speed
|
17 |
+
tts_engine.setProperty('volume', 2.0) # Max volume
|
18 |
+
voices = tts_engine.getProperty('voices')
|
19 |
+
|
20 |
+
if gender == 'male':
|
21 |
+
tts_engine.setProperty('voice', voices[0].id) # Male voice
|
22 |
+
else:
|
23 |
+
tts_engine.setProperty('voice', voices[1].id) # Female voice
|
24 |
+
|
25 |
+
tts_engine.save_to_file(text, filename)
|
26 |
+
tts_engine.runAndWait()
|
27 |
+
elif engine == 'online':
|
28 |
+
tts = gTTS(text=text, lang='en', slow=False)
|
29 |
+
filename = f"audio_{int(time.time())}.mp3"
|
30 |
+
tts.save(filename)
|
31 |
+
return filename
|
32 |
+
|
33 |
+
# Function to Modify Voice Pitch
|
34 |
+
def change_voice(input_file, gender="male"):
|
35 |
+
y, sr = librosa.load(input_file, sr=44100)
|
36 |
+
pitch_factor = -3 if gender == "male" else 5 # Adjust pitch naturally
|
37 |
+
y_shifted = librosa.effects.pitch_shift(y, n_steps=pitch_factor, sr=sr)
|
38 |
+
output_file = f"modified_{int(time.time())}.wav"
|
39 |
+
sf.write(output_file, y_shifted, sr)
|
40 |
+
return output_file
|
41 |
+
|
42 |
+
# Streamlit UI
|
43 |
+
st.set_page_config(page_title="π€ Voice Generator App", layout="centered")
|
44 |
+
st.title("π€ AI-Powered Voice Generator")
|
45 |
+
st.markdown("**Convert your text into speech with natural, clear voices!** πΆ")
|
46 |
+
st.divider()
|
47 |
+
|
48 |
+
st.subheader("Enter Your Text")
|
49 |
+
text = st.text_area("π Type or paste your text below:")
|
50 |
+
|
51 |
+
st.subheader("Choose Voice Engine")
|
52 |
+
engine = st.radio("βοΈ Select a Text-to-Speech Engine:",
|
53 |
+
["Offline (Fast, Customizable)", "Online (Natural, Requires Internet)"])
|
54 |
+
engine_mode = "offline" if "Offline" in engine else "online"
|
55 |
+
|
56 |
+
st.subheader("Select Voice Type")
|
57 |
+
gender = st.radio("π Choose Voice Gender:", ["Male", "Female"])
|
58 |
+
|
59 |
+
if st.button("ποΈ Generate Voice"):
|
60 |
+
if text:
|
61 |
+
st.info("β³ Processing your request... Please wait.")
|
62 |
+
audio_file = text_to_speech(text, engine_mode, gender.lower())
|
63 |
+
modified_audio = change_voice(audio_file, gender.lower())
|
64 |
+
|
65 |
+
st.success("β
Voice generated successfully!")
|
66 |
+
st.audio(modified_audio, format='audio/wav')
|
67 |
+
|
68 |
+
with open(modified_audio, "rb") as file:
|
69 |
+
audio_bytes = file.read()
|
70 |
+
|
71 |
+
st.download_button(label="β¬οΈ Download Audio", data=audio_bytes,
|
72 |
+
file_name=modified_audio, mime="audio/wav")
|
73 |
+
else:
|
74 |
+
st.warning("β οΈ Please enter text to generate voice.")
|
75 |
+
|
76 |
+
st.markdown("---")
|
77 |
+
st.caption("πΉ **Offline Mode** uses your system's built-in voices and works without the internet.")
|
78 |
+
st.caption("πΉ **Online Mode** uses Google TTS for a more natural voice but requires an internet connection.")
|
79 |
+
st.divider()
|
80 |
+
st.caption("π» So called Arman.")
|
requirements.txt
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit
|
2 |
+
pyttsx3
|
3 |
+
gtts
|
4 |
+
librosa
|
5 |
+
soundfile
|
6 |
+
numpy
|
7 |
+
pydub
|