This commit is contained in:
2026-02-03 10:20:43 +03:00
parent 007d700a8e
commit 011f7be20f
4 changed files with 225 additions and 24 deletions

View File

@@ -61,6 +61,7 @@ class Recording:
user_id: int # dataset_speaker_id
scenario_id: str
replica_index: int
duration: float # длительность в секундах
created_at: datetime
@@ -120,6 +121,7 @@ def init_db() -> None:
user_id INTEGER NOT NULL,
scenario_id TEXT NOT NULL,
replica_index INTEGER NOT NULL,
duration REAL DEFAULT 0.0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (scenario_id) REFERENCES scenarios(id),
@@ -147,6 +149,14 @@ def init_db() -> None:
CREATE INDEX IF NOT EXISTS idx_recordings_scenario
ON recordings(scenario_id);
""")
# Миграция: добавляем колонку duration если её нет
cursor = conn.execute("PRAGMA table_info(recordings)")
columns = [row[1] for row in cursor.fetchall()]
if "duration" not in columns:
conn.execute("ALTER TABLE recordings ADD COLUMN duration REAL DEFAULT 0.0")
logger.info("Добавлена колонка duration в таблицу recordings")
conn.commit()
logger.info("База данных инициализирована")
@@ -317,9 +327,9 @@ def create_recording(user_id: int, scenario_id: str, replica_index: int) -> Reco
"""Создаёт запись об озвучке реплики."""
with get_connection() as conn:
cursor = conn.execute(
"INSERT INTO recordings (user_id, scenario_id, replica_index) "
"VALUES (?, ?, ?) "
"RETURNING id, user_id, scenario_id, replica_index, created_at",
"INSERT INTO recordings (user_id, scenario_id, replica_index, duration) "
"VALUES (?, ?, ?, 0.0) "
"RETURNING id, user_id, scenario_id, replica_index, duration, created_at",
(user_id, scenario_id, replica_index),
)
row = cursor.fetchone()
@@ -329,22 +339,25 @@ def create_recording(user_id: int, scenario_id: str, replica_index: int) -> Reco
user_id=row["user_id"],
scenario_id=row["scenario_id"],
replica_index=row["replica_index"],
duration=row["duration"],
created_at=row["created_at"],
)
def upsert_recording(user_id: int, scenario_id: str, replica_index: int) -> Recording:
def upsert_recording(
user_id: int, scenario_id: str, replica_index: int, duration: float
) -> Recording:
"""Создаёт или обновляет запись об озвучке реплики."""
with get_connection() as conn:
cursor = conn.execute(
"""
INSERT INTO recordings (user_id, scenario_id, replica_index)
VALUES (?, ?, ?)
INSERT INTO recordings (user_id, scenario_id, replica_index, duration)
VALUES (?, ?, ?, ?)
ON CONFLICT(user_id, scenario_id, replica_index)
DO UPDATE SET created_at = CURRENT_TIMESTAMP
RETURNING id, user_id, scenario_id, replica_index, created_at
DO UPDATE SET created_at = CURRENT_TIMESTAMP, duration = excluded.duration
RETURNING id, user_id, scenario_id, replica_index, duration, created_at
""",
(user_id, scenario_id, replica_index),
(user_id, scenario_id, replica_index, duration),
)
row = cursor.fetchone()
conn.commit()
@@ -353,6 +366,7 @@ def upsert_recording(user_id: int, scenario_id: str, replica_index: int) -> Reco
user_id=row["user_id"],
scenario_id=row["scenario_id"],
replica_index=row["replica_index"],
duration=row["duration"],
created_at=row["created_at"],
)
@@ -361,7 +375,7 @@ def get_user_recordings_for_scenario(user_id: int, scenario_id: str) -> list[Rec
"""Получает все записи пользователя для сценария."""
with get_connection() as conn:
cursor = conn.execute(
"SELECT id, user_id, scenario_id, replica_index, created_at "
"SELECT id, user_id, scenario_id, replica_index, duration, created_at "
"FROM recordings WHERE user_id = ? AND scenario_id = ? "
"ORDER BY replica_index",
(user_id, scenario_id),
@@ -372,6 +386,7 @@ def get_user_recordings_for_scenario(user_id: int, scenario_id: str) -> list[Rec
user_id=row["user_id"],
scenario_id=row["scenario_id"],
replica_index=row["replica_index"],
duration=row["duration"],
created_at=row["created_at"],
)
for row in cursor.fetchall()
@@ -501,6 +516,32 @@ def get_stats() -> dict:
)
""").fetchone()[0]
# Количество полностью озвученных сценариев (все дорожки сценария озвучены)
stats["completed_scenarios"] = conn.execute("""
SELECT COUNT(*) FROM scenarios s
WHERE (
SELECT COUNT(DISTINCT speaker_id) FROM replicas WHERE scenario_id = s.id
) = (
SELECT COUNT(DISTINCT speaker_id) FROM (
SELECT r.scenario_id, rep.speaker_id, COUNT(*) as cnt
FROM recordings r
JOIN replicas rep ON r.scenario_id = rep.scenario_id
AND r.replica_index = rep.replica_index
WHERE r.scenario_id = s.id
GROUP BY r.scenario_id, rep.speaker_id
HAVING cnt = (
SELECT COUNT(*) FROM replicas rp
WHERE rp.scenario_id = r.scenario_id
AND rp.speaker_id = rep.speaker_id
)
) AS completed
)
""").fetchone()[0]
# Общая длительность всех записей в секундах
result = conn.execute("SELECT SUM(duration) FROM recordings").fetchone()[0]
stats["total_duration"] = result if result else 0.0
return stats
@@ -551,3 +592,51 @@ def delete_scenario_data(scenario_id: str) -> None:
conn.execute("DELETE FROM scenarios WHERE id = ?", (scenario_id,))
conn.commit()
logger.info(f"Deleted scenario {scenario_id} from database")
def get_user_stats(user_id: int) -> dict:
"""Получает статистику пользователя."""
with get_connection() as conn:
stats = {}
# Количество озвученных реплик
stats["total_replicas"] = conn.execute(
"SELECT COUNT(*) FROM recordings WHERE user_id = ?", (user_id,)
).fetchone()[0]
# Количество уникальных сценариев
stats["total_scenarios"] = conn.execute(
"SELECT COUNT(DISTINCT scenario_id) FROM recordings WHERE user_id = ?",
(user_id,),
).fetchone()[0]
# Количество полностью озвученных дорожек
stats["completed_tracks"] = conn.execute(
"""
SELECT COUNT(*) FROM (
SELECT r.scenario_id, rep.speaker_id, COUNT(*) as cnt
FROM recordings r
JOIN replicas rep ON r.scenario_id = rep.scenario_id
AND r.replica_index = rep.replica_index
WHERE r.user_id = ?
GROUP BY r.scenario_id, rep.speaker_id
HAVING cnt = (
SELECT COUNT(*) FROM replicas rp
WHERE rp.scenario_id = r.scenario_id
AND rp.speaker_id = rep.speaker_id
)
)
""",
(user_id,),
).fetchone()[0]
return stats
def get_user_audio_duration(user_id: int) -> float:
"""Получает общую длительность аудиозаписей пользователя в секундах."""
with get_connection() as conn:
result = conn.execute(
"SELECT SUM(duration) FROM recordings WHERE user_id = ?", (user_id,)
).fetchone()[0]
return result if result else 0.0