import logging
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from transformers import LlamaForCausalLM, LlamaTokenizer
import torch
import faiss
from googleapiclient.discovery import build

# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Define a FastAPI application
app = FastAPI()

# Define a Pydantic model for input data
class EmotionRequest(BaseModel):
    video_id: str  # Accepts the video ID from the request body

class EmotionAnalyzer:
    def __init__(self, model_name='meta-llama/Llama-2-7b-hf', knowledge_base=None, max_length=512):
        logger.info(f"Loading model: {model_name}")

        # Load the LLaMA-2 model and tokenizer
        self.model = LlamaForCausalLM.from_pretrained(model_name)
        self.tokenizer = LlamaTokenizer.from_pretrained(model_name)

        # Set pad_token to eos_token if missing
        if self.tokenizer.pad_token is None:
            self.tokenizer.pad_token = self.tokenizer.eos_token

        # Knowledge base (FAISS index) for RAG
        self.knowledge_base = knowledge_base
        self.knowledge_base_texts = []  # Populate this elsewhere in your code
        self.max_length = max_length

    def retrieve_context(self, query_text):
  def retrieve_context(self, query_text):
        """Retrieve related context from the knowledge base using FAISS."""
        logger.info(f"Retrieving context for query: {query_text}")

        if self.knowledge_base is None:
            logger.warning("Knowledge base is None, returning empty context.")
            return ""

        # Get the embedding for the query text
        query_embedding = self.model.get_input_embeddings()(self.tokenizer(query_text, return_tensors="pt")['input_ids'])
        query_embedding = query_embedding.detach().cpu().numpy()

        # Retrieve nearest context from FAISS index
        _, I = self.knowledge_base.search(query_embedding, k=1)

        try:
            retrieved_text = self.knowledge_base_texts[I[0][0]]  # Ensure knowledge_base_texts is defined somewhere
            logger.info(f"Retrieved text: {retrieved_text}")
        except IndexError:
            logger.error("Index out of bounds: Ensure knowledge_base_texts is populated correctly.")
            retrieved_text = ""

        return retrieved_text
        
    def analyze_emotions(self, text):
        """Perform RAG-based emotion analysis."""
        logger.info(f"Analyzing emotions for text: {text}")
        
        # Retrieve context using RAG method (retrieval)
        context = self.retrieve_context(text)
        
        # Create the prompt combining the original text and retrieved context
        prompt = f"Context: {context}\nText: {text}\nEmotion:"
        logger.info(f"Generated prompt: {prompt}")

        # Tokenize the prompt with max_length
 # Tokenize the prompt with max_length
        inputs = self.tokenizer(
            prompt,
            return_tensors="pt",
            padding=True,
            truncation=True,
            max_length=self.max_length  # Define max_length explicitly
        )
        
        # Generate the output using the LLaMA model
        outputs = self.model.generate(
            inputs['input_ids'],
            attention_mask=inputs['attention_mask'],
            max_new_tokens=50,
            pad_token_id=self.tokenizer.pad_token_id  # Use the pad_token_id directly
        )   
            
        # Decode and extract the emotion from the generated text
        generated_text = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
        logger.info(f"Generated text: {generated_text}")
            
        try:
            emotion = generated_text.split("Emotion:")[-1].strip().split()[0]
        except IndexError:
            logger.error("Error extracting emotion from the generated text.")
            emotion = "Unknown"
        
        return emotion, generated_text
        
# YouTube API setup
YOUTUBE_API_KEY = 'YOUR_YOUTUBE_API_KEY'  # Replace with your YouTube API key
        
def get_video_comments(video_id):
    """Fetch comments from a YouTube video using the video_id."""
    youtube = build('youtube', 'v3', developerKey=YOUTUBE_API_KEY)
    comments = []
youtube = build('youtube', 'v3', developerKey=YOUTUBE_API_KEY)
    comments = []
        
    try:
        response = youtube.commentThreads().list(
            part='snippet',
            videoId=video_id,
            textFormat='plainText',
            maxResults=100  # Adjust this value as needed
        ).execute()
        
        # Process the response to extract comments
        for item in response.get('items', []):
            comment = item['snippet']['topLevelComment']['snippet']['textDisplay']
            comments.append(comment)
            
    except Exception as e:
        logger.error(f"Error fetching comments: {str(e)}")
        
    return comments
        
# Instantiate the EmotionAnalyzer
knowledge_base = None  # Load your FAISS index and texts here
emotion_analyzer = EmotionAnalyzer(knowledge_base=knowledge_base)
        
@app.post("/analyze_emotion/")
async def analyze_emotion(request: EmotionRequest):
    """Analyze emotions for comments from a YouTube video."""
    comments = get_video_comments(request.video_id)
        
    if not comments:
        raise HTTPException(status_code=404, detail="No comments found for this video ID.")
        
    results = []
    for comment in comments:
        emotion, generated_text = emotion_analyzer.analyze_emotions(comment)
        results.append({"comment": comment, "emotion": emotion, "generated_text": generated_text})
 emotion, generated_text = emotion_analyzer.analyze_emotions(comment)
        results.append({"comment": comment, "emotion": emotion, "generated_text": generated_text})
        
    return {"video_id": request.video_id, "analysis": results}
        
# Run the application
if __name__ == "__main__":   
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

check this code, I want fast api to ask me to insert video id in the window. and also YT api key are stored in config.py. help me update the full code and fix all bugs