Spaces:
Sleeping
Sleeping
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() | |