Рабочий пайплайн: YouTube -> транскрипция -> выжимка -> Postgres

- новый api/: /pipeline/process (yt-dlp, субтитры или Vosk, LLM/экстрактивная
  суммаризация), /videos, /llm; старый код перенесён в api_legacy/
- web/: Flet UI (flet 0.28.3 + flet-web, порт 8550)
- Dockerfile.api: ffmpeg слоем из mwader/static-ffmpeg, pip с кэш-маунтом
- requirements/pyproject: убраны moviepy, imageio-ffmpeg, битый asyncio
- README с инструкцией запуска и загрузкой Vosk-модели

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jze9
2026-07-14 11:12:46 +05:00
parent 564c9c2d2f
commit 2697e01714
51 changed files with 2313 additions and 284 deletions

View File

@@ -1,28 +1,38 @@
from pydantic_settings import BaseSettings
import os
from pydantic_settings import BaseSettings
def _env(*names, default=None):
for n in names:
v = os.getenv(n)
if v:
return v
return default
class Settings(BaseSettings):
# support both custom DB_* names and common POSTGRES_* names from postgres images
DB_USER: str = _env("DB_USER", "POSTGRES_USER", default="postgres")
DB_PASS: str = _env("DB_PASS", "POSTGRES_PASSWORD", default="postgres")
DB_NAME: str = _env("DB_NAME", "POSTGRES_DB", default="test_db")
DB_HOST: str = _env("DB_HOST", "POSTGRES_HOST", "DB_HOST", default="db")
DB_PORT: str = _env("DB_PORT", "POSTGRES_PORT", default="5432")
DB_USER: str = os.getenv("DB_USER", "postgres")
DB_PASS: str = os.getenv("DB_PASS", "postgres")
DB_NAME: str = os.getenv("DB_NAME", "test_db")
DB_HOST: str = os.getenv("DB_HOST", "db")
DB_PORT: str = os.getenv("DB_PORT", "5432")
# If explicit DB_* variables are provided, build DATABASE_URL from them (priority).
# Otherwise fall back to explicit DATABASE_URL or DATABASE_URL_ASYNC env.
_built_db_url: str | None = None
if DB_USER and DB_PASS and DB_NAME and DB_HOST and DB_PORT:
_built_db_url = f"postgresql+asyncpg://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
DEFAULT_VOSK_MODEL: str = os.getenv(
"DEFAULT_VOSK_MODEL", "models/vosk-model-small-ru-0.22"
)
SUBTITLE_LANGS: str = os.getenv("SUBTITLE_LANGS", "ru,en")
DATABASE_URL: str = _built_db_url or _env("DATABASE_URL", "DATABASE_URL_ASYNC", default="")
# External LLM (OpenAI-compatible). The LLM itself is NOT hosted in this container —
# point at any provider/proxy/local server that speaks /v1/chat/completions.
LLM_BASE_URL: str = os.getenv("LLM_BASE_URL", "")
LLM_API_KEY: str = os.getenv("LLM_API_KEY", "")
LLM_MODEL: str = os.getenv("LLM_MODEL", "")
LLM_TIMEOUT: int = int(os.getenv("LLM_TIMEOUT", "120"))
LLM_MAX_TOKENS: int = int(os.getenv("LLM_MAX_TOKENS", "1000"))
LLM_TEMPERATURE: float = float(os.getenv("LLM_TEMPERATURE", "0.3"))
@property
def database_url(self) -> str:
return (
f"postgresql+asyncpg://{self.DB_USER}:{self.DB_PASS}"
f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
)
@property
def subtitle_langs_list(self) -> list[str]:
return [x.strip() for x in self.SUBTITLE_LANGS.split(",") if x.strip()]
settings = Settings()