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
2 changes: 1 addition & 1 deletion ai-backend/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ repos:
rev: 5.12.0
hooks:
- id: isort
args: ["--profile", "black"]
args: ['--profile', 'black']

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.7.1
Expand Down
4 changes: 1 addition & 3 deletions ai-backend/agents/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ async def review_article(
logger.info("Reviewing article content")
return article_content, {}

async def fact_check(
self, article_content: str, source_data: dict[str, Any]
) -> dict[str, Any]:
async def fact_check(self, article_content: str, source_data: dict[str, Any]) -> dict[str, Any]:
"""Fact-check article content against source data.

Args:
Expand Down
8 changes: 2 additions & 6 deletions ai-backend/agents/researcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ def __init__(self, config: dict[str, Any]):
self.config = config
logger.info("Research Agent initialized")

async def research_team_history(
self, team_id: str, opponent_id: str
) -> dict[str, Any]:
async def research_team_history(self, team_id: str, opponent_id: str) -> dict[str, Any]:
"""Research historical matchups between teams.

Args:
Expand All @@ -35,9 +33,7 @@ async def research_team_history(
"""
# TODO: Implement team history research
team_safe, opponent_safe = sanitize_multiple_log_inputs(team_id, opponent_id)
logger.info(
"Researching history between teams: %s vs %s", team_safe, opponent_safe
)
logger.info("Researching history between teams: %s vs %s", team_safe, opponent_safe)
return {}

async def research_player_performance(
Expand Down
51 changes: 23 additions & 28 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,14 +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(
..., min_length=10, description="RapidAPI key for API-Football"
)
RAPIDAPI_KEY: str = Field(..., min_length=10, description="RapidAPI key for API-Football")

# OpenAI Configuration
openai_model: str = Field(default="gpt-4-turbo", description="OpenAI model to use")
Expand All @@ -40,9 +38,7 @@ class Settings(BaseSettings):

# Chainlit Configuration
chainlit_host: str = Field(default="127.0.0.1", description="Chainlit host")
chainlit_port: int = Field(
default=8001, ge=1, le=65535, description="Chainlit port"
)
chainlit_port: int = Field(default=8001, ge=1, le=65535, description="Chainlit port")

# Environment Configuration
environment: str = Field(default="development", description="Environment name")
Expand All @@ -56,39 +52,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 +111,7 @@ 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
16 changes: 4 additions & 12 deletions ai-backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,7 @@ async def generate_article(self, request: ArticleRequest) -> ArticleResponse:

except Exception as e:
logger.error(f"Error generating article: {e!s}")
raise HTTPException(
status_code=500, detail=f"Failed to generate article: {e!s}"
) from e
raise HTTPException(status_code=500, detail=f"Failed to generate article: {e!s}") from e

async def _collect_game_data(
self, collector: DataCollectorAgent, game_id: str
Expand Down Expand Up @@ -149,15 +147,11 @@ async def _generate_content(
},
}

async def _edit_content(
self, editor: EditorAgent, content: dict[str, Any]
) -> dict[str, Any]:
async def _edit_content(self, editor: EditorAgent, content: dict[str, Any]) -> dict[str, Any]:
"""Edit and finalize content."""
article_content = content.get("content", "")
metadata = content.get("metadata", {})
edited_content, review_feedback = await editor.review_article(
article_content, metadata
)
edited_content, review_feedback = await editor.review_article(article_content, metadata)
return {
"content": edited_content,
"metadata": {**metadata, "review_feedback": review_feedback},
Expand Down Expand Up @@ -275,9 +269,7 @@ async def root() -> dict[str, str]:
if __name__ == "__main__":
import uvicorn

logger.info(
"Starting server on %s:%s", settings.fastapi_host, settings.fastapi_port
)
logger.info("Starting server on %s:%s", settings.fastapi_host, settings.fastapi_port)
uvicorn.run(
"main:app",
host=settings.fastapi_host,
Expand Down
14 changes: 11 additions & 3 deletions ai-backend/pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
--verbose
--tb=short
--strict-markers
--disable-warnings
--verbose
asyncio_default_fixture_loop_scope = function
asyncio_mode = auto
--cov=.
--cov-report=term-missing
--cov-report=html:htmlcov
--cov-fail-under=80
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
integration: marks tests as integration tests
unit: marks tests as unit tests
asyncio: marks tests as asyncio tests
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}")

Comment on lines +8 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical bug: Missing import statements in dependency tests.

The test file is missing the actual import statements in each try block, making the environment verification completely ineffective. Each try block will always execute the success message regardless of whether the packages are installed.

Apply this diff to add the missing import statements:

 try:
+    import openai
     print("βœ… OpenAI package imported successfully")
 except ImportError as e:
     print(f"❌ OpenAI import failed: {e}")

 try:
+    import openai_agents
     print("βœ… OpenAI Agents package imported successfully")
 except ImportError as e:
     print(f"❌ OpenAI Agents import failed: {e}")

 try:
+    import fastapi
     print("βœ… FastAPI package imported successfully")
 except ImportError as e:
     print(f"❌ FastAPI import failed: {e}")

 try:
+    import pydantic
     print("βœ… Pydantic package imported successfully")
 except ImportError as e:
     print(f"❌ Pydantic import failed: {e}")

 try:
+    import supabase
     print("βœ… Supabase package imported successfully")
 except ImportError as e:
     print(f"❌ Supabase import failed: {e}")

 try:
+    import aiohttp
     print("βœ… Aiohttp package imported successfully")
 except ImportError as e:
     print(f"❌ Aiohttp import failed: {e}")

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

 try:
+    import structlog
     print("βœ… Structlog package imported successfully")
 except ImportError as e:
     print(f"❌ Structlog import failed: {e}")
πŸ“ 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
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}")
try:
import openai
print("βœ… OpenAI package imported successfully")
except ImportError as e:
print(f"❌ OpenAI import failed: {e}")
try:
import openai_agents
print("βœ… OpenAI Agents package imported successfully")
except ImportError as e:
print(f"❌ OpenAI Agents import failed: {e}")
try:
import fastapi
print("βœ… FastAPI package imported successfully")
except ImportError as e:
print(f"❌ FastAPI import failed: {e}")
try:
import pydantic
print("βœ… Pydantic package imported successfully")
except ImportError as e:
print(f"❌ Pydantic import failed: {e}")
try:
import supabase
print("βœ… Supabase package imported successfully")
except ImportError as e:
print(f"❌ Supabase import failed: {e}")
try:
import aiohttp
print("βœ… Aiohttp package imported successfully")
except ImportError as e:
print(f"❌ Aiohttp import failed: {e}")
try:
import dotenv
print("βœ… Python-dotenv package imported successfully")
except ImportError as e:
print(f"❌ Python-dotenv import failed: {e}")
try:
import structlog
print("βœ… Structlog package imported successfully")
except ImportError as e:
print(f"❌ Structlog import failed: {e}")
πŸ€– Prompt for AI Agents
In ai-backend/tests/test_environment.py between lines 8 and 47, the try blocks
only print success messages without actually importing the packages, so they
always succeed regardless of package presence. To fix this, add the appropriate
import statements inside each try block before the print statement to properly
verify if the packages can be imported, ensuring the test accurately reflects
the environment status.

print("\nπŸŽ‰ Environment test completed!")
Loading