File size: 6,213 Bytes
42966de
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3020c69
42966de
 
3020c69
42966de
 
3020c69
42966de
 
 
 
dfb71ed
 
42966de
 
 
2449b0e
 
dac7224
c0ae2ab
dac7224
c0ae2ab
dac7224
2449b0e
dac7224
c0ae2ab
dac7224
2449b0e
 
 
 
 
 
 
 
 
 
dac7224
2449b0e
 
 
dac7224
2449b0e
dac7224
42966de
dfb71ed
3020c69
42966de
 
dfb71ed
42966de
 
 
 
 
 
3020c69
42966de
 
 
 
 
 
 
 
db69a9c
e3f2b5b
3020c69
 
 
42966de
 
 
 
 
 
 
 
 
 
 
 
 
3020c69
 
 
dac7224
3020c69
42966de
 
 
3020c69
 
dac7224
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3020c69
dac7224
 
3020c69
42966de
dfb71ed
dac7224
42966de
 
dac7224
 
3020c69
42966de
dfb71ed
dac7224
dfb71ed
 
dac7224
7068a4f
42966de
 
dfb71ed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import gradio as gr
import tempfile
import openai

def tts(input_text: str, model: str, voice: str, api_key: str) -> str:
    """
    Convert input text to speech using OpenAI's Text-to-Speech API.

    :param input_text: The text to be converted to speech.
    :type input_text: str
    :param model: The model to use for synthesis (e.g., 'tts-1', 'tts-1-hd').
    :type model: str
    :param voice: The voice profile to use (e.g., 'alloy', 'echo', 'fable', etc.).
    :type voice: str
    :param api_key: OpenAI API key.
    :type api_key: str
    :return: File path to the generated audio file.
    :rtype: str
    :raises gr.Error: If input parameters are invalid or API call fails.
    """
    if not input_text.strip():
        raise gr.Error("Input text cannot be empty.")

    if not api_key.strip():
        raise gr.Error("API key is required.")

    openai.api_key = api_key

    try:
        response = openai.Audio.create(
            text=input_text,
            voice=voice,
            model=model
        )

    except openai.APITimeoutError as e:
        raise gr.Error(f"OpenAI API request timed out: {e}")
    except openai.APIConnectionError as e:
        raise gr.Error(f"OpenAI API request failed to connect: {e}")
    except openai.AuthenticationError as e:
        raise gr.Error(f"OpenAI API request was not authorized: {e}")
    except openai.PermissionDeniedError as e:
        raise gr.Error(f"OpenAI API request was not permitted: {e}")
    except openai.RateLimitError as e:
        raise gr.Error(f"OpenAI API request exceeded rate limit: {e}")
    except openai.BadRequestError as e:
        raise gr.Error(f"OpenAI API bad request: {e}")
    except openai.UnprocessableEntityError as e:
        raise gr.Error(f"OpenAI API request could not be processed: {e}")
    except openai.NotFoundError as e:
        raise gr.Error(f"OpenAI API resource not found: {e}")
    except openai.InternalServerError as e:
        raise gr.Error(f"OpenAI API internal server error: {e}")
    except openai.APIError as e:
        # This will catch other API-related errors not captured above
        raise gr.Error(f"OpenAI API Error: {e}")
    except openai.OpenAIError as e:
        # Catch-all for any other OpenAI exceptions
        raise gr.Error(f"An OpenAI error occurred: {e}")
    except Exception as e:
        # Catch any other exceptions
        raise gr.Error(f"An unexpected error occurred: {e}")

    if not hasattr(response, 'audio'):
        raise gr.Error("Invalid response from OpenAI API. The response does not contain audio content.")

    with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as temp_file:
        temp_file.write(response.audio)
        temp_file_path = temp_file.name

    return temp_file_path

def main():
    """
    Main function to create and launch the Gradio interface with input validation and error handling.
    """
    MODEL_OPTIONS = ["tts-1", "tts-1-hd"]
    VOICE_OPTIONS = ["alloy", "echo", "fable", "onyx", "nova", "shimmer"]

    with gr.Blocks() as demo:
        with gr.Row():
            with gr.Column(scale=1):
                api_key_input = gr.Textbox(
                    label="OpenAI API Key",
                    info="Get OpenAI key at: https://platform.openai.com/account/api-keys",
                    type="password",
                    placeholder="Enter your OpenAI API Key",
                    value="",
                )
                model_dropdown = gr.Dropdown(
                    choices=MODEL_OPTIONS, label="Model", value="tts-1"
                )
                voice_dropdown = gr.Dropdown(
                    choices=VOICE_OPTIONS, label="Voice Options", value="echo"
                )
            with gr.Column(scale=2):
                input_textbox = gr.Textbox(
                    label="Input Text",
                    lines=10,
                    placeholder="Type your text here..."
                )
                submit_button = gr.Button(
                    "Convert Text to Speech",
                    variant="primary",
                    interactive=False  # Initially disabled
                )
            with gr.Column(scale=1):
                output_audio = gr.Audio(label="Output Audio")

        # Define the event handler for the submit button with error handling
        def on_submit(input_text, model, voice, api_key):
            try:
                audio_file = tts(input_text, model, voice, api_key)
                return audio_file
            except gr.Error as err:
                # Re-raise gr.Error exceptions to display message without traceback
                raise err
            except Exception as e:
                # Handle any other exceptions and display error message
                raise gr.Error(f"An unexpected error occurred: {e}")

        # Function to update the submit button state
        def update_submit_button_state(api_key, input_text):
            if api_key.strip() and input_text.strip():
                return gr.update(interactive=True)
            else:
                return gr.update(interactive=False)

        # Update the submit button state when the API key or input text changes
        api_key_input.change(
            fn=update_submit_button_state,
            inputs=[api_key_input, input_textbox],
            outputs=submit_button
        )
        input_textbox.change(
            fn=update_submit_button_state,
            inputs=[api_key_input, input_textbox],
            outputs=submit_button
        )

        # Allow pressing Enter in the input textbox to trigger the conversion
        input_textbox.submit(
            fn=on_submit,
            inputs=[input_textbox, model_dropdown, voice_dropdown, api_key_input],
            outputs=output_audio,
            api_name="tts",
        )

        # Trigger the conversion when the submit button is clicked
        submit_button.click(
            fn=on_submit,
            inputs=[input_textbox, model_dropdown, voice_dropdown, api_key_input],
            outputs=output_audio,
            api_name="tts",
        )

    # Launch the Gradio app with error display enabled
    demo.launch(show_error=True)

if __name__ == "__main__":
    main()