diff --git a/sijapi/__init__.py b/sijapi/__init__.py index 40ffb1f..829ec6d 100644 --- a/sijapi/__init__.py +++ b/sijapi/__init__.py @@ -115,8 +115,6 @@ COMFYUI_OUTPUT_DIR = COMFYUI_DIR / 'output' COMFYUI_LAUNCH_CMD = os.getenv('COMFYUI_LAUNCH_CMD', 'mamba activate comfyui && python main.py') SD_CONFIG_PATH = CONFIG_DIR / 'sd.yaml' - - ### ASR ASR_DIR = DATA_DIR / "asr" os.makedirs(ASR_DIR, exist_ok=True) diff --git a/sijapi/__main__.py b/sijapi/__main__.py index 75a1ae3..c3ee5f5 100755 --- a/sijapi/__main__.py +++ b/sijapi/__main__.py @@ -6,7 +6,7 @@ from starlette.middleware.base import BaseHTTPMiddleware from starlette.middleware.base import BaseHTTPMiddleware from starlette.requests import ClientDisconnect from hypercorn.asyncio import serve -from hypercorn.config import Config +from hypercorn.config import Config as HypercornConfig import sys import asyncio import httpx @@ -18,15 +18,13 @@ from dotenv import load_dotenv from pathlib import Path from datetime import datetime import argparse -from . import L, API, OBSIDIAN_VAULT_DIR -from .logs import Logger parser = argparse.ArgumentParser(description='Personal API.') parser.add_argument('--debug', action='store_true', help='Set log level to L.INFO') parser.add_argument('--test', type=str, help='Load only the specified module.') args = parser.parse_args() -from sijapi import L +from . import L, API, ROUTER_DIR L.setup_from_args(args) from sijapi import ROUTER_DIR @@ -132,11 +130,10 @@ def main(argv): if getattr(API.MODULES, module_name): load_router(module_name) - config = Config() - config.keep_alive_timeout = 1200 - config.bind = [API.BIND] + + config = HypercornConfig() + config.bind = [API.BIND] # Use the resolved BIND value asyncio.run(serve(api, config)) - if __name__ == "__main__": main(sys.argv[1:]) \ No newline at end of file diff --git a/sijapi/classes.py b/sijapi/classes.py index 532fd26..a93dfd2 100644 --- a/sijapi/classes.py +++ b/sijapi/classes.py @@ -1,56 +1,36 @@ -from pydantic import BaseModel, Field -from typing import List, Optional, Any, Tuple, Dict, Union, Tuple -from datetime import datetime, timedelta, timezone import asyncio import json -import os -import re -from pathlib import Path -from typing import Union, Dict, Any, Optional -from pydantic import BaseModel, create_model -import yaml -from dotenv import load_dotenv -import os -import re -import yaml import math -from timezonefinder import TimezoneFinder -from pathlib import Path -import asyncpg -import aiohttp -import aiofiles -from contextlib import asynccontextmanager -from concurrent.futures import ThreadPoolExecutor -import reverse_geocoder as rg -from timezonefinder import TimezoneFinder -from srtm import get_data -from pathlib import Path -import yaml -from typing import Union, List, TypeVar, Type -from pydantic import BaseModel, create_model - -from pydantic import BaseModel, Field -from typing import List, Dict -import yaml -from pathlib import Path import os +import re +from concurrent.futures import ThreadPoolExecutor +from contextlib import asynccontextmanager +from datetime import datetime, timedelta, timezone +from pathlib import Path +from typing import Any, Dict, List, Optional, Tuple, Union, TypeVar, Type + +import aiofiles +import aiohttp +import asyncpg +import reverse_geocoder as rg +import yaml from dotenv import load_dotenv +from pydantic import BaseModel, Field, create_model +from srtm import get_data +from timezonefinder import TimezoneFinder T = TypeVar('T', bound='Configuration') -from pydantic import BaseModel, Field, create_model -from typing import List, Optional, Any, Dict -from pathlib import Path -import yaml class APIConfig(BaseModel): - BIND: str + HOST: str PORT: int + BIND: str URL: str PUBLIC: List[str] TRUSTED_SUBNETS: List[str] MODULES: Any # This will be replaced with a dynamic model - BaseTZ: Optional[str] = 'UTC' + TZ: str KEYS: List[str] @classmethod @@ -73,6 +53,11 @@ class APIConfig(BaseModel): print(f"Error parsing secrets YAML: {e}") secrets_data = {} + # Resolve internal placeholders + config_data = cls.resolve_placeholders(config_data) + + print(f"Resolved config: {config_data}") # Debug print + # Handle KEYS placeholder if isinstance(config_data.get('KEYS'), list) and len(config_data['KEYS']) == 1: placeholder = config_data['KEYS'][0] @@ -105,6 +90,33 @@ class APIConfig(BaseModel): return cls(**config_data) + @classmethod + def resolve_placeholders(cls, config_data: Dict[str, Any]) -> Dict[str, Any]: + def resolve_value(value): + if isinstance(value, str): + pattern = r'\{\{\s*([^}]+)\s*\}\}' + matches = re.findall(pattern, value) + for match in matches: + if match in config_data: + value = value.replace(f'{{{{ {match} }}}}', str(config_data[match])) + return value + + resolved_data = {} + for key, value in config_data.items(): + if isinstance(value, dict): + resolved_data[key] = cls.resolve_placeholders(value) + elif isinstance(value, list): + resolved_data[key] = [resolve_value(item) for item in value] + else: + resolved_data[key] = resolve_value(value) + + # Resolve BIND separately to ensure HOST and PORT are used + if 'BIND' in resolved_data: + resolved_data['BIND'] = resolved_data['BIND'].replace('{{ HOST }}', str(resolved_data['HOST'])) + resolved_data['BIND'] = resolved_data['BIND'].replace('{{ PORT }}', str(resolved_data['PORT'])) + + return resolved_data + def __getattr__(self, name: str) -> Any: if name == 'MODULES': return self.__dict__['MODULES'] diff --git a/sijapi/routers/email.py b/sijapi/routers/email.py index a3d1f7b..200c33d 100644 --- a/sijapi/routers/email.py +++ b/sijapi/routers/email.py @@ -373,7 +373,6 @@ async def process_all_accounts(): autoresponding_tasks = [asyncio.create_task(process_account_autoresponding(account)) for account in email_accounts] await asyncio.gather(*summarization_tasks, *autoresponding_tasks) - @email.on_event("startup") async def startup_event(): await asyncio.sleep(5)