Spaces:
Build error
Build error
| """ | |
| Configuration API endpoints for FastAPI. | |
| Provides configuration management, instructions, and state information. | |
| """ | |
| from typing import Any, Optional, List | |
| from pydantic import BaseModel | |
| from fastapi import APIRouter, Request, HTTPException, Depends | |
| from pathlib import Path | |
| import json | |
| import os | |
| from ..config import get_settings | |
| from ..lib.utils.auth import AuthManager | |
| from ..lib.core.sessions import SessionManager | |
| from ..lib.utils.server_utils import get_session_id_from_request | |
| from ..lib.utils.config_utils import get_config | |
| from ..lib.utils.logging_utils import get_logger | |
| logger = get_logger(__name__) | |
| router = APIRouter(prefix="/config", tags=["configuration"]) | |
| # Get config instance | |
| config = get_config() | |
| # Pydantic Models | |
| class ConfigSetRequest(BaseModel): | |
| """Request model for setting config values""" | |
| key: str | |
| value: Any | |
| class InstructionItem(BaseModel): | |
| """Model for extraction instructions""" | |
| label: str | |
| extractor: List[str] | |
| text: List[str] | |
| class StateResponse(BaseModel): | |
| """Response model for application state""" | |
| hasInternet: Optional[bool] = None | |
| class ConfigSetResponse(BaseModel): | |
| """Response for config set operation""" | |
| result: str | |
| # Authentication dependency | |
| async def require_auth(request: Request) -> dict: | |
| """ | |
| Dependency that requires valid authentication. | |
| Returns authenticated user data. | |
| """ | |
| settings = get_settings() | |
| session_id = get_session_id_from_request(request) | |
| if not session_id: | |
| raise HTTPException(status_code=401, detail="Authentication required") | |
| auth_manager = AuthManager(settings.db_dir, logger=logger) | |
| session_manager = SessionManager(settings.db_dir, logger=logger) | |
| # Validate session | |
| if not session_manager.is_session_valid(session_id, settings.session_timeout): | |
| raise HTTPException(status_code=401, detail="Session expired") | |
| # Get user | |
| user = auth_manager.get_user_by_session_id(session_id, session_manager) | |
| if not user: | |
| raise HTTPException(status_code=401, detail="Invalid session") | |
| return user | |
| # Helper functions | |
| def has_internet() -> bool: | |
| """Check if internet connection is available""" | |
| # Simple check - can be enhanced later | |
| import socket | |
| try: | |
| socket.create_connection(("8.8.8.8", 53), timeout=3) | |
| return True | |
| except OSError: | |
| return False | |
| # API Endpoints | |
| async def list_config() -> dict: | |
| """ | |
| List all configuration values. | |
| Returns complete configuration object. | |
| """ | |
| config_data = config.load() | |
| return config_data | |
| async def get_config(key: str) -> Any: | |
| """ | |
| Get a specific configuration value by key. | |
| Returns the value associated with the key. | |
| """ | |
| if not key: | |
| raise HTTPException(status_code=400, detail="Invalid or empty key") | |
| config_data = config.load() | |
| if key not in config_data: | |
| raise HTTPException(status_code=404, detail=f"Key '{key}' not found") | |
| return config_data[key] | |
| async def set_config( | |
| request_data: ConfigSetRequest, | |
| user: dict = Depends(require_auth) | |
| ): | |
| """ | |
| Set a configuration value. | |
| Requires authentication. | |
| """ | |
| if not request_data.key: | |
| raise HTTPException(status_code=400, detail="Missing 'key' in request") | |
| success, message = config.set(request_data.key, request_data.value) | |
| if not success: | |
| raise HTTPException(status_code=400, detail=message) | |
| logger.info(f"User {user['username']} set config {request_data.key}") | |
| return ConfigSetResponse(result="OK") | |
| async def get_instructions(user: dict = Depends(require_auth)) -> List[InstructionItem]: | |
| """ | |
| Get extraction instructions. | |
| Requires authentication. | |
| Returns list of instruction items. | |
| """ | |
| settings = get_settings() | |
| instruction_file = settings.db_dir / "prompt.json" | |
| if instruction_file.exists(): | |
| with open(instruction_file, 'r', encoding='utf-8') as f: | |
| instructions = json.load(f) | |
| else: | |
| instructions = [{ | |
| "label": "Default instructions", | |
| "extractor": ["llamore-gemini"], | |
| "text": [] | |
| }] | |
| return instructions | |
| class SaveInstructionsResponse(BaseModel): | |
| """Response for saving instructions""" | |
| result: str | |
| async def save_instructions( | |
| instructions: List[InstructionItem], | |
| user: dict = Depends(require_auth) | |
| ) -> SaveInstructionsResponse: | |
| """ | |
| Save extraction instructions. | |
| Requires authentication. | |
| """ | |
| settings = get_settings() | |
| instruction_file = settings.db_dir / "prompt.json" | |
| # Ensure directory exists | |
| instruction_file.parent.mkdir(parents=True, exist_ok=True) | |
| # Convert Pydantic models to dicts for JSON serialization | |
| instructions_data = [item.model_dump() for item in instructions] | |
| with open(instruction_file, 'w', encoding='utf-8') as f: | |
| json.dump(instructions_data, f, indent=4) | |
| logger.info(f"User {user['username']} saved instructions") | |
| return SaveInstructionsResponse(result="ok") | |
| async def get_state(): | |
| """ | |
| Get application state information. | |
| Returns state including internet connectivity. | |
| """ | |
| return StateResponse(hasInternet=has_internet()) | |