import asyncio import signal from rich.console import Console from config import load_config from capture import capture_frames from analyzer import VisionAnalyzer from output import print_description, log_description console = Console() async def run(config) -> None: analyzer = VisionAnalyzer( api_key=config.gemini_api_key, base_url=config.gemini_base_url, lang=config.lang, ) console.print( f"[bold green]Starting stream analysis[/bold green] " f"channel=[cyan]{config.channel}[/cyan] " f"interval=[cyan]{config.interval}s[/cyan] " f"quality=[cyan]{config.quality}[/cyan]" ) console.print("[dim]Press Ctrl+C to stop[/dim]\n") frame_number = 0 try: async for frame_data in capture_frames( config.channel, config.quality, config.interval ): frame_number += 1 console.print(f"[dim]Captured frame #{frame_number}, analyzing...[/dim]") try: description = await analyzer.analyze_frame(frame_data) except Exception as e: console.print(f"[bold red]Analysis error:[/bold red] {e}") continue print_description(description, frame_number) await log_description(config.log_file, description, frame_number) except RuntimeError as e: console.print(f"[bold red]Error:[/bold red] {e}") finally: if frame_number == 0: console.print("[bold yellow]No frames were captured.[/bold yellow]") def main() -> None: config = load_config() loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) task = loop.create_task(run(config)) def shutdown(sig, frame): console.print("\n[bold yellow]Shutting down...[/bold yellow]") task.cancel() signal.signal(signal.SIGINT, shutdown) signal.signal(signal.SIGTERM, shutdown) try: loop.run_until_complete(task) except asyncio.CancelledError: console.print("[bold green]Stopped.[/bold green]") finally: loop.close() if __name__ == "__main__": main()