添加webhook回调处理
This commit is contained in:
@@ -19,6 +19,7 @@ with ffmpeg_worker_image.imports():
|
||||
import shutil, psutil, os, backoff, json, sentry_sdk
|
||||
from typing import List, Optional, Tuple, Dict, Any
|
||||
from loguru import logger
|
||||
import httpx
|
||||
from modal import current_function_call_id
|
||||
from ffmpeg.asyncio import FFmpeg
|
||||
from BowongModalFunctions.utils.SentryUtils import SentryUtils
|
||||
@@ -26,13 +27,14 @@ with ffmpeg_worker_image.imports():
|
||||
from BowongModalFunctions.utils.VideoUtils import VideoUtils
|
||||
from BowongModalFunctions.models.ffmpeg_worker_model import FFMpegSliceSegment
|
||||
from BowongModalFunctions.models.media_model import MediaSources, MediaSource, MediaProtocol
|
||||
from BowongModalFunctions.models.web_model import SentryTransactionInfo
|
||||
from BowongModalFunctions.models.web_model import SentryTransactionInfo, WebhookNotify, WebhookMethodEnum, \
|
||||
FFMPEGConcatTaskStatusResponse, TaskStatus, ErrorCode
|
||||
from BowongModalFunctions.config import WorkerConfig
|
||||
|
||||
config = WorkerConfig()
|
||||
|
||||
s3_mount = config.S3_mount_dir
|
||||
output_path_prefix = "/mnt/outputs"
|
||||
output_path_prefix = config.local_output_mount
|
||||
|
||||
sentry_sdk.init(
|
||||
dsn="https://75cca970bfcc3d45d24361e7c0f1833c@sentry.bowongai.com/4",
|
||||
@@ -111,7 +113,7 @@ with ffmpeg_worker_image.imports():
|
||||
# region='ap-northeast',
|
||||
max_containers=config.ffmpeg_worker_concurrency,
|
||||
volumes={
|
||||
f"/mntS3": modal.CloudBucketMount(
|
||||
s3_mount: modal.CloudBucketMount(
|
||||
bucket_name=config.S3_bucket_name,
|
||||
secret=modal.Secret.from_name("aws-s3-secret",
|
||||
environment_name=config.modal_environment),
|
||||
@@ -119,7 +121,8 @@ with ffmpeg_worker_image.imports():
|
||||
}, )
|
||||
@modal.concurrent(max_inputs=1)
|
||||
async def ffmpeg_concat_medias(medias: MediaSources,
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None) -> Tuple[
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None,
|
||||
webhook: Optional[WebhookNotify] = None) -> Tuple[
|
||||
str, Optional[SentryTransactionInfo]]:
|
||||
|
||||
fn_id = current_function_call_id()
|
||||
@@ -127,15 +130,17 @@ with ffmpeg_worker_image.imports():
|
||||
@SentryUtils.sentry_tracker(name="视频合并任务", op="ffmpeg.concat", fn_id=fn_id,
|
||||
sentry_trace_id=sentry_trace.x_trace_id if sentry_trace else None,
|
||||
sentry_baggage=sentry_trace.x_baggage if sentry_trace else None)
|
||||
@SentryUtils.webhook_handler(webhook=webhook, func_id=fn_id)
|
||||
async def ffmpeg_process(media_sources: MediaSources, output_filepath: str) -> str:
|
||||
input_videos = [f"{s3_mount}/{media_source.cache_filepath}" for media_source in media_sources.inputs]
|
||||
local_output_path = await VideoUtils.ffmpeg_concat_medias(media_paths=input_videos,
|
||||
output_path=output_filepath)
|
||||
return local_output_path
|
||||
|
||||
output_path = f"{output_path_prefix}/concat/outputs/{fn_id}/output.mp4"
|
||||
output_path = f"{output_path_prefix}/{config.modal_environment}/concat/outputs/{fn_id}/output.mp4"
|
||||
local_output = await ffmpeg_process(media_sources=medias, output_filepath=output_path)
|
||||
s3_outputs = local_copy_to_s3([local_output])
|
||||
|
||||
if not sentry_trace:
|
||||
sentry_trace = SentryTransactionInfo(x_trace_id=sentry_sdk.get_traceparent(),
|
||||
x_baggage=sentry_sdk.get_baggage())
|
||||
@@ -147,7 +152,7 @@ with ffmpeg_worker_image.imports():
|
||||
cloud="aws",
|
||||
max_containers=config.ffmpeg_worker_concurrency,
|
||||
volumes={
|
||||
f"/mntS3": modal.CloudBucketMount(
|
||||
s3_mount: modal.CloudBucketMount(
|
||||
bucket_name=config.S3_bucket_name,
|
||||
secret=modal.Secret.from_name("aws-s3-secret",
|
||||
environment_name=config.modal_environment),
|
||||
@@ -157,14 +162,15 @@ with ffmpeg_worker_image.imports():
|
||||
@modal.concurrent(max_inputs=1)
|
||||
async def ffmpeg_slice_media(media: MediaSource,
|
||||
markers: List[FFMpegSliceSegment],
|
||||
webhook: Optional[str], # todo : handle webhook callback
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None) -> Tuple[
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None,
|
||||
webhook: Optional[WebhookNotify] = None) -> Tuple[
|
||||
List[str], Optional[SentryTransactionInfo]]:
|
||||
fn_id = current_function_call_id()
|
||||
|
||||
@SentryUtils.sentry_tracker(name="视频切割任务", op="ffmpeg.slice", fn_id=fn_id,
|
||||
sentry_trace_id=sentry_trace.x_trace_id if sentry_trace else None,
|
||||
sentry_baggage=sentry_trace.x_baggage if sentry_trace else None)
|
||||
@SentryUtils.webhook_handler(webhook=webhook, func_id=fn_id)
|
||||
async def ffmpeg_slice_process(media_source: MediaSource, media_markers: List[FFMpegSliceSegment],
|
||||
fn_id: str) -> List[str]:
|
||||
cache_filepath = f"{s3_mount}/{media_source.cache_filepath}"
|
||||
@@ -268,7 +274,7 @@ with ffmpeg_worker_image.imports():
|
||||
@app.function(timeout=600, cloud="aws",
|
||||
max_containers=config.ffmpeg_worker_concurrency,
|
||||
volumes={
|
||||
f"/mntS3": modal.CloudBucketMount(
|
||||
s3_mount: modal.CloudBucketMount(
|
||||
bucket_name=config.S3_bucket_name,
|
||||
secret=modal.Secret.from_name("aws-s3-secret",
|
||||
environment_name=config.modal_environment),
|
||||
@@ -277,8 +283,8 @@ with ffmpeg_worker_image.imports():
|
||||
)
|
||||
@modal.concurrent(max_inputs=1)
|
||||
async def ffmpeg_extract_audio(media_source: MediaSource,
|
||||
webhook: Optional[str], # todo handle webhook callback
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None) -> Tuple[
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None,
|
||||
webhook: Optional[WebhookNotify] = None) -> Tuple[
|
||||
Optional[str], Optional[SentryTransactionInfo]]:
|
||||
|
||||
fn_id = current_function_call_id()
|
||||
@@ -286,9 +292,10 @@ with ffmpeg_worker_image.imports():
|
||||
@SentryUtils.sentry_tracker(name="视频切割任务", op="ffmpeg.extract.audio", fn_id=fn_id,
|
||||
sentry_trace_id=sentry_trace.x_trace_id if sentry_trace else None,
|
||||
sentry_baggage=sentry_trace.x_baggage if sentry_trace else None)
|
||||
@SentryUtils.webhook_handler(webhook=webhook, func_id=fn_id)
|
||||
async def ffmpeg_process(media: MediaSource, fn_id: str) -> str:
|
||||
cache_filepath = f"{s3_mount}/{media.cache_filepath}"
|
||||
output_path = f"{output_path_prefix}/extract_audio/outputs/{fn_id}/output.wav"
|
||||
output_path = f"{output_path_prefix}/{config.modal_environment}/extract_audio/outputs/{fn_id}/output.wav"
|
||||
await VideoUtils.ffmpeg_extract_audio_async(cache_filepath, output_path)
|
||||
s3_outputs = local_copy_to_s3([output_path])
|
||||
return s3_outputs[0]
|
||||
@@ -304,7 +311,7 @@ with ffmpeg_worker_image.imports():
|
||||
@app.function(timeout=600, cloud="aws",
|
||||
max_containers=config.ffmpeg_worker_concurrency,
|
||||
volumes={
|
||||
f"/mntS3": modal.CloudBucketMount(
|
||||
s3_mount: modal.CloudBucketMount(
|
||||
bucket_name=config.S3_bucket_name,
|
||||
secret=modal.Secret.from_name("aws-s3-secret",
|
||||
environment_name=config.modal_environment),
|
||||
@@ -315,17 +322,19 @@ with ffmpeg_worker_image.imports():
|
||||
mirror_scale_down_size: int = 6,
|
||||
mirror_from_right: bool = True,
|
||||
mirror_position: tuple[float, float] = (40, 40),
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None):
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None,
|
||||
webhook: Optional[WebhookNotify] = None):
|
||||
fn_id = current_function_call_id()
|
||||
|
||||
@SentryUtils.sentry_tracker(name="视频镜像去重", op="ffmpeg.mirror", fn_id=fn_id,
|
||||
sentry_trace_id=sentry_trace.x_trace_id if sentry_trace else None,
|
||||
sentry_baggage=sentry_trace.x_baggage if sentry_trace else None)
|
||||
@SentryUtils.webhook_handler(webhook=webhook, func_id=fn_id)
|
||||
async def ffmpeg_process(media: MediaSource, func_id: str, mirror_scale_down_size: int = 6,
|
||||
mirror_from_right: bool = True,
|
||||
mirror_position: tuple[float, float] = (40, 40)) -> str:
|
||||
media_filepath = f"{s3_mount}/{media.cache_filepath}"
|
||||
output_path = f"{output_path_prefix}/corner_mirror/outputs/{func_id}/output.mp4"
|
||||
output_path = f"{output_path_prefix}/{config.modal_environment}/corner_mirror/outputs/{func_id}/output.mp4"
|
||||
local_output_filepath = await VideoUtils.ffmpeg_corner_mirror(media_path=media_filepath,
|
||||
output_path=output_path,
|
||||
mirror_from_right=mirror_from_right,
|
||||
@@ -346,7 +355,7 @@ with ffmpeg_worker_image.imports():
|
||||
@app.function(timeout=600, cloud="aws",
|
||||
max_containers=config.ffmpeg_worker_concurrency,
|
||||
volumes={
|
||||
f"/mntS3": modal.CloudBucketMount(
|
||||
s3_mount: modal.CloudBucketMount(
|
||||
bucket_name=config.S3_bucket_name,
|
||||
secret=modal.Secret.from_name("aws-s3-secret",
|
||||
environment_name=config.modal_environment),
|
||||
@@ -354,16 +363,18 @@ with ffmpeg_worker_image.imports():
|
||||
}, )
|
||||
@modal.concurrent(max_inputs=1)
|
||||
async def ffmpeg_overlay_gif(media: MediaSource, gif: MediaSource,
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None):
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None,
|
||||
webhook: Optional[WebhookNotify] = None):
|
||||
fn_id = current_function_call_id()
|
||||
|
||||
@SentryUtils.sentry_tracker(name="视频叠加GIF特效", op="ffmpeg.overlay", fn_id=fn_id,
|
||||
sentry_trace_id=sentry_trace.x_trace_id if sentry_trace else None,
|
||||
sentry_baggage=sentry_trace.x_baggage if sentry_trace else None)
|
||||
@SentryUtils.webhook_handler(webhook=webhook, func_id=fn_id)
|
||||
async def ffmpeg_process(media: MediaSource, func_id: str, gif: MediaSource) -> str:
|
||||
media_filepath = f"{s3_mount}/{media.cache_filepath}"
|
||||
gif_filepath = f"{s3_mount}/{gif.cache_filepath}"
|
||||
output_path = f"{output_path_prefix}/overlay/outputs/{func_id}/output.mp4"
|
||||
output_path = f"{output_path_prefix}/{config.modal_environment}/overlay/outputs/{func_id}/output.mp4"
|
||||
local_output_filepath = await VideoUtils.ffmpeg_overlay_gif(media_path=media_filepath,
|
||||
output_path=output_path,
|
||||
overlay_gif_path=gif_filepath)
|
||||
@@ -380,7 +391,7 @@ with ffmpeg_worker_image.imports():
|
||||
@app.function(timeout=600, cloud="aws",
|
||||
max_containers=config.ffmpeg_worker_concurrency,
|
||||
volumes={
|
||||
f"/mntS3": modal.CloudBucketMount(
|
||||
s3_mount: modal.CloudBucketMount(
|
||||
bucket_name=config.S3_bucket_name,
|
||||
secret=modal.Secret.from_name("aws-s3-secret",
|
||||
environment_name=config.modal_environment),
|
||||
@@ -388,15 +399,17 @@ with ffmpeg_worker_image.imports():
|
||||
}, )
|
||||
@modal.concurrent(max_inputs=1)
|
||||
async def ffmpeg_zoom_loop(media: MediaSource, duration: int = 6, zoom: float = 0.1,
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None):
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None,
|
||||
webhook: Optional[WebhookNotify] = None):
|
||||
fn_id = current_function_call_id()
|
||||
|
||||
@SentryUtils.sentry_tracker(name="视频放大缩小去重", op="ffmpeg.zoom.loop", fn_id=fn_id,
|
||||
sentry_trace_id=sentry_trace.x_trace_id if sentry_trace else None,
|
||||
sentry_baggage=sentry_trace.x_baggage if sentry_trace else None)
|
||||
@SentryUtils.webhook_handler(webhook=webhook, func_id=fn_id)
|
||||
async def ffmpeg_process(media: MediaSource, func_id: str, duration: int = 6, zoom: float = 0.1) -> str:
|
||||
media_filepath = f"{s3_mount}/{media.cache_filepath}"
|
||||
output_path = f"{output_path_prefix}/zoom_loop/outputs/{func_id}/output.mp4"
|
||||
output_path = f"{output_path_prefix}/{config.modal_environment}/zoom_loop/outputs/{func_id}/output.mp4"
|
||||
local_output_filepath = await VideoUtils.ffmpeg_zoom_loop(media_path=media_filepath,
|
||||
output_path=output_path,
|
||||
duration=duration,
|
||||
@@ -414,7 +427,7 @@ with ffmpeg_worker_image.imports():
|
||||
@app.function(timeout=600, cloud="aws",
|
||||
max_containers=config.ffmpeg_worker_concurrency,
|
||||
volumes={
|
||||
f"/mntS3": modal.CloudBucketMount(
|
||||
s3_mount: modal.CloudBucketMount(
|
||||
bucket_name=config.S3_bucket_name,
|
||||
secret=modal.Secret.from_name("aws-s3-secret",
|
||||
environment_name=config.modal_environment),
|
||||
@@ -423,18 +436,20 @@ with ffmpeg_worker_image.imports():
|
||||
@modal.concurrent(max_inputs=1)
|
||||
async def ffmpeg_bgm_nosie_reduce(media: MediaSource, bgm: MediaSource, noise_sample: Optional[MediaSource] = None,
|
||||
video_volume: float = 1.4, music_volume: float = 0.1,
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None):
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None,
|
||||
webhook: Optional[WebhookNotify] = None):
|
||||
fn_id = current_function_call_id()
|
||||
|
||||
@SentryUtils.sentry_tracker(name="视频混合BGM降噪", op="ffmpeg.bgm.nosie.reduce", fn_id=fn_id,
|
||||
sentry_trace_id=sentry_trace.x_trace_id if sentry_trace else None,
|
||||
sentry_baggage=sentry_trace.x_baggage if sentry_trace else None)
|
||||
@SentryUtils.webhook_handler(webhook=webhook, func_id=fn_id)
|
||||
async def ffmpeg_process(video: MediaSource, bgm: MediaSource, func_id: str,
|
||||
noise_sample: Optional[MediaSource] = None) -> str:
|
||||
local_input_filepath = f"{s3_mount}/{video.cache_filepath}"
|
||||
bgm_filepath = f"{s3_mount}/{bgm.cache_filepath}"
|
||||
noise_sample_path = f"{s3_mount}/{noise_sample.cache_filepath}" if noise_sample else None
|
||||
output_path = f"{output_path_prefix}/bgm_nosie_reduce/outputs/{func_id}/output.mp4"
|
||||
output_path = f"{output_path_prefix}/{config.modal_environment}/bgm_nosie_reduce/outputs/{func_id}/output.mp4"
|
||||
local_output_filepath = await VideoUtils.ffmpeg_mix_bgm_with_noise_reduce(media_path=local_input_filepath,
|
||||
bgm_audio_path=bgm_filepath,
|
||||
video_volume=video_volume,
|
||||
@@ -457,7 +472,7 @@ with ffmpeg_worker_image.imports():
|
||||
@app.function(timeout=600, cloud="aws",
|
||||
max_containers=config.ffmpeg_worker_concurrency,
|
||||
volumes={
|
||||
f"/mntS3": modal.CloudBucketMount(
|
||||
s3_mount: modal.CloudBucketMount(
|
||||
bucket_name=config.S3_bucket_name,
|
||||
secret=modal.Secret.from_name("aws-s3-secret",
|
||||
environment_name=config.modal_environment),
|
||||
@@ -465,26 +480,31 @@ with ffmpeg_worker_image.imports():
|
||||
}, )
|
||||
@modal.concurrent(max_inputs=1)
|
||||
async def ffmpeg_subtitle_apply(media: MediaSource, subtitle: MediaSource,
|
||||
sentry_trace: Optional[SentryTransactionInfo] = None):
|
||||
fonts: List[MediaSource], sentry_trace: Optional[SentryTransactionInfo] = None,
|
||||
webhook: Optional[WebhookNotify] = None):
|
||||
fn_id = current_function_call_id()
|
||||
|
||||
@SentryUtils.sentry_tracker(name="视频叠加字幕", op="ffmpeg.subtitle.apply", fn_id=fn_id,
|
||||
sentry_trace_id=sentry_trace.x_trace_id if sentry_trace else None,
|
||||
sentry_baggage=sentry_trace.x_baggage if sentry_trace else None)
|
||||
async def ffmpeg_process(video: MediaSource, subtitle: MediaSource, func_id: str, font_dir: str) -> str:
|
||||
@SentryUtils.webhook_handler(webhook=webhook, func_id=fn_id)
|
||||
async def ffmpeg_process(video: MediaSource, subtitle: MediaSource,
|
||||
fonts: List[MediaSource], func_id: str) -> str:
|
||||
media_path = f"{s3_mount}/{video.cache_filepath}"
|
||||
subtitle_path = f"{s3_mount}/{subtitle.cache_filepath}"
|
||||
output_path = f"{output_path_prefix}/subtitle_apply/{func_id}/output.mp4"
|
||||
|
||||
output_path = f"{output_path_prefix}/{config.modal_environment}/subtitle_apply/{func_id}/output.mp4"
|
||||
font_dir = f"{output_path_prefix}/{config.modal_environment}/subtitle_apply/{func_id}/fonts"
|
||||
os.makedirs(font_dir, exist_ok=True)
|
||||
local_fonts = [f"{s3_mount}/{font.cache_filepath}" for font in fonts]
|
||||
for font in local_fonts:
|
||||
font_filename = os.path.basename(font)
|
||||
shutil.copy(font, f"{font_dir}/{font_filename}")
|
||||
local_output = await VideoUtils.ffmpeg_subtitle_apply(media_path=media_path, subtitle_path=subtitle_path,
|
||||
font_dir=font_dir, output_path=output_path)
|
||||
|
||||
s3_outputs = local_copy_to_s3([local_output])
|
||||
return s3_outputs[0]
|
||||
|
||||
# todo : check if subtitle use fonts exist in fonts dir
|
||||
font_dir = f"{s3_mount}/fonts"
|
||||
result = await ffmpeg_process(video=media, subtitle=subtitle, func_id=fn_id, font_dir=font_dir)
|
||||
result = await ffmpeg_process(video=media, subtitle=subtitle, fonts=fonts, func_id=fn_id)
|
||||
if not sentry_trace:
|
||||
sentry_trace = SentryTransactionInfo(x_trace_id=sentry_sdk.get_traceparent(),
|
||||
x_baggage=sentry_sdk.get_baggage())
|
||||
|
||||
Reference in New Issue
Block a user