112 lines
3.8 KiB
Python
112 lines
3.8 KiB
Python
# Standalone MicroPython Voice Animation: Caption Scan
|
|
# Exposes run(text="", frames=...) and runs automatically if executed directly.
|
|
import time
|
|
|
|
try:
|
|
import board_config
|
|
display = getattr(board_config, 'display_instance', None)
|
|
except Exception:
|
|
board_config = None
|
|
display = None
|
|
|
|
def wrap_text(msg, max_chars=36):
|
|
words = msg.split()
|
|
lines = []
|
|
curr = ""
|
|
for w in words:
|
|
if len(curr) + len(w) + 1 > max_chars:
|
|
lines.append(curr)
|
|
curr = w
|
|
else:
|
|
curr = (curr + " " + w).strip()
|
|
if curr:
|
|
lines.append(curr)
|
|
return lines
|
|
|
|
def run(text="", frames=100):
|
|
if not display:
|
|
print("board_config.display_instance is not available. Skipping animation.")
|
|
return
|
|
|
|
width = getattr(display, 'width', 400)
|
|
height = getattr(display, 'height', 300)
|
|
cx, cy = width // 2, height // 2
|
|
|
|
# Simulated text sequence if no real-time caption text is supplied
|
|
default_script = [
|
|
"RECEIVING VOICE PACKETS...",
|
|
"DECODING AUDIO STREAM...",
|
|
"MATCHING PHONEME VECTORS...",
|
|
"EXTRACTING INTENT AND CONTEXT...",
|
|
"STT METRICS: LATENCY 42MS",
|
|
"TRANSCRIPTION STABILIZED.",
|
|
"AWAITING PIPELINE RESPONSE..."
|
|
]
|
|
|
|
frame = 0
|
|
|
|
try:
|
|
while True:
|
|
if frames is not None and frames > 0 and frame >= frames:
|
|
break
|
|
|
|
display.clear(0)
|
|
|
|
# Draw outer scan framing
|
|
display.rect(15, 15, width - 30, height - 50, 1)
|
|
|
|
# Draw moving scanner bar line
|
|
scan_y = 20 + ((frame * 6) % (height - 60))
|
|
display.line(20, scan_y, width - 20, scan_y, 1)
|
|
|
|
# Draw static top status line
|
|
display.text("SPEECH-TO-TEXT DECODER", 25, 25, 1)
|
|
display.line(25, 37, width - 25, 37, 1)
|
|
|
|
# Determine what text to write based on typewriter frame counter
|
|
if text:
|
|
lines = wrap_text(text, max_chars=(width - 50) // 8)
|
|
char_limit = int(frame * 2.5)
|
|
chars_drawn = 0
|
|
for idx, line in enumerate(lines):
|
|
if chars_drawn >= char_limit:
|
|
break
|
|
line_to_draw = line[:char_limit - chars_drawn]
|
|
display.text(line_to_draw, 25, 55 + idx * 18, 1)
|
|
chars_drawn += len(line)
|
|
else:
|
|
# Typewriter animation of simulated lines
|
|
active_line_idx = (frame // 15) % len(default_script)
|
|
char_limit = int((frame % 15) * 3)
|
|
|
|
# Show previously printed lines in full
|
|
start_line = max(0, active_line_idx - 5)
|
|
for idx in range(start_line, active_line_idx):
|
|
display.text(default_script[idx], 25, 55 + (idx - start_line) * 18, 1)
|
|
|
|
# Typewriter effect on the current line
|
|
curr_line_text = default_script[active_line_idx][:char_limit]
|
|
display.text(curr_line_text, 25, 55 + (active_line_idx - start_line) * 18, 1)
|
|
|
|
# Flash a cursor at the end of the typing line
|
|
if (frame // 3) % 2 == 0:
|
|
cursor_x = 25 + len(curr_line_text) * 8
|
|
cursor_y = 55 + (active_line_idx - start_line) * 18
|
|
display.fill_rect(cursor_x, cursor_y, 8, 8, 1)
|
|
|
|
# Draw bottom transcription indicator
|
|
display.text("TRANSCRIBING...", 25, height - 25, 1)
|
|
|
|
display.show()
|
|
frame += 1
|
|
|
|
try:
|
|
time.sleep_ms(60)
|
|
except AttributeError:
|
|
time.sleep(0.06)
|
|
except KeyboardInterrupt:
|
|
print("Animation interrupted by user.")
|
|
|
|
if __name__ in ('__main__', '__name__'):
|
|
run()
|