Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, Depends, HTTPException, Query | |
| from fastapi.responses import JSONResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from sqlalchemy.orm import Session | |
| from typing import List, Optional | |
| from .db import crud, models | |
| from .db.database import SessionLocal, engine, get_db | |
| from .schemas import video as video_schema | |
| from .schemas import comment as comment_schema | |
| from .services import comments_analysis, video_analysis, youtube_search | |
| # Create database tables | |
| models.Base.metadata.create_all(bind=engine) | |
| app = FastAPI( | |
| title="YouTube Analysis API", | |
| description="An API to search, analyze, and get insights from YouTube videos and comments.", | |
| version="1.0.0" | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["http://localhost:3000"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| def root(): | |
| return {"message": "Welcome to the YouTube Analysis API"} | |
| # --- Search Endpoints --- | |
| async def search( | |
| query: str, | |
| max_results: int = Query(5, ge=1, le=50), | |
| page_token: str = None, | |
| ): | |
| try: | |
| results_df, next_page_token = await youtube_search.search_youtube(query, max_results=max_results, page_token=page_token) | |
| if results_df.empty: | |
| return JSONResponse( | |
| status_code=404, | |
| content={"message": f"No YouTube videos found for query: '{query}'", | |
| "results": {"videos": [], | |
| "nextPageToken": None}} | |
| ) | |
| results = { | |
| "videos": results_df.to_dict(orient="records"), | |
| "nextPageToken": next_page_token | |
| } | |
| return {"results": results} | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Error getting sentiments: {str(e)}") | |
| async def get_video_details(video_id: str): | |
| try: | |
| video_details = await youtube_search.search_video(video_id) | |
| if video_details.empty: | |
| print(f"No video found or an issue occurred for video ID: {video_id}") | |
| return JSONResponse( | |
| status_code=404, | |
| content={"message": f"No YouTube videos found for videoId: '{video_id}'", | |
| "results": {}} | |
| ) | |
| return {"results": video_details.to_dict(orient="records")[0]} | |
| except Exception as e: | |
| print(f"An unexpected error occurred while fetching video details for {video_id}: {e}") | |
| raise HTTPException(status_code=500, detail=f"An internal error occurred: {str(e)}") | |
| # --- Video Endpoints --- | |
| def get_video_transcript(video_id: str, db: Session = Depends(get_db)): | |
| try: | |
| transcript = video_analysis.get_transcript(db, video_id) | |
| return { | |
| "results": transcript, | |
| "length": len(transcript), | |
| "word_count": len(transcript.split()) | |
| } | |
| except ValueError as ve: | |
| raise HTTPException( | |
| status_code=404, | |
| detail=f"{ve}" | |
| ) | |
| except RuntimeError as re: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"{re}" | |
| ) | |
| except Exception as e: | |
| print(f"An unexpected error occurred in get_video_transcript endpoint for {video_id}: {e}") | |
| raise HTTPException(status_code=500, detail=f"An unknown internal error occurred: {str(e)}") | |
| async def video_summary( | |
| video_id: str, | |
| title: str = Query(default="", description="Title of the YouTube video"), | |
| channel_name: str = Query(default="", description="Name of the YouTube channel"), | |
| db: Session = Depends(get_db) | |
| ): | |
| try: | |
| summary = await video_analysis.summarize_video(db, video_id, title, channel_name) | |
| return {"results": summary} | |
| except ValueError as ve: | |
| raise HTTPException( | |
| status_code=404, | |
| detail=f"{ve}" | |
| ) | |
| except RuntimeError as re: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"{re}" | |
| ) | |
| except Exception as e: | |
| print(f"An unexpected error occurred in video_summary endpoint for {video_id}: {e}") | |
| raise HTTPException(status_code=500, detail=f"An unknown internal error occurred: {str(e)}") | |
| async def video_qa( | |
| video_id: str, | |
| question: str = Query(..., description="Question to ask about the video comments"), | |
| db: Session = Depends(get_db) | |
| ): | |
| try: | |
| answer = await video_analysis.answer_video_question(db, video_id, question) | |
| return {"results": answer} | |
| except ValueError as ve: | |
| raise HTTPException( | |
| status_code=404, | |
| detail=f"{ve}" | |
| ) | |
| except RuntimeError as re: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"{re}" | |
| ) | |
| except Exception as e: | |
| print(f"An unexpected error occurred in video_qa endpoint for {video_id} with question '{question}': {e}") | |
| raise HTTPException(status_code=500, detail=f"An unknown internal error occurred: {str(e)}") | |
| # --- Comment Endpoints --- | |
| async def get_comments(video_id: str): | |
| try: | |
| comments = await comments_analysis.extract_comments(video_id) | |
| if not comments: | |
| print(f"No comments found or an issue occurred for video ID: {video_id}") | |
| return JSONResponse( | |
| status_code=404, | |
| content={"message": f"No comments found for videoId: '{video_id}'", | |
| "results": []} | |
| ) | |
| return {"results": comments} | |
| except Exception as e: | |
| print(f"An unexpected error occurred while fetching comments for {video_id}: {e}") | |
| raise HTTPException(status_code=500, detail=f"An internal error occurred: {str(e)}") | |
| async def comments_sentiments(input_data: comment_schema.CommentsInput): | |
| try: | |
| sentiments = await youtube_search.get_sentiments(input_data.comments) | |
| return {"results": sentiments} | |
| except ValueError as ve: | |
| raise HTTPException( | |
| status_code=400, | |
| detail=f"{ve}" | |
| ) | |
| except RuntimeError as re: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"{re}" | |
| ) | |
| except Exception as e: | |
| print(f"An unexpected error occurred in comments_sentiments endpoint: {e}") | |
| raise HTTPException(status_code=500, detail=f"An unknown internal error occurred: {str(e)}") | |
| async def comment_summary( | |
| video_id: str, | |
| title: str = Query(default="", description="Title of the YouTube video"), | |
| channel_name: str = Query(default="", description="Name of the YouTube channel"), | |
| db: Session = Depends(get_db) | |
| ): | |
| try: | |
| summary = await comments_analysis.summarize_comments(db, video_id, title, channel_name) | |
| if not summary: | |
| return JSONResponse( | |
| status_code=404, | |
| content={"message": f"Summary could not be generated or was empty for videoId: '{video_id}'", | |
| "results": {}} | |
| ) | |
| return {"results": summary} | |
| except ValueError as ve: | |
| # This catches the ValueError raised from summarize_comments if no valid comments were found | |
| raise HTTPException( | |
| status_code=404, | |
| detail=f"{ve}" # Use the message from the raised ValueError | |
| ) | |
| except RuntimeError as re: | |
| # This catches the RuntimeError raised from summarize_comments for other internal issues | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"{re}" # Use the message from the raised RuntimeError | |
| ) | |
| except Exception as e: | |
| # Catch any unexpected exceptions that weren't caught by the specific ones above | |
| print(f"An unexpected error occurred in comment_summary endpoint for {video_id}: {e}") | |
| raise HTTPException(status_code=500, detail=f"An unknown internal error occurred: {str(e)}") | |
| async def comment_qa( | |
| video_id: str, | |
| question: str = Query(..., description="Question to ask about the video comments"), | |
| db: Session = Depends(get_db) | |
| ): | |
| try: | |
| answer = await comments_analysis.answer_question(db, video_id, question) | |
| return {"results": answer} | |
| except ValueError as ve: | |
| # Catches ValueErrors from service functions (e.g., no comments, LLM couldn't answer) | |
| raise HTTPException( | |
| status_code=404, | |
| detail=f"{ve}" | |
| ) | |
| except RuntimeError as re: | |
| # Catches RuntimeErrors from service functions (e.g., internal LLM error, vectorstore issue) | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"{re}" | |
| ) | |
| except Exception as e: | |
| # General catch-all for any other unforeseen issues | |
| print(f"An unexpected error occurred in comment_qa endpoint for {video_id} with question '{question}': {e}") | |
| raise HTTPException(status_code=500, detail=f"An unknown internal error occurred: {str(e)}") |