|
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 |
|
|
|
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 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: |
|
|
|
query = query.replace(" ", "") |
|
|
|
|
|
expr = sp.sympify(query) |
|
|
|
|
|
result = expr |
|
|
|
|
|
result_text = f"The result is: {result}" |
|
audio_path = generate_tts(result_text, engine_choice=tts_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 |
|
|
|
|
|
|
|
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}" |
|
|
|
|
|
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. |
|
""" |
|
|
|
text = text.lower() |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
text = re.sub(r'log of (\d+)', r'log(\1)', text) |
|
text = re.sub(r'log base (\d+) of (\d+)', r'log(\2, \1)', text) |
|
text = re.sub(r'natural log of (\d+)', r'ln(\1)', text) |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
text = re.sub(r'matrix of (\[.*\])', r'Matrix(\1)', text) |
|
|
|
|
|
text = re.sub(r'absolute value of (.+)', r'Abs(\1)', text) |
|
text = re.sub(r'conjugate of (.+)', r'conjugate(\1)', text) |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
text = re.sub(r'\s*\(', r'(', text) |
|
text = re.sub(r'to the power of (\d+)', r'**\1', text) |
|
|
|
|
|
text = re.sub(r'logof(\d+)', r'log(\1)', text) |
|
text = re.sub(r'sqrt(\d+)', r'sqrt(\1)', text) |
|
|
|
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}") |
|
query = convert_speech_to_math(query) |
|
elif text_input: |
|
query = text_input |
|
print(f"Text Input: {query}") |
|
else: |
|
return "No valid input provided.", None |
|
|
|
|
|
return process_math(query, tts_engine) |
|
|
|
|
|
def start_interface(): |
|
|
|
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", |
|
gr.Audio(label="Listen to the 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() |
|
|
|
|