nailarais1's picture
Update app.py
c752b08 verified
import sympy as sp
import gradio as gr
import speech_recognition as sr
from gtts import gTTS
import os
import re
def generate_tts(text, engine_choice="auto", output_file="response.mp3"):
"""
Generate TTS audio using gTTS or pyttsx3.
- If `engine_choice` is "gTTS", uses Google TTS (online).
- If `engine_choice` is "pyttsx3", uses pyttsx3 (offline).
- If `engine_choice` is "auto", tries gTTS first, then falls back to pyttsx3.
Args:
- text (str): The text to convert to speech.
- engine_choice (str): "gTTS", "pyttsx3", or "auto".
- output_file (str): Name of the output audio file.
Returns:
- str: Path to the saved audio file.
"""
if engine_choice == "gTTS" or engine_choice == "auto":
try:
tts = gTTS(text, lang="en")
tts.save(output_file)
print(f"Audio generated using gTTS: {output_file}")
return output_file
except Exception as e:
print(f"gTTS failed: {e}")
if engine_choice == "gTTS":
raise e # Raise the error if gTTS is explicitly requested
if engine_choice == "pyttsx3" or engine_choice == "auto":
try:
engine.save_to_file(text, output_file)
engine.runAndWait()
print(f"Audio generated using pyttsx3: {output_file}")
return output_file
except Exception as e:
print(f"pyttsx3 failed: {e}")
raise e # Raise the error if pyttsx3 fails even in auto mode
# Raise an error if no valid engine choice is provided
raise ValueError("Invalid TTS engine choice. Use 'gTTS', 'pyttsx3', or 'auto'.")
def process_math(query, tts_engine="auto"):
"""
Process the math query and convert the result into audio using the selected TTS engine.
Args:
- query (str): The math expression to evaluate.
- tts_engine (str): The TTS engine to use ("gTTS", "pyttsx3", or "auto").
Returns:
- tuple: (result_text, audio_path)
"""
try:
# Clean up the input by removing unnecessary spaces
query = query.replace(" ", "") # Removing extra spaces around operators or parentheses
# Try to process the query using sympy
expr = sp.sympify(query)
# Basic operations handled automatically by sympy
result = expr
# Generate TTS output
result_text = f"The result is: {result}"
audio_path = generate_tts(result_text, engine_choice=tts_engine) # Pass the selected engine
return result_text, audio_path
except Exception as e:
return f"Error: Unable to process the query. Please check the syntax. Error: {e}", None
# Function to handle voice input (speech-to-text)
def voice_to_text(audio):
recognizer = sr.Recognizer()
try:
with sr.AudioFile(audio) as source:
audio_data = recognizer.record(source)
text = recognizer.recognize_google(audio_data)
return text
except Exception as e:
return f"Error in voice recognition: {e}"
# Mapping words to their corresponding numerical values
word_to_num = {
"one": 1, "two": 2, "three": 3, "four": 4, "five": 5,
"six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10,
"eleven": 11, "twelve": 12, "thirteen": 13, "fourteen": 14,
"fifteen": 15, "sixteen": 16, "seventeen": 17, "eighteen": 18,
"nineteen": 19, "twenty": 20, "thirty": 30, "forty": 40,
"fifty": 50, "sixty": 60, "seventy": 70, "eighty": 80, "ninety": 90,
"hundred": 100, "thousand": 1000
}
import re
def convert_speech_to_math(text):
"""
Converts natural language math queries into valid mathematical expressions.
Args:
text (str): The natural language input.
Returns:
str: The converted mathematical expression.
"""
# Convert the input text to lowercase
text = text.lower()
# Arithmetic operations
text = re.sub(r'add (\d+) and (\d+)', r'\1 + \2', text)
text = re.sub(r'subtract (\d+) from (\d+)', r'\2 - \1', text)
text = re.sub(r'multiply (\d+) by (\d+)', r'\1 * \2', text)
text = re.sub(r'divide (\d+) by (\d+)', r'\1 / \2', text)
# Exponentiation and roots
text = re.sub(r'power of (\d+) to (\d+)', r'\1**\2', text)
text = re.sub(r'square of (\d+)', r'\1**2', text)
text = re.sub(r'cube of (\d+)', r'\1**3', text)
text = re.sub(r'square root of (\d+)', r'sqrt(\1)', text)
text = re.sub(r'cube root of (\d+)', r'cbrt(\1)', text)
# Logarithmic operations
text = re.sub(r'log of (\d+)', r'log(\1)', text) # Convert "log of 100" to "log(100)"
text = re.sub(r'log base (\d+) of (\d+)', r'log(\2, \1)', text) # Handle "log base 2 of 8"
text = re.sub(r'natural log of (\d+)', r'ln(\1)', text) # Handle "natural log of 10"
# Trigonometric operations
text = re.sub(r'sine of (.+)', r'sin(\1)', text)
text = re.sub(r'cosine of (.+)', r'cos(\1)', text)
text = re.sub(r'tangent of (.+)', r'tan(\1)', text)
# Inverse trigonometric operations
text = re.sub(r'arc sine of (.+)', r'asin(\1)', text)
text = re.sub(r'arc cosine of (.+)', r'acos(\1)', text)
text = re.sub(r'arc tangent of (.+)', r'atan(\1)', text)
# Factorials and combinatorics
text = re.sub(r'factorial of (\w+)', lambda m: f'factorial({m.group(1)})', text)
text = re.sub(r'permutation of (\d+), (\d+)', r'permutation(\1, \2)', text)
text = re.sub(r'combination of (\d+), (\d+)', r'combinations(\1, \2)', text)
# Calculus
text = re.sub(r'differentiate (.+)', r'diff(\1, x)', text)
text = re.sub(r'integrate (.+)', r'integrate(\1, x)', text)
text = re.sub(r'limit of (.+)', r'limit(\1, x, 0)', text)
# Matrices
text = re.sub(r'matrix of (\[.*\])', r'Matrix(\1)', text)
# Complex numbers
text = re.sub(r'absolute value of (.+)', r'Abs(\1)', text)
text = re.sub(r'conjugate of (.+)', r'conjugate(\1)', text)
# Set operations
text = re.sub(r'union of (.+) and (.+)', r'Union(\1, \2)', text)
text = re.sub(r'intersection of (.+) and (.+)', r'Intersection(\1, \2)', text)
text = re.sub(r'complement of (.+)', r'Complement(\1)', text)
# Statistical operations
text = re.sub(r'mean of (.+)', r'Mean(\1)', text)
text = re.sub(r'median of (.+)', r'Median(\1)', text)
text = re.sub(r'standard deviation of (.+)', r'std(\1)', text)
text = re.sub(r'variance of (.+)', r'variance(\1)', text)
# Custom math operations
text = re.sub(r'absolute difference between (\d+) and (\d+)', r'Abs(\1 - \2)', text)
text = re.sub(r'floor of (.+)', r'floor(\1)', text)
text = re.sub(r'ceiling of (.+)', r'ceiling(\1)', text)
# Miscellaneous formatting fixes
text = re.sub(r'\s*\(', r'(', text) # Remove spaces before parentheses
text = re.sub(r'to the power of (\d+)', r'**\1', text) # Handle "to the power of"
# Handle additional edge cases
text = re.sub(r'logof(\d+)', r'log(\1)', text) # Correct misinterpreted "logof100"
text = re.sub(r'sqrt(\d+)', r'sqrt(\1)', text) # Ensure proper sqrt function
return text
def calculator(audio=None, text_input=None, tts_engine="auto"):
"""
Main function to handle input and process it for math calculation (text or voice).
Args:
- audio: Filepath to the audio input.
- text_input: Math expression in text form.
- tts_engine: Selected TTS engine ("gTTS", "pyttsx3", or "auto").
"""
if audio:
query = voice_to_text(audio)
print(f"Voice Input Detected: {query}") # Debugging: Print detected voice input
query = convert_speech_to_math(query) # Convert the voice input into valid math expression
elif text_input:
query = text_input
print(f"Text Input: {query}") # Debugging: Print detected text input
else:
return "No valid input provided.", None
# Process the math problem
return process_math(query, tts_engine)
def start_interface():
# Gradio Interface with Voice Input, Text Input, and TTS Engine Choice
interface = gr.Interface(
fn=calculator,
inputs=[
gr.Audio(type="filepath", label="Speak a Math Expression (e.g., factorial(5), differentiate x squared, integrate sin(x), matrix([[1, 2], [3, 4]]) )"),
gr.Textbox(label="Or Type a Math Expression (Optional)", placeholder="Type your math expression here..."),
gr.Radio(choices=["auto", "gTTS", "pyttsx3"], value="auto", label="Select TTS Engine")
],
outputs=[
"text", # Show the text result
gr.Audio(label="Listen to the result") # Provide the audio result
],
title="Advanced Math Solver with Dual TTS",
description="Solve math problems with both online (gTTS) and offline (pyttsx3) TTS support.",
live=True
)
interface.launch(share=True)
if __name__ == "__main__":
start_interface()