使用 qwen 进行语音识别,加入 tag

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-29 20:10:08 +08:00
co-authored by Copilot
parent 040273586b
commit 206a561ee7
26 changed files with 3720 additions and 443 deletions
@@ -1,6 +1,6 @@
"use client";
import { X, Copy, CheckCheck, Check } from "lucide-react";
import { Check, CheckCheck, Copy, X } from "lucide-react";
import { useState } from "react";
import type { VideoTranscript } from "../types";
@@ -38,18 +38,23 @@ export function TranscriptPanel({
if (!transcript?.speech_detected || !transcript.transcript?.length) {
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm"
onClick={onClose}
>
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm">
<button
type="button"
aria-label="关闭"
className="absolute inset-0 h-full w-full cursor-default"
onClick={onClose}
/>
<div
className="relative w-full max-w-2xl max-h-[80vh] m-4 bg-zinc-900/95 backdrop-blur-xl border border-white/10 rounded-2xl shadow-2xl"
onClick={(e) => e.stopPropagation()}
role="dialog"
aria-modal="true"
className="relative z-10 w-full max-w-2xl max-h-[80vh] m-4 bg-zinc-900/95 backdrop-blur-xl border border-white/10 rounded-2xl shadow-2xl"
>
{/* 头部 */}
<div className="flex items-center justify-between p-4 border-b border-white/10">
<h2 className="text-lg font-semibold text-white">语音转录</h2>
<button
type="button"
onClick={onClose}
className="p-2 rounded-full hover:bg-white/10 transition-colors"
aria-label="关闭"
@@ -68,13 +73,17 @@ export function TranscriptPanel({
}
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm"
onClick={onClose}
>
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm">
<button
type="button"
aria-label="关闭"
className="absolute inset-0 h-full w-full cursor-default"
onClick={onClose}
/>
<div
className="relative w-full max-w-2xl max-h-[80vh] m-4 bg-zinc-900/95 backdrop-blur-xl border border-white/10 rounded-2xl shadow-2xl flex flex-col"
onClick={(e) => e.stopPropagation()}
role="dialog"
aria-modal="true"
className="relative z-10 w-full max-w-2xl max-h-[80vh] m-4 bg-zinc-900/95 backdrop-blur-xl border border-white/10 rounded-2xl shadow-2xl flex flex-col"
>
{/* 头部 */}
<div className="flex items-center justify-between p-4 border-b border-white/10 flex-shrink-0">
@@ -85,9 +94,22 @@ export function TranscriptPanel({
语言: {transcript.language}
</p>
)}
{transcript.content_tags?.length > 0 && (
<div className="mt-2 flex flex-wrap gap-1.5">
{transcript.content_tags.map((tag) => (
<span
key={tag}
className="rounded bg-blue-500/15 px-2 py-0.5 text-xs text-blue-200"
>
{tag}
</span>
))}
</div>
)}
</div>
<div className="flex items-center gap-2">
<button
type="button"
onClick={handleCopyAll}
className="flex items-center gap-2 px-3 py-2 text-sm bg-blue-600/20 text-blue-300 rounded-lg hover:bg-blue-600/30 transition-colors"
>
@@ -104,6 +126,7 @@ export function TranscriptPanel({
)}
</button>
<button
type="button"
onClick={onClose}
className="p-2 rounded-full hover:bg-white/10 transition-colors"
aria-label="关闭"
@@ -117,9 +140,8 @@ export function TranscriptPanel({
<div className="flex-1 overflow-y-auto p-4 space-y-2">
{transcript.transcript.map((text, index) => (
<div
key={index}
className="group bg-white/5 rounded-lg p-3 hover:bg-white/10 transition-colors cursor-pointer"
onClick={() => handleCopy(text, index)}
key={`${index}-${text}`}
className="group bg-white/5 rounded-lg p-3 hover:bg-white/10 transition-colors"
>
<div className="flex items-start justify-between gap-3">
<div className="flex-1 min-w-0">
@@ -133,8 +155,9 @@ export function TranscriptPanel({
</p>
</div>
<button
type="button"
onClick={() => handleCopy(text, index)}
className="flex-shrink-0 p-2 rounded-lg opacity-0 group-hover:opacity-100 hover:bg-white/10 transition-all"
className="flex-shrink-0 p-2 rounded-lg opacity-0 group-hover:opacity-100 focus:opacity-100 hover:bg-white/10 transition-all"
aria-label="复制"
>
{copiedIndex === index ? (