aghilTQ commited on
Commit
7b2e259
·
verified ·
1 Parent(s): a5a1bf6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +45 -152
app.py CHANGED
@@ -1,159 +1,52 @@
1
- import gradio as gr
2
- import edge_tts
3
  import asyncio
4
- from typing import Optional
5
- import os
6
-
7
- # Global variables to manage playback
8
- current_playback_task = None
9
- current_position = 0
10
- stop_playback_flag = False
11
-
12
- async def text_to_speech(text: str, play_from: int = 0, voice: str = "en-US-GuyNeural") -> tuple[str, str]:
13
- global current_playback_task, current_position, stop_playback_flag
14
-
15
- # Stop any ongoing playback
16
- stop_playback()
17
-
18
- # Get only the text from the specified position
19
- text_to_read = text[play_from:]
20
- current_position = play_from
21
-
22
- # Create a new playback task
23
- current_playback_task = asyncio.create_task(play_audio(text_to_read, voice))
24
-
25
- return text, f"Playing from position {play_from}..."
26
-
27
- async def play_audio(text: str, voice: str):
28
- try:
29
- communicate = edge_tts.Communicate(text, voice)
30
- async for chunk in communicate.stream():
31
- if stop_playback_flag:
32
- break
33
- except Exception as e:
34
- print(f"Playback error: {e}")
35
-
36
- def stop_playback():
37
- global current_playback_task, stop_playback_flag
38
- if current_playback_task:
39
- stop_playback_flag = True
40
- current_playback_task.cancel()
41
- stop_playback_flag = False
42
-
43
- def handle_word_click(word_index: int, text: str, voice: str) -> tuple[str, str]:
44
- global current_position
45
-
46
- # Convert word index to character position
47
- words = text.split()
48
- if word_index < len(words):
49
- # Find the character position of the clicked word
50
- char_pos = 0
51
- for i, word in enumerate(words):
52
- if i == word_index:
53
- break
54
- char_pos += len(word) + 1 # +1 for the space
55
-
56
- # Start playback from this position
57
- return asyncio.run(text_to_speech(text, char_pos, voice))
58
- return text, "Invalid word selection"
59
-
60
- async def get_voices():
61
- voices = await edge_tts.list_voices()
62
- return [v["ShortName"] for v in voices if v["Locale"].startswith("en-")]
63
-
64
- # JavaScript for interactive text
65
- js = """
66
- function splitText(text) {
67
- if (!text) return '';
68
- const words = text.split(' ');
69
- return words.map((word, index) => {
70
- return `<span class="word" data-index="${index}"
71
- style="cursor:pointer; margin-right:5px;"
72
- onmouseover="this.style.backgroundColor='#f0f0f0'"
73
- onmouseout="this.style.backgroundColor='transparent'"
74
- onclick="handleWordClick(this)">${word}</span>`;
75
- }).join(' ');
76
- }
77
-
78
- function handleWordClick(element) {
79
- const index = element.getAttribute('data-index');
80
- document.getElementById('word-index').value = index;
81
- document.getElementById('word-index').dispatchEvent(new Event('input'));
82
- }
83
 
84
- function updateTextDisplay(text) {
85
- const container = document.getElementById('text-display');
86
- container.innerHTML = splitText(text);
87
- }
88
 
89
- document.addEventListener('DOMContentLoaded', function() {
90
- // Update display when text changes
91
- const textInput = document.querySelector('#text-input textarea');
92
- if (textInput) {
93
- textInput.addEventListener('input', function() {
94
- updateTextDisplay(this.value);
95
- });
96
- }
97
- });
98
- """
99
 
100
- css = """
101
- .word:hover { background-color: #f0f0f0; }
102
- #text-display {
103
- padding: 10px;
104
- border: 1px solid #ccc;
105
- border-radius: 5px;
106
- min-height: 100px;
107
- white-space: pre-wrap;
108
- }
109
- """
110
 
111
- with gr.Blocks(js=js, css=css) as demo:
112
- gr.Markdown("# Interactive TTS Service (edge-tts)")
113
- gr.Markdown("Enter text below and click 'Speak' to hear it. Click on any word to start playback from that point.")
114
-
115
- with gr.Row():
116
- text_input = gr.Textbox(label="Input Text", lines=5, elem_id="text-input")
117
- word_index = gr.Number(visible=False, elem_id="word-index")
118
-
119
- with gr.Row():
120
- text_display = gr.HTML(elem_id="text-display")
121
-
122
- with gr.Row():
123
- voice_dropdown = gr.Dropdown(label="Voice", choices=asyncio.run(get_voices()), value="en-US-GuyNeural")
124
- rate_slider = gr.Slider(50, 200, value=100, label="Speed (%)")
125
-
126
- with gr.Row():
127
- speak_btn = gr.Button("Speak", variant="primary")
128
- stop_btn = gr.Button("Stop")
129
-
130
- status = gr.Textbox(label="Status", interactive=False)
131
-
132
- # Event handlers
133
- text_input.change(
134
- fn=lambda x: x,
135
- inputs=text_input,
136
- outputs=text_display,
137
- _js="(x) => { updateTextDisplay(x); return x; }"
138
- )
139
-
140
- word_index.change(
141
- fn=handle_word_click,
142
- inputs=[word_index, text_input, voice_dropdown],
143
- outputs=[text_input, status]
144
- )
145
-
146
- speak_btn.click(
147
- fn=lambda text, voice: asyncio.run(text_to_speech(text, 0, voice)),
148
- inputs=[text_input, voice_dropdown],
149
- outputs=[text_input, status]
150
- )
151
-
152
- stop_btn.click(
153
- fn=stop_playback,
154
- outputs=status,
155
- _js="() => { return 'Playback stopped'; }"
156
- )
157
 
158
  if __name__ == "__main__":
159
- demo.launch()
 
 
 
1
  import asyncio
2
+ from pyglet import app, clock, textinput
3
+ from microsoft_edge_tts import EdgeTTS
4
+
5
+ async def generate_speech(text):
6
+ tts = EdgeTTS()
7
+ speech = await tts.speak_async(text)
8
+ return speech
9
+
10
+ def handle_click(event):
11
+ global current_text, current_position
12
+ if event.button == 1: # Left mouse button
13
+ current_position = event.x, event.y
14
+ print(f"Clicked at {current_position}")
15
+
16
+ async def update_text():
17
+ global current_text, current_position
18
+ while True:
19
+ if current_text != original_text:
20
+ await generate_speech(current_text)
21
+ current_text = original_text
22
+ await asyncio.sleep(0.5)
23
+
24
+ async def main():
25
+ global current_text, original_text
26
+ window = app.Window(width=800, height=600)
27
+
28
+ label = textinput.Label(
29
+ text="Click anywhere to start",
30
+ multiline=True,
31
+ width=700,
32
+ height=500,
33
+ x=50, y=50
34
+ )
35
+ window.add_handlers(label)
36
+ label.on_mouse_press = handle_click
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
+ input_handler = textinput.TextInput()
39
+ window.add_handlers(input_handler)
40
+ input_handler.on_text_entry = lambda text: label.text = text
 
41
 
42
+ current_text = ""
43
+ original_text = ""
44
+ current_position = None
 
 
 
 
 
 
 
45
 
46
+ clock.schedule_interval(update_text, 0.5)
 
 
 
 
 
 
 
 
 
47
 
48
+ async with window:
49
+ await app.run()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  if __name__ == "__main__":
52
+ asyncio.run(main())