mirror of
https://github.com/Sosokker/plain-rag.git
synced 2025-12-18 14:34:05 +01:00
initial commit
This commit is contained in:
commit
9985ba430d
19
.env.example
Normal file
19
.env.example
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# API Configuration
|
||||||
|
API_PORT=8001
|
||||||
|
|
||||||
|
# security
|
||||||
|
SECRET_KEY=your-secret-key-here
|
||||||
|
|
||||||
|
# LLM
|
||||||
|
OPENAI_API_KEY=your-openai-key
|
||||||
|
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
DB_PORT=5432
|
||||||
|
POSTGRES_USER=user
|
||||||
|
POSTGRES_PASSWORD=password
|
||||||
|
POSTGRES_DB=mydatabase
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
ENVIRONMENT=production
|
||||||
|
DEBUG=False
|
||||||
108
.gitignore
vendored
Normal file
108
.gitignore
vendored
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
|
### Python template
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
|
||||||
|
.idea/*
|
||||||
84
.trae/rules/project_rules.md
Normal file
84
.trae/rules/project_rules.md
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
### 🛠️ Project Tech & Environment Rules
|
||||||
|
|
||||||
|
* **Python Version:** `3.12`
|
||||||
|
* **Dependency Management:** [`uv`](https://github.com/astral-sh/uv) (fast, deterministic, PEP 582-compatible)
|
||||||
|
* **Backend Framework:** [`FastAPI`](https://fastapi.tiangolo.com/)
|
||||||
|
* **ORM:** [`SQLAlchemy 2.x`](https://docs.sqlalchemy.org/en/20/)
|
||||||
|
* **Migrations:** [`Alembic`](https://alembic.sqlalchemy.org/)
|
||||||
|
* **Authentication:** [`fastapi-users`](https://fastapi-users.github.io/fastapi-users/latest/) + [`fastapi-jwt-auth`](https://indominusbyte.github.io/fastapi-jwt-auth/)
|
||||||
|
* **Rate Limiting:** [`fastapi-limiter`](https://github.com/long2ice/fastapi-limiter)
|
||||||
|
* **Caching:** [`fastapi-cache`](https://github.com/long2ice/fastapi-cache)
|
||||||
|
* **Email Service:** [`fastapi-mail`](https://github.com/sabuhish/fastapi-mail)
|
||||||
|
* **Pagination:** [`fastapi-pagination`](https://github.com/uriyyo/fastapi-pagination)
|
||||||
|
* **LLM Layer:** [`litellm`](https://github.com/BerriAI/litellm)
|
||||||
|
* **Embedding Models:** [`Hugging Face Transformers`](https://huggingface.co/models)
|
||||||
|
* **Vector Store:** `pgvector` with PostgreSQL
|
||||||
|
|
||||||
|
Use pure dataclasses between in-app layers (as a transport objects). Use pydantic to validate user (external) input like web APIs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🧑💻 Python & Backend Code Quality Rules
|
||||||
|
|
||||||
|
#### 📦 Structure & Conventions
|
||||||
|
|
||||||
|
* **Follow modern `SQLAlchemy 2.0` best practices** (use `async engine`, `DeclarativeBase`, `SessionLocal()` pattern).
|
||||||
|
* **Separate concerns clearly:**
|
||||||
|
|
||||||
|
* `models/`: SQLAlchemy models
|
||||||
|
* `schemas/`: Pydantic models
|
||||||
|
* `api/routes/`: FastAPI routers
|
||||||
|
* `services/`: Business logic
|
||||||
|
* `core/`: Settings, config, and utilities
|
||||||
|
* `tests/`: Test suite
|
||||||
|
|
||||||
|
#### 🧹 Clean Code Principles
|
||||||
|
|
||||||
|
1. **Use Meaningful Names:** Functions, classes, variables, and routes should clearly communicate their intent.
|
||||||
|
2. **Avoid Overengineering:** YAGNI (You Aren’t Gonna Need It) — keep your code minimal, testable, and readable.
|
||||||
|
3. **Follow PEP 8 + Black Formatting:** Auto-format with `ruff`, lint with `ruff` or `flake8`.
|
||||||
|
4. **Use Type Hints Everywhere:** Both function arguments and return types must use type annotations.
|
||||||
|
5. **Use Docstrings:**
|
||||||
|
|
||||||
|
* One-liner for simple functions.
|
||||||
|
* Full docstring for public APIs and complex logic.
|
||||||
|
6. **Write Isolated, Testable Logic:** Favor pure functions where possible, especially in `services/`.
|
||||||
|
7. **Handle Exceptions Gracefully:**
|
||||||
|
|
||||||
|
* Use `HTTPException` for expected FastAPI errors.
|
||||||
|
* Log unexpected errors using `structlog`.
|
||||||
|
8. **Use Dependency Injection:** Use `Depends()` for shared logic (e.g., current user, DB session, rate limiter).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🧪 Testing Rules
|
||||||
|
|
||||||
|
* Use `pytest` as your testing framework.
|
||||||
|
* Coverage should include:
|
||||||
|
|
||||||
|
* CRUD operations
|
||||||
|
* API endpoints
|
||||||
|
* Embedding & RAG pipeline logic
|
||||||
|
* Use `pytest-asyncio` for async route testing.
|
||||||
|
* Use fixtures for test data setup.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🔒 Security Practices
|
||||||
|
|
||||||
|
* Never store plaintext passwords — use hashing (`argon2`, `bcrypt` via `fastapi-users`).
|
||||||
|
* Sanitize file uploads & inputs — protect against injection.
|
||||||
|
* Use CORS middleware correctly (`allow_credentials`, `allow_methods`, etc.).
|
||||||
|
* Enable rate limiting on sensitive routes like login & upload.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🚀 Performance & Observability
|
||||||
|
|
||||||
|
* Add `structlog` structured logging to:
|
||||||
|
|
||||||
|
* API entry/exit points
|
||||||
|
* Query vector lookup latency
|
||||||
|
* LLM response times
|
||||||
|
* Cache results where appropriate (`fastapi-cache`) — especially static vector responses.
|
||||||
|
* Stream LLM responses via FastAPI's `StreamingResponse`.
|
||||||
88
.windsurf/rules/fastapi-style-guide.md
Normal file
88
.windsurf/rules/fastapi-style-guide.md
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
---
|
||||||
|
trigger: always_on
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🛠️ Project Tech & Environment Rules
|
||||||
|
|
||||||
|
* **Python Version:** `3.12`
|
||||||
|
* **Dependency Management:** [`uv`](https://github.com/astral-sh/uv) (fast, deterministic, PEP 582-compatible)
|
||||||
|
* **Backend Framework:** [`FastAPI`](https://fastapi.tiangolo.com/)
|
||||||
|
* **ORM:** [`SQLAlchemy 2.x`](https://docs.sqlalchemy.org/en/20/)
|
||||||
|
* **Migrations:** [`Alembic`](https://alembic.sqlalchemy.org/)
|
||||||
|
* **Authentication:** [`fastapi-users`](https://fastapi-users.github.io/fastapi-users/latest/) + [`fastapi-jwt-auth`](https://indominusbyte.github.io/fastapi-jwt-auth/)
|
||||||
|
* **Rate Limiting:** [`fastapi-limiter`](https://github.com/long2ice/fastapi-limiter)
|
||||||
|
* **Caching:** [`fastapi-cache`](https://github.com/long2ice/fastapi-cache)
|
||||||
|
* **Email Service:** [`fastapi-mail`](https://github.com/sabuhish/fastapi-mail)
|
||||||
|
* **Pagination:** [`fastapi-pagination`](https://github.com/uriyyo/fastapi-pagination)
|
||||||
|
* **LLM Layer:** [`litellm`](https://github.com/BerriAI/litellm)
|
||||||
|
* **Embedding Models:** [`Hugging Face Transformers`](https://huggingface.co/models)
|
||||||
|
* **Vector Store:** `pgvector` with PostgreSQL
|
||||||
|
|
||||||
|
Use pure dataclasses between in-app layers (as a transport objects). Use pydantic to validate user (external) input like web APIs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🧑💻 Python & Backend Code Quality Rules
|
||||||
|
|
||||||
|
#### 📦 Structure & Conventions
|
||||||
|
|
||||||
|
* **Follow modern `SQLAlchemy 2.0` best practices** (use `async engine`, `DeclarativeBase`, `SessionLocal()` pattern).
|
||||||
|
* **Separate concerns clearly:**
|
||||||
|
|
||||||
|
* `models/`: SQLAlchemy models
|
||||||
|
* `schemas/`: Pydantic models
|
||||||
|
* `api/routes/`: FastAPI routers
|
||||||
|
* `services/`: Business logic
|
||||||
|
* `core/`: Settings, config, and utilities
|
||||||
|
* `tests/`: Test suite
|
||||||
|
|
||||||
|
#### 🧹 Clean Code Principles
|
||||||
|
|
||||||
|
1. **Use Meaningful Names:** Functions, classes, variables, and routes should clearly communicate their intent.
|
||||||
|
2. **Avoid Overengineering:** YAGNI (You Aren’t Gonna Need It) — keep your code minimal, testable, and readable.
|
||||||
|
3. **Follow PEP 8 + Black Formatting:** Auto-format with `ruff`, lint with `ruff` or `flake8`.
|
||||||
|
4. **Use Type Hints Everywhere:** Both function arguments and return types must use type annotations.
|
||||||
|
5. **Use Docstrings:**
|
||||||
|
|
||||||
|
* One-liner for simple functions.
|
||||||
|
* Full docstring for public APIs and complex logic.
|
||||||
|
6. **Write Isolated, Testable Logic:** Favor pure functions where possible, especially in `services/`.
|
||||||
|
7. **Handle Exceptions Gracefully:**
|
||||||
|
|
||||||
|
* Use `HTTPException` for expected FastAPI errors.
|
||||||
|
* Log unexpected errors using `structlog`.
|
||||||
|
8. **Use Dependency Injection:** Use `Depends()` for shared logic (e.g., current user, DB session, rate limiter).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🧪 Testing Rules
|
||||||
|
|
||||||
|
* Use `pytest` as your testing framework.
|
||||||
|
* Coverage should include:
|
||||||
|
|
||||||
|
* CRUD operations
|
||||||
|
* API endpoints
|
||||||
|
* Embedding & RAG pipeline logic
|
||||||
|
* Use `pytest-asyncio` for async route testing.
|
||||||
|
* Use fixtures for test data setup.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🔒 Security Practices
|
||||||
|
|
||||||
|
* Never store plaintext passwords — use hashing (`argon2`, `bcrypt` via `fastapi-users`).
|
||||||
|
* Sanitize file uploads & inputs — protect against injection.
|
||||||
|
* Use CORS middleware correctly (`allow_credentials`, `allow_methods`, etc.).
|
||||||
|
* Enable rate limiting on sensitive routes like login & upload.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🚀 Performance & Observability
|
||||||
|
|
||||||
|
* Add `structlog` structured logging to:
|
||||||
|
|
||||||
|
* API entry/exit points
|
||||||
|
* Query vector lookup latency
|
||||||
|
* LLM response times
|
||||||
|
* Cache results where appropriate (`fastapi-cache`) — especially static vector responses.
|
||||||
|
* Stream LLM responses via FastAPI's `StreamingResponse`.
|
||||||
36
Dockerfile
Normal file
36
Dockerfile
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Start with the official Python 3.12 slim-buster image.
|
||||||
|
# slim-buster is a good choice for production as it's smaller.
|
||||||
|
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
|
||||||
|
|
||||||
|
# Install the project into `/app`
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Enable bytecode compilation
|
||||||
|
ENV UV_COMPILE_BYTECODE=1
|
||||||
|
|
||||||
|
# Copy from the cache instead of linking since it's a mounted volume
|
||||||
|
ENV UV_LINK_MODE=copy
|
||||||
|
|
||||||
|
# Install the project's dependencies using the lockfile and settings
|
||||||
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||||
|
--mount=type=bind,source=uv.lock,target=uv.lock \
|
||||||
|
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
|
||||||
|
uv sync --locked --no-install-project --no-dev
|
||||||
|
|
||||||
|
# Then, add the rest of the project source code and install it
|
||||||
|
# Installing separately from its dependencies allows optimal layer caching
|
||||||
|
COPY . /app
|
||||||
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||||
|
uv sync --locked --no-dev
|
||||||
|
|
||||||
|
# Place executables in the environment at the front of the path
|
||||||
|
ENV PATH="/app/.venv/Lib:$PATH"
|
||||||
|
|
||||||
|
# Reset the entrypoint, don't invoke `uv`
|
||||||
|
ENTRYPOINT []
|
||||||
|
|
||||||
|
# Command to run the application
|
||||||
|
# Use uvicorn to run the FastAPI application.
|
||||||
|
# --host 0.0.0.0 is required to make the app accessible from outside the container
|
||||||
|
# --port 8000 to match the exposed port
|
||||||
|
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
0
app/__init__.py
Normal file
0
app/__init__.py
Normal file
0
app/api/__init__.py
Normal file
0
app/api/__init__.py
Normal file
0
app/components/__init__.py
Normal file
0
app/components/__init__.py
Normal file
0
app/core/__init__.py
Normal file
0
app/core/__init__.py
Normal file
99
app/core/config.py
Normal file
99
app/core/config.py
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import os
|
||||||
|
import secrets
|
||||||
|
from functools import lru_cache
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from pydantic import AnyHttpUrl, PostgresDsn, field_validator, model_validator
|
||||||
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parent.parent.parent
|
||||||
|
ENV_FILE = ROOT / ".env"
|
||||||
|
|
||||||
|
|
||||||
|
class Settings(BaseSettings):
|
||||||
|
# Project
|
||||||
|
PROJECT_NAME: str = "Chat Hub"
|
||||||
|
VERSION: str = "0.1.0"
|
||||||
|
API_V1_STR: str = "/api/v1"
|
||||||
|
SECRET_KEY: str = secrets.token_urlsafe(32)
|
||||||
|
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8 # 8 days
|
||||||
|
|
||||||
|
# Security
|
||||||
|
ALGORITHM: str = "HS256"
|
||||||
|
|
||||||
|
# Backend Server
|
||||||
|
BACKEND_CORS_ORIGINS: list[str | AnyHttpUrl] = []
|
||||||
|
|
||||||
|
@field_validator("BACKEND_CORS_ORIGINS", mode="before")
|
||||||
|
def assemble_cors_origins(self, v: str | list[str]) -> list[str] | str:
|
||||||
|
if isinstance(v, str) and not v.startswith("["):
|
||||||
|
return [i.strip() for i in v.split(",")]
|
||||||
|
if isinstance(v, (list, str)):
|
||||||
|
return v
|
||||||
|
raise ValueError(v)
|
||||||
|
|
||||||
|
# Database
|
||||||
|
POSTGRES_SERVER: str = "localhost"
|
||||||
|
POSTGRES_USER: str = "postgres"
|
||||||
|
POSTGRES_PASSWORD: str = ""
|
||||||
|
POSTGRES_DB: str = "chat_hub"
|
||||||
|
POSTGRES_PORT: str = "5432"
|
||||||
|
DATABASE_URI: PostgresDsn | None = None
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def assemble_db_connection(self) -> "Settings":
|
||||||
|
if self.DATABASE_URI is None:
|
||||||
|
self.DATABASE_URI = PostgresDsn.build(
|
||||||
|
scheme="postgresql+asyncpg",
|
||||||
|
username=self.POSTGRES_USER,
|
||||||
|
password=self.POSTGRES_PASSWORD,
|
||||||
|
host=self.POSTGRES_SERVER,
|
||||||
|
port=int(self.POSTGRES_PORT),
|
||||||
|
path=f"/{self.POSTGRES_DB or ''}",
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
|
||||||
|
# LLM Configuration
|
||||||
|
OPENAI_API_KEY: str | None = None
|
||||||
|
ANTHROPIC_API_KEY: str | None = None
|
||||||
|
|
||||||
|
# Vector Store
|
||||||
|
VECTOR_STORE_TYPE: str = "pgvector" # or "chroma", "faiss", etc.
|
||||||
|
EMBEDDING_MODEL: str = "sentence-transformers/all-mpnet-base-v2"
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
LOG_LEVEL: str = "INFO"
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
ENVIRONMENT: str = "development"
|
||||||
|
DEBUG: bool = False
|
||||||
|
TESTING: bool = False
|
||||||
|
|
||||||
|
# Rate Limiting
|
||||||
|
RATE_LIMIT: str = "100/minute"
|
||||||
|
|
||||||
|
# Caching
|
||||||
|
CACHE_TTL: int = 300 # 5 minutes
|
||||||
|
|
||||||
|
model_config = SettingsConfigDict(
|
||||||
|
env_file=ENV_FILE,
|
||||||
|
env_file_encoding="utf-8",
|
||||||
|
case_sensitive=True,
|
||||||
|
extra="ignore",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def get_settings() -> Settings:
|
||||||
|
"""
|
||||||
|
Get cached settings instance.
|
||||||
|
This function uses lru_cache to prevent re-reading the environment on each call.
|
||||||
|
"""
|
||||||
|
return Settings()
|
||||||
|
|
||||||
|
|
||||||
|
# Create settings instance
|
||||||
|
settings = get_settings()
|
||||||
|
|
||||||
|
# Set environment variables for third-party libraries
|
||||||
|
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
||||||
0
app/core/enums.py
Normal file
0
app/core/enums.py
Normal file
0
app/core/interfaces.py
Normal file
0
app/core/interfaces.py
Normal file
83
app/main.py
Normal file
83
app/main.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import os
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
|
# Load environment variables
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# Application metadata
|
||||||
|
APP_NAME = "Chat Hub API"
|
||||||
|
API_VERSION = "0.1.0"
|
||||||
|
APP_DESCRIPTION = """
|
||||||
|
Chat Hub API - A modern chat application with AI capabilities.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# Application lifespan
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(app: FastAPI):
|
||||||
|
# Startup: Initialize resources
|
||||||
|
print("Starting application...")
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
# Shutdown: Clean up resources
|
||||||
|
print("Shutting down application...")
|
||||||
|
|
||||||
|
|
||||||
|
# Initialize FastAPI application
|
||||||
|
app = FastAPI(
|
||||||
|
title=APP_NAME,
|
||||||
|
description=APP_DESCRIPTION,
|
||||||
|
version=API_VERSION,
|
||||||
|
docs_url="/docs",
|
||||||
|
redoc_url="/redoc",
|
||||||
|
openapi_url="/openapi.json",
|
||||||
|
lifespan=lifespan,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Configure CORS
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=["*"], # In production, replace with specific origins
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Health check endpoint
|
||||||
|
@app.get("/health", response_model=dict[str, Any])
|
||||||
|
async def health_check() -> dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Health check endpoint to verify the API is running.
|
||||||
|
"""
|
||||||
|
return {"status": "healthy", "service": APP_NAME, "version": API_VERSION}
|
||||||
|
|
||||||
|
|
||||||
|
# Root endpoint
|
||||||
|
@app.get("/")
|
||||||
|
async def root():
|
||||||
|
"""
|
||||||
|
Root endpoint that provides basic information about the API.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"message": f"Welcome to {APP_NAME}",
|
||||||
|
"version": API_VERSION,
|
||||||
|
"docs": "/docs",
|
||||||
|
"health_check": "/health",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# This allows running the app with: uvicorn main:app --reload
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
|
||||||
|
port = int(os.getenv("API_PORT", 8001))
|
||||||
|
uvicorn.run(
|
||||||
|
"main:app", host="0.0.0.0", port=port, reload=True, reload_dirs=["./app"]
|
||||||
|
)
|
||||||
0
app/pipelines/__init__.py
Normal file
0
app/pipelines/__init__.py
Normal file
32
docker-compose.yml
Normal file
32
docker-compose.yml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
services:
|
||||||
|
api:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "${API_PORT:-8001}:8000"
|
||||||
|
volumes:
|
||||||
|
- ./app:/app
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: pgvector/pgvector:pg17
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=${POSTGRES_USER:-user}
|
||||||
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}
|
||||||
|
- POSTGRES_DB=${POSTGRES_DB:-mydatabase}
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- "${DB_PORT:-5432}:5432"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
14
pyproject.toml
Normal file
14
pyproject.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[project]
|
||||||
|
name = "chat-hub"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = [
|
||||||
|
"fastapi[standard]>=0.115.13",
|
||||||
|
"litellm>=1.73.0",
|
||||||
|
"pydantic-settings>=2.10.0",
|
||||||
|
"structlog>=25.4.0",
|
||||||
|
"transformers>=4.52.4",
|
||||||
|
"uvicorn>=0.34.3",
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue
Block a user