""" Main entry point for YouTube Study Notes AI. Provides CLI interface and server startup. """ import sys import argparse import os from pathlib import Path # Import necessary modules for server and middleware from src.utils.logger import setup_logger from src.utils.config import settings logger = setup_logger(__name__) def run_server(): """Start the FastAPI server with CORS enabled for Flutter Web.""" import uvicorn from fastapi.middleware.cors import CORSMiddleware from src.api.main import app # Import the app instance directly logger.info("Configuring CORS for Flutter Web...") # Add CORS Middleware to allow requests from Chrome/Flutter app.add_middleware( CORSMiddleware, allow_origins=["*"], # Allows all origins allow_credentials=True, allow_methods=["*"], # Allows all methods allow_headers=["*"], # Allows all headers ) # --------------------------------------------------------- # TWEAK FOR HUGGING FACE SPACES # Hugging Face sets the 'PORT' environment variable to 7860. # We use it if available, otherwise fallback to 7860 default. # --------------------------------------------------------- port = int(os.environ.get("PORT", 7860)) logger.info("Starting YouTube Study Notes AI server...") logger.info(f"Server will be available at http://0.0.0.0:{port}") logger.info(f"API Documentation: http://0.0.0.0:{port}/docs") # Run the server using the app object directly # Host must be "0.0.0.0" to be accessible externally uvicorn.run(app, host="0.0.0.0", port=port, log_level="info") def run_cli(youtube_url: str, output_file: str = None): """ Run note generation from command line. """ from src.audio.downloader import YouTubeDownloader from src.transcription.whisper_transcriber import WhisperTranscriber from src.summarization.note_generator import NoteGenerator logger.info("Starting CLI mode") logger.info(f"Processing URL: {youtube_url}") try: # Step 1: Download audio logger.info("Step 1/3: Downloading audio...") downloader = YouTubeDownloader() video_info = downloader.get_video_info(youtube_url) audio_file = downloader.download_audio(youtube_url) # Step 2: Transcribe logger.info("Step 2/3: Transcribing audio...") transcriber = WhisperTranscriber() transcript_data = transcriber.transcribe(audio_file) # Step 3: Generate notes logger.info("Step 3/3: Generating notes...") note_gen = NoteGenerator() notes = note_gen.generate_notes_from_full_transcript( transcript_data["text"], video_info["title"] ) # Format and save final_notes = note_gen.format_final_notes( notes, video_info["title"], youtube_url, video_info["duration"] ) if output_file: output_path = Path(output_file) else: output_path = settings.output_dir / f"{video_info['title'][:50]}_notes.md" output_path.write_text(final_notes, encoding="utf-8") logger.info(f"āœ… Notes saved to: {output_path}") print(f"\nāœ… Success! Notes saved to: {output_path}") # Cleanup downloader.cleanup(audio_file) except Exception as e: logger.error(f"Failed: {e}") print(f"\nāŒ Error: {e}") sys.exit(1) def main(): """Main entry point with argument parsing.""" parser = argparse.ArgumentParser( description="YouTube Study Notes AI - Generate structured notes from educational videos" ) parser.add_argument( "mode", choices=["server", "cli"], help="Run mode: server (API + web UI) or cli (direct processing)", ) parser.add_argument( "--url", type=str, help="YouTube video URL (required for cli mode)" ) parser.add_argument( "--output", type=str, help="Output file path (optional for cli mode)" ) args = parser.parse_args() if args.mode == "server": run_server() elif args.mode == "cli": if not args.url: print("Error: --url is required for cli mode") sys.exit(1) run_cli(args.url, args.output) if __name__ == "__main__": main()