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()