diff --git a/demo/ci_image.py b/demo/ci_image.py index 4b4f093..8f8eadf 100644 --- a/demo/ci_image.py +++ b/demo/ci_image.py @@ -625,6 +625,63 @@ def ci_super_resolution_process(): response['Body'].get_stream_to_file('super-resolution-result.jpg') +def add_aigc_metadata_when_put_object(): + # 图片AIGC元数据添加 + label = base64.b64encode('label'.encode('utf-8')).decode('utf-8') + content_producer = base64.b64encode('contentProducer'.encode('utf-8')).decode('utf-8') + produce_id = base64.b64encode('produceId'.encode('utf-8')).decode('utf-8') + reserved_code1 = base64.b64encode('reservedCode1'.encode('utf-8')).decode('utf-8') + reserved_code2 = base64.b64encode('reservedCode2'.encode('utf-8')).decode('utf-8') + content_propagator = base64.b64encode('contentPropagator'.encode('utf-8')).decode('utf-8') + propagate_id = base64.b64encode('propagateID'.encode('utf-8')).decode('utf-8') + + rule=('imageMogr2/AIGCMetadata/Label/' + label + + '/ContentProducer/' + content_producer + + '/ProduceID/' + produce_id + + '/ReservedCode1/' + reserved_code1 + + '/ReservedCode2/' + reserved_code2 + + '/PropagateID/' + propagate_id + + '/ContentPropagator/' + content_propagator) + + operations = '{"is_pic_info":1,"rules":[{"fileid": "aigc-result.png",' \ + '"rule": "' + rule + '" }]}' + when_put_object('format.png', "aigc.png", operations) + + +def add_aigc_metadata_process_on_cloud(): + # 图片AIGC元数据添加 + label = base64.b64encode('label'.encode('utf-8')).decode('utf-8') + content_producer = base64.b64encode('contentProducer'.encode('utf-8')).decode('utf-8') + produce_id = base64.b64encode('produceId'.encode('utf-8')).decode('utf-8') + reserved_code1 = base64.b64encode('reservedCode1'.encode('utf-8')).decode('utf-8') + reserved_code2 = base64.b64encode('reservedCode2'.encode('utf-8')).decode('utf-8') + content_propagator = base64.b64encode('contentPropagator'.encode('utf-8')).decode('utf-8') + propagate_id = base64.b64encode('propagateID'.encode('utf-8')).decode('utf-8') + + rule=('imageMogr2/AIGCMetadata/Label/' + label + + '/ContentProducer/' + content_producer + + '/ProduceID/' + produce_id + + '/ReservedCode1/' + reserved_code1 + + '/ReservedCode2/' + reserved_code2 + + '/PropagateID/' + propagate_id + + '/ContentPropagator/' + content_propagator) + + operations = '{"is_pic_info":1,"rules":[{"fileid": "aigc-result.png",' \ + '"rule": "' + rule + '" }]}' + process_on_cloud('aigc.png', operations) + + +def get_image_aigc_metadata(): + # 查询图片中保存的AIGC元数据标识信息 + response, data = client.ci_get_image_aigc_metadata( + Bucket=bucket_name, + Key='aigc.png' + ) + print(response) + print(data) + return response, data + + if __name__ == '__main__': # format.png # thumbnail_when_put_object() @@ -694,4 +751,7 @@ def ci_super_resolution_process(): # ci_image_detect_label() # ci_recognize_logo_process() # ci_image_inspect() - ci_super_resolution_process() + # ci_super_resolution_process() + # add_aigc_metadata_when_put_object() + # add_aigc_metadata_process_on_cloud() + get_image_aigc_metadata() diff --git a/demo/ci_media.py b/demo/ci_media.py index 608e1e1..b7e8e7f 100644 --- a/demo/ci_media.py +++ b/demo/ci_media.py @@ -1,4 +1,5 @@ # -*- coding=utf-8 +import base64 import time from qcloud_cos import CosConfig @@ -374,6 +375,69 @@ def ci_create_media_transcode_jobs(): return response +def ci_create_media_transcode_jobs_with_aigc_metadata(): + # 创建转码任务(包含aigc metadata信息) + body = { + 'Input': { + 'Object': 'demo.mp4' + }, + 'Tag': 'Transcode', + 'Operation': { + "Transcode": { + "Container": { + "Format": "mp4" + }, + "Video": { + "Codec": "H.264", + }, + "Audio": { + "Codec": "aac", + }, + "TransConfig": { + # aigc元数据信息配置 + # 非必选 + 'AIGCMetadata': { + # 生成合成标签要素,用于表示视频属于、可能、疑似为人工智能生成合成的属性信息 + # 必选 + 'Label': 'label', + # 生成合成服务提供者要素,内容为视频生成合成服务提供者的名称或编码 + # 必选 + 'ContentProducer': 'testProducer', + # 内容制作编号要素,内容为视频生成合成服务提供者对该内容的唯一编号 + # 必选 + 'ProduceID': 'testProduceId', + # 预留字段1,内容为用户自主开展安全防护,保护内容、标识完整性的信息,需经过 Base64 编码后传入 + # 非必选 + 'ReservedCode1': 'e1wibmFtZVwiOlwidGVzdE5hbWVcIn0=', + # 预留字段2,内容为用户自主开展安全防护,保护内容、标识完整性的信息,需经过 Base64 编码后传入 + # 非必选 + 'ReservedCode2': 'e1wibmFtZVwiOlwidGVzdE5hbWVcIn0=', + # 内容传播服务提供者要素,内容为视频传播服务提供者的名称或编码 + # 非必选 + 'ContentPropagator': 'contentPropagator', + # 内容传播编号要素,内容为视频传播服务提供者对该视频的唯一编号 + # 非必选 + 'PropagateID': 'propagateID' + }, + }, + }, + 'Output': { + 'Bucket': bucket_name, + 'Region': region, + 'Object': 'transcode_with_aigc_metadata_output.mp4' + }, + } + } + response = client.ci_create_media_jobs( + Bucket=bucket_name, + Jobs=body, + Lst={}, + ContentType='application/xml' + ) + print(response) + return response + + def ci_create_media_snapshot_jobs(): # 创建截图任务 body = { @@ -857,6 +921,59 @@ def ci_create_media_segment_jobs(): return response +def ci_create_media_segment_with_aigc_metadata_jobs(): + # 创建转封装任务(包含aigc metadata) + body = { + 'Input': { + 'Object': 'demo.mp4' + }, + 'Tag': 'Segment', + 'Operation': { + "Segment": { + "Format": "mp4", + # aigc元数据信息配置 + # 非必选 + 'AIGCMetadata': { + # 生成合成标签要素,用于表示视频属于、可能、疑似为人工智能生成合成的属性信息 + # 必选 + 'Label': 'label', + # 生成合成服务提供者要素,内容为视频生成合成服务提供者的名称或编码 + # 必选 + 'ContentProducer': 'testProducer', + # 内容制作编号要素,内容为视频生成合成服务提供者对该内容的唯一编号 + # 必选 + 'ProduceID': 'testProduceId', + # 预留字段1,内容为用户自主开展安全防护,保护内容、标识完整性的信息,需经过 Base64 编码后传入 + # 非必选 + 'ReservedCode1': 'e1wibmFtZVwiOlwidGVzdE5hbWVcIn0=', + # 预留字段2,内容为用户自主开展安全防护,保护内容、标识完整性的信息,需经过 Base64 编码后传入 + # 非必选 + 'ReservedCode2': 'e1wibmFtZVwiOlwidGVzdE5hbWVcIn0=', + # 内容传播服务提供者要素,内容为视频传播服务提供者的名称或编码 + # 非必选 + 'ContentPropagator': 'contentPropagator', + # 内容传播编号要素,内容为视频传播服务提供者对该视频的唯一编号 + # 非必选 + 'PropagateID': 'propagateID' + }, + }, + 'Output': { + 'Bucket': bucket_name, + 'Region': region, + 'Object': 'segment-output-with-aigc-metadata.mp4' + }, + }, + } + response = client.ci_create_media_jobs( + Bucket=bucket_name, + Jobs=body, + Lst={}, + ContentType='application/xml' + ) + print(response) + return response + + def ci_create_multi_jobs(): # 创建多任务 body = { @@ -948,6 +1065,51 @@ def ci_create_media_pic_jobs(): return response +def ci_create_media_pic_with_aigc_metadata_jobs(): + # 创建图片处理任务(包含aigc元数据信息) + label = base64.b64encode('label'.encode('utf-8')).decode('utf-8') + content_producer = base64.b64encode('contentProducer'.encode('utf-8')).decode('utf-8') + produce_id = base64.b64encode('produceId'.encode('utf-8')).decode('utf-8') + reserved_code1 = base64.b64encode('reservedCode1'.encode('utf-8')).decode('utf-8') + reserved_code2 = base64.b64encode('reservedCode2'.encode('utf-8')).decode('utf-8') + content_propagator = base64.b64encode('contentPropagator'.encode('utf-8')).decode('utf-8') + propagate_id = base64.b64encode('propagateID'.encode('utf-8')).decode('utf-8') + + rule = ('imageMogr2/AIGCMetadata/Label/' + label + + '/ContentProducer/' + content_producer + + '/ProduceID/' + produce_id + + '/ReservedCode1/' + reserved_code1 + + '/ReservedCode2/' + reserved_code2 + + '/PropagateID/' + propagate_id + + '/ContentPropagator/' + content_propagator) + + body = { + 'Input': { + 'Object': 'test.png' + }, + 'Tag': 'PicProcess', + 'Operation': { + "PicProcess": { + "IsPicInfo": "true", + "ProcessRule": rule, + }, + 'Output': { + 'Bucket': bucket_name, + 'Region': region, + 'Object': 'pic-process-with-aigc-metadata-result.png' + }, + } + } + response = client.ci_create_media_pic_jobs( + Bucket=bucket_name, + Jobs=body, + Lst={}, + ContentType='application/xml' + ) + print(response) + return response + + def ci_list_media_transcode_jobs(): # 转码任务列表 response = client.ci_list_media_jobs( @@ -1007,6 +1169,17 @@ def get_media_info(): print(response) +def get_media_aigc_metadata(): + # 查询音视频中保存的AIGC元数据标识信息接口 + response, data = client.ci_get_media_aigc_metadata( + Bucket=bucket_name, + Key='demo.mp4' + ) + print(response) + print(data) + return response, data + + def get_snapshot(): # 产生同步截图 response = client.get_snapshot( @@ -1234,6 +1407,148 @@ def ci_cancel_jobs(): return response +def ci_create_workflow_segment_with_aigc_metadata(): + # 创建转封装工作流(包含aigc元数据信息) + + # 工作流配置详情 + body = { + # 工作流节点 固定值传入即可 + 'MediaWorkflow': { + # 创建的工作流名称,可自定义输入名称 + # 支持中文、英文、数字、—和_,长度限制128字符 + # 必传参数 + 'Name': 'segment-with-aigc', + # 工作流状态,表示创建时是否开启COS上传对象事件通知 + # 支持 Active / Paused + # 非必选,默认Paused 不开启 + 'State': 'Paused', + # 工作流拓扑结构 + # 必传参数 + 'Topology': { + # 工作流节点依赖关系 + # 必传参数 + 'Dependencies': { + # Start 工作流开始节点,用于存储工作流回调,前缀,后缀等配置信息,只有一个开始节点 + # End 工作流结束节点 + # SegmentNode 转封装节点信息 + # 此示例表示 Start -> SegmentNode -> End 的依赖关系 + 'Start': 'SegmentNode', + 'SegmentNode': 'End', + }, + # 工作流各节点的详细配置信息 + # 必传参数 + 'Nodes': { + # 工作流开始节点配置信息 + 'Start': { + # 节点类型,开始节点固定为 Start + # 必传参数 + 'Type': 'Start', + # 工作流的输入信息 + # 必传参数 + 'Input': { + # Object 前缀,COS上传对象的前缀,只有当前缀匹配时,才会触发该工作流 + # 如该示例,会触发根目录下的对象 + # 必传参数 + 'ObjectPrefix': '/', + # 工作流自定义回调配置信息,当配置了该项后,当工作流执行完成或工作流中的子节点中的任务执行完成,会发送回调给指定Url或tdmq + # 非必传配置 + 'NotifyConfig': { + # 回调类型,支持Url TDMQ两种类型 + 'Type': 'Url', + # 回调地址,当回调类型为Url时有效 + 'Url': 'http://www.callback.com', + # 回调事件 支持多种事件,以逗号分割 + 'Event': 'WorkflowFinish,TaskFinish', + # 回调信息格式,支持XML JSON两种格式,非必传,默认为XML + 'ResultFormat': '', + # TDMQ 所属园区,当回调类型为TDMQ时有效,支持园区详见https://cloud.tencent.com/document/product/406/12667 + 'MqRegion': '', + # TDMQ 使用模式,当回调类型为TDMQ时有效 + # Topic:主题订阅 + # Queue:队列服务 + 'MqMode': '', + # TDMQ 主题名称,当回调类型为TDMQ时有效 + 'MqName': '', + }, + # 文件后缀过滤器,当需要只处理部分后缀文件时,可配置此项 + # 非必传配置 + 'ExtFilter': { + # 是否开始后缀过滤,On/Off,非必选,默认为Off + 'State': 'On', + # 打开视频后缀限制,false/true,非必选,默认为false + 'Video': 'true', + # 打开音频后缀限制,false/true,非必选,默认为false + 'Audio': '', + # 打开图片后缀限制,false/true,非必选,默认为false + 'Image': '', + # 打开 ContentType 限制,false/true,非必选,默认为false + 'ContentType': '', + # 打开自定义后缀限制,false/true,非必选,默认为false + 'Custom': '', + # 自定义后缀,当Custom为true时有效,多种文件后缀以/分隔,后缀个数不超过10个 + 'CustomExts': '', + # 所有文件,false/true,非必选,默认为false + 'AllFile': '', + }, + } + }, + # 转封装节点配置信息 + 'SegmentNode': { + # 节点类型,转封装固定为Segment + 'Type': 'Segment', + # 节点执行操作集合 + # 非必选配置 + 'Operation': { + # 转封装配置详情 + 'Segment': { + "Format": "mp4", + # aigc元数据信息配置 + # 非必选 + 'AIGCMetadata': { + # 生成合成标签要素,用于表示视频属于、可能、疑似为人工智能生成合成的属性信息 + # 必选 + 'Label': 'label', + # 生成合成服务提供者要素,内容为视频生成合成服务提供者的名称或编码 + # 必选 + 'ContentProducer': 'testProducer', + # 内容制作编号要素,内容为视频生成合成服务提供者对该内容的唯一编号 + # 必选 + 'ProduceID': 'testProduceId', + # 预留字段1,内容为用户自主开展安全防护,保护内容、标识完整性的信息,需经过 Base64 编码后传入 + # 非必选 + 'ReservedCode1': 'e1wibmFtZVwiOlwidGVzdE5hbWVcIn0=', + # 预留字段2,内容为用户自主开展安全防护,保护内容、标识完整性的信息,需经过 Base64 编码后传入 + # 非必选 + 'ReservedCode2': 'e1wibmFtZVwiOlwidGVzdE5hbWVcIn0=', + # 内容传播服务提供者要素,内容为视频传播服务提供者的名称或编码 + # 非必选 + 'ContentPropagator': 'contentPropagator', + # 内容传播编号要素,内容为视频传播服务提供者对该视频的唯一编号 + # 非必选 + 'PropagateID': 'propagateID' + }, + }, + 'Output': { + 'Bucket': bucket_name, + 'Region': region, + 'Object': 'segment-with-aigc-metadata-workflow.mp4' + }, + } + }, + }, + }, + }, + } + response = client.ci_create_workflow( + Bucket=bucket_name, # 桶名称 + Body=body, # 工作流配置信息 + ContentType='application/xml', + Accept="application/xml" + ) + print(response) + return response + + def ci_create_workflow_image_inspect(): # 创建异常图片检测工作流 @@ -2004,4 +2319,10 @@ def ci_update_hls_play_key(): # ci_create_words_generalize_jobs() # ci_get_presigned_download_url() # ci_update_hls_play_key() - ci_get_hls_play_key() + # ci_get_hls_play_key() + # ci_create_media_transcode_jobs_with_aigc_metadata() + # ci_create_media_segment_with_aigc_metadata_jobs() + # ci_create_workflow_segment_with_aigc_metadata() + # ci_create_media_pic_with_aigc_metadata_jobs() + get_media_aigc_metadata() + diff --git a/demo/ci_template.py b/demo/ci_template.py index 007614e..0bc05cc 100644 --- a/demo/ci_template.py +++ b/demo/ci_template.py @@ -410,6 +410,31 @@ def ci_update_snapshot_template(): # 非必选 'UriKey': '' }, + # aigc元数据信息配置 + # 非必选 + 'AIGCMetadata': { + # 生成合成标签要素,用于表示视频属于、可能、疑似为人工智能生成合成的属性信息 + # 必选 + 'Label': 'label', + # 生成合成服务提供者要素,内容为视频生成合成服务提供者的名称或编码 + # 必选 + 'ContentProducer': 'testProducer', + # 内容制作编号要素,内容为视频生成合成服务提供者对该内容的唯一编号 + # 必选 + 'ProduceID': 'testProduceId', + # 预留字段1,内容为用户自主开展安全防护,保护内容、标识完整性的信息,需经过 Base64 编码后传入 + # 非必选 + 'ReservedCode1': 'e1wibmFtZVwiOlwidGVzdE5hbWVcIn0=', + # 预留字段2,内容为用户自主开展安全防护,保护内容、标识完整性的信息,需经过 Base64 编码后传入 + # 非必选 + 'ReservedCode2': 'e1wibmFtZVwiOlwidGVzdE5hbWVcIn0=', + # 内容传播服务提供者要素,内容为视频传播服务提供者的名称或编码 + # 非必选 + 'ContentPropagator': 'contentPropagator', + # 内容传播编号要素,内容为视频传播服务提供者对该视频的唯一编号 + # 非必选 + 'PropagateID': 'propagateID' + }, }, # 混音参数 # 非必选 @@ -1313,9 +1338,30 @@ def ci_update_voice_separate_template(): }, } +pic_process_template_aigc_metadata_config = { + # 模板名称,仅支持中文、英文、数字、_、-和*,长度不超过 64 + # 必选 + 'Name': 'pic_process_template', + # 模板类型:图片处理模板固定值为 PicProcess + # 必选 + 'Tag': 'PicProcess', + # 图片处理信息 + # 必选 + 'PicProcess': { + # 是否返回原图信息 + # 取值 true/false + # 非必选 默认 false + 'IsPicInfo': 'false', + # 图片处理规则 + # 详见 https://cloud.tencent.com/document/product/436/44879 + # 必选 + 'ProcessRule': 'imageMogr2/AIGCMetadata/Label/bGFiZWw/ContentProducer/Q29udGVudFByb2R1Y2Vy/ProduceID/UHJvZHVjZUlE/ReservedCode1/UmVzZXJ2ZWRDb2RlMQ/ContentPropagator/Q29udGVudFByb3BhZ2F0b3I', + }, +} + def ci_create_pic_process_template(): - # 创建人声分离模板 + # 创建图片处理模板 response = client.ci_create_template( Bucket=bucket_name, Template=pic_process_template_config, @@ -1481,7 +1527,7 @@ def ci_update_watermark_template(): def ci_get_template(): - # 更新人声分离模板 + # 查询模板 response = client.ci_get_template( Bucket=bucket_name, ) diff --git a/qcloud_cos/cos_client.py b/qcloud_cos/cos_client.py index 0b0a0b8..b220180 100644 --- a/qcloud_cos/cos_client.py +++ b/qcloud_cos/cos_client.py @@ -5806,6 +5806,30 @@ def ci_image_inspect(self, Bucket, Key, **kwargs): data = rt.content return response, data + def ci_get_image_aigc_metadata(self, Bucket, Key, **kwargs): + """ci_get_image_aigc_metadata查询图片中保存的AIGC元数据标识信息接口 + + :param Bucket(string): 存储桶名称. + :param Key(string): COS路径. + :param kwargs(dict): 设置下载的headers. + :return(dict): response header. + :return(dict): AIGC元数据标识信息结果,dict类型. + + .. code-block:: python + + config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key, Token=token) # 获取配置对象 + client = CosS3Client(config) + response, data = client.ci_get_image_aigc_metadata( + Bucket='bucket', + ObjectKey='' + ) + print data + print response + """ + + path = "/" + Key + return self.ci_process(Bucket, path, "ImageAIGCMetadata", NeedHeader=True, **kwargs) + def ci_put_object_from_local_file_and_get_qrcode(self, Bucket, LocalFilePath, Key, EnableMD5=False, **kwargs): """本地CI文件上传接口并返回二维码,适用于小文件,最大不得超过5GB @@ -8446,6 +8470,30 @@ def get_pm3u8(self, Bucket, Key, Expires, **kwargs): return response + def ci_get_media_aigc_metadata(self, Bucket, Key, **kwargs): + """ci_get_media_aigc_metadata查询音视频中保存的AIGC元数据标识信息接口 + + :param Bucket(string): 存储桶名称. + :param Key(string): COS路径. + :param kwargs(dict): 设置下载的headers. + :return(dict): response header. + :return(dict): AIGC元数据标识信息结果,dict类型. + + .. code-block:: python + + config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key, Token=token) # 获取配置对象 + client = CosS3Client(config) + response, data = client.ci_get_media_aigc_metadata( + Bucket='bucket', + ObjectKey='', + ) + print data + print response + """ + + path = "/" + Key + return self.ci_process(Bucket, path, "MediaAIGCMetadata", NeedHeader=True, **kwargs) + def ci_get_doc_queue(self, Bucket, State='All', QueueIds='', PageNumber=1, PageSize=10, **kwargs): """查询文档转码处理队列接口 https://cloud.tencent.com/document/product/460/46946 diff --git a/ut/test.py b/ut/test.py index 975f77a..82e8121 100644 --- a/ut/test.py +++ b/ut/test.py @@ -5967,6 +5967,38 @@ def test_ci_hls_play_key(): assert data['PlayKeyList']['BackupPlayKey'] == '128d75fd2b6b4f958ccbb6fc38f60f04' +def test_get_media_aigc_metadata(): + if TEST_CI != 'true': + return + # 获取音视频aigc元数据信息 + try: + kwargs = {"CacheControl": "no-cache", "ResponseCacheControl": "no-cache"} + response = client.ci_get_media_aigc_metadata( + Bucket=ci_bucket_name, + Key=ci_test_media, + **kwargs + ) + assert response + except Exception: + pass + + +def test_get_image_aigc_metadata(): + if TEST_CI != 'true': + return + # 获取图片aigc元数据信息 + try: + kwargs = {"CacheControl": "no-cache", "ResponseCacheControl": "no-cache"} + response = client.ci_get_image_aigc_metadata( + Bucket=ci_bucket_name, + Key=ci_test_image + '.aigc.png', + **kwargs + ) + assert response + except Exception: + pass + + def test_ci_asr_bucket(): # 关闭智能语音服务 kwargs = {"CacheControl": "no-cache", "ResponseCacheControl": "no-cache"}