Team Ai
Apppublic

Programmer140/Hackathon

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
chat_openai.py184 linesDownload Raw Back to root
1"""Chat functionality using OpenAI-compatible API and Qdrant for retrieval."""2 3import os4from openai import OpenAI5from qdrant_client import QdrantClient6from qdrant_client.models import VectorParams, Distance, SearchParams7from qdrant_client.http import models8from config import (9    OPENAI_API_KEY, COHERE_API_KEY, QDRANT_URL, QDRANT_API_KEY,10    COLLECTION_NAME, SEARCH_TOP_K, MAX_TOKENS_RESPONSE, TEMPERATURE11)12import cohere13 14 15# Initialize OpenAI client with OpenRouter as backend16client = OpenAI(17    api_key=OPENAI_API_KEY,18    base_url="https://openrouter.ai/api/v1",19)20 21# Initialize Cohere client for embeddings22cohere_client = cohere.Client(COHERE_API_KEY)23 24# Initialize Qdrant client - using grpc=False to ensure REST API is used25qdrant_client = QdrantClient(url=QDRANT_URL, api_key=QDRANT_API_KEY, prefer_grpc=False)26 27 28def embed_query(query):29    """Generate embeddings for the input query using Cohere."""30    response = cohere_client.embed(31        model="embed-english-v3.0",32        input_type="search_query",33        texts=[query],34    )35    return response.embeddings[0]36 37 38def query_qdrant(query_text):39    """Query the Qdrant database for similar documents to the query."""40    query_embedding = embed_query(query_text)41 42    # Check if search method exists and call it appropriately43    search_results = []44    try:45        # Check if the collection exists before searching46        collection_exists = False47        try:48            collection_info = qdrant_client.get_collection(collection_name=COLLECTION_NAME)49            # Access point_count using dictionary-style access for compatibility50            point_count = collection_info.points_count if hasattr(collection_info, 'points_count') else collection_info.get('points_count', 0) if isinstance(collection_info, dict) else 051            collection_exists = True52            print(f"Collection exists with {point_count} points")53        except Exception as e:54            print(f"Collection {COLLECTION_NAME} does not exist or is inaccessible: {e}")55            return []  # Return empty if collection doesn't exist56 57        # Standard approach for newer qdrant-client versions58        search_results = qdrant_client.search(59            collection_name=COLLECTION_NAME,60            query_vector=query_embedding,61            limit=SEARCH_TOP_K,62            with_payload=True63        )64 65        # Log the number of retrieved book chunks66        print(f"Retrieved {len(search_results)} book chunks for query: '{query_text}'")67    except AttributeError as e:68        if "'QdrantClient' object has no attribute 'search'" in str(e):69            # This error occurs when the client doesn't have the search method70            # Return empty results as a fallback for this specific error71            print(f"Qdrant search method not available: {e}")72            search_results = []73        else:74            # Re-raise other attribute errors75            raise76    except Exception as e:77        # Log other errors and return empty results as fallback78        print(f"Error during Qdrant search: {e}")79        search_results = []80 81    return search_results82 83 84def format_response(query, search_results):85    """Format the response using OpenRouter based on query and search results."""86    # Prepare context from search results87    context_parts = []88 89    # Check if search_results exist and have content90    if search_results:91        for result in search_results:92            # Handle different possible structures of result objects93            if hasattr(result, 'payload'):94                text = result.payload.get('text', '') if result.payload else ''95                source = result.payload.get('source_file', 'Unknown source') if result.payload else 'Unknown source'96            else:97                # If result is a dict or other format98                text = result.get('text', '') if isinstance(result, dict) else ''99                source = result.get('source_file', 'Unknown source') if isinstance(result, dict) else 'Unknown source'100 101            score = getattr(result, 'score', 0) if hasattr(result, 'score') else result.get('score', 0) if isinstance(result, dict) else 0102 103            context_parts.append(f"Source: {source}\nRelevance Score: {score}\nContent: {text}\n---")104 105    combined_context = "\n".join(context_parts)106 107    # Create a prompt for OpenRouter that includes the context108    prompt = f"""109    You are an AI assistant for the Physical AI & Humanoid Robotics Curriculum.110    Answer the user's query based on the provided context from the curriculum.111    If the context doesn't contain relevant information, politely say that you don't have enough information to answer the query.112 113    Context:114    {combined_context}115 116    User Query:117    {query}118 119    Response:120    """121 122    # Use OpenRouter models to generate a response123    # Using specific primary and fallback models for production stability124    model_name = None125 126    # Primary and fallback models for OpenRouter127    primary_model = 'openai/gpt-4o'  # Using GPT-4o as primary model128    fallback_model = 'openai/gpt-4o-mini'  # Using GPT-4o-mini as fallback129 130    # Try primary model first131    try:132        response = client.chat.completions.create(133            model=primary_model,134            messages=[135                {136                    "role": "system",137                    "content": "You are an AI assistant for the Physical AI & Humanoid Robotics Curriculum. Answer the user's query based on the provided context from the curriculum. If the context doesn't contain relevant information, politely say that you don't have enough information to answer the query."138                },139                {140                    "role": "user",141                    "content": prompt142                }143            ],144            max_tokens=MAX_TOKENS_RESPONSE,145            temperature=TEMPERATURE146        )147        model_name = primary_model148        print(f"Using primary model: {primary_model}")149        response_text = response.choices[0].message.content150    except Exception as e:151        print(f"Primary model {primary_model} failed: {e}")152        # Try fallback model153        try:154            response = client.chat.completions.create(155                model=fallback_model,156                messages=[157                    {158                        "role": "system",159                        "content": "You are an AI assistant for the Physical AI & Humanoid Robotics Curriculum. Answer the user's query based on the provided context from the curriculum. If the context doesn't contain relevant information, politely say that you don't have enough information to answer the query."160                    },161                    {162                        "role": "user",163                        "content": prompt164                    }165                ],166                max_tokens=MAX_TOKENS_RESPONSE,167                temperature=TEMPERATURE168            )169            model_name = fallback_model170            print(f"Fallback to model: {fallback_model}")171            response_text = response.choices[0].message.content172        except Exception as e2:173            print(f"Fallback model {fallback_model} also failed: {e2}")174            response_text = None175 176    # If no model worked, provide a fallback response instead of failing177    if model_name is None or not response_text:178        # Fallback: return the context directly if LLM fails179        if combined_context:180            return f"Based on the curriculum materials:\n\n{combined_context[:1000]}...\n\n(Truncated for brevity)"181        else:182            return "I'm sorry, but I'm currently unable to generate a response. The AI service might be unavailable. Please try again later."183 184    return response_text