feat(sync): 长语音音频本地化(voice_clip media_hash+download+local-first playback)
Mirror download_call_recordings pattern for voice_clips:
- VoiceClip.media_hash column + Alembic migration (c4d5e6f7a8b9)
- VoiceClipOut.media_hash + frontend VoiceClip.media_hash type
- download_voice_clip_audio in app/scraper/media.py (resilient, sha256-dedup,
same download_url/upsert_media helpers as call recordings)
- sync_voice_clip_audio orchestrator wrapper (commits own SyncRun, mirrors
sync_call_recordings semantics)
- scheduler: _run_voice_clip_audio + ENTITY_FUNCS['voice_clip_audio'] +
appended to daily _run_all job (after voice_clips)
- VoiceClipModal playClip local-first: /api/media/{media_hash} with OSS
oss_file_name fallback (mirrors CallList.playRecord)
Tested: 376 pytest pass; vue-tsc clean; migration applied; 1523/1533 clips
localized (10 pending are genuine upstream HTTP 404s — resilient skip).
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,8 @@ import { formatCallDuration, formatTime } from '@/utils/format'
|
||||
* 关联到 customer.friend_id,不回写云客。matched_friend_name 由后端在 GET 时
|
||||
* 经 Customer join 解析(remark > nickname > real_name > friend_id)。
|
||||
*
|
||||
* 录音播放仍用 `oss_file_name` 的 OSS 直链(已知全本地妥协,随 ASR 一起修)。
|
||||
* 录音播放采用 local-first:优先 `/api/media/{media_hash}`(本地化音频),
|
||||
* 回退到 `oss_file_name` 的 OSS 直链(mirrors CallList.playRecord)。
|
||||
*/
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -146,7 +147,10 @@ const displayItems = computed(() =>
|
||||
)
|
||||
|
||||
function playClip(row: VoiceClip): void {
|
||||
const url = row.oss_file_name
|
||||
// Local-first: 优先本地化的 /api/media/{media_hash},回退到 OSS 直链
|
||||
// (mirrors CallList.playRecord)。
|
||||
const local = row.media_hash ? `/api/media/${row.media_hash}` : null
|
||||
const url = local ?? row.oss_file_name
|
||||
if (!url) {
|
||||
ElMessage.info('该片段无录音文件')
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user