This commit is contained in:
2025-09-02 06:55:13 +08:00
parent 4078acb909
commit 1b959b3ba9
11 changed files with 1106 additions and 74 deletions

View File

@@ -1,73 +0,0 @@
#coding=utf-8
'''
requires Python 3.6 or later
pip install requests
'''
import base64
import json
import uuid
import requests
from Config.Config import HS_APP_ID, HS_ACCESS_TOKEN, HS_CLUSTER_ID, HS_VOICE_TYPE_QINCANG
# 填写平台申请的appid, access_token以及cluster
appid = HS_APP_ID
access_token= HS_ACCESS_TOKEN
cluster = HS_CLUSTER_ID
voice_type = HS_VOICE_TYPE_QINCANG
host = "openspeech.bytedance.com"
api_url = f"https://{host}/api/v1/tts"
header = {"Authorization": f"Bearer;{access_token}"}
request_json = {
"app": {
"appid": appid,
"token": "access_token",
"cluster": cluster
},
"user": {
"uid": "388808087185088"
},
"audio": {
"voice_type": voice_type,
"encoding": "mp3",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0,
},
"request": {
"reqid": str(uuid.uuid4()),
"text": """
君不见,黄河之水天上来,奔流到海不复回。
君不见,高堂明镜悲白发,朝如青丝暮成雪。
人生得意须尽欢,莫使金樽空对月。
天生我材必有用,千金散尽还复来。
烹羊宰牛且为乐,会须一饮三百杯。
岑夫子,丹丘生,将进酒,杯莫停。
与君歌一曲,请君为我倾耳听。
钟鼓馔玉不足贵,但愿长醉不复醒。
古来圣贤皆寂寞,惟有饮者留其名。
陈王昔时宴平乐,斗酒十千恣欢谑。
主人何为言少钱,径须沽取对君酌。
五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。
""",
"text_type": "plain",
"operation": "query",
"with_frontend": 1,
"frontend_type": "unitTson"
}
}
if __name__ == '__main__':
try:
resp = requests.post(api_url, json.dumps(request_json), headers=header)
#print(f"resp body: \n{resp.json()}")
if "data" in resp.json():
data = resp.json()["data"]
file_to_save = open("test_submit.mp3", "wb")
file_to_save.write(base64.b64decode(data))
except Exception as e:
e.with_traceback()

View File

@@ -1,211 +0,0 @@
import requests
import time
from typing import Dict, Optional
from Config import Config
class VideoRetalk:
"""
阿里云DashScope LivePortrait视频生成类
videoretalk是一个人物视频生成模型可基于人物视频和人声音频生成人物讲话口型与输入音频相匹配的新视频。
视频口型替换-声动人像VideoRetalk
实现图像和音频合成视频功能
"""
def __init__(self, api_key: str):
"""
初始化视频生成类
Args:
api_key: 阿里云DashScope API密钥
"""
self.api_key = api_key
self.base_url = "https://dashscope.aliyuncs.com/api/v1"
self.video_synthesis_url = f"{self.base_url}/services/aigc/image2video/video-synthesis"
def submit_video_task(self, image_url: str, audio_url: str,
template_id: str = "normal",
eye_move_freq: float = 0.5,
video_fps: int = 30,
mouth_move_strength: float = 1.0,
paste_back: bool = True,
head_move_strength: float = 0.7) -> Dict:
"""
提交视频生成任务
Args:
image_url: 输入图片URL
audio_url: 输入音频URL
template_id: 模板ID默认为"normal"
eye_move_freq: 眼睛移动频率默认0.5
video_fps: 视频帧率默认30
mouth_move_strength: 嘴巴移动强度默认1.0
paste_back: 是否粘贴背景默认True
head_move_strength: 头部移动强度默认0.7
Returns:
Dict: 包含task_id和task_status的响应数据
"""
headers = {
'X-DashScope-Async': 'enable',
'Authorization': f'Bearer {self.api_key}',
'Content-Type': 'application/json'
}
payload = {
"model": "liveportrait",
"input": {
"image_url": image_url,
"audio_url": audio_url
},
"parameters": {
"template_id": template_id,
"eye_move_freq": eye_move_freq,
"video_fps": video_fps,
"mouth_move_strength": mouth_move_strength,
"paste_back": paste_back,
"head_move_strength": head_move_strength
}
}
try:
response = requests.post(self.video_synthesis_url,
headers=headers,
json=payload)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
raise Exception(f"提交视频任务失败: {e}")
def get_task_status(self, task_id: str) -> Dict:
"""
查询任务状态
Args:
task_id: 任务ID
Returns:
Dict: 任务状态信息
"""
headers = {
'Authorization': f'Bearer {self.api_key}'
}
task_url = f"{self.base_url}/tasks/{task_id}"
try:
response = requests.get(task_url, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
raise Exception(f"查询任务状态失败: {e}")
def wait_for_task_completion(self, task_id: str,
poll_interval: int = 5,
timeout: int = 300) -> Dict:
"""
等待任务完成
Args:
task_id: 任务ID
poll_interval: 轮询间隔(秒)默认5秒
timeout: 超时时间(秒)默认300秒
Returns:
Dict: 任务完成后的结果
"""
start_time = time.time()
while time.time() - start_time < timeout:
task_status = self.get_task_status(task_id)
status = task_status.get('output', {}).get('task_status')
if status == 'SUCCEEDED':
return task_status
elif status == 'FAILED':
error_code = task_status.get('output', {}).get('code', '未知错误')
error_message = task_status.get('output', {}).get('message', '无错误信息')
raise Exception(f"任务执行失败: {error_code} - {error_message}")
elif status in ['PENDING', 'RUNNING']:
print(f"任务状态: {status}, 等待中...")
time.sleep(poll_interval)
else:
raise Exception(f"未知的任务状态: {status}")
raise Exception(f"任务超时,未在{timeout}秒内完成")
def generate_video(self, image_url: str, audio_url: str,
**kwargs) -> Optional[str]:
"""
生成视频的完整流程
Args:
image_url: 输入图片URL
audio_url: 输入音频URL
**kwargs: 其他参数同submit_video_task
Returns:
str: 生成的视频URL失败返回None
"""
try:
# 提交任务
submit_response = self.submit_video_task(image_url, audio_url, **kwargs)
task_id = submit_response.get('output', {}).get('task_id')
if not task_id:
print("提交任务失败未获取到task_id")
return None
print(f"任务已提交task_id: {task_id}")
# 等待任务完成
result = self.wait_for_task_completion(task_id)
# 获取视频URL
video_url = result.get('output', {}).get('results', {}).get('video_url')
if video_url:
print(f"视频生成成功: {video_url}")
# 获取使用情况信息
usage = result.get('usage', {})
if usage:
print(f"视频时长: {usage.get('video_duration')}")
print(f"视频比例: {usage.get('video_ratio')}")
return video_url
else:
print("未找到生成的视频URL")
return None
except Exception as e:
print(f"视频生成失败: {e}")
return None
# 使用示例
if __name__ == "__main__":
# 替换为您的实际API密钥
API_KEY = Config.ALY_LLM_API_KEY
# 创建视频生成实例
video_retalk = VideoRetalk(API_KEY)
# 示例:生成视频
try:
video_url = video_retalk.generate_video(
image_url="https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Backup/LiBai.jpg",
audio_url="https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Backup/JiangJinJiu.mp3",
template_id="normal",
eye_move_freq=0.5,
video_fps=30,
mouth_move_strength=1.0,
paste_back=True,
head_move_strength=0.7
)
if video_url:
print(f"最终视频URL: {video_url}")
except Exception as e:
print(f"执行过程中发生错误: {e}")