parent
c87232512b
commit
e5029a7922
|
|
@ -1,4 +1,4 @@
|
|||
MODAL_ENVIRONMENT=dev
|
||||
MODAL_ENVIRONMENT=test
|
||||
modal_app_name=bowong-ai-video
|
||||
S3_mount_dir=/mntS3
|
||||
S3_bucket_name=modal-media-cache
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from typing import Union, Any
|
||||
from pydantic import BaseModel, Field, computed_field, field_validator
|
||||
from pydantic import BaseModel, Field, computed_field, field_validator, model_validator
|
||||
from pydantic.json_schema import JsonSchemaValue
|
||||
from ..utils.TimeUtils import TimeDelta
|
||||
|
||||
|
|
@ -43,6 +43,12 @@ class FFMpegSliceSegment(BaseModel):
|
|||
else:
|
||||
raise TypeError(v)
|
||||
|
||||
@model_validator(mode='after')
|
||||
def validate_end_after_start(self) -> 'FFMpegSliceSegment':
|
||||
if self.end <= self.start:
|
||||
raise ValueError("end time must be greater than start time")
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_json_schema__(cls, core_schema: Any, handler: Any) -> JsonSchemaValue:
|
||||
# Override the schema to represent it as a string
|
||||
|
|
|
|||
|
|
@ -201,7 +201,14 @@ class MediaSources(BaseModel):
|
|||
@classmethod
|
||||
def parse_inputs(cls, v: Union[str, MediaSource]) -> List[MediaSource]:
|
||||
if not v:
|
||||
raise ValidationError("inputs为空")
|
||||
raise ValidationError([
|
||||
{
|
||||
'loc': ('inputs',),
|
||||
'msg': "inputs为空",
|
||||
'type': 'value_error',
|
||||
'input': v
|
||||
}
|
||||
], MediaSources)
|
||||
result = []
|
||||
for item in v:
|
||||
if isinstance(item, str):
|
||||
|
|
@ -209,7 +216,14 @@ class MediaSources(BaseModel):
|
|||
elif isinstance(item, MediaSource):
|
||||
result.append(item)
|
||||
else:
|
||||
raise ValidationError("inputs元素类型错误: 必须是字符串")
|
||||
raise ValidationError([
|
||||
{
|
||||
'loc': ('inputs',),
|
||||
'msg': "inputs元素类型错误: 必须是字符串",
|
||||
'type': 'value_error',
|
||||
'input': v
|
||||
}
|
||||
], MediaSources)
|
||||
return result
|
||||
|
||||
model_config = {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class SentryUtils:
|
|||
op=op,
|
||||
name=name)
|
||||
else:
|
||||
transaction = sentry_sdk.start_transaction(op='modal.function', name='Modal Function直接调用')
|
||||
transaction = sentry_sdk.start_transaction(op=op, name=name)
|
||||
with transaction:
|
||||
with transaction.start_child(op=op, name=name) as span:
|
||||
cpu_freq, cpu_count, mem = SentryUtils.capture_hardware_info()
|
||||
|
|
@ -43,23 +43,18 @@ class SentryUtils:
|
|||
'x_trace.id': sentry_trace_id,
|
||||
'x_trace.baggage': sentry_baggage,
|
||||
'cpu.count': cpu_count,
|
||||
'cpu.frequency': cpu_freq.current / 1000,
|
||||
'cpu.frequency': f"{cpu_freq.current / 1000:.2f}",
|
||||
'cpu.frequency.format': f"{cpu_freq.current / 1000:.2f} GHz",
|
||||
'memory.available': total_mb,
|
||||
'memory.available.format': f"{total_mb} Mb",
|
||||
'cloud_resource': {
|
||||
"cloud.provider": 'Modal',
|
||||
"type": "cloud_resource"
|
||||
},
|
||||
'modal': {
|
||||
'modal.region': os.environ.get('MODAL_REGION', 'unknown'),
|
||||
'modal.provider': os.environ.get('MODAL_CLOUD_PROVIDER', 'unknown'),
|
||||
'modal.task.id': os.environ.get('MODAL_TASK_ID', 'unknown'),
|
||||
'modal.identity.token': os.environ.get('MODAL_IDENTITY_TOKEN', 'unknown'),
|
||||
'modal.image.id': os.environ.get('MODAL_IMAGE_ID', 'unknown'),
|
||||
}
|
||||
'modal.cloud.region': os.environ.get('MODAL_REGION', 'unknown'),
|
||||
'modal.cloud.provider': os.environ.get('MODAL_CLOUD_PROVIDER', 'unknown'),
|
||||
'modal.task.id': os.environ.get('MODAL_TASK_ID', 'unknown'),
|
||||
'modal.identity.token': os.environ.get('MODAL_IDENTITY_TOKEN', 'unknown'),
|
||||
'modal.image.id': os.environ.get('MODAL_IMAGE_ID', 'unknown'),
|
||||
})
|
||||
result = func(*args, **kwargs)
|
||||
span.set_status('ok')
|
||||
return result
|
||||
|
||||
return wrapper
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ with ffmpeg_worker_image.imports():
|
|||
List[str], Optional[SentryTransactionInfo]]:
|
||||
fn_id = current_function_call_id()
|
||||
|
||||
@SentryUtils.sentry_tracker(name="视频切割任务", op="ffmpeg.slice", fn_id=fn_id,
|
||||
@SentryUtils.sentry_tracker(name="视频文件切割任务", op="ffmpeg.slice.media", 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)
|
||||
|
|
@ -164,15 +164,15 @@ with ffmpeg_worker_image.imports():
|
|||
fn_id: str) -> List[FFMPEGResult]:
|
||||
cache_filepath = f"{s3_mount}/{media_source.cache_filepath}"
|
||||
logger.info(f"从{media_source.urn}切割")
|
||||
for marker in media_markers:
|
||||
logger.info(f"{marker.start.toFormatStr()} --> {marker.end.toFormatStr()}")
|
||||
for i, marker in enumerate(media_markers):
|
||||
logger.info(f"[{i}] {marker.start.toFormatStr()} --> {marker.end.toFormatStr()}")
|
||||
segments = await VideoUtils.ffmpeg_slice_media(media_path=cache_filepath,
|
||||
media_markers=media_markers,
|
||||
output_path=f"{output_path_prefix}/{config.modal_environment}/slice/outputs/{fn_id}/output.mp4")
|
||||
return [FFMPEGResult(urn=local_copy_to_s3([segment[0]])[0], metadata=segment[1],
|
||||
content_length=os.path.getsize(segment[0])) for segment in segments]
|
||||
|
||||
@SentryUtils.sentry_tracker(name="视频切割任务", op="ffmpeg.slice", fn_id=fn_id,
|
||||
@SentryUtils.sentry_tracker(name="直播视频切割任务", op="ffmpeg.slice.stream", 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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue