行车记录仪视频拼接

摘要: 本文介绍了作者为实现行车记录仪视频拼接而设计的基于大模型的文件分组方案。由于不同记录仪生成的文件名格式变化较大,作者利用提示设计让模型根据文件名中的时间信息,将视频文件按时间连续性分组,确保每组内视频时间相差不超过10分钟。模型输出以json格式返回分组信息,作者通过代码验证输出的正确性,确保所有文件都被正确分组。实践中强调了模型输出检查的重要性,并指出调整prompt以优化结果。最后总结了模型输出验证和prompt设计的经验,强调非创造性任务中保持输出确定性的重要性。 (评价: A)



在遇到漂亮的风景、不安全的驾驶行为等情况时,我习惯于将行车记录仪的视频拷贝下来,保存在nas上;但是大部分行车记录仪的视频都是分段存储的,通常是每1或5分钟一个文件。为了方便查看,我需要将这些视频拼接成一个完整的视频。

文件metadata中的创建/修改时间戳并不完全可靠。因此,主要方向是通过视频文件名中包含的时间戳来进行拼接。

以往的做法,需要分析视频文件名,从中找到时间戳的特征,然后提取出时间戳,根据时间戳的范围来分组视频,进而拼接成一个完整的视频,我车上原装的记录仪和后装的都有相似的格式,可以共用提取逻辑;这种方案我使用了一年,没什么大问题。但是最近换了一款记录仪,文件名的结构变化较大,不再适用此前的提取逻辑。为了适应新的文件名格式,我需要重新设计视频拼接的逻辑。

修改的唯一目的是,这个提取逻辑可以适配不同行车记录仪的文件名格式。我想到让大模型来做这件事。

设计思路

prompt设计如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
seperator = "#" * 10
prompt = f"""你负责整理文件;给你输入一系列的文件。

给你输入的文件是mp4文件。

这些文件用绝对目录表示。

每一个文件用一行表示,格式是:

<文件序号> <文件绝对路径>

这些文件来自行车记录仪,文件名中会包含时间信息。这个时间信息表示这个视频的开始时间。

你需要把这些文件分组,使得每一组内的mp4文件首位衔接,可以合成一个时间上连续的视频。

所以,你需要按照文件名中包含的时间信息来分组。

每一个文件一般不超过10分钟。所以,按照时间分组的时候,如果一个待分组的文件的时间和某个组内的某一个文件的时间相差不超过10分钟,就可以把这个文件划分到这个组内。

比如第一个视频是2023年10月1日的10:00:00,第二个视频是2023年10月1日的10:09:00,第三个视频是2023年10月1日的10:15:00,第四个视频是2023年10月1日的10:30:00.

这种情况下,第一个、第二个和第三个视频可以划分在同一组,第四个视频单独划分在一组。

你将分组后的结果用json格式返回。返回结果的json包含三个字段:

- group:分组的名称,字符串类型,表示分组的名称,比如P1、P2等。
- time:分组的时间,字符串类型,表示分组的时间,用这个分组中最早的时间表示,比如2023-10-01T10:00:00。
- files:分组的文件列表,使用文件的序号表示,文件的序号是从0开始的整数,比如0、1、2等。

注意使用json格式返回结果,json格式为:

[
    {{
        "group": "P1",
        "time": "2023-10-01T10:00:00",
        "files": [0, 1, 2]
    }},
    {{
        "group": "P2",
        "time": "2023-10-01T10:30:00",
        "files": [3]
    }}
]

注意:输出必须是json格式,不能有其他的输出。

输入的所有文件都必须被分组。输入的每一个文件,都必须在某一个组内。

比如给你输入的文件列表包含的编号是1、2、3、4、5,
那么你返回的json中,files字段的值必须包含1、2、3、4、5。不能有遗漏。

输入的文件列表被{seperator}包含。

输入的文件列表是:
"""

prompt中要求模型返回文件的序号,而不是文件路径,这是为了减少模型返回的内容长度。否则,在文件数量较多时,模型返回的内容会很长,可能导致超时或者超出token限制。

我们还需要检查模型的输出,一方面检查输出格式是否符合json要求,另一方面检查输出内容,确保没有遗漏文件,也没有新增文件。

如果检查不通过,则可以告诉模型哪些地方不对,然后拼接历史消息,然后再送给模型,让模型再次输出。

当生成正确时,就可以将分组好的文件路径传给ffmpeg进行拼接了。ffmpeg拼接方法本文不再赘述。

当然,在调试过程中我也发现了一些错误分类的情况,比如某10个文件实际可以拼接成一个连续的视频,它们可以划分在同一组,但是模型输出的结果把他们划分为了两个组。针对这种情况,一方面可以思考是否也算符合自己的需求,另一方面则是通过修改prompt来优化模型输出。比如针对本文的视频拼接需求,偶尔把一个长视频划分成两个短视频也并不糟糕;因此我只修改了若干次prompt,没再发现这种划分多组的问题就算它通过了,并没有再经过复杂的验证。

脚本源码相继于本文的思路来说不算重要,我就不贴了(偷懒,不想整理)。

总结

通过这次实践,可以发现,对模型输出的检查是非常重要的。因为模型的输出不能保证总是正确的。检查方法需要根据具体的需求来设计。比如在本例中,我们使用计算机代码来检查模型的输出是否正确,而不是使用另一个模型来检查。本例中,如果检查失败,我们会将错误信息反馈给模型,要求它重新输出正确的结果。

对于本文讨论的这种非创造性的需求,一般会设置模型的temperature为0,确保模型的输出是确定的。而对于之前讨论的“文章摘要”话题,可以适当给模型一些创造的空间。

另外,结合最近两次实践的prompt来看,有一些表述显得啰嗦,是因为目前发现重复(啰嗦)的一些表述,可以提高模型的输出质量,使其返回内容更满足需求。