Files
2026-06-21 21:19:51 -04:00

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()