Files
LLM-infa/api/db/connection.py
jze9 e87f6cd215 Фоновые задачи: плейлисты, длинные лекции, вкладка настроек
- таблица jobs + очередь с воркером: POST /jobs сразу отвечает, элементы
  плейлиста обрабатываются последовательно, есть отмена и живой прогресс
  (скачивание %, минуты распознанного Vosk-аудио)
- expand_url: плейлист раскрывается в список видео
- keep_video=false теперь качает только аудио (для 4-5ч лекций)
- настройки (LLM-ключ, модель, длина выжимки, хранение видео, путь Vosk)
  хранятся в Postgres: переживают перезапуск и перезагрузку страницы
- длина выжимки прокидывается в LLM-промпт ({n} предложений)
- UI: вкладки «Главная»/«Настройки», карточка задач с автообновлением
  каждые 3 сек, прогресс-бар, отмена, библиотека обновляется по мере
  готовности элементов

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 15:01:11 +05:00

77 lines
2.7 KiB
Python

import asyncio
import logging
import asyncpg
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker
from api.config import settings
from api.models.base import Base
import api.models.job # noqa: F401 - register model with Base.metadata
import api.models.section # noqa: F401 - register model with Base.metadata
import api.models.setting # noqa: F401 - register model with Base.metadata
import api.models.video # noqa: F401 - register model with Base.metadata
logger = logging.getLogger("db")
engine = create_async_engine(settings.database_url, echo=False, future=True)
SessionLocal = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession)
async def wait_for_postgres(retries: int = 30, delay: float = 1.0) -> None:
"""Wait for the postgres server to accept connections (using the default 'postgres' db)."""
last_exc: Exception | None = None
for attempt in range(1, retries + 1):
try:
conn = await asyncpg.connect(
user=settings.DB_USER,
password=settings.DB_PASS,
database="postgres",
host=settings.DB_HOST,
port=int(settings.DB_PORT),
)
await conn.close()
return
except Exception as e:
last_exc = e
wait = min(delay * (2 ** (attempt - 1)), 5)
logger.info("Waiting for postgres (attempt %s/%s): %s", attempt, retries, e)
await asyncio.sleep(wait)
raise RuntimeError(f"Could not connect to postgres after {retries} attempts") from last_exc
async def _create_database_if_missing() -> None:
admin = await asyncpg.connect(
user=settings.DB_USER,
password=settings.DB_PASS,
database="postgres",
host=settings.DB_HOST,
port=int(settings.DB_PORT),
)
try:
exists = await admin.fetchval(
"SELECT 1 FROM pg_database WHERE datname=$1", settings.DB_NAME
)
if not exists:
await admin.execute(f'CREATE DATABASE "{settings.DB_NAME}"')
finally:
await admin.close()
async def init_db() -> None:
await _create_database_if_missing()
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
# create_all не добавляет колонки в уже существующие таблицы
await conn.execute(
text(
"ALTER TABLE videos ADD COLUMN IF NOT EXISTS section_id INTEGER "
"REFERENCES sections(id) ON DELETE SET NULL"
)
)
await conn.execute(
text("ALTER TABLE videos ADD COLUMN IF NOT EXISTS job_id VARCHAR")
)