我用夸克网盘给你分享了「解锁网盘!SVIP会员到期2341年,百度网盘1080P高清画质+倍速播放+字幕功能,一键解锁」,点击链接或复制整段内容,打开「夸克APP」即可获取。 /~4ece3YzhkL~ 链接: https://pan.quark.cn/s/1122fd7ef0fb 提取码:ABwR 9 个帖子 - 7 位参与者 阅读完整话题
Python版本 """ 基于音节/字数精确分配时间 """ import re import tkinter as tk from tkinter import ttk, filedialog, messagebox, scrolledtext # ==================== 核心逻辑 ==================== def count_english_syllables(word): w = word.strip('.,;:!?"\'()[]{}').lower() if not w: return 0 vowels = set("aeiouy") count = 0 prev_is_vowel = False for ch in w: is_vowel = ch in vowels if is_vowel and not prev_is_vowel: count += 1 prev_is_vowel = is_vowel if w.endswith("e") and not w.endswith("le") and count > 1: count -= 1 if w.endswith("le") and len(w) > 2 and w[-3] not in vowels: count += 1 return max(count, 1) def count_pronunciation_units(text): total = 0 tokens = re.findall(r'[\u4e00-\u9fff]|[a-zA-Z]+|\d+%?|[^\s]', text) for token in tokens: if re.match(r'[\u4e00-\u9fff]', token): total += 1 elif re.match(r'[a-zA-Z]+', token): total += count_english_syllables(token) elif re.match(r'\d+%?', token): digits = token.replace('%', '') total += min(len(digits) + 1, 5) return total def split_sentences(text): parts = re.split(r'(?<=[.,;])\s+', text) return [p.strip() for p in parts if p.strip()] def ms_to_parts(ms): total_sec = ms / 1000 m = int(total_sec // 60) s = total_sec - m * 60 return m, s def fmt_lyrics3(ms): m, s = ms_to_parts(ms) return f"[{m:02d}:{s:05.2f}]" def fmt_srt(ms): m, s = ms_to_parts(ms) return f"{m:02d}:{s:05.2f}".replace(".", ",") def fmt_ass(ms): m, s = ms_to_parts(ms) h = m // 60 m = m % 60 return f"{h}:{m:02d}:{s:05.2f}" def fmt_vtt(ms): m, s = ms_to_parts(ms) return f"{m:02d}:{s:06.3f}" def generate_subtitles(text, total_seconds, fmt="lyrics3"): total_ms = float(total_seconds) * 1000 sentences = split_sentences(text) if not sentences: return "", 0 units_per_sentence = [count_pronunciation_units(s) for s in sentences] total_units = sum(units_per_sentence) if total_units == 0: return "", 0 ms_per_unit = total_ms / total_units timings = [] cur = 0.0 for i, s in enumerate(sentences): dur = units_per_sentence[i] * ms_per_unit timings.append((cur, cur + dur, s)) cur += dur formatters = {"lyrics3": fmt_lyrics3, "srt": fmt_srt, "ass": fmt_ass, "vtt": fmt_vtt} f = formatters.get(fmt, fmt_lyrics3) lines = [] if fmt == "vtt": lines.append("WEBVTT\n") elif fmt == "ass": lines.append("[Script Info]") lines.append("ScriptType: v4.00+") lines.append("PlayResX: 384") lines.append("PlayResY: 288\n") lines.append("[V4+ Styles]") lines.append("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding") lines.append("Style: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,10,10,10,1\n") lines.append("[Events]") lines.append("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text") for i, (start, end, sent) in enumerate(timings): if fmt == "srt": lines.append(str(i + 1)) lines.append(f"{f(start)} --> {f(end)}") lines.append(sent) lines.append("") elif fmt == "ass": lines.append(f"Dialogue: 0,{f(start)},{f(end)},Default,,0,0,0,,{sent}") elif fmt == "vtt": lines.append(f"{f(start)} --> {f(end)}") lines.append(sent) lines.append("") else: lines.append(f"{f(start)}{sent}") return "\n".join(lines), len(sentences) # ==================== GUI ==================== class SubtitleApp: def __init__(self, root): self.root = root self.root.title("字幕时间轴生成器") self.root.geometry("900x720") self.root.configure(bg="#1e1e2e") self.root.minsize(700, 550) # 样式 style = ttk.Style() style.theme_use("clam") style.configure("TFrame", background="#1e1e2e") style.configure("TLabel", background="#1e1e2e", foreground="#cdd6f4", font=("Segoe UI", 11)) style.configure("TButton", background="#45475a", foreground="#cdd6f4", font=("Segoe UI", 10), borderwidth=0, padding=8) style.map("TButton", background=[("active", "#585b70")]) style.configure("TEntry", fieldbackground="#313244", foreground="#cdd6f4", font=("Segoe UI", 11), padding=6) style.configure("TCombobox", fieldbackground="#313244", foreground="#cdd6f4", font=("Segoe UI", 11), padding=4) self.build_ui() def build_ui(self): # 主容器 main = ttk.Frame(self.root, padding=20) main.pack(fill="both", expand=True) # 标题 title = tk.Label(main, text="🎬 字幕时间轴生成器", font=("Segoe UI", 20, "bold"), bg="#1e1e2e", fg="#cba6f7") title.pack(pady=(0, 5)) subtitle = tk.Label(main, text="基于音节/字数精确分配时间 · 支持中英混合", font=("Segoe UI", 10), bg="#1e1e2e", fg="#6c7086") subtitle.pack(pady=(0, 20)) # 输入区域 input_frame = ttk.Frame(main) input_frame.pack(fill="both", expand=True) lbl_input = tk.Label(input_frame, text="📝 输入文本(按句号/逗号/分号自动分句)", font=("Segoe UI", 11, "bold"), bg="#1e1e2e", fg="#a6adc8") lbl_input.pack(anchor="w") self.text_input = scrolledtext.ScrolledText( input_frame, height=10, font=("Segoe UI", 11), bg="#313244", fg="#cdd6f4", insertbackground="#cdd6f4", relief="flat", borderwidth=0, padx=12, pady=12, wrap=tk.WORD, highlightthickness=1, highlightbackground="#45475a" ) self.text_input.pack(fill="both", expand=True, pady=(5, 15)) # 设置行 settings_frame = ttk.Frame(main) settings_frame.pack(fill="x", pady=(0, 15)) # 时长 dur_frame = ttk.Frame(settings_frame) dur_frame.pack(side="left", padx=(0, 30)) ttk.Label(dur_frame, text="⏱ 总时长(秒)").pack(side="left", padx=(0, 8)) self.duration_var = tk.StringVar(value="73") self.duration_entry = ttk.Entry(dur_frame, textvariable=self.duration_var, width=10) self.duration_entry.pack(side="left") # 格式 fmt_frame = ttk.Frame(settings_frame) fmt_frame.pack(side="left", padx=(0, 30)) ttk.Label(fmt_frame, text="📄 输出格式").pack(side="left", padx=(0, 8)) self.format_var = tk.StringVar(value="lyrics3") fmt_combo = ttk.Combobox(fmt_frame, textvariable=self.format_var, values=["lyrics3", "srt", "ass", "vtt"], state="readonly", width=10) fmt_combo.pack(side="left") # 统计 self.stats_var = tk.StringVar(value="分句: 0 句 | 总发音单位: 0") stats_label = tk.Label(settings_frame, textvariable=self.stats_var, font=("Segoe UI", 10), bg="#1e1e2e", fg="#6c7086") stats_label.pack(side="right") # 按钮 btn_frame = ttk.Frame(main) btn_frame.pack(fill="x", pady=(0, 15)) self.btn_generate = tk.Button( btn_frame, text="✨ 生成字幕", font=("Segoe UI", 12, "bold"), bg="#cba6f7", fg="#1e1e2e", activebackground="#b4befe", activeforeground="#1e1e2e", relief="flat", borderwidth=0, padx=24, pady=10, cursor="hand2", command=self.on_generate ) self.btn_generate.pack(side="left", padx=(0, 10)) self.btn_copy = tk.Button( btn_frame, text="📋 复制全部", font=("Segoe UI", 11), bg="#45475a", fg="#cdd6f4", activebackground="#585b70", activeforeground="#cdd6f4", relief="flat", borderwidth=0, padx=20, pady=10, cursor="hand2", command=self.on_copy ) self.btn_copy.pack(side="left", padx=(0, 10)) self.btn_save = tk.Button( btn_frame, text="💾 保存文件", font=("Segoe UI", 11), bg="#45475a", fg="#cdd6f4", activebackground="#585b70", activeforeground="#cdd6f4", relief="flat", borderwidth=0, padx=20, pady=10, cursor="hand2", command=self.on_save ) self.btn_save.pack(side="left") # 输出区域 output_frame = ttk.Frame(main) output_frame.pack(fill="both", expand=True) lbl_output = tk.Label(output_frame, text="📤 生成结果", font=("Segoe UI", 11, "bold"), bg="#1e1e2e", fg="#a6adc8") lbl_output.pack(anchor="w") self.text_output = scrolledtext.ScrolledText( output_frame, height=12, font=("Cascadia Code", 10), bg="#11111b", fg="#a6e3a1", insertbackground="#a6e3a1", relief="flat", borderwidth=0, padx=12, pady=12, wrap=tk.NONE, highlightthickness=1, highlightbackground="#45475a" ) self.text_output.pack(fill="both", expand=True, pady=(5, 0)) def on_generate(self): text = self.text_input.get("1.0", "end-1c").strip() if not text: messagebox.showwarning("提示", "请先输入文本。") return try: duration = float(self.duration_var.get()) if duration <= 0: raise ValueError except ValueError: messagebox.showwarning("提示", "请输入有效的正数时长(秒)。") return fmt = self.format_var.get() result, count = generate_subtitles(text, duration, fmt) self.text_output.delete("1.0", "end") if result: self.text_output.insert("1.0", result) total_units = sum(count_pronunciation_units(s) for s in split_sentences(text)) self.stats_var.set(f"分句: {count} 句 | 总发音单位: {total_units}") def on_copy(self): result = self.text_output.get("1.0", "end-1c").strip() if result: self.root.clipboard_clear() self.root.clipboard_append(result) messagebox.showinfo("提示", "已复制到剪贴板!") def on_save(self): result = self.text_output.get("1.0", "end-1c").strip() if not result: messagebox.showwarning("提示", "没有可保存的内容,请先生成字幕。") return fmt = self.format_var.get() exts = {"lyrics3": ".txt", "srt": ".srt", "ass": ".ass", "vtt": ".vtt"} ext = exts.get(fmt, ".txt") path = filedialog.asksaveasfilename( defaultextension=ext, filetypes=[(f"{fmt.upper()} 字幕", f"*{ext}"), ("所有文件", "*.*")] ) if path: with open(path, "w", encoding="utf-8") as f: f.write(result) messagebox.showinfo("提示", f"已保存到:{path}") if __name__ == "__main__": root = tk.Tk() app = SubtitleApp(root) root.mainloop() HTML版本 3 个帖子 - 3 位参与者 阅读完整话题
字幕类型的 AI 翻译软件有没有搞头?像是 qq 音乐的歌词那种界面,可以翻译系统音频中的外语显示在字幕上 10 个帖子 - 9 位参与者 阅读完整话题
视频去字幕 最近在做短剧相关内容,基本每天都会遇到这种情况:用 seedance 2.0 生成的视频虽然 prompt 里要求不要生成字幕,但实际生成结果里偶尔还是会带上字幕。 如果直接重新生成,一条视频往往要花十几块钱,每天来个六七条就得花掉近 100 块的成本 寻找解决方案 一开始我尝试找现成的视频去字幕工具。 实际体验下来发现几个比较常见的问题: 有些工具限制视频时长,只支持上传 1 分钟以内的视频; 有些工具不支持手动框选字幕区域,处理效果不稳定; 有些工具按次数或套餐收费,长视频处理成本比较高; 部分工具上传速度和处理速度也不太理想。 折腾了一圈之后,索性自己做了一个专门用于视频去字幕的小工具。 目前接入的是火山引擎的视频去字幕能力,支持: 最大 1GB 视频上传 不限制视频时长 支持框选字幕区域 精确到按秒计费 比起 AI 重新生成成本缩减 50 倍 如果你也遇到同样的问题可以试试看: https://subtitleremover.com 也欢迎大家提建议交流
我有个英文视频,看不太懂,也是英文字幕,有没有能把视频传进去给加上中文字幕的软件? 2 个帖子 - 2 位参与者 阅读完整话题
有佬友对日剧了解的吗,求日剧的下载地址和中日字幕的下载地址 14 个帖子 - 8 位参与者 阅读完整话题
虽然实时字幕工具已经很多了,不过目前没看到一个免费开源的实时语音翻译工具能满足我的需求: 完全本地推理,可以离线使用,隐私安全。 转录质量。个人体感 whisper 等国外的开源模型和系统自带 asr 工具其实对亚洲语言支持并不好,个人认为要处理中日韩语 asr ,现在能用的唯一开源模型就是 qwen3-asr 。翻译用的 Hy-MT2-1.8B 。 低延迟。在不牺牲质量使用原始权重的条件下优化了推理速度,在 rtx4090 上能够 500ms 左右实时看到结果 所以我做了这样一个本地运行的实时字幕工具。它基于 Qwen3-ASR-1.7B ,后端在本机启动 ASR WebSocket 服务,桌面端用 Tauri 做轻量字幕窗口。目标是本地单用户看直播、视频、会议等场景。 目前支持: 本地语音转文字 / 实时字幕 Windows/macOS 桌面客户端 后端在 Linux 或 WSL + NVIDIA CUDA GPU 上跑 可选翻译目标语言 系统音频和麦克风采集 项目地址及演示 demo: https://github.com/vauxe/funyi https://github.com/vauxe/funyi#demo
虽然实时字幕工具已经很多了,不过目前没看到一个免费开源的实时语音翻译工具能满足我的需求: 完全本地推理,可以离线使用,隐私安全。 转录质量。个人体感 whisper 等国外的开源模型和系统自带 asr 工具其实对亚洲语言支持并不好,个人认为要处理中日韩语 asr ,现在能用的唯一开源模型就是 qwen3-asr 。翻译用的 Hy-MT2-1.8B 。 低延迟。在不牺牲质量使用原始权重的条件下优化了推理速度,在 rtx4090 上能够 500ms 左右实时看到结果 所以我做了这样一个本地运行的实时字幕工具。它基于 Qwen3-ASR-1.7B ,后端在本机启动 ASR WebSocket 服务,桌面端用 Tauri 做轻量字幕窗口。目标是本地单用户看直播、视频、会议等场景。 目前支持: 本地语音转文字 / 实时字幕 Windows/macOS 桌面客户端 后端在 Linux 或 WSL + NVIDIA CUDA GPU 上跑 可选翻译目标语言 系统音频和麦克风采集 项目地址及演示 demo: https://github.com/vauxe/funyi https://github.com/vauxe/funyi#demo
虽然实时字幕工具已经很多了,不过目前没看到一个免费开源的实时语音翻译工具能满足我的需求: 完全本地推理,可以离线使用,隐私安全。 转录质量。个人体感 whisper 等国外的开源模型和系统自带 asr 工具其实对亚洲语言支持并不好,个人认为要处理中日韩语 asr ,现在能用的唯一开源模型就是 qwen3-asr 。翻译用的 Hy-MT2-1.8B 。 低延迟。在不牺牲质量使用原始权重的条件下优化了推理速度,在 rtx4090 上能够 500ms 左右实时看到结果 所以我做了这样一个本地运行的实时字幕工具。它基于 Qwen3-ASR-1.7B ,后端在本机启动 ASR WebSocket 服务,桌面端用 Tauri 做轻量字幕窗口。目标是本地单用户看直播、视频、会议等场景。 目前支持: 本地语音转文字 / 实时字幕 Windows/macOS 桌面客户端 后端在 Linux 或 WSL + NVIDIA CUDA GPU 上跑 可选翻译目标语言 系统音频和麦克风采集 项目地址及演示 demo: https://github.com/vauxe/funyi https://github.com/vauxe/funyi#demo
之前安装了一个扩展 dualpip,最近更新发现支持实时展示字幕和翻译了。 我发现作者 发到了推广区 https://v2ex.com/t/1217309 我决定帮他一把,让更多朋友们可以看见~
之前安装了一个扩展 dualpip,最近更新发现支持实时展示字幕和翻译了。 我发现作者 发到了推广区 https://v2ex.com/t/1217309 我决定帮他一把,让更多朋友们可以看见~
我平时用来输出词级字幕,最近测试了 qwen 的 asr 感觉准确率和时间戳都不是很准啊。。
我平时用来输出词级字幕,最近测试了 qwen 的 asr 感觉准确率和时间戳都不是很准啊。。
我平时用来输出词级字幕,最近测试了 qwen 的 asr 感觉准确率和时间戳都不是很准啊。。
我平时用来输出词级字幕,最近测试了 qwen 的 asr 感觉准确率和时间戳都不是很准啊。。
我平时用来输出词级字幕,最近测试了 qwen 的 asr 感觉准确率和时间戳都不是很准啊。。
我平时用来输出词级字幕,最近测试了 qwen 的 asr 感觉准确率和时间戳都不是很准啊。。
我平时用来输出词级字幕,最近测试了 qwen 的 asr 感觉准确率和时间戳都不是很准啊。。
我平时用来输出词级字幕,最近测试了 qwen 的 asr 感觉准确率和时间戳都不是很准啊。。
本想着开个SVIP看一下视频,实在是太垃圾了。先不说开字幕要生成半天,一旦倍速就卡的不行,不如百度网盘的普通用户,不用会员的画质更是没法看。。不知道有没有什么方法可以在外部看吗 5 个帖子 - 4 位参与者 阅读完整话题