feat: add environment endpoint for weather, forecast, and sun data
Build and Push / release (push) Successful in 3s
Build and Push / build (push) Successful in 2m14s

Add GET /tools/environment endpoint that fetches weather, forecast, sun times,
and air quality data from user's volatile Qdrant collection.

- Add qdrant-client dependency
- Create QdrantReadClient wrapper for read-only queries
- Add environment schemas and service in tools domain
- Parse weather, forecast, sun times, and air quality from Qdrant payloads
- Support user-specific collections via preferred_username from OIDC
- Add comprehensive service tests (13 tests)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jeroen Schweitzer
2026-01-06 23:04:59 +01:00
co-authored by Claude Opus 4.5
parent b8fca7060f
commit 6045c6ac6a
11 changed files with 1019 additions and 3 deletions
+60 -1
View File
@@ -3,14 +3,20 @@ Tools Controller
Provides utility tool endpoints including:
- DNS lookups
- Environment data (weather, forecast, sun times, air quality)
"""
from fastapi import APIRouter, HTTPException, status
from typing import Dict, Optional
from fastapi import APIRouter, Depends, HTTPException, status
from src.controllers.base import BaseController
from src.logging_config import get_logger
from src.dns.schemas import DNSLookupRequest, DNSLookupResponse
from src.dns.service import DNSService
from src.dns.exceptions import DNSQueryError
from src.domains.tools.environment.schemas import EnvironmentResponse
from src.domains.tools.environment.service import get_environment_service
from src.oidc.dependencies import get_optional_user
logger = get_logger(__name__)
@@ -26,6 +32,7 @@ class ToolsController(BaseController):
def __init__(self):
super().__init__(prefix="/tools", tags=["Tools"])
self.dns_service = DNSService()
self.environment_service = get_environment_service()
def create_router(self) -> APIRouter:
"""Create and configure the router"""
@@ -95,6 +102,58 @@ class ToolsController(BaseController):
detail="An unexpected error occurred during DNS lookup"
)
@router.get(
"/environment",
response_model=EnvironmentResponse,
status_code=status.HTTP_200_OK,
summary="Get environment data",
description="""
Fetch current environment data including weather, forecast, sun times,
and optionally air quality.
Data is retrieved from the user's volatile Qdrant collection which is
populated by background data collectors.
**Data Sources:**
- Weather: Current temperature, conditions, humidity, wind
- Forecast: Multi-day weather outlook
- Sun Times: Sunrise, sunset, daylight duration
- Air Quality: AQI and pollutant levels (when available)
**Authentication:**
- Uses authenticated user's `preferred_username` if available
- Falls back to 'default' for unauthenticated requests
"""
)
async def get_environment(
user: Optional[Dict] = Depends(get_optional_user),
) -> EnvironmentResponse:
"""
Get current environment data.
Args:
user: Optional authenticated user info
Returns:
Environment data with weather, forecast, sun times, and air quality
"""
try:
# Determine user identifier
user_id = "default"
if user:
user_id = user.get("preferred_username") or user.get("sub", "default")
logger.info(f"Fetching environment data for user: {user_id}")
result = await self.environment_service.get_current(user_id)
return result
except Exception as e:
logger.error(f"Error fetching environment data: {str(e)}", exc_info=True)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to fetch environment data"
)
return router