Разделы, фильтры и просмотр текстов в UI; опция «не хранить видео»
- таблица sections (дерево через parent_id), у видео section_id
- API: CRUD /sections, фильтры /videos (поиск, раздел с потомками, метод),
GET /videos/{id}/text, PATCH раздела, DELETE вместе с файлами
- pipeline: keep_video=false удаляет mp4 после расшифровки, section_id
- UI: панель разделов с вложенностью и счётчиками, поиск, фильтр по методу,
диалоги полного текста/выжимки, привязка к разделу, удаление,
переключатель «Сохранять видео на диске»
- compose: bind-mount ./web для правок без пересборки
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,11 +13,13 @@ async def create_video(
|
||||
text_full_path: str,
|
||||
text_summary_path: str,
|
||||
transcription_method: str,
|
||||
section_id: int | None = None,
|
||||
) -> Video:
|
||||
async with SessionLocal() as session:
|
||||
v = Video(
|
||||
uuid=uuid,
|
||||
source_url=source_url,
|
||||
section_id=section_id,
|
||||
title=title or "",
|
||||
video_path=video_path or "",
|
||||
text_full_path=text_full_path or "",
|
||||
@@ -36,12 +38,39 @@ async def get_video(video_uuid: str) -> Video | None:
|
||||
return res.scalars().first()
|
||||
|
||||
|
||||
async def list_videos() -> list[Video]:
|
||||
async def list_videos(
|
||||
*,
|
||||
q: str | None = None,
|
||||
section_ids: list[int] | None = None,
|
||||
method: str | None = None,
|
||||
) -> list[Video]:
|
||||
"""Каталог с фильтрами: поиск по названию/URL, разделы (уже с потомками), метод."""
|
||||
stmt = select(Video)
|
||||
if q:
|
||||
pattern = f"%{q}%"
|
||||
stmt = stmt.where(Video.title.ilike(pattern) | Video.source_url.ilike(pattern))
|
||||
if section_ids is not None:
|
||||
stmt = stmt.where(Video.section_id.in_(section_ids))
|
||||
if method:
|
||||
stmt = stmt.where(Video.transcription_method.ilike(f"{method}%"))
|
||||
stmt = stmt.order_by(Video.created_at.desc())
|
||||
async with SessionLocal() as session:
|
||||
res = await session.execute(select(Video).order_by(Video.created_at.desc()))
|
||||
res = await session.execute(stmt)
|
||||
return list(res.scalars().all())
|
||||
|
||||
|
||||
async def set_video_section(video_uuid: str, section_id: int | None) -> Video | None:
|
||||
async with SessionLocal() as session:
|
||||
res = await session.execute(select(Video).where(Video.uuid == video_uuid))
|
||||
v = res.scalars().first()
|
||||
if not v:
|
||||
return None
|
||||
v.section_id = section_id
|
||||
await session.commit()
|
||||
await session.refresh(v)
|
||||
return v
|
||||
|
||||
|
||||
async def delete_video(video_uuid: str) -> bool:
|
||||
async with SessionLocal() as session:
|
||||
res = await session.execute(select(Video).where(Video.uuid == video_uuid))
|
||||
|
||||
Reference in New Issue
Block a user