import gradio as gr
import numpy as np
import io
import tempfile
import os
from scipy.io import wavfile
import speech_recognition as sr
import soundfile as sf

# Morse code dictionary (ITU standard)
MORSE_CODE_DICT = {
    'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.',
    'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..',
    'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.',
    'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
    'Y': '-.--', 'Z': '--..', '1': '.----', '2': '..---', '3': '...--',
    '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..',
    '9': '----.', '0': '-----', ' ': '/'
}
MORSE_TO_CHAR = {v: k for k, v in MORSE_CODE_DICT.items()}

# Morse code timing (in seconds)
DIT_DURATION = 0.1  # 100ms for dit
DAH_DURATION = 3 * DIT_DURATION
SPACE_DURATION = 7 * DIT_DURATION
CHAR_SPACE = DIT_DURATION
SAMPLE_RATE = 44100

# Decode Morse from audio beeps
def decode_morse_from_audio(audio_data, is_file=False):
    if audio_data is None:
        return "", ""
    if is_file:
        sample_rate, data = wavfile.read(audio_data)
    else:
        sample_rate, data = audio_data
    if len(data.shape) > 1:
        data = data.mean(axis=1)
    data = data / np.max(np.abs(data))
    
    threshold = 0.1
    signal = data > threshold
    morse_code, decoded_text = "", ""
    i = 0
    
    while i < len(signal) - int(SAMPLE_RATE * DIT_DURATION):
        if signal[i]:
            start = i
            while i < len(signal) and signal[i]:
                i += 1
            duration = (i - start) / sample_rate
            morse_code += "-" if duration >= DAH_DURATION else "."
        else:
            start = i
            while i < len(signal) and not signal[i]:
                i += 1
            pause = (i - start) / sample_rate
            if pause >= SPACE_DURATION and morse_code:
                decoded_text += " "
                morse_code = ""
            elif pause >= DIT_DURATION and morse_code:
                decoded_text += MORSE_TO_CHAR.get(morse_code, "?")
                morse_code = ""
        i += 1
    
    if morse_code:
        decoded_text += MORSE_TO_CHAR.get(morse_code, "?")
    return morse_code, decoded_text.strip()

# Decode Morse from text (e.g., ".... . .-.. .-.. ---")
def decode_morse_from_text(morse_text):
    if not morse_text:
        return ""
    words = morse_text.split("/")
    decoded_text = ""
    for word in words:
        chars = word.strip().split()
        for char in chars:
            decoded_text += MORSE_TO_CHAR.get(char, "?")
        decoded_text += " "
    return decoded_text.strip()

# Convert text to Morse code
def text_to_morse(text):
    text = text.upper()
    morse = " ".join(MORSE_CODE_DICT.get(char, "?") for char in text if char in MORSE_CODE_DICT)
    return morse

# Generate Morse audio from Morse code string
def generate_morse_audio(morse):
    audio = []
    frequency = 750
    
    for symbol in morse.split():
        if symbol == "/":
            audio.extend([0] * int(SAMPLE_RATE * SPACE_DURATION))
        else:
            for char in symbol:
                duration = DAH_DURATION if char == "-" else DIT_DURATION
                t = np.linspace(0, duration, int(SAMPLE_RATE * duration), False)
                tone = 0.5 * np.sin(2 * np.pi * frequency * t)
                audio.extend(tone)
                audio.extend([0] * int(SAMPLE_RATE * DIT_DURATION))
            audio.extend([0] * int(SAMPLE_RATE * CHAR_SPACE))
    
    audio = np.array(audio, dtype=np.float32)
    with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_file:
        sf.write(temp_file.name, audio, SAMPLE_RATE, format="wav")
        return temp_file.name

# Speech to text (for both plain speech and spoken Morse)
def speech_to_text(audio_path):
    recognizer = sr.Recognizer()
    with sr.AudioFile(audio_path) as source:
        audio_data = recognizer.record(source)
    try:
        return recognizer.recognize_google(audio_data)
    except sr.UnknownValueError:
        return "Could not understand audio"
    except sr.RequestError:
        return "Speech recognition service unavailable"

# Highlight alphabet
def generate_alphabet_html(decoded_text):
    html = "<div style='font-family: monospace; font-size: 16px;'>"
    for char in MORSE_CODE_DICT.keys():
        color = "red" if char in decoded_text.upper() else "black"
        html += f"<span style='color: {color}; margin: 5px;'>{char}: {MORSE_CODE_DICT[char]}</span>"
        if char in "AEIMQUZ":
            html += "<br>"
    html += "</div>"
    return html

# Main processing function
def process_input(text=None, speech=None, live_audio=None, upload_audio=None, morse_text=None, morse_speech=None, morse_audio=None):
    morse_output, text_output, audio_output = "", "", None
    
    # Encoding: Text/Speech/Audio to Morse
    if text:  # Plain text to Morse
        morse_output = text_to_morse(text)
        text_output = text
        audio_output = generate_morse_audio(morse_output)
    
    elif speech:  # Spoken text to Morse
        transcribed = speech_to_text(speech)
        morse_output = text_to_morse(transcribed)
        text_output = transcribed
        audio_output = generate_morse_audio(morse_output)
    
    elif live_audio:  # Live audio to Morse (assuming plain audio, not Morse)
        # For simplicity, treat as Morse audio for decoding instead
        morse_output, text_output = decode_morse_from_audio(live_audio, is_file=False)
    
    elif upload_audio:  # Uploaded audio to Morse (assuming plain audio, not Morse)
        # For simplicity, treat as Morse audio for decoding instead
        morse_output, text_output = decode_morse_from_audio(upload_audio, is_file=True)
    
    # Decoding: Morse Text/Speech/Audio to Text
    elif morse_text:  # Morse text to plain text
        morse_output = morse_text
        text_output = decode_morse_from_text(morse_text)
        audio_output = generate_morse_audio(morse_text)
    
    elif morse_speech:  # Spoken Morse (e.g., "dit dah") to text
        transcribed = speech_to_text(morse_speech).replace("dit", ".").replace("dah", "-").replace("slash", "/")
        morse_output = transcribed
        text_output = decode_morse_from_text(transcribed)
        audio_output = generate_morse_audio(transcribed)
    
    elif morse_audio:  # Morse audio file to text
        morse_output, text_output = decode_morse_from_audio(morse_audio, is_file=True)
    
    alphabet_html = generate_alphabet_html(text_output)
    return morse_output, text_output, alphabet_html, audio_output

# Gradio UI
with gr.Blocks(title="Morse Code Converter") as demo:
    gr.Markdown("# Morse Code Converter")
    gr.Markdown("Encode text/speech to Morse, or decode Morse text/speech/audio to text!")
    
    # Encode Section
    with gr.Tab("Encode Text to Morse"):
        text_input = gr.Textbox(label="Enter Text", placeholder="e.g., HELLO")
        text_btn = gr.Button("Convert to Morse")
        with gr.Row():
            with gr.Column():
                text_morse_out = gr.Textbox(label="Morse Code", interactive=False)
                text_text_out = gr.Textbox(label="Original Text", interactive=False)
            text_alphabet = gr.HTML(label="Alphabet (Highlighted)")
        text_audio = gr.Audio(label="Morse Audio", interactive=False)
        text_btn.click(fn=process_input, inputs=[text_input], outputs=[text_morse_out, text_text_out, text_alphabet, text_audio])

    with gr.Tab("Encode Speech to Morse"):
        speech_input = gr.Audio(type="filepath", label="Record Speech (e.g., say 'HELLO')")
        speech_btn = gr.Button("Convert to Morse")
        with gr.Row():
            with gr.Column():
                speech_morse_out = gr.Textbox(label="Morse Code", interactive=False)
                speech_text_out = gr.Textbox(label="Transcribed Text", interactive=False)
            speech_alphabet = gr.HTML(label="Alphabet (Highlighted)")
        speech_audio = gr.Audio(label="Morse Audio", interactive=False)
        speech_btn.click(fn=process_input, inputs=[speech_input], outputs=[speech_morse_out, speech_text_out, speech_alphabet, speech_audio])

    # Decode Section
    with gr.Tab("Decode Morse Text"):
        morse_text_input = gr.Textbox(label="Enter Morse Text", placeholder="e.g., .... . .-.. .-.. ---")
        morse_text_btn = gr.Button("Decode Morse")
        with gr.Row():
            with gr.Column():
                morse_text_morse_out = gr.Textbox(label="Morse Code", interactive=False)
                morse_text_text_out = gr.Textbox(label="Decoded Text", interactive=False)
            morse_text_alphabet = gr.HTML(label="Alphabet (Highlighted)")
        morse_text_audio = gr.Audio(label="Morse Audio", interactive=False)
        morse_text_btn.click(fn=process_input, inputs=[morse_text_input], outputs=[morse_text_morse_out, morse_text_text_out, morse_text_alphabet, morse_text_audio])

    with gr.Tab("Decode Morse Speech"):
        morse_speech_input = gr.Audio(type="filepath", label="Record Morse Speech (e.g., say 'dit dit dit dit dit')")
        morse_speech_btn = gr.Button("Decode Morse")
        with gr.Row():
            with gr.Column():
                morse_speech_morse_out = gr.Textbox(label="Transcribed Morse", interactive=False)
                morse_speech_text_out = gr.Textbox(label="Decoded Text", interactive=False)
            morse_speech_alphabet = gr.HTML(label="Alphabet (Highlighted)")
        morse_speech_audio = gr.Audio(label="Morse Audio", interactive=False)
        morse_speech_btn.click(fn=process_input, inputs=[morse_speech_input], outputs=[morse_speech_morse_out, morse_speech_text_out, morse_speech_alphabet, morse_speech_audio])

    with gr.Tab("Decode Morse Audio"):
        morse_audio_input = gr.Audio(type="filepath", label="Upload Morse Audio (WAV of beeps)")
        morse_audio_btn = gr.Button("Decode Morse")
        with gr.Row():
            with gr.Column():
                morse_audio_morse_out = gr.Textbox(label="Detected Morse", interactive=False)
                morse_audio_text_out = gr.Textbox(label="Decoded Text", interactive=False)
            morse_audio_alphabet = gr.HTML(label="Alphabet (Highlighted)")
        morse_audio_btn.click(fn=process_input, inputs=[morse_audio_input], outputs=[morse_audio_morse_out, morse_audio_text_out, morse_audio_alphabet, gr.Audio(visible=False)])

    with gr.Tab("Decode Live Morse Audio"):
        live_audio_input = gr.Audio(type="numpy", label="Live Morse Input (Use Microphone)", streaming=True)
        with gr.Row():
            with gr.Column():
                live_morse_out = gr.Textbox(label="Detected Morse", interactive=False)
                live_text_out = gr.Textbox(label="Decoded Text", interactive=False)
            live_alphabet = gr.HTML(label="Alphabet (Highlighted)")
        live_audio_input.stream(fn=process_input, inputs=[live_audio_input], outputs=[live_morse_out, live_text_out, live_alphabet, gr.Audio(visible=False)])

demo.launch()

'''
import gradio as gr
import numpy as np
import io
import tempfile
import os
from scipy.io import wavfile
import speech_recognition as sr
import soundfile as sf

# Morse code dictionary (ITU standard)
MORSE_CODE_DICT = {
    'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.',
    'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..',
    'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.',
    'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
    'Y': '-.--', 'Z': '--..', '1': '.----', '2': '..---', '3': '...--',
    '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..',
    '9': '----.', '0': '-----', ' ': '/'
}
MORSE_TO_CHAR = {v: k for k, v in MORSE_CODE_DICT.items()}

# Morse code timing (in seconds)
DIT_DURATION = 0.1  # 100ms for dit
DAH_DURATION = 3 * DIT_DURATION  # 300ms for dah
SPACE_DURATION = 7 * DIT_DURATION  # 700ms for word space
CHAR_SPACE = DIT_DURATION  # Space between characters
SAMPLE_RATE = 44100  # Standard audio sample rate

# Decode Morse from audio (live or uploaded)
def decode_morse_from_audio(audio_data, is_file=False):
    if audio_data is None:
        return "", ""
    
    if is_file:
        # For uploaded files, audio_data is a file path
        sample_rate, data = wavfile.read(audio_data)
    else:
        # For live streaming, audio_data is (sample_rate, data)
        sample_rate, data = audio_data
    
    if len(data.shape) > 1:
        data = data.mean(axis=1)
    data = data / np.max(np.abs(data))
    
    threshold = 0.1
    signal = data > threshold
    morse_code, decoded_text = "", ""
    i = 0
    
    while i < len(signal) - int(SAMPLE_RATE * DIT_DURATION):
        if signal[i]:
            start = i
            while i < len(signal) and signal[i]:
                i += 1
            duration = (i - start) / sample_rate
            morse_code += "-" if duration >= DAH_DURATION else "."
        else:
            start = i
            while i < len(signal) and not signal[i]:
                i += 1
            pause = (i - start) / sample_rate
            if pause >= SPACE_DURATION and morse_code:
                decoded_text += " "
                morse_code = ""
            elif pause >= DIT_DURATION and morse_code:
                decoded_text += MORSE_TO_CHAR.get(morse_code, "?")
                morse_code = ""
        i += 1
    
    if morse_code:
        decoded_text += MORSE_TO_CHAR.get(morse_code, "?")
    return morse_code, decoded_text.strip()

# Convert text to Morse code
def text_to_morse(text):
    text = text.upper()
    morse = " ".join(MORSE_CODE_DICT.get(char, "?") for char in text if char in MORSE_CODE_DICT)
    return morse

# Generate Morse code audio and save to temporary file
def generate_morse_audio(morse):
    audio = []
    frequency = 750  # Hz for Morse tone
    
    for symbol in morse.split():
        if symbol == "/":
            audio.extend([0] * int(SAMPLE_RATE * SPACE_DURATION))
        else:
            for char in symbol:
                duration = DAH_DURATION if char == "-" else DIT_DURATION
                t = np.linspace(0, duration, int(SAMPLE_RATE * duration), False)
                tone = 0.5 * np.sin(2 * np.pi * frequency * t)
                audio.extend(tone)
                audio.extend([0] * int(SAMPLE_RATE * DIT_DURATION))  # Space between dits/dahs
            audio.extend([0] * int(SAMPLE_RATE * CHAR_SPACE))  # Space between characters
    
    audio = np.array(audio, dtype=np.float32)
    with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_file:
        sf.write(temp_file.name, audio, SAMPLE_RATE, format="wav")
        temp_file_path = temp_file.name
    return temp_file_path

# Speech to text
def speech_to_text(audio_path):
    recognizer = sr.Recognizer()
    with sr.AudioFile(audio_path) as source:
        audio_data = recognizer.record(source)
    try:
        return recognizer.recognize_google(audio_data)
    except sr.UnknownValueError:
        return "Could not understand audio"
    except sr.RequestError:
        return "Speech recognition service unavailable"

# Highlight alphabet in UI
def generate_alphabet_html(decoded_text):
    html = "<div style='font-family: monospace; font-size: 16px;'>"
    for char in MORSE_CODE_DICT.keys():
        color = "red" if char in decoded_text.upper() else "black"
        html += f"<span style='color: {color}; margin: 5px;'>{char}: {MORSE_CODE_DICT[char]}</span>"
        if char in "AEIMQUZ":
            html += "<br>"
    html += "</div>"
    return html

# Combined processing function
def process_input(text=None, speech=None, live_audio=None, upload_audio=None):
    morse, decoded_text, audio_output = "", "", None
    
    if text:  # Text input
        morse = text_to_morse(text)
        decoded_text = text
        audio_output = generate_morse_audio(morse)
    
    elif speech:  # Speech input
        text = speech_to_text(speech)
        morse = text_to_morse(text)
        decoded_text = text
        audio_output = generate_morse_audio(morse)
    
    elif live_audio:  # Live audio input
        morse, decoded_text = decode_morse_from_audio(live_audio, is_file=False)
    
    elif upload_audio:  # Uploaded audio file
        morse, decoded_text = decode_morse_from_audio(upload_audio, is_file=True)
    
    alphabet_html = generate_alphabet_html(decoded_text)
    return morse, decoded_text, alphabet_html, audio_output

# Gradio UI with Blocks
with gr.Blocks(title="Morse Code Decoder & Generator") as demo:
    gr.Markdown("# Morse Code Decoder & Generator")
    gr.Markdown("Decode live or uploaded Morse audio, or generate Morse from text/speech!")
    
    with gr.Tab("Decode Live Audio"):
        audio_input = gr.Audio(type="numpy", label="Live Audio Input (Use Microphone)", streaming=True)
        with gr.Row():
            with gr.Column():
                morse_output = gr.Textbox(label="Detected Morse Code", interactive=False)
                text_output = gr.Textbox(label="Decoded Text", interactive=False)
            alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)")
        
        audio_input.stream(
            fn=process_input,
            inputs=[audio_input],
            outputs=[morse_output, text_output, alphabet_display, gr.Audio(visible=False)],
        )
    
    with gr.Tab("Generate from Text"):
        text_input = gr.Textbox(label="Enter Text", placeholder="Type here...")
        generate_btn = gr.Button("Generate Morse")
        with gr.Row():
            with gr.Column():
                morse_gen_output = gr.Textbox(label="Morse Code", interactive=False)
                text_gen_output = gr.Textbox(label="Original Text", interactive=False)
            gen_alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)")
        audio_playback = gr.Audio(label="Morse Audio Playback", interactive=False)
        
        generate_btn.click(
            fn=process_input,
            inputs=[text_input],
            outputs=[morse_gen_output, text_gen_output, gen_alphabet_display, audio_playback]
        )
    
    with gr.Tab("Generate from Speech"):
        speech_input = gr.Audio(type="filepath", label="Speak Your Text (Record Audio)")
        speech_btn = gr.Button("Convert Speech to Morse")
        with gr.Row():
            with gr.Column():
                morse_speech_output = gr.Textbox(label="Morse Code", interactive=False)
                text_speech_output = gr.Textbox(label="Transcribed Text", interactive=False)
            speech_alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)")
        speech_audio_playback = gr.Audio(label="Morse Audio Playback", interactive=False)
        
        speech_btn.click(
            fn=process_input,
            inputs=[speech_input],
            outputs=[morse_speech_output, text_speech_output, speech_alphabet_display, speech_audio_playback]
        )
    
    with gr.Tab("Decode from Audio Upload"):
        upload_input = gr.Audio(type="filepath", label="Upload Morse Audio File (WAV)")
        upload_btn = gr.Button("Decode Morse")
        with gr.Row():
            with gr.Column():
                morse_upload_output = gr.Textbox(label="Detected Morse Code", interactive=False)
                text_upload_output = gr.Textbox(label="Decoded Text", interactive=False)
            upload_alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)")
        
        upload_btn.click(
            fn=process_input,
            inputs=[upload_input],
            outputs=[morse_upload_output, text_upload_output, upload_alphabet_display, gr.Audio(visible=False)]
        )

# Launch the app
demo.launch()
'''
'''
import gradio as gr
import numpy as np
import io
import tempfile
import os
from scipy.io import wavfile
import speech_recognition as sr
import soundfile as sf

# Morse code dictionary (ITU standard)
MORSE_CODE_DICT = {
    'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.',
    'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..',
    'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.',
    'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
    'Y': '-.--', 'Z': '--..', '1': '.----', '2': '..---', '3': '...--',
    '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..',
    '9': '----.', '0': '-----', ' ': '/'
}
MORSE_TO_CHAR = {v: k for k, v in MORSE_CODE_DICT.items()}

# Morse code timing (in seconds)
DIT_DURATION = 0.1  # 100ms for dit
DAH_DURATION = 3 * DIT_DURATION  # 300ms for dah
SPACE_DURATION = 7 * DIT_DURATION  # 700ms for word space
CHAR_SPACE = DIT_DURATION  # Space between characters
SAMPLE_RATE = 44100  # Standard audio sample rate

# Decode Morse from audio
def decode_morse_from_audio(audio_data):
    if audio_data is None:
        return "", ""
    sample_rate, data = audio_data
    if len(data.shape) > 1:
        data = data.mean(axis=1)
    data = data / np.max(np.abs(data))
    
    threshold = 0.1
    signal = data > threshold
    morse_code, decoded_text = "", ""
    i = 0
    
    while i < len(signal) - int(SAMPLE_RATE * DIT_DURATION):
        if signal[i]:
            start = i
            while i < len(signal) and signal[i]:
                i += 1
            duration = (i - start) / sample_rate
            morse_code += "-" if duration >= DAH_DURATION else "."
        else:
            start = i
            while i < len(signal) and not signal[i]:
                i += 1
            pause = (i - start) / sample_rate
            if pause >= SPACE_DURATION and morse_code:
                decoded_text += " "
                morse_code = ""
            elif pause >= DIT_DURATION and morse_code:
                decoded_text += MORSE_TO_CHAR.get(morse_code, "?")
                morse_code = ""
        i += 1
    
    if morse_code:
        decoded_text += MORSE_TO_CHAR.get(morse_code, "?")
    return morse_code, decoded_text.strip()

# Convert text to Morse code
def text_to_morse(text):
    text = text.upper()
    morse = " ".join(MORSE_CODE_DICT.get(char, "?") for char in text if char in MORSE_CODE_DICT)
    return morse

# Generate Morse code audio and save to temporary file
def generate_morse_audio(morse):
    audio = []
    frequency = 750  # Hz for Morse tone
    
    for symbol in morse.split():
        if symbol == "/":
            audio.extend([0] * int(SAMPLE_RATE * SPACE_DURATION))
        else:
            for char in symbol:
                duration = DAH_DURATION if char == "-" else DIT_DURATION
                t = np.linspace(0, duration, int(SAMPLE_RATE * duration), False)
                tone = 0.5 * np.sin(2 * np.pi * frequency * t)
                audio.extend(tone)
                audio.extend([0] * int(SAMPLE_RATE * DIT_DURATION))  # Space between dits/dahs
            audio.extend([0] * int(SAMPLE_RATE * CHAR_SPACE))  # Space between characters
    
    audio = np.array(audio, dtype=np.float32)
    # Save to a temporary file
    with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_file:
        sf.write(temp_file.name, audio, SAMPLE_RATE, format="wav")
        temp_file_path = temp_file.name
    return temp_file_path

# Speech to text
def speech_to_text(audio_path):
    recognizer = sr.Recognizer()
    with sr.AudioFile(audio_path) as source:
        audio_data = recognizer.record(source)
    try:
        return recognizer.recognize_google(audio_data)
    except sr.UnknownValueError:
        return "Could not understand audio"
    except sr.RequestError:
        return "Speech recognition service unavailable"

# Highlight alphabet in UI
def generate_alphabet_html(decoded_text):
    html = "<div style='font-family: monospace; font-size: 16px;'>"
    for char in MORSE_CODE_DICT.keys():
        color = "red" if char in decoded_text.upper() else "black"
        html += f"<span style='color: {color}; margin: 5px;'>{char}: {MORSE_CODE_DICT[char]}</span>"
        if char in "AEIMQUZ":
            html += "<br>"
    html += "</div>"
    return html

# Combined processing function with cleanup
def process_input(text=None, speech=None, audio=None):
    morse, decoded_text, audio_output = "", "", None
    
    if text:  # Text input
        morse = text_to_morse(text)
        decoded_text = text
        audio_output = generate_morse_audio(morse)
    
    elif speech:  # Speech input
        text = speech_to_text(speech)
        morse = text_to_morse(text)
        decoded_text = text
        audio_output = generate_morse_audio(morse)
    
    elif audio:  # Live audio input
        morse, decoded_text = decode_morse_from_audio(audio)
    
    alphabet_html = generate_alphabet_html(decoded_text)
    return morse, decoded_text, alphabet_html, audio_output

# Gradio UI with Blocks
with gr.Blocks(title="Morse Code Decoder & Generator") as demo:
    gr.Markdown("# Morse Code Decoder & Generator")
    gr.Markdown("Decode live Morse audio, or generate Morse from text/speech!")
    
    with gr.Tab("Decode Live Audio"):
        audio_input = gr.Audio(type="numpy", label="Live Audio Input (Use Microphone)", streaming=True)
        with gr.Row():
            with gr.Column():
                morse_output = gr.Textbox(label="Detected Morse Code", interactive=False)
                text_output = gr.Textbox(label="Decoded Text", interactive=False)
            alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)")
        
        audio_input.stream(
            fn=process_input,
            inputs=[audio_input],
            outputs=[morse_output, text_output, alphabet_display, gr.Audio(visible=False)],
        )
    
    with gr.Tab("Generate from Text"):
        text_input = gr.Textbox(label="Enter Text", placeholder="Type here...")
        generate_btn = gr.Button("Generate Morse")
        with gr.Row():
            with gr.Column():
                morse_gen_output = gr.Textbox(label="Morse Code", interactive=False)
                text_gen_output = gr.Textbox(label="Original Text", interactive=False)
            gen_alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)")
        audio_playback = gr.Audio(label="Morse Audio Playback", interactive=False)
        
        generate_btn.click(
            fn=process_input,
            inputs=[text_input],
            outputs=[morse_gen_output, text_gen_output, gen_alphabet_display, audio_playback]
        )
    
    with gr.Tab("Generate from Speech"):
        speech_input = gr.Audio(type="filepath", label="Speak Your Text (Record Audio)")
        speech_btn = gr.Button("Convert Speech to Morse")
        with gr.Row():
            with gr.Column():
                morse_speech_output = gr.Textbox(label="Morse Code", interactive=False)
                text_speech_output = gr.Textbox(label="Transcribed Text", interactive=False)
            speech_alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)")
        speech_audio_playback = gr.Audio(label="Morse Audio Playback", interactive=False)
        
        speech_btn.click(
            fn=process_input,
            inputs=[speech_input],
            outputs=[morse_speech_output, text_speech_output, speech_alphabet_display, speech_audio_playback]
        )

# Launch the app
demo.launch()
'''

'''
import gradio as gr
import numpy as np
import io
from scipy.io import wavfile
import speech_recognition as sr
import soundfile as sf

# Morse code dictionary (ITU standard)
MORSE_CODE_DICT = {
    'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.',
    'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..',
    'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.',
    'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
    'Y': '-.--', 'Z': '--..', '1': '.----', '2': '..---', '3': '...--',
    '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..',
    '9': '----.', '0': '-----', ' ': '/'
}
MORSE_TO_CHAR = {v: k for k, v in MORSE_CODE_DICT.items()}

# Morse code timing (in seconds)
DIT_DURATION = 0.1  # 100ms for dit
DAH_DURATION = 3 * DIT_DURATION  # 300ms for dah
SPACE_DURATION = 7 * DIT_DURATION  # 700ms for word space
CHAR_SPACE = DIT_DURATION  # Space between characters
SAMPLE_RATE = 44100  # Standard audio sample rate

# Decode Morse from audio
def decode_morse_from_audio(audio_data):
    if audio_data is None:
        return "", ""
    sample_rate, data = audio_data
    if len(data.shape) > 1:
        data = data.mean(axis=1)
    data = data / np.max(np.abs(data))
    
    threshold = 0.1
    signal = data > threshold
    morse_code, decoded_text = "", ""
    i = 0
    
    while i < len(signal) - int(SAMPLE_RATE * DIT_DURATION):
        if signal[i]:
            start = i
            while i < len(signal) and signal[i]:
                i += 1
            duration = (i - start) / sample_rate
            morse_code += "-" if duration >= DAH_DURATION else "."
        else:
            start = i
            while i < len(signal) and not signal[i]:
                i += 1
            pause = (i - start) / sample_rate
            if pause >= SPACE_DURATION and morse_code:
                decoded_text += " "
                morse_code = ""
            elif pause >= DIT_DURATION and morse_code:
                decoded_text += MORSE_TO_CHAR.get(morse_code, "?")
                morse_code = ""
        i += 1
    
    if morse_code:
        decoded_text += MORSE_TO_CHAR.get(morse_code, "?")
    return morse_code, decoded_text.strip()

# Convert text to Morse code
def text_to_morse(text):
    text = text.upper()
    morse = " ".join(MORSE_CODE_DICT.get(char, "?") for char in text if char in MORSE_CODE_DICT)
    return morse

# Generate Morse code audio
def generate_morse_audio(morse):
    audio = []
    frequency = 750  # Hz for Morse tone
    
    for symbol in morse.split():
        if symbol == "/":
            audio.extend([0] * int(SAMPLE_RATE * SPACE_DURATION))
        else:
            for char in symbol:
                duration = DAH_DURATION if char == "-" else DIT_DURATION
                t = np.linspace(0, duration, int(SAMPLE_RATE * duration), False)
                tone = 0.5 * np.sin(2 * np.pi * frequency * t)
                audio.extend(tone)
                audio.extend([0] * int(SAMPLE_RATE * DIT_DURATION))  # Space between dits/dahs
            audio.extend([0] * int(SAMPLE_RATE * CHAR_SPACE))  # Space between characters
    
    audio = np.array(audio, dtype=np.float32)
    buffer = io.BytesIO()
    sf.write(buffer, audio, SAMPLE_RATE, format="wav")
    buffer.seek(0)
    return buffer

# Speech to text
def speech_to_text(audio_path):
    recognizer = sr.Recognizer()
    with sr.AudioFile(audio_path) as source:
        audio_data = recognizer.record(source)
    try:
        return recognizer.recognize_google(audio_data)
    except sr.UnknownValueError:
        return "Could not understand audio"
    except sr.RequestError:
        return "Speech recognition service unavailable"

# Highlight alphabet in UI
def generate_alphabet_html(decoded_text):
    html = "<div style='font-family: monospace; font-size: 16px;'>"
    for char in MORSE_CODE_DICT.keys():
        color = "red" if char in decoded_text.upper() else "black"
        html += f"<span style='color: {color}; margin: 5px;'>{char}: {MORSE_CODE_DICT[char]}</span>"
        if char in "AEIMQUZ":
            html += "<br>"
    html += "</div>"
    return html

# Combined processing function
def process_input(text=None, speech=None, audio=None):
    morse, decoded_text, audio_output = "", "", None
    
    if text:  # Text input
        morse = text_to_morse(text)
        decoded_text = text
        audio_output = generate_morse_audio(morse)
    
    elif speech:  # Speech input
        text = speech_to_text(speech)
        morse = text_to_morse(text)
        decoded_text = text
        audio_output = generate_morse_audio(morse)
    
    elif audio:  # Live audio input
        morse, decoded_text = decode_morse_from_audio(audio)
    
    alphabet_html = generate_alphabet_html(decoded_text)
    return morse, decoded_text, alphabet_html, audio_output

# Gradio UI with Blocks
with gr.Blocks(title="Morse Code Decoder & Generator") as demo:
    gr.Markdown("# Morse Code Decoder & Generator")
    gr.Markdown("Decode live Morse audio, or generate Morse from text/speech!")
    
    with gr.Tab("Decode Live Audio"):
        audio_input = gr.Audio(type="numpy", label="Live Audio Input (Use Microphone)", streaming=True)
        with gr.Row():
            with gr.Column():
                morse_output = gr.Textbox(label="Detected Morse Code", interactive=False)
                text_output = gr.Textbox(label="Decoded Text", interactive=False)
            alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)")
        
        audio_input.stream(
            fn=process_input,
            inputs=[audio_input],
            outputs=[morse_output, text_output, alphabet_display, gr.Audio(visible=False)],
        )
    
    with gr.Tab("Generate from Text"):
        text_input = gr.Textbox(label="Enter Text", placeholder="Type here...")
        generate_btn = gr.Button("Generate Morse")
        with gr.Row():
            with gr.Column():
                morse_gen_output = gr.Textbox(label="Morse Code", interactive=False)
                text_gen_output = gr.Textbox(label="Original Text", interactive=False)
            gen_alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)")
        audio_playback = gr.Audio(label="Morse Audio Playback", interactive=False)
        
        generate_btn.click(
            fn=process_input,
            inputs=[text_input],
            outputs=[morse_gen_output, text_gen_output, gen_alphabet_display, audio_playback]
        )
    
    with gr.Tab("Generate from Speech"):
        speech_input = gr.Audio(type="filepath", label="Speak Your Text (Record Audio)")
        speech_btn = gr.Button("Convert Speech to Morse")
        with gr.Row():
            with gr.Column():
                morse_speech_output = gr.Textbox(label="Morse Code", interactive=False)
                text_speech_output = gr.Textbox(label="Transcribed Text", interactive=False)
            speech_alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)")
        speech_audio_playback = gr.Audio(label="Morse Audio Playback", interactive=False)
        
        speech_btn.click(
            fn=process_input,
            inputs=[speech_input],
            outputs=[morse_speech_output, text_speech_output, speech_alphabet_display, speech_audio_playback]
        )

# Launch the app
demo.launch()
'''

'''
import gradio as gr
import numpy as np
import time
from scipy.io import wavfile
import io

# Morse code dictionary (ITU standard)
MORSE_CODE_DICT = {
    'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.',
    'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..',
    'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.',
    'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
    'Y': '-.--', 'Z': '--..', '1': '.----', '2': '..---', '3': '...--',
    '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..',
    '9': '----.', '0': '-----', ' ': ' '
}

# Reverse dictionary for decoding
MORSE_TO_CHAR = {v: k for k, v in MORSE_CODE_DICT.items()}

# Function to process audio and detect Morse code (simplified)
def decode_morse_from_audio(audio_data):
    if audio_data is None:
        return "", ""
    
    # Audio comes as (sample_rate, data) from Gradio
    sample_rate, data = audio_data
    if len(data.shape) > 1:  # Convert stereo to mono if needed
        data = data.mean(axis=1)
    
    # Normalize audio data
    data = data / np.max(np.abs(data))
    
    # Threshold for detecting signal (tweak as needed)
    threshold = 0.1
    signal = data > threshold
    
    # Timing parameters (in samples, adjust based on sample_rate)
    dit_length = int(sample_rate * 0.1)  # 100ms for a dit
    dah_length = dit_length * 3         # 300ms for a dah
    space_length = dit_length * 7       # 700ms for word space
    
    morse_code = ""
    decoded_text = ""
    i = 0
    
    while i < len(signal) - dit_length:
        if signal[i]:
            # Measure signal duration
            start = i
            while i < len(signal) and signal[i]:
                i += 1
            duration = i - start
            
            # Classify as dit or dah
            if duration >= dah_length:
                morse_code += "-"
            elif duration >= dit_length:
                morse_code += "."
        
        # Check for spaces (pauses)
        else:
            start = i
            while i < len(signal) and not signal[i]:
                i += 1
            pause = i - start
            
            if pause >= space_length:
                if morse_code:
                    decoded_text += MORSE_TO_CHAR.get(morse_code, "?")
                decoded_text += " "
                morse_code = ""
            elif pause >= dit_length and morse_code:
                decoded_text += MORSE_TO_CHAR.get(morse_code, "?")
                morse_code = ""
        
        i += 1
    
    # Handle any remaining code
    if morse_code:
        decoded_text += MORSE_TO_CHAR.get(morse_code, "?")
    
    return morse_code, decoded_text.strip()

# Function to generate highlighted alphabet UI
def generate_alphabet_html(decoded_text):
    html = "<div style='font-family: monospace; font-size: 16px;'>"
    for char in MORSE_CODE_DICT.keys():
        color = "red" if char in decoded_text.upper() else "black"
        html += f"<span style='color: {color}; margin: 5px;'>{char}: {MORSE_CODE_DICT[char]}</span>"
        if char in "AEIMQUZ":
            html += "<br>"
    html += "</div>"
    return html

# Gradio streaming function
def stream_morse_decoder(audio):
    morse, text = decode_morse_from_audio(audio)
    alphabet_html = generate_alphabet_html(text)
    return morse, text, alphabet_html

# Gradio UI with Blocks
with gr.Blocks(title="Morse Code Decoder") as demo:
    gr.Markdown("# Morse Code Decoder")
    gr.Markdown("Speak or play Morse code into your microphone to decode it live!")
    
    with gr.Row():
        audio_input = gr.Audio(source="microphone", type="numpy", streaming=True, label="Live Audio Input")
    
    with gr.Row():
        with gr.Column():
            morse_output = gr.Textbox(label="Detected Morse Code", interactive=False)
            text_output = gr.Textbox(label="Decoded Text", interactive=False)
        with gr.Column():
            alphabet_display = gr.HTML(label="Morse Alphabet (Highlighted)")
    
    # Event listener for streaming audio
    audio_input.stream(
        fn=stream_morse_decoder,
        inputs=[audio_input],
        outputs=[morse_output, text_output, alphabet_display],
        _js="() => { return [navigator.mediaDevices.getUserMedia({ audio: true })];"
    )

# Launch the app
demo.launch()
'''