feat: Phase 3 AI Radio (DJ Host & interleaved playlist) and Like/Dislike/Delete actions

- Add Like button: promotes wave track to permanent library and refills buffer
- Add Dislike button: blacklists track in SQLite disliked_tracks, removes audio, refills buffer
- Add Delete button in history table for library file removal
- Add AI Radio module: wttr.in weather, Qwen 2.5 host monologues, speech synthesis, ID3 tags
- Generate interleaved 'AI Радио.m3u8' alongside clean 'Моя Волна.m3u8'
- Update Web UI with Radio DJ card, voice selection, and track actions
This commit is contained in:
Antigravity committed 2026-10-12 16:34:46 +03:00
1 parent 3db9bdb38b
commit e5afeb06cc
15 files changed
+945 -8

No files matched your search

+51 -1
View File
@@ -143,6 +143,55 @@
</div>
</section>
<!-- AI Radio Card (Phase 3) -->
<section class="card radio-card">
<div class="radio-header">
<div class="radio-header-title">
<h2>🎙️ AI Радио <span class="badge badge-radio">AI DJ Эфир</span> <span class="badge badge-llm">🤖 Qwen 2.5 + Edge-TTS</span></h2>
<p class="radio-subtitle">
Персональный радиоэфир: AI-ведущий объявляет погоду, время суток и делает динамичные подводки перед песнями в отдельном плейлисте «AI Радио».
</p>
</div>
<div class="radio-controls">
<button id="radioGenerateBtn" class="btn btn-primary" style="background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);">🎙️ Сгенерировать радиоэфир</button>
</div>
</div>
<!-- Radio Host Voice & Context Row -->
<div class="radio-settings-row">
<div class="radio-voice-group">
<label for="radioVoiceSelect" class="radio-voice-label">Голос ведущего:</label>
<select id="radioVoiceSelect" class="radio-voice-select">
<option value="ru-RU-DmitryNeural" selected>🎙️ Дмитрий (Харизматичный)</option>
<option value="ru-RU-SvetlanaNeural">🎙️ Светлана (Мягкий)</option>
</select>
</div>
<div class="radio-status-badge-wrap">
<span id="radioStatusLabel" class="badge badge-context">Эфир готов к запуску</span>
</div>
</div>
<div class="radio-stats-row">
<div class="radio-stat">
<span class="radio-stat-label">Реплик ведущего:</span>
<strong id="radioClipsCountLabel">0 записей</strong>
</div>
<div class="radio-stat">
<span class="radio-stat-label">Эфирный плейлист:</span>
<strong><a href="https://music.qpid.pro" target="_blank">AI Радио.m3u8 ↗</a></strong>
</div>
<div class="radio-stat">
<span class="radio-stat-label">Чистая музыка (без ведущего):</span>
<strong><a href="https://music.qpid.pro" target="_blank">Моя Волна.nsp ↗</a></strong>
</div>
</div>
<div id="radioSegmentsContainer" class="radio-segments-container" style="margin-top: 1rem; display: none;">
<h3 style="font-size: 0.95rem; margin-bottom: 0.4rem;">📻 Реплики ведущего в текущем радиоэфире:</h3>
<div id="radioSegmentsList" class="radio-segments-list"></div>
</div>
</section>
<!-- Active Tasks -->
<section class="card tasks-card">
<h2>⚡ Очередь задач</h2>
@@ -163,11 +212,12 @@
<th>Трек</th>
<th>Альбом</th>
<th>Дата</th>
<th>Действия</th>
</tr>
</thead>
<tbody id="historyBody">
<tr>
<td colspan="5" class="empty-state">Пока нет загрузок</td>
<td colspan="6" class="empty-state">Пока нет загрузок</td>
</tr>
</tbody>
</table>