diff --git a/ai-hub/app/app.py b/ai-hub/app/app.py index d18d97b..e357d57 100644 --- a/ai-hub/app/app.py +++ b/ai-hub/app/app.py @@ -1,7 +1,6 @@ import os from contextlib import asynccontextmanager from fastapi import FastAPI -from dotenv import load_dotenv from typing import List # Import core application logic @@ -13,9 +12,6 @@ from app.db.session import create_db_and_tables from app.api.routes import create_api_router -# Load environment variables from a .env file -load_dotenv() - # --- Application Factory Function --- def create_app() -> FastAPI: """ diff --git a/ai-hub/app/app.py b/ai-hub/app/app.py index d18d97b..e357d57 100644 --- a/ai-hub/app/app.py +++ b/ai-hub/app/app.py @@ -1,7 +1,6 @@ import os from contextlib import asynccontextmanager from fastapi import FastAPI -from dotenv import load_dotenv from typing import List # Import core application logic @@ -13,9 +12,6 @@ from app.db.session import create_db_and_tables from app.api.routes import create_api_router -# Load environment variables from a .env file -load_dotenv() - # --- Application Factory Function --- def create_app() -> FastAPI: """ diff --git a/ai-hub/app/core/llm_providers.py b/ai-hub/app/core/llm_providers.py index de36a55..cd422e3 100644 --- a/ai-hub/app/core/llm_providers.py +++ b/ai-hub/app/core/llm_providers.py @@ -1,33 +1,21 @@ -import os import httpx import logging import json from abc import ABC, abstractmethod from openai import OpenAI from typing import final +from app.config import settings # <-- Import the centralized settings -# --- 0. Configure Logging --- -# Set up basic logging to print INFO level messages to the console. -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(levelname)s - [%(funcName)s] - %(message)s' -) +# Configure logging (can be moved to a higher level, like app.py, if preferred) +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +# --- 1. Initialize API Clients from Central Config --- +# All environment variable access is now gone from this file. +deepseek_client = OpenAI(api_key=settings.DEEPSEEK_API_KEY, base_url="https://api.deepseek.com") +GEMINI_URL = f"https://generativelanguage.googleapis.com/v1beta/models/{settings.GEMINI_MODEL_NAME}:generateContent?key={settings.GEMINI_API_KEY}" -# --- 1. Load Configuration from Environment --- -DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY") -GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") -DEEPSEEK_MODEL = os.getenv("DEEPSEEK_MODEL_NAME", "deepseek-chat") -GEMINI_MODEL = os.getenv("GEMINI_MODEL_NAME", "gemini-1.5-flash-latest") - - -# --- 2. Initialize API Clients and URLs --- -deepseek_client = OpenAI(api_key=DEEPSEEK_API_KEY, base_url="https://api.deepseek.com") -GEMINI_URL = f"https://generativelanguage.googleapis.com/v1beta/models/{GEMINI_MODEL}:generateContent?key={GEMINI_API_KEY}" - - -# --- 3. Provider Interface and Implementations --- - +# --- 2. Provider Interface and Implementations (Unchanged) --- class LLMProvider(ABC): """Abstract base class ('Interface') for all LLM providers.""" @abstractmethod @@ -40,31 +28,14 @@ """Provider for the DeepSeek API.""" def __init__(self, model_name: str): self.model = model_name - logging.info(f"DeepSeekProvider initialized with model: {self.model}") async def generate_response(self, prompt: str) -> str: - # Construct the request payload - messages_payload = [ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": prompt}, - ] - - # Log the payload before sending the request - logging.info(f"--- DeepSeek Request Payload ---\n{json.dumps(messages_payload, indent=2)}") - + messages = [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": prompt}] try: - chat_completion = deepseek_client.chat.completions.create( - model=self.model, - messages=messages_payload, - stream=False - ) - - # Log the full, raw response object from the API - logging.info(f"--- DeepSeek Raw Response ---\n{chat_completion.model_dump_json(indent=2)}") - + chat_completion = deepseek_client.chat.completions.create(model=self.model, messages=messages) return chat_completion.choices[0].message.content except Exception as e: - logging.error("DeepSeek Provider Error", exc_info=True) # exc_info=True logs the traceback + logging.error("DeepSeek Provider Error", exc_info=True) raise @final @@ -72,34 +43,24 @@ """Provider for the Google Gemini API.""" def __init__(self, api_url: str): self.url = api_url - logging.info(f"GeminiProvider initialized for URL: {self.url.split('?')[0]}") async def generate_response(self, prompt: str) -> str: - # Construct the request payload payload = {"contents": [{"parts": [{"text": prompt}]}]} headers = {"Content-Type": "application/json"} - - # Log the payload before sending the request - logging.info(f"--- Gemini Request Payload ---\n{json.dumps(payload, indent=2)}") - try: async with httpx.AsyncClient() as client: response = await client.post(self.url, json=payload, headers=headers) - - # Log the raw response text, which is crucial for debugging any errors - logging.info(f"--- Gemini Raw Response ---\n{response.text}") - - response.raise_for_status() # Raise an exception for non-2xx status codes + response.raise_for_status() data = response.json() return data['candidates'][0]['content']['parts'][0]['text'] - except (httpx.HTTPStatusError, KeyError, IndexError) as e: + except Exception as e: logging.error("Gemini Provider Error", exc_info=True) raise -# --- 4. The Factory Function --- - +# --- 3. The Factory Function --- +# The dictionary of providers is now built using values from the settings object. _providers = { - "deepseek": DeepSeekProvider(model_name=DEEPSEEK_MODEL), + "deepseek": DeepSeekProvider(model_name=settings.DEEPSEEK_MODEL_NAME), "gemini": GeminiProvider(api_url=GEMINI_URL) } diff --git a/ai-hub/app/app.py b/ai-hub/app/app.py index d18d97b..e357d57 100644 --- a/ai-hub/app/app.py +++ b/ai-hub/app/app.py @@ -1,7 +1,6 @@ import os from contextlib import asynccontextmanager from fastapi import FastAPI -from dotenv import load_dotenv from typing import List # Import core application logic @@ -13,9 +12,6 @@ from app.db.session import create_db_and_tables from app.api.routes import create_api_router -# Load environment variables from a .env file -load_dotenv() - # --- Application Factory Function --- def create_app() -> FastAPI: """ diff --git a/ai-hub/app/core/llm_providers.py b/ai-hub/app/core/llm_providers.py index de36a55..cd422e3 100644 --- a/ai-hub/app/core/llm_providers.py +++ b/ai-hub/app/core/llm_providers.py @@ -1,33 +1,21 @@ -import os import httpx import logging import json from abc import ABC, abstractmethod from openai import OpenAI from typing import final +from app.config import settings # <-- Import the centralized settings -# --- 0. Configure Logging --- -# Set up basic logging to print INFO level messages to the console. -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(levelname)s - [%(funcName)s] - %(message)s' -) +# Configure logging (can be moved to a higher level, like app.py, if preferred) +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +# --- 1. Initialize API Clients from Central Config --- +# All environment variable access is now gone from this file. +deepseek_client = OpenAI(api_key=settings.DEEPSEEK_API_KEY, base_url="https://api.deepseek.com") +GEMINI_URL = f"https://generativelanguage.googleapis.com/v1beta/models/{settings.GEMINI_MODEL_NAME}:generateContent?key={settings.GEMINI_API_KEY}" -# --- 1. Load Configuration from Environment --- -DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY") -GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") -DEEPSEEK_MODEL = os.getenv("DEEPSEEK_MODEL_NAME", "deepseek-chat") -GEMINI_MODEL = os.getenv("GEMINI_MODEL_NAME", "gemini-1.5-flash-latest") - - -# --- 2. Initialize API Clients and URLs --- -deepseek_client = OpenAI(api_key=DEEPSEEK_API_KEY, base_url="https://api.deepseek.com") -GEMINI_URL = f"https://generativelanguage.googleapis.com/v1beta/models/{GEMINI_MODEL}:generateContent?key={GEMINI_API_KEY}" - - -# --- 3. Provider Interface and Implementations --- - +# --- 2. Provider Interface and Implementations (Unchanged) --- class LLMProvider(ABC): """Abstract base class ('Interface') for all LLM providers.""" @abstractmethod @@ -40,31 +28,14 @@ """Provider for the DeepSeek API.""" def __init__(self, model_name: str): self.model = model_name - logging.info(f"DeepSeekProvider initialized with model: {self.model}") async def generate_response(self, prompt: str) -> str: - # Construct the request payload - messages_payload = [ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": prompt}, - ] - - # Log the payload before sending the request - logging.info(f"--- DeepSeek Request Payload ---\n{json.dumps(messages_payload, indent=2)}") - + messages = [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": prompt}] try: - chat_completion = deepseek_client.chat.completions.create( - model=self.model, - messages=messages_payload, - stream=False - ) - - # Log the full, raw response object from the API - logging.info(f"--- DeepSeek Raw Response ---\n{chat_completion.model_dump_json(indent=2)}") - + chat_completion = deepseek_client.chat.completions.create(model=self.model, messages=messages) return chat_completion.choices[0].message.content except Exception as e: - logging.error("DeepSeek Provider Error", exc_info=True) # exc_info=True logs the traceback + logging.error("DeepSeek Provider Error", exc_info=True) raise @final @@ -72,34 +43,24 @@ """Provider for the Google Gemini API.""" def __init__(self, api_url: str): self.url = api_url - logging.info(f"GeminiProvider initialized for URL: {self.url.split('?')[0]}") async def generate_response(self, prompt: str) -> str: - # Construct the request payload payload = {"contents": [{"parts": [{"text": prompt}]}]} headers = {"Content-Type": "application/json"} - - # Log the payload before sending the request - logging.info(f"--- Gemini Request Payload ---\n{json.dumps(payload, indent=2)}") - try: async with httpx.AsyncClient() as client: response = await client.post(self.url, json=payload, headers=headers) - - # Log the raw response text, which is crucial for debugging any errors - logging.info(f"--- Gemini Raw Response ---\n{response.text}") - - response.raise_for_status() # Raise an exception for non-2xx status codes + response.raise_for_status() data = response.json() return data['candidates'][0]['content']['parts'][0]['text'] - except (httpx.HTTPStatusError, KeyError, IndexError) as e: + except Exception as e: logging.error("Gemini Provider Error", exc_info=True) raise -# --- 4. The Factory Function --- - +# --- 3. The Factory Function --- +# The dictionary of providers is now built using values from the settings object. _providers = { - "deepseek": DeepSeekProvider(model_name=DEEPSEEK_MODEL), + "deepseek": DeepSeekProvider(model_name=settings.DEEPSEEK_MODEL_NAME), "gemini": GeminiProvider(api_url=GEMINI_URL) } diff --git a/ai-hub/tests/app.py b/ai-hub/tests/app.py deleted file mode 100644 index b7e6fb3..0000000 --- a/ai-hub/tests/app.py +++ /dev/null @@ -1,56 +0,0 @@ -import os -from contextlib import asynccontextmanager -from fastapi import FastAPI -from dotenv import load_dotenv -from typing import List - -# Import core application logic -from app.core.vector_store import FaissVectorStore -from app.core.retrievers import FaissDBRetriever, Retriever -from app.core.services import RAGService - -# Import the new files for database and API routes -from app.db.session import create_db_tables -from app.api.routes import create_api_router - -# Load environment variables from a .env file -load_dotenv() - -# --- Application Factory Function --- -def create_app() -> FastAPI: - """ - Factory function to create and configure the FastAPI application. - This encapsulates all setup logic, making the main entry point clean. - """ - # Initialize core services for RAG - # CORRECTED: Now passing the required arguments to FaissVectorStore - vector_store = FaissVectorStore(index_file_path="data/faiss_index.bin", dimension=768) - retrievers: List[Retriever] = [ - FaissDBRetriever(vector_store=vector_store), - ] - rag_service = RAGService(vector_store=vector_store, retrievers=retrievers) - - @asynccontextmanager - async def lifespan(app: FastAPI): - """ - Initializes the database and vector store on startup and handles - cleanup on shutdown. - """ - print("Initializing application services...") - create_db_tables() - yield - print("Shutting down application services...") - vector_store.save_index() - - app = FastAPI( - title="AI Model Hub Service", - description="A extensible hub to route requests to various LLMs with RAG capabilities.", - version="0.0.0", - lifespan=lifespan - ) - - # Create and include the API router - api_router = create_api_router(rag_service=rag_service) - app.include_router(api_router) - - return app