豆包Marscode体验官:不写一行代码创建一个srt字幕翻译工具

我正在参加「豆包MarsCode初体验」征文活动

当 GitHub Copilot 还是免费的时候,用起来真是畅快淋漓,大呼666。不过,自从它开始收费,每月要10美元,虽然知道它的价值,但考虑到那总是鼓不起来的钱包,还是决定放弃了。又回到了古老编程时代,偶尔需要AI帮助时:打开浏览器某个AI对话框,输入问题复制答案,虽有挺多免费类Copilot工具,但总觉用的不顺手。

最近,试用了字节跳动推出的 Marscode,感觉挺不错。最让人惊喜的是,它还自带了一个在线IDE,不仅拥有智能补全、预测和问答等强大功能,而且操作起来流畅的就像使用本地编辑器一样,完全感觉不到延迟。更棒的是,它还提供了2核CPU、4G内存和10G硬盘的项目空间,真的很实用了!

使用方法

打开 www.marscode.cn/dashboard 注册登录,然后新建项目

支持 python、nodejs、go等多种模板,并可从GitHub导入项目,我需要一个python项目,自然选择python模板了,创建后就进入了编辑空间

可以愉快使用了,如果不是上面有个浏览器地址栏,简直以为是本地编辑器了。

最近在鼓捣字幕翻译,那就以此为契机搞个"字幕翻译项目吧"

项目概述

一个srt格式字幕翻译功能,将字幕从一种语言翻译到另一种语言,并保持字幕格式不变。

整体思路

AI虽然够聪明,但首先要让它理解你在指挥它做什么任务,你输入的指令越准确、逻辑越清晰,它完成的就越好,反之你不会得到想要的结果。

首先整理思路,然后根据该思路写提示词。

一. 写个函数1,用于读取srt字幕文件并转为字典对象列表

将每条字幕转为一个dict对象,line键对应行号、time键对应字幕时间戳行、text键对应字幕文本文字。如

原字幕

lua 复制代码
1
00:00:01.000 --> 00:00:05.400
AI技术的发展超出了预期

转为dict对象后

json 复制代码
{
    "line":1,
    "time":"00:00:01.000 --> 00:00:05.400",
    "text":"AI技术的发展超出了预期"
}

为何这样处理呢?主要是方便批量获取多行字幕文本,然后将这多行文本以换行符\n连接后,发给翻译引擎,再将翻译结果一一对应填充回dict。

干吗不直接带上 行号和时间戳行 的完整字幕格式进行翻译呢?

原因主要有二:

1. 传统翻译引擎,如百度,可能会将时间戳行中的英文标点转为中文标点,或者将时间戳也翻译一遍,导致格式出错。即便号称全世界最准确的DeepL也可能犯类似错误。

2. AI模型虽不会犯此错误,但会浪费很多token,并且不同厂家不同规模的模型智能程度不同,一些的模型仍然会犯格式错误,比如可能删除字幕之间的2个空白行。

或者出现合并2行内容为一行,尤其是下一行只有孤零零的一个或几个单词,而且该单词在语义上属于上一行时。

例如

sql 复制代码
2
00:00:01,860 --> 00:00:04,660
you are my friend, i am 

3
00:00:06,400 --> 00:00:07,580
from China

在一些不够庞大或智能的模型时,可能会遇到一个棘手的问题:有时会将"from China"这样的短语错误地合并到上一行,结果导致该行变成了空白。

尽管尝试通过使用严格的提示词和翻译示例来避免这种情况,但只要翻译量足够大时,比如成千上万的字幕条或数百个字幕文件,这种小概率的错误仍然难以完全避免。

为了应对这些偶发的格式问题,不得不编写大量的修正代码,还消耗了大量的token,从成本效益的角度来看,不划算。

特别是,考虑到我的字幕文件是通过语音识别生成的,其准确性和标点的正确性本身就无法保证

因此,经过深思熟虑,我决定采取一种更为简洁高效的方法:不再发送带有复杂格式的字幕,而只发送字幕中的文字行。这样既简化了处理流程,又避免了因格式问题带来的额外工作量,当出现行数不对应时,转而对此次任务采用逐行翻译。

如果一条字幕的文本行由两行或多行组成怎么办?这种情况下似乎带格式翻译更好,不过更简单的方式是直接将换行符替换为多个句号转为一行,最终字幕文件中再替换回来。

二:再写个函数2,用于组装发送翻译请求

在该函数中,调用函数1读取字幕文件返回字典对象列表,然后遍历该列表,取出text键对应的字幕文本,发送翻译请求,得到翻译结果后再替换text键对应的文本。

该处为加快翻译速度,同时在AI翻译时提供上下文以提升翻译质量,一次发送15行或更多行,具体方法是每15个dict对象的text值用换行符连接为一个字符串,得到翻译结果后再按行拆分为15行,填充回对应的dict对象的text值中。

如上文所述,这种情况下要求译文行数同原文行数严格一致,但聪明的AI往往会遵照语义合并行,尤其是孤零零一两个单词的行,即便已提供了严格的提示词限制。

虽然直接发送带行号和时间行格式的字幕能减少该情况出现的几率,但绝不会降到零,反而因此大幅增加了token消耗,得不偿失。

可在出现该情况时,对该次任务的15行字幕文本重新逐行翻译,通过容许一定的质量降低来保证行数绝对正确。

三:再写个函数3,将翻译后的字幕保存为新的字幕文件

遍历翻译后组装好的列表对象,组成srt格式的字幕字符串,重新保存回srt格式字幕文件。

css 复制代码
dict["line"]
dict["time"]
dict["text"]

dict["line"]
dict["time"]
dict["text"]

写提示词

根据上文思路,编写提示词,可根据任务阶段,每完成一个任务后,再编写写一个提示词。也可以一次完成整个任务所有步骤,我是按后者执行。

在左侧点击新建图标创建一个start.py文件

然后在 start.py中输入提示词,在代码中,注释就是提示词。

以下是该项目的完整提示词或者说是注释

shell 复制代码
# 创建一个srt格式的字幕翻译工具,实现从一种语言翻译为另一种语言

# 首先从命令行参数1中读取srt字幕路径,从参数2中读取要翻译到的目标语言代码

# 然后创建函数1,该函数读取字幕文件,并返回一个list列表,列表中每个元素都是一个dict字典对象,每个dict对象对应一条字幕,字典对象中的 line键值对应字幕行号数字、time键值对应时间戳行内容、text键值对应字幕的文本内容,注意文本可能有一行或多行。

# 再创建函数2,该函数中调用函数1,得到包含字典对象元素的列表list,然后遍历该list,取出dict中的text键对应的值

# 接着向  https://g3.pyvideotrans.com/translate_a/single 发起get请求。参数分别是 client=gtx,dt=t,sl=auto,tl=参数2,q=text键值

# 请求头headers中user-agnet模仿chrome104浏览器

# 请求返回的数据是一个json格式的字符串,转为json对象后是一个list列表,可命名为res,res[0]中存储翻译结果,它也是一个list,可能由1个或多个子元素组成,每个子元素也是一个list,将所有子元素的0索引元素拼接成一个字符串,即为翻译结果文本,将该结果替换text键对应的内容。

# 创建函数3,将函数2中替换text后的list对象进行遍历,组装为完整的srt格式字幕字符串,然后保存为srt文件,文件名是 原文件名+目标语言.srt

# 最后调用函数3,将函数2中替换text后的list对象保存为srt文件。

# 即可实现从一种语言翻译为另一种语言。

为简化示例,方便展示,没有采用一次15行文本进行翻译,而是一次只翻译一行

代码自动生成

如上,在最后一行提示词结束后,按回车新起一行,无意外的情况下,即自动开始生成代码,以浅灰半透明显示。

可大致扫一眼,如果感觉合适,按Tab键采用,然后不断循环 回车 + Tab 直到完成。

有时按了一次回车后,并没有出现提示代码,这种情况时有发生,尤其是在一个函数完成或一段代码结束,需要开启新的代码片段时,可以继续再按一次或两次回车,稍作等待,提示代码应该就会出现了。

动图展示代码自动生成

从动图中也能看出,有时按一次回车后并没有显示可用的代码,此时需要再次按下回车。

以下是生成的全部代码,未经任何修改

scss 复制代码
import sys
import json
import requests
import urllib.parse

def read_srt(srt_file):
    with open(srt_file, 'r', encoding='utf-8') as f:
        srt_data = f.read()
    srt_lines = srt_data.split('\n')
    srt_list = []
    i = 0
    while i < len(srt_lines):
        line = srt_lines[i]
        if line.isdigit():
            line_dict = {}
            line_dict['line'] = int(line)
            i += 1
            line_dict['time'] = srt_lines[i]
            i += 1
            text = []
            while i < len(srt_lines) and srt_lines[i]!= '' and not srt_lines[i].isdigit():
                text.append(srt_lines[i])
                i += 1
            line_dict['text'] = '\n'.join(text)
            srt_list.append(line_dict)
        else:
            i+=1
    return srt_list

def translate_srt(srt_list, target_lang):
    for line_dict in srt_list:
        text = line_dict['text']
        url = 'URL_ADDRESS'
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
        }
        params = {
            'client': 'gtx',
            'dt': 't',
           'sl': 'auto',
            'tl': target_lang,
            'q': text
        }
        response = requests.get(url, headers=headers, params=params)
        res = json.loads(response.text)
        line_dict['text'] = '\n'.join(res[0])
    return srt_list

def save_srt(srt_list, srt_file, target_lang):
    with open(srt_file, 'w', encoding='utf-8') as f:
        for line_dict in srt_list:
            f.write(str(line_dict['line']) + '\n')
            f.write(line_dict['time'] + '\n')
            f.write(line_dict['text'] + '\n')
            f.write('\n')

if __name__ == '__main__':
    srt_file = sys.argv[1]
    target_lang = sys.argv[2]
    srt_list = read_srt(srt_file)
    srt_list = translate_srt(srt_list, target_lang)
    save_srt(srt_list, srt_file + '.' + target_lang, target_lang)

然而并不能直接用,存在几个错误。

存在的问题

  1. 没有使用我在提示词中指定的 url ,即 https://g3.pyvideotrans.com/translate_a/single,而是使用的占位符 url = 'URL_ADDRESS',需要手动修改
  2. 我已经在提示词中写明了返回的是json字符串,其实直接调用res=response.json()方法就行了,没必要多此一举的使用 res = json.loads(response.text)
  3. 可能是返回结果过于复杂,或我的提示词不够清晰,它没有按照我预想的方式获取翻译结果

生成的 line_dict['text'] = '\n'.join(res[0]) 这种方式是错误的。

返回的json数据结构

css 复制代码
[    [        ['朋友你好', 'hello,my friend', None, None, 10]
    ], None, 'en', None, None, None, 1, [], [['en'], None, [1], ['en']]]
    ...

预期的获取方式应该是

line_dict['text'] = ''.join([te[0] for te in res[0]])

修改后的代码: 为方便控制台观看实时结果,加了一行代码,print(line_dict)

scss 复制代码
import sys
import json
import requests
import urllib.parse

def read_srt(srt_file):
    with open(srt_file, 'r', encoding='utf-8') as f:
        srt_data = f.read()
    srt_lines = srt_data.split('\n')
    srt_list = []
    i = 0
    while i < len(srt_lines):
        line = srt_lines[i]
        if line.isdigit():
            line_dict = {}
            line_dict['line'] = int(line)
            i += 1
            line_dict['time'] = srt_lines[i]
            i += 1
            text = []
            while i < len(srt_lines) and srt_lines[i]!= '' and not srt_lines[i].isdigit():
                text.append(srt_lines[i])
                i += 1
            line_dict['text'] = ''.join(text)
            srt_list.append(line_dict)
        else:
            i+=1
    return srt_list

def translate_srt(srt_list, target_lang):
    for line_dict in srt_list:
        text = line_dict['text']
        url = 'https://g3.pyvideotrans.com/translate_a/single'
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
        }
        params = {
            'client': 'gtx',
            'dt': 't',
           'sl': 'auto',
            'tl': target_lang,
            'q': text
        }
        response = requests.get(url, headers=headers, params=params)
        res = response.json()
        line_dict['text'] = ''.join([te[0] for te in res[0]])
        print(line_dict)
    return srt_list

def save_srt(srt_list, srt_file, target_lang):
    with open(srt_file, 'w', encoding='utf-8') as f:
        for line_dict in srt_list:
            f.write(str(line_dict['line']) + '\n')
            f.write(line_dict['time'] + '\n')
            f.write(line_dict['text'] + '\n')
            f.write('\n')

if __name__ == '__main__':
    srt_file = sys.argv[1]
    target_lang = sys.argv[2]
    srt_list = read_srt(srt_file)
    srt_list = translate_srt(srt_list, target_lang)
    save_srt(srt_list, srt_file + '.' + target_lang, target_lang)

找个srt字幕文件,直接拖动到左侧文件区,我这里从本地拖动名为 1.srt的英文字幕

控制台输入 python start.py 1.srt zh-cn 我需要翻译为简体中文,因此输入 zh-cn

没有意外发生的话,1.srt.zh-cn.srt已经生成了。

这里使用的是Google翻译,质量还凑合

遇到的一些奇怪问题/Bug

  1. 出现了一个奇怪有趣的bug,在生成函数2完成后,继续回车,又提示生成函数3,和函数2功能完全一样,只是名字略不同,3完成后,又出现4。。。。如此直到10还没结束。不得不删掉,然后加了个 if开头行,然后按下空格,才开始正常提示 if __name__

如下图所示

  1. 在一行注释后回车,有一定几率生成的代码以 # 开头,也就是被注释掉了。如下图

总结

标题有点夸大了,不写代码或许可以,但不修改代码几乎是不可能的。

总体上体验还是挺不错的,尤其是在线IDE,使用流畅度不逊色于本地编辑器。

右侧还有更多功能待体验哦

相关推荐
数据智能老司机7 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
逛逛GitHub7 小时前
飞书多维表“独立”了!功能强大的超出想象。
人工智能·github·产品
机器之心8 小时前
刚刚,DeepSeek-R1论文登上Nature封面,通讯作者梁文锋
人工智能·openai
安思派Anspire8 小时前
创建完整的评估生命周期以构建高(三)
aigc·openai·agent
数据智能老司机8 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机8 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机8 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i9 小时前
drf初步梳理
python·django
每日AI新事件9 小时前
python的异步函数
python
努力的小雨9 小时前
混元开源之力:spring-ai-hunyuan 项目功能升级与实战体验
后端·github