feat: initial project scaffold

pyproject.toml (Python 3.12, uv), codex/ package (config, db, models),
infra/ (docker-compose + schema), .env.example, .gitignore, README.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-06-04 11:19:10 +02:00
commit e7ac7766a5
13 changed files with 2136 additions and 0 deletions

85
codex/config.py Normal file
View File

@@ -0,0 +1,85 @@
"""Application configuration via environment variables / .env file.
All settings are read from the environment (or a .env file in the project
root). Import :func:`get_settings` wherever you need configuration; the
returned object is cached after the first call.
"""
from __future__ import annotations
from functools import lru_cache
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
"""Centralised, env-driven configuration for the codex application."""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore",
)
# ------------------------------------------------------------------
# Database
# ------------------------------------------------------------------
database_url: str = Field(
default="postgresql://researcher:change_me@localhost:5432/papers",
description=(
"libpq-compatible connection string consumed by psycopg. "
"Example: postgresql://user:pass@host:5432/dbname"
),
)
# ------------------------------------------------------------------
# External services
# ------------------------------------------------------------------
grobid_url: str = Field(
default="http://localhost:8070",
description="Base URL of the GROBID HTTP API (containerised).",
)
ollama_base_url: str = Field(
default="http://localhost:11434",
description="Base URL of the local Ollama endpoint (optional Q&A layer).",
)
# ------------------------------------------------------------------
# Embeddings
# ------------------------------------------------------------------
embedding_model: str = Field(
default="BAAI/bge-m3",
description=(
"sentence-transformers model identifier. "
"Must match EMBEDDING_DIM. Default: BAAI/bge-m3 (1024 dims)."
),
)
embedding_dim: int = Field(
default=1024,
gt=0,
description=(
"Dimension of the dense embedding vectors. "
"Must match the output dimension of EMBEDDING_MODEL."
),
)
# ------------------------------------------------------------------
# API etiquette
# ------------------------------------------------------------------
openalex_mailto: str = Field(
default="",
description=(
"E-mail address for the OpenAlex Polite Pool (faster rate limits). "
"Required by OpenAlex ToS for automated access."
),
)
@lru_cache(maxsize=1)
def get_settings() -> Settings:
"""Return the cached application settings singleton."""
return Settings()