Skip to content

Commit 959a156

Browse files
authored
feat: introduce auto slice video (#238)
fix #233 Introduce the auto-slice-video package. Update the zhipu model to glm-4v-plus-0111.
1 parent 2a7c09b commit 959a156

File tree

11 files changed

+89
-146
lines changed

11 files changed

+89
-146
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pnpm-lock.yaml
66
**/__pycache__
77
test/*
88
Videos/*
9+
!Videos/.gitkeep
910
settings-production.toml
1011
startRecord-production.sh
1112
src/utils/cookies.json

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ $RECYCLE.BIN/
350350
# End of https://www.toptal.com/developers/gitignore/api/intellij+all,python,pycharm+all,macos,windows
351351
# Data&test
352352
Videos/
353+
!Videos/.gitkeep
353354
test/
354355
.cache
355356
.vscode/

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "src/danmaku/DanmakuConvert"]
22
path = src/danmaku/DanmakuConvert
33
url = https://github.com/timerring/DanmakuConvert.git
4+
[submodule "src/autoslice/auto_slice_video"]
5+
path = src/autoslice/auto_slice_video
6+
url = [email protected]:timerring/auto-slice-video.git

src/autoslice/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22

33
import sys
44
import os
5-
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
5+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
6+
from .auto_slice_video.autosv import slice_video_by_danmaku
7+
8+
__all__ = ["slice_video_by_danmaku"]

src/autoslice/auto_slice_video

Submodule auto_slice_video added at c26376d

src/autoslice/calculate_density.py

Lines changed: 0 additions & 51 deletions
This file was deleted.

src/autoslice/inject_metadata.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright (c) 2024 bilive.
2+
3+
import subprocess
4+
from src.log.logger import scan_log
5+
6+
# https://stackoverflow.com/questions/64849478/cant-insert-stream-metadata-into-mp4
7+
def inject_metadata(video_path, generate_title, output_path):
8+
"""Slice the video using ffmpeg."""
9+
command = [
10+
'ffmpeg',
11+
'-i', video_path,
12+
'-metadata:g', f'generate={generate_title}',
13+
'-c:v', 'copy',
14+
'-c:a', 'copy',
15+
output_path
16+
]
17+
try:
18+
result = subprocess.run(command, check=True, capture_output=True, text=True)
19+
scan_log.debug(f"FFmpeg output: {result.stdout}")
20+
if result.stderr:
21+
scan_log.debug(f"FFmpeg debug: {result.stderr}")
22+
except subprocess.CalledProcessError as e:
23+
scan_log.error(f"Error: {e.stderr}")

src/autoslice/slice_video.py

Lines changed: 0 additions & 74 deletions
This file was deleted.

src/autoslice/zhipu_sdk.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Copyright (c) 2024 bilive.
2+
3+
import base64
4+
from src.config import Your_API_KEY
5+
from zhipuai import ZhipuAI
6+
from src.log.logger import scan_log
7+
8+
def zhipu_glm_4v_plus_generate_title(video_path, artist):
9+
with open(video_path, 'rb') as video_file:
10+
video_base = base64.b64encode(video_file.read()).decode('utf-8')
11+
12+
client = ZhipuAI(api_key=Your_API_KEY)
13+
response = client.chat.completions.create(
14+
model="glm-4v-plus-0111",
15+
messages=[
16+
{
17+
"role": "user",
18+
"content": [
19+
{
20+
"type": "video_url",
21+
"video_url": {
22+
"url" : video_base
23+
}
24+
},
25+
{
26+
"type": "text",
27+
"text": f"视频是{artist}的直播的切片,请根据该视频中的内容及弹幕信息,为这段视频起一个调皮并且吸引眼球的标题,注意标题中如果有“主播”请替换成{artist}"
28+
}
29+
]
30+
}
31+
]
32+
)
33+
scan_log.info(f"Prompt: 视频是{artist}的直播的切片,请根据该视频中的内容及弹幕信息,为这段视频起一个调皮并且吸引眼球的标题,注意标题中如果有“主播”请替换成{artist}")
34+
scan_log.info(f"生成的切片标题为: {response.choices[0].message.content}")
35+
return response.choices[0].message.content.replace("《", "").replace("》", "")

src/burn/render_video.py

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
import argparse
44
import os
55
import subprocess
6-
from src.config import GPU_EXIST, SRC_DIR, MODEL_TYPE, AUTO_SLICE, SLICE_DURATION, MIN_VIDEO_SIZE
6+
from src.config import GPU_EXIST, SRC_DIR, MODEL_TYPE, AUTO_SLICE, SLICE_DURATION, MIN_VIDEO_SIZE, SLICE_NUM, SLICE_OVERLAP, SLICE_STEP
77
from src.danmaku.generate_danmakus import get_resolution, process_danmakus
88
from src.subtitle.generate_subtitles import generate_subtitles
99
from src.burn.render_command import render_command
10-
from src.autoslice.slice_video import slice_video, inject_metadata, zhipu_glm_4v_plus_generate_title
11-
from src.autoslice.calculate_density import extract_dialogues, calculate_density, format_time
10+
from autoslice import slice_video_by_danmaku
11+
from src.autoslice.inject_metadata import inject_metadata
12+
from src.autoslice.zhipu_sdk import zhipu_glm_4v_plus_generate_title
1213
from src.upload.extract_video_info import get_video_info
1314
from src.log.logger import scan_log
1415

@@ -61,16 +62,18 @@ def render_video(video_path):
6162
if AUTO_SLICE:
6263
if check_file_size(format_video_path) > MIN_VIDEO_SIZE:
6364
title, artist, date = get_video_info(format_video_path)
64-
slice_video_path = format_video_path[:-4] + '_slice.mp4'
65-
dialogues = extract_dialogues(ass_path)
66-
max_start_time, max_density = calculate_density(dialogues)
67-
formatted_time = format_time(max_start_time)
68-
scan_log.info(f"The 30-second window with the highest density starts at {formatted_time} seconds with {max_density} danmakus.")
69-
slice_video(format_video_path, max_start_time, slice_video_path)
70-
glm_title = zhipu_glm_4v_plus_generate_title(slice_video_path, artist)
71-
slice_video_flv_path = slice_video_path[:-4] + '.flv'
72-
inject_metadata(slice_video_path, glm_title, slice_video_flv_path)
73-
os.remove(slice_video_path)
65+
slices_path = slice_video_by_danmaku(ass_path, format_video_path, SLICE_DURATION, SLICE_NUM, SLICE_OVERLAP, SLICE_STEP)
66+
for slice_path in slices_path:
67+
try:
68+
glm_title = zhipu_glm_4v_plus_generate_title(slice_path, artist)
69+
slice_video_flv_path = slice_path[:-4] + '.flv'
70+
inject_metadata(slice_path, glm_title, slice_video_flv_path)
71+
os.remove(slice_path)
72+
with open(f"{SRC_DIR}/upload/uploadVideoQueue.txt", "a") as file:
73+
scan_log.info(f"Complete {slice_video_flv_path} and wait for uploading!")
74+
file.write(f"{slice_video_flv_path}\n")
75+
except Exception as e:
76+
scan_log.error(f"Error in {slice_path}: {e}")
7477

7578
# Delete relative files
7679
for remove_path in [original_video_path, xml_path, ass_path, srt_path, jsonl_path]:
@@ -82,9 +85,4 @@ def render_video(video_path):
8285
# os.rename(original_video_path, test_path)
8386

8487
with open(f"{SRC_DIR}/upload/uploadVideoQueue.txt", "a") as file:
85-
file.write(f"{format_video_path}\n")
86-
if AUTO_SLICE:
87-
scan_log.info("Complete slice video and wait for uploading!")
88-
slice_video_path = format_video_path[:-4] + '_slice.mp4'
89-
slice_video_flv_path = slice_video_path[:-4] + '.flv'
90-
file.write(f"{slice_video_flv_path}\n")
88+
file.write(f"{format_video_path}\n")

0 commit comments

Comments
 (0)