/
mikopbx
/
ModulePhraseStudio
Обзор
Документация
Войти
/
mikopbx
/
ModulePhraseStudio
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
Models/PhraseStudioVoices.php
140 строк
4 KB
Nikolay Beketov
feat: async voice install + UI status polling
05 май 2026, 06:32
05 май 2026, 06:32
8b826c8
Код
Авторство
О чём код?
<?php declare(strict_types=1); /* * MikoPBX - free phone system for small business * Copyright © 2017-2026 Alexey Portnov and Nikolay Beketov */ namespace Modules\ModulePhraseStudio\Models; use MikoPBX\Modules\Models\ModulesModelsBase; /** * Inventory of voice models that have been downloaded onto this PBX. * * One row per (voice_id, quality) pair. The catalogue of *available* voices * is built statically by Lib/Engines/PiperVoicesCatalog.php — this table * only tracks what the user has actually installed locally. * * @package Modules\ModulePhraseStudio\Models */ class PhraseStudioVoices extends ModulesModelsBase { /** * @Primary * @Identity * @Column(type="integer", nullable=false) */ public $id; /** * Piper voice identifier in the form "{lang}_{LOCALE}-{name}-{quality}". * Example: "ru_RU-irina-medium", "en_US-amy-low". * * @Column(type="string", nullable=false) */ public ?string $voice_id = ''; /** * Language tag (e.g. "ru-ru", "en-us"). * * @Column(type="string", nullable=true) */ public ?string $language = ''; /** * Human-readable voice name (e.g. "Irina", "Amy"). * * @Column(type="string", nullable=true) */ public ?string $voice_name = ''; /** * Quality label: "x_low" | "low" | "medium" | "high". * * @Column(type="string", nullable=true) */ public ?string $quality = ''; /** * Absolute path to the .onnx model file on the PBX filesystem. * * @Column(type="string", nullable=true) */ public ?string $model_path = ''; /** * Absolute path to the matching .onnx.json config file. * * @Column(type="string", nullable=true) */ public ?string $config_path = ''; /** * Total size on disk in bytes (model + config). * * @Column(type="integer", default="0", nullable=true) */ public ?string $size_bytes = '0'; /** * Native sample rate of the model in Hz (e.g. "22050", "16000"). * * @Column(type="integer", default="22050", nullable=true) */ public ?string $sample_rate = '22050'; /** * Unix timestamp of when the model finished downloading. * * @Column(type="integer", default="0", nullable=true) */ public ?string $installed_at = '0'; /** * Lifecycle of the voice install job: * '' — legacy row from before async installs (treat as installed) * 'installing' — worker is downloading the .onnx files right now * 'installed' — files on disk and verified * 'failed' — last install attempt errored; see install_error * * Decoupled from `installed_at` so the UI can poll for completion * without ambiguity ("installed_at=0" used to be both "in progress" * and "no row at all" depending on whether the row existed yet). * * @Column(type="string", nullable=true) */ public ?string $install_status = ''; /** * Last install-failure message, surfaced to the UI in the voices * table so the user knows why the download failed (network error, * 404 from the voice repo, etc.). Cleared on the next successful * install attempt. * * @Column(type="string", nullable=true) */ public ?string $install_error = ''; /** * Unix timestamp of when the current install attempt was queued. * Used by the UI's polling loop to detect stalled installs (worker * killed / OOM) and offer a retry instead of spinning forever. * * @Column(type="integer", default="0", nullable=true) */ public ?string $install_started_at = '0'; public static function getDynamicRelations(&$calledModelObject): void { // No cross-model relations. } public function initialize(): void { $this->setSource('m_ModulePhraseStudio_Voices'); parent::initialize(); } }