Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 24 additions & 23 deletions ai-backend/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
from typing import Any

from dotenv import load_dotenv
from pydantic import Field, validator
from pydantic_settings import BaseSettings
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict

# Load environment variables from .env file
load_dotenv()
Expand All @@ -21,12 +21,12 @@ class Settings(BaseSettings):
"""Application settings loaded from environment variables with validation."""

# Required settings
openai_api_key: str = Field(..., min_length=20, description="OpenAI API key")
supabase_url: str = Field(..., description="Supabase project URL")
supabase_service_role_key: str = Field(
OPENAI_API_KEY: str = Field(..., min_length=20, description="OpenAI API key")
SUPABASE_URL: str = Field(..., description="Supabase project URL")
SUPABASE_SERVICE_ROLE_KEY: str = Field(
..., min_length=20, description="Supabase service role key"
)
rapidapi_key: str = Field(
RAPIDAPI_KEY: str = Field(
..., min_length=10, description="RapidAPI key for API-Football"
)

Expand Down Expand Up @@ -56,39 +56,44 @@ class Settings(BaseSettings):
description="API-Football base URL",
)

@validator("openai_api_key")
def validate_openai_key(cls, v: str) -> str: # noqa: N805
@field_validator("OPENAI_API_KEY")
@classmethod
def validate_openai_key(cls, v: str) -> str:
if not v or v == "your-openai-api-key" or v == "sk-...":
raise ValueError("Valid OpenAI API key is required")
if not v.startswith("sk-"):
raise ValueError('OpenAI API key must start with "sk-"')
return v

@validator("supabase_url")
def validate_supabase_url(cls, v: str) -> str: # noqa: N805
@field_validator("SUPABASE_URL")
@classmethod
def validate_supabase_url(cls, v: str) -> str:
if not v.startswith("https://"):
raise ValueError("Supabase URL must be a valid HTTPS URL")
if not v.endswith(".supabase.co"):
raise ValueError("Supabase URL must end with .supabase.co")
return v

@validator("environment")
def validate_environment(cls, v: str) -> str: # noqa: N805
@field_validator("environment")
@classmethod
def validate_environment(cls, v: str) -> str:
allowed = ["development", "staging", "production"]
if v not in allowed:
raise ValueError(f"Environment must be one of: {allowed}")
return v

@validator("log_level")
def validate_log_level(cls, v: str) -> str: # noqa: N805
@field_validator("log_level")
@classmethod
def validate_log_level(cls, v: str) -> str:
allowed = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
v_upper = v.upper()
if v_upper not in allowed:
raise ValueError(f"Log level must be one of: {allowed}")
return v_upper

@validator("log_format")
def validate_log_format(cls, v: str) -> str: # noqa: N805
@field_validator("log_format")
@classmethod
def validate_log_format(cls, v: str) -> str:
allowed = ["json", "text"]
if v not in allowed:
raise ValueError(f"Log format must be one of: {allowed}")
Expand All @@ -110,13 +115,9 @@ def to_dict(self) -> dict[str, Any]:
"api_football_base_url": self.api_football_base_url,
}

class Config:
"""Pydantic configuration for Settings model."""

env_file = ".env"
case_sensitive = True
# Allow extra fields for forward compatibility
extra = "ignore"
model_config = SettingsConfigDict(
env_file=".env", case_sensitive=True, extra="ignore"
)


# Global settings instance
Expand Down
66 changes: 66 additions & 0 deletions ai-backend/test_environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""
Test script to verify all dependencies are properly installed
"""

import sys

print(f"Python version: {sys.version}")

# Test core dependencies
try:
import openai

Check warning on line 11 in ai-backend/test_environment.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

ai-backend/test_environment.py#L11

Unused import openai

print("✅ OpenAI package imported successfully")
except ImportError as e:
print(f"❌ OpenAI import failed: {e}")

try:
from agents.researcher import ResearchAgent

Check warning on line 18 in ai-backend/test_environment.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

ai-backend/test_environment.py#L18

Unused ResearchAgent imported from agents.researcher

print("✅ OpenAI Agents package imported successfully")
except ImportError as e:
print(f"❌ OpenAI Agents import failed: {e}")

try:
import fastapi

Check warning on line 25 in ai-backend/test_environment.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

ai-backend/test_environment.py#L25

Unused import fastapi

print("✅ FastAPI package imported successfully")
except ImportError as e:
print(f"❌ FastAPI import failed: {e}")

try:
from pydantic import BaseModel

Check warning on line 32 in ai-backend/test_environment.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

ai-backend/test_environment.py#L32

Unused BaseModel imported from pydantic

print("✅ Pydantic package imported successfully")
except ImportError as e:
print(f"❌ Pydantic import failed: {e}")

try:
from supabase import create_client

Check warning on line 39 in ai-backend/test_environment.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

ai-backend/test_environment.py#L39

Unused create_client imported from supabase

print("✅ Supabase package imported successfully")
except ImportError as e:
print(f"❌ Supabase import failed: {e}")

try:
import aiohttp

Check warning on line 46 in ai-backend/test_environment.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

ai-backend/test_environment.py#L46

Unused import aiohttp

print("✅ Aiohttp package imported successfully")
except ImportError as e:
print(f"❌ Aiohttp import failed: {e}")

try:
from dotenv import load_dotenv

Check warning on line 53 in ai-backend/test_environment.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

ai-backend/test_environment.py#L53

Unused load_dotenv imported from dotenv

print("✅ Python-dotenv package imported successfully")
except ImportError as e:
print(f"❌ Python-dotenv import failed: {e}")

try:
import structlog

Check warning on line 60 in ai-backend/test_environment.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

ai-backend/test_environment.py#L60

Unused import structlog

print("✅ Structlog package imported successfully")
except ImportError as e:
print(f"❌ Structlog import failed: {e}")

print("\n🎉 Environment test completed!")
38 changes: 38 additions & 0 deletions ai-backend/test_openai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
Test OpenAI API connection
"""
import os
from dotenv import load_dotenv
import openai

# Load environment variables
load_dotenv()

# Set up OpenAI client
client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def test_openai_connection():
"""Test basic OpenAI API connection"""
if not os.getenv("OPENAI_API_KEY") or os.getenv("OPENAI_API_KEY") == "your_openai_api_key_here":
print("⚠️ OpenAI API key not set. Skipping connection test.")
return

try:
# Test with a simple completion
response = client.chat.completions.create(
model="gpt-4.1-nano",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify the OpenAI model name.

The model name "gpt-4.1-nano" doesn't appear to be a valid OpenAI model. Please verify this is correct or update to a valid model name like "gpt-4-turbo" or "gpt-3.5-turbo".


🌐 Web query:

What are the current available OpenAI models for chat completions as of 2024?

💡 Result:

As of mid-2025, the current available OpenAI chat completion models—including API and platform access (such as ChatGPT)—span several generations. The major families and notable individual models are:

1. GPT-4o Series

  • GPT-4o is the flagship general-purpose model, supporting text and vision inputs, and real-time multimodal reasoning[4][5].
  • GPT-4o mini is a smaller, more cost-efficient variant, maintaining high performance for its size[6].
  • Audio-specialized versions like gpt-4o-audio-preview, gpt-4o-mini-audio-preview, and gpt-4o-mini-realtime-preview enable advanced audio generation and real-time audio interactions through the Chat Completions API[2].

2. GPT-4.1 and GPT-4.5

  • GPT-4.1: Latest release with a 1 million token context window, focused on both chat and text/image tasks[2][5].
  • GPT-4.5: Introduced as a research preview, this model improves general chat experience with broader knowledge, creativity, and reliability. It especially excels at following user intent and performing diverse tasks[4][5].

3. O-Series Reasoning Models

  • o3, o4-mini: Advanced reasoning models, designed for complex problem-solving and agentic behaviors. They deeply integrate with tool use in ChatGPT and via the API[8].
  • o3-mini, o3-pro, o1, o1-mini, o1-pro: Several iterations focused on specific reasoning improvements and enhanced agent-like capabilities. These models are designed for more thoughtful, multi-step reasoning tasks and are accessible via both ChatGPT and API to select users[4][6][8].

4. GPT-3.5 Turbo

  • GPT-3.5-turbo and its extended context variant (gpt-3.5-turbo-16k) remain available for many workloads, offering a cost-effective, robust baseline for chat and completion tasks[7].

5. Specialized Models

  • codex-mini (fine-tuned for programming tasks, derived from o4-mini)[5].
  • Model routers and model selection utilities for automatic optimization based on prompt requirements[5].

Notes on Access and Use

  • The API and ChatGPT interfaces often offer slightly different model lineups and rate limits. Some new models (particularly reasoning/“o-series”) may require ChatGPT Pro or Team plans or limited-access API credentials[6][8].
  • Deprecated Models: Older models via the legacy Completions API (e.g., text-davinci-003) are deprecated; developers are encouraged to migrate to the Chat Completions API[7].

Summary Table of Current OpenAI Chat Completion Models (2024–2025)

Model Family Notable Model Names Key Features
GPT-4o Series gpt-4o, gpt-4o-mini, audio Multimodal (text, vision, audio), real-time, API
GPT-4.x gpt-4.1, gpt-4.5 Large context window, diverse tasks, API/ChatGPT
O-Series o3, o4-mini, o3-pro, o1 Advanced reasoning, agentic, tool integration
GPT-3.5 Turbo gpt-3.5-turbo, 16k variant Stable, cost-effective, broad compatibility
Specialized codex-mini, model-router Code, adaptive routing

For a full, always-updated listing and details on current API-available models, consult OpenAI or Azure documentation for your workspace or account[5][7].

In summary: As of 2024, OpenAI’s primary chat completion models are GPT-4o (full and mini), GPT-4.1, GPT-4.5, o-series (o3, o4-mini, o1, etc.), and GPT-3.5 Turbo, with audio and reasoning-specialized models available for advanced use cases[2][4][5][6][8].

Citations:


Use a valid OpenAI model name

The value “gpt-4.1-nano” is not a recognized model. Please update it to one of the currently supported chat-completion models. For example:

  • gpt-4.1
  • gpt-4.5
  • gpt-4o-mini
  • gpt-3.5-turbo

Locations to update:

  • ai-backend/test_openai.py: line 23

Example change:

-            model="gpt-4.1-nano",
+            model="gpt-4.1",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
model="gpt-4.1-nano",
model="gpt-4.1",
🤖 Prompt for AI Agents
In ai-backend/test_openai.py at line 23, the model name "gpt-4.1-nano" is
invalid. Replace it with a valid OpenAI model name such as "gpt-4.1", "gpt-4.5",
"gpt-4o-mini", or "gpt-3.5-turbo" to ensure compatibility with the API.

messages=[
{"role": "user", "content": "Say 'Hello from Sport Scribe AI!'"}
],
max_tokens=50
)

print("✅ OpenAI API connection successful!")
print(f"Response: {response.choices[0].message.content}")

except Exception as e:
print(f"❌ OpenAI API connection failed: {e}")

if __name__ == "__main__":
test_openai_connection()

48 changes: 48 additions & 0 deletions ai-backend/tests/test_environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""Test script to verify all dependencies are properly installed."""

import sys

print(f"Python version: {sys.version}")

# Test core dependencies
try:
print("✅ OpenAI package imported successfully")
except ImportError as e:
print(f"❌ OpenAI import failed: {e}")

try:
print("✅ OpenAI Agents package imported successfully")
except ImportError as e:
print(f"❌ OpenAI Agents import failed: {e}")

try:
print("✅ FastAPI package imported successfully")
except ImportError as e:
print(f"❌ FastAPI import failed: {e}")

try:
print("✅ Pydantic package imported successfully")
except ImportError as e:
print(f"❌ Pydantic import failed: {e}")

try:
print("✅ Supabase package imported successfully")
except ImportError as e:
print(f"❌ Supabase import failed: {e}")

try:
print("✅ Aiohttp package imported successfully")
except ImportError as e:
print(f"❌ Aiohttp import failed: {e}")

try:
print("✅ Python-dotenv package imported successfully")
except ImportError as e:
print(f"❌ Python-dotenv import failed: {e}")

try:
print("✅ Structlog package imported successfully")
except ImportError as e:
print(f"❌ Structlog import failed: {e}")

print("\n🎉 Environment test completed!")
37 changes: 37 additions & 0 deletions ai-backend/tests/test_openai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Test OpenAI API connection."""

import os

import openai
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

# Set up OpenAI client
client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))


def test_openai_connection() -> None:
"""Test basic OpenAI API connection."""
if not os.getenv("OPENAI_API_KEY") or os.getenv("OPENAI_API_KEY") == "your_openai_api_key_here":
print("⚠️ OpenAI API key not set. Skipping connection test.")
return

try:
# Test with a simple completion
response = client.chat.completions.create(
model="gpt-4.1-nano",
messages=[{"role": "user", "content": "Say 'Hello from Sport Scribe AI!'"}],
max_tokens=50,
)

print("✅ OpenAI API connection successful!")
print(f"Response: {response.choices[0].message.content}")

except Exception as e:
print(f"❌ OpenAI API connection failed: {e}")


if __name__ == "__main__":
test_openai_connection()
66 changes: 66 additions & 0 deletions ai-backend/tests/test_quality_tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""Sample code to test quality tools."""

import asyncio

Comment on lines +1 to +4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Clarify the purpose: this isn't a proper test file.

The file is located in the tests/ directory and has a docstring mentioning "test quality tools," but it doesn't import any testing frameworks (unittest, pytest) or contain actual test cases. Consider either:

  • Moving this to a different directory if it's sample/demo code
  • Adding proper test cases with assertions using a testing framework
🤖 Prompt for AI Agents
In ai-backend/tests/test_quality_tools.py at lines 1 to 4, the file is labeled
as a test but lacks any testing framework imports or test cases. To fix this,
either move the file out of the tests directory if it is only sample or demo
code, or convert it into a proper test file by importing a testing framework
like pytest or unittest and adding actual test functions with assertions.


class FootballDataProcessor:
"""Process football data for AI analysis."""

def __init__(self, league: str) -> None:
"""Initialize processor with league."""
self.league = league
self.processed_games: list[dict[str, str]] = []

def process_game_data(
self, home_team: str, away_team: str, score: str | None = None
) -> dict[str, str]:
"""Process individual game data.

Args:
home_team: Name of home team
away_team: Name of away team
score: Optional match score

Returns:
Processed game data dictionary
"""
game_data = {
"home_team": home_team.strip(),
"away_team": away_team.strip(),
"league": self.league,
}

if score:
game_data["score"] = score.strip()

return game_data

async def fetch_recent_games(self, limit: int = 10) -> list[dict[str, str]]:
"""Fetch recent games asynchronously.

Args:
limit: Maximum number of games to fetch

Returns:
list of recent games
"""
# Simulate async API call
await asyncio.sleep(0.1)

return [
self.process_game_data("Arsenal", "Chelsea", "2-1"),
self.process_game_data("Liverpool", "Manchester City", "1-3"),
][:limit]


def main() -> None:
"""Main function to test the processor."""
processor = FootballDataProcessor("Premier League")

# Test synchronous processing
game = processor.process_game_data("Arsenal", "Chelsea", "2-1")
print(f"Processed game: {game}")


if __name__ == "__main__":
main()