mirror of
https://github.com/linyqh/NarratoAI.git
synced 2025-12-11 02:12:50 +00:00
Merge pull request #181 from linyqh/dev072
新增大模型代理,新增腾讯tts,优化 gemini 请求
This commit is contained in:
commit
b8013ee468
5
.gitignore
vendored
5
.gitignore
vendored
@ -36,4 +36,7 @@ app/models/faster-whisper-large-v3/*
|
||||
app/models/bert/*
|
||||
|
||||
bug清单.md
|
||||
task.md
|
||||
task.md
|
||||
.claude/*
|
||||
.serena/*
|
||||
CLAUDE.md
|
||||
98
README.md
98
README.md
@ -25,16 +25,13 @@ NarratoAI 是一个自动化影视解说工具,基于LLM实现文案撰写、
|
||||
|
||||

|
||||
|
||||
<h3>视频审查界面</h3>
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## 许可证
|
||||
本项目仅供学习和研究使用,不得商用。如需商业授权,请联系作者。
|
||||
|
||||
## 最新资讯
|
||||
- 2025.08.18 发布新版本 0.7.1,支持 **语音克隆** 和 最新大模型
|
||||
- 2025.05.11 发布新版本 0.6.0,支持 **短剧解说** 和 优化剪辑流程
|
||||
- 2025.03.06 发布新版本 0.5.2,支持 DeepSeek R1 和 DeepSeek V3 模型进行短剧混剪
|
||||
- 2024.12.16 发布新版本 0.3.9,支持阿里 Qwen2-VL 模型理解视频;支持短剧混剪
|
||||
@ -44,38 +41,45 @@ NarratoAI 是一个自动化影视解说工具,基于LLM实现文案撰写、
|
||||
- 2024.11.10 发布新版本 v0.3.5;优化视频剪辑流程,
|
||||
|
||||
## 重磅福利 🎉
|
||||
即日起全面支持DeepSeek模型!注册即享2000万免费Token(价值14元平台配额),剪辑10分钟视频仅需0.1元!
|
||||
> 1️⃣
|
||||
> **开发者专属福利:一站式AI平台,注册即送体验金!**
|
||||
>
|
||||
> 还在为接入各种AI模型烦恼吗?向您推荐 302.ai,一个企业级的AI资源中心。一次接入,即可调用上百种AI模型,涵盖语言、图像、音视频等,按量付费,极大降低开发成本。
|
||||
>
|
||||
> 通过下方我的专属链接注册,**立获1美元免费体验金**,助您轻松开启AI开发之旅。
|
||||
>
|
||||
> **立即注册领取:** [https://share.302.ai/I9P6mP](https://share.302.ai/I9P6mP)
|
||||
|
||||
🔥 快速领福利:
|
||||
1️⃣ 点击链接注册:https://cloud.siliconflow.cn/i/pyOKqFCV
|
||||
2️⃣ 使用手机号登录,**务必填写邀请码:pyOKqFCV**
|
||||
3️⃣ 领取14元配额,极速体验高性价比AI剪辑
|
||||
---
|
||||
> 2️⃣
|
||||
> 即日起全面支持硅基流动!注册即享2000万免费Token(价值14元平台配额),剪辑10分钟视频仅需0.1元!
|
||||
>
|
||||
> 🔥 快速领福利:
|
||||
> 1️⃣ 点击链接注册:https://cloud.siliconflow.cn/i/pyOKqFCV
|
||||
> 2️⃣ 使用手机号登录,**务必填写邀请码:pyOKqFCV**
|
||||
> 3️⃣ 领取14元配额,极速体验高性价比AI剪辑
|
||||
>
|
||||
> 💡 小成本大创作:
|
||||
> 硅基流动API Key一键接入,智能剪辑效率翻倍!
|
||||
> (注:邀请码为福利领取唯一凭证,注册后自动到账)
|
||||
>
|
||||
> 立即行动,用「pyOKqFCV」解锁你的AI生产力!
|
||||
|
||||
💡 小成本大创作:
|
||||
硅基流动API Key一键接入,智能剪辑效率翻倍!
|
||||
(注:邀请码为福利领取唯一凭证,注册后自动到账)
|
||||
|
||||
立即行动,用「pyOKqFCV」解锁你的AI生产力!
|
||||
|
||||
😊 更新步骤:
|
||||
整合包:点击 update.bat 一键更新脚本
|
||||
代码构建:使用 git pull 拉去最新代码
|
||||
|
||||
## ⚠️谨防被骗 📢
|
||||
|
||||
_**1. NarratoAI 是一款完全免费的软件,近期在社交媒体(抖音等)上发现,有人将 NarratoAI 改名后售卖,下面是部分截图,切忌不要上当受骗!!!**_
|
||||
_**1. NarratoAI 是一款完全免费的软件,近期在社交媒体(抖音,B站等)上发现,有人将 NarratoAI 改名后售卖,下面是部分截图,请大家务必提高警惕,切勿上当受骗**_
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/464b877c-b061-4856-8260-a0ef6fad7e52" alt="Screenshot_20250109_114131_Samsung Internet" style="width:30%; height:auto;">
|
||||
<img src="https://github.com/user-attachments/assets/9cc0e5e4-bd5b-4655-b5ef-7d9085cdbc50" alt="Screenshot_20250109_114131_Samsung Internet" style="width:30%; height:auto;">
|
||||
<img src="https://github.com/user-attachments/assets/9d7a6ea9-4bca-42b5-a61e-7e464037930f" alt="Screenshot_20250109_114131_Samsung Internet" style="width:30%; height:auto;">
|
||||
<img src="https://github.com/user-attachments/assets/09eeb94d-c670-4d7d-ba19-c0468bed3291" alt="Screenshot_20250109_114131_Samsung Internet" style="width:30%; height:auto;">
|
||||
---
|
||||
|
||||
_**2. 近期在 x (推特) 上发现有人冒充作者在 pump.fun 平台上发行代币! 这是骗子!!! 不要被割了韭菜
|
||||
!!!目前 NarratoAI 没有在 x(推特) 上做任何官方宣传,注意甄别**_
|
||||
<div style="display: flex; flex-wrap: wrap; justify-content: space-around; align-items: flex-start; gap: 10px;">
|
||||
<img src="https://github.com/user-attachments/assets/9cc0e5e4-bd5b-4655-b5ef-7d9085cdbc50" alt="诈骗截图 1" style="width: 23%; max-width: 250px; height: auto; border: 1px solid #ddd; border-radius: 5px; box-shadow: 2px 2px 8px rgba(0,0,0,0.1);">
|
||||
<img src="https://github.com/user-attachments/assets/464b877c-b061-4856-8260-a0ef6fad7e52" alt="诈骗截图 2" style="width: 23%; max-width: 250px; height: auto; border: 1px solid #ddd; border-radius: 5px; box-shadow: 2px 2px 8px rgba(0,0,0,0.1);">
|
||||
<img src="https://github.com/user-attachments/assets/9d7a6ea9-4bca-42b5-a61e-7e464037930f" alt="诈骗截图 3" style="width: 23%; max-width: 250px; height: auto; border: 1px solid #ddd; border-radius: 5px; box-shadow: 2px 2px 8px rgba(0,0,0,0.1);">
|
||||
<img src="https://github.com/user-attachments/assets/09eeb94d-c670-4d7d-ba19-c0468bed3291" alt="诈骗截图 4" style="width: 23%; max-width: 250px; height: auto; border: 1px solid #ddd; border-radius: 5px; box-shadow: 2px 2px 8px rgba(0,0,0,0.1);">
|
||||
</div>
|
||||
|
||||
下面是此人 x(推特) 首页截图
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/c492ab99-52cd-4ba2-8695-1bd2073ecf12" alt="Screenshot_20250109_114131_Samsung Internet" style="width:30%; height:auto;">
|
||||
---
|
||||
|
||||
## 未来计划 🥳
|
||||
- [x] windows 整合包发布
|
||||
@ -93,6 +97,44 @@ _**2. 近期在 x (推特) 上发现有人冒充作者在 pump.fun 平台上发
|
||||
- [ ] 支持更多 TTS 引擎
|
||||
- [ ] ...
|
||||
|
||||
## 快速启动 🚀
|
||||
|
||||
### 方式一:macos Docker 部署(macos 推荐)
|
||||
```bash
|
||||
# 1. 克隆项目
|
||||
git clone https://github.com/linyqh/NarratoAI.git
|
||||
cd NarratoAI
|
||||
|
||||
# 2. 一键部署
|
||||
docker compose up -d
|
||||
|
||||
# 3. 访问应用
|
||||
# 浏览器打开 http://localhost:8501
|
||||
```
|
||||
### 方式二:整合包(Windows 推荐)
|
||||
> *关注微信公众号 **NarratoAI 助手** 右下角菜单栏获取下载链接*
|
||||
|
||||
### 方式三:本地运行
|
||||
```bash
|
||||
# 1. 克隆项目
|
||||
git clone https://github.com/linyqh/NarratoAI.git
|
||||
cd NarratoAI
|
||||
|
||||
# 2. 安装依赖
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 3. 复制配置文件
|
||||
cp config.example.toml config.toml
|
||||
|
||||
# 4. 编辑 config.toml,配置你的 API 密钥
|
||||
|
||||
# 5. 启动应用
|
||||
streamlit run webui.py --server.maxUploadSize=2048
|
||||
|
||||
# 6. 访问应用
|
||||
# 浏览器打开 http://localhost:8501
|
||||
```
|
||||
|
||||
## 配置要求 📦
|
||||
|
||||
- 建议最低 CPU 4核或以上,内存 8G 或以上,显卡非必须
|
||||
|
||||
@ -176,7 +176,7 @@ class VideoClipParams(BaseModel):
|
||||
voice_volume: Optional[float] = Field(default=AudioVolumeDefaults.VOICE_VOLUME, description="解说语音音量")
|
||||
voice_rate: Optional[float] = Field(default=1.0, description="语速")
|
||||
voice_pitch: Optional[float] = Field(default=1.0, description="语调")
|
||||
tts_engine: Optional[str] = Field(default="tencent", description="TTS 引擎")
|
||||
tts_engine: Optional[str] = Field(default="", description="TTS 引擎")
|
||||
bgm_name: Optional[str] = Field(default="random", description="背景音乐名称")
|
||||
bgm_type: Optional[str] = Field(default="random", description="背景音乐类型")
|
||||
bgm_file: Optional[str] = Field(default="", description="背景音乐文件")
|
||||
|
||||
@ -152,13 +152,13 @@ class SubtitleAnalyzer:
|
||||
}
|
||||
|
||||
# 构建请求URL
|
||||
url = f"{self.base_url}/models/{self.model}:generateContent?key={self.api_key}"
|
||||
url = f"{self.base_url}/models/{self.model}:generateContent"
|
||||
|
||||
# 发送请求
|
||||
response = requests.post(
|
||||
url,
|
||||
json=payload,
|
||||
headers={"Content-Type": "application/json", "User-Agent": "NarratoAI/1.0"},
|
||||
headers={"Content-Type": "application/json", "x-goog-api-key": self.api_key},
|
||||
timeout=120
|
||||
)
|
||||
|
||||
@ -440,13 +440,13 @@ class SubtitleAnalyzer:
|
||||
}
|
||||
|
||||
# 构建请求URL
|
||||
url = f"{self.base_url}/models/{self.model}:generateContent?key={self.api_key}"
|
||||
url = f"{self.base_url}/models/{self.model}:generateContent"
|
||||
|
||||
# 发送请求
|
||||
response = requests.post(
|
||||
url,
|
||||
json=payload,
|
||||
headers={"Content-Type": "application/json", "User-Agent": "NarratoAI/1.0"},
|
||||
headers={"Content-Type": "application/json", "x-goog-api-key": self.api_key},
|
||||
timeout=120
|
||||
)
|
||||
|
||||
|
||||
@ -140,7 +140,7 @@ class GeminiVisionProvider(VisionModelProvider):
|
||||
"""执行原生Gemini API调用,包含重试机制"""
|
||||
from app.config import config
|
||||
|
||||
url = f"{self.base_url}/models/{self.model_name}:generateContent?key={self.api_key}"
|
||||
url = f"{self.base_url}/models/{self.model_name}:generateContent"
|
||||
|
||||
max_retries = config.app.get('llm_max_retries', 3)
|
||||
base_timeout = config.app.get('llm_vision_timeout', 120)
|
||||
@ -157,7 +157,7 @@ class GeminiVisionProvider(VisionModelProvider):
|
||||
json=payload,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "NarratoAI/1.0"
|
||||
"x-goog-api-key": self.api_key
|
||||
},
|
||||
timeout=timeout
|
||||
)
|
||||
@ -330,7 +330,7 @@ class GeminiTextProvider(TextModelProvider):
|
||||
"""执行原生Gemini API调用,包含重试机制"""
|
||||
from app.config import config
|
||||
|
||||
url = f"{self.base_url}/models/{self.model_name}:generateContent?key={self.api_key}"
|
||||
url = f"{self.base_url}/models/{self.model_name}:generateContent"
|
||||
|
||||
max_retries = config.app.get('llm_max_retries', 3)
|
||||
base_timeout = config.app.get('llm_text_timeout', 180) # 文本生成任务使用更长的基础超时时间
|
||||
@ -347,7 +347,7 @@ class GeminiTextProvider(TextModelProvider):
|
||||
json=payload,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "NarratoAI/1.0"
|
||||
"x-goog-api-key": self.api_key
|
||||
},
|
||||
timeout=timeout
|
||||
)
|
||||
|
||||
@ -1085,7 +1085,7 @@ def tts(
|
||||
) -> Union[SubMaker, None]:
|
||||
logger.info(f"使用 TTS 引擎: '{tts_engine}', 语音: '{voice_name}'")
|
||||
|
||||
if tts_engine == "tencent":
|
||||
if tts_engine == "tencent_tts":
|
||||
logger.info("分发到腾讯云 TTS")
|
||||
return tencent_tts(text, voice_name, voice_file, speed=voice_rate)
|
||||
|
||||
@ -1093,12 +1093,16 @@ def tts(
|
||||
logger.info("分发到 SoulVoice TTS")
|
||||
return soulvoice_tts(text, voice_name, voice_file, speed=voice_rate)
|
||||
|
||||
if tts_engine == "azure":
|
||||
if tts_engine == "azure_speech":
|
||||
if should_use_azure_speech_services(voice_name):
|
||||
logger.info("分发到 Azure Speech Services (V2)")
|
||||
return azure_tts_v2(text, voice_name, voice_file)
|
||||
logger.info("分发到 Edge TTS (Azure V1)")
|
||||
return azure_tts_v1(text, voice_name, voice_rate, voice_pitch, voice_file)
|
||||
|
||||
if tts_engine == "edge_tts":
|
||||
logger.info("分发到 Edge TTS")
|
||||
return azure_tts_v1(text, voice_name, voice_rate, voice_pitch, voice_file)
|
||||
|
||||
# Fallback for unknown engine - default to azure v1
|
||||
logger.warning(f"未知的 TTS 引擎: '{tts_engine}', 将默认使用 Edge TTS (Azure V1)。")
|
||||
|
||||
@ -107,7 +107,7 @@ class VisionAnalyzer:
|
||||
}
|
||||
|
||||
# 构建请求URL
|
||||
url = f"{self.base_url}/models/{self.model_name}:generateContent?key={self.api_key}"
|
||||
url = f"{self.base_url}/models/{self.model_name}:generateContent"
|
||||
|
||||
# 发送请求
|
||||
response = await asyncio.to_thread(
|
||||
@ -116,7 +116,7 @@ class VisionAnalyzer:
|
||||
json=request_data,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "NarratoAI/1.0"
|
||||
"x-goog-api-key": self.api_key
|
||||
},
|
||||
timeout=120 # 增加超时时间
|
||||
)
|
||||
|
||||
@ -230,7 +230,7 @@ class GeminiOpenAIGenerator(BaseGenerator):
|
||||
}
|
||||
|
||||
# 构建请求URL
|
||||
url = f"{self.base_url}/models/{self.model_name}:generateContent?key={self.api_key}"
|
||||
url = f"{self.base_url}/models/{self.model_name}:generateContent"
|
||||
|
||||
# 发送请求
|
||||
response = requests.post(
|
||||
@ -238,7 +238,7 @@ class GeminiOpenAIGenerator(BaseGenerator):
|
||||
json=request_data,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "NarratoAI/1.0"
|
||||
"x-goog-api-key": self.api_key
|
||||
},
|
||||
timeout=120
|
||||
)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
[app]
|
||||
project_version="0.7.1"
|
||||
project_version="0.7.2"
|
||||
|
||||
# 模型验证模式配置
|
||||
# true: 严格模式,只允许使用预定义支持列表中的模型(默认)
|
||||
|
||||
@ -1 +1 @@
|
||||
0.7.1
|
||||
0.7.2
|
||||
376
webui.txt
376
webui.txt
@ -1,376 +0,0 @@
|
||||
@echo off
|
||||
set CURRENT_DIR=%CD%
|
||||
echo ***** Current directory: %CURRENT_DIR% *****
|
||||
set PYTHONPATH=%CURRENT_DIR%
|
||||
|
||||
set "vpn_proxy_url=%http://127.0.0.1:7890%"
|
||||
|
||||
:: 使用VPN代理进行一些操作,例如通过代理下载文件
|
||||
set "http_proxy=%vpn_proxy_url%"
|
||||
set "https_proxy=%vpn_proxy_url%"
|
||||
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
rem 创建链接和路径的数组
|
||||
set "urls_paths[0]=https://zenodo.org/records/13293144/files/MicrosoftYaHeiBold.ttc|.\resource\fonts"
|
||||
set "urls_paths[1]=https://zenodo.org/records/13293144/files/MicrosoftYaHeiNormal.ttc|.\resource\fonts"
|
||||
set "urls_paths[2]=https://zenodo.org/records/13293144/files/STHeitiLight.ttc|.\resource\fonts"
|
||||
set "urls_paths[3]=https://zenodo.org/records/13293144/files/STHeitiMedium.ttc|.\resource\fonts"
|
||||
set "urls_paths[4]=https://zenodo.org/records/13293144/files/UTM%20Kabel%20KT.ttf|.\resource\fonts"
|
||||
set "urls_paths[5]=https://zenodo.org/records/14167125/files/test.mp4|.\resource\videos"
|
||||
set "urls_paths[6]=https://zenodo.org/records/13293150/files/output000.mp3|.\resource\songs"
|
||||
set "urls_paths[7]=https://zenodo.org/records/13293150/files/output001.mp3|.\resource\songs"
|
||||
set "urls_paths[8]=https://zenodo.org/records/13293150/files/output002.mp3|.\resource\songs"
|
||||
set "urls_paths[9]=https://zenodo.org/records/13293150/files/output003.mp3|.\resource\songs"
|
||||
set "urls_paths[10]=https://zenodo.org/records/13293150/files/output004.mp3|.\resource\songs"
|
||||
set "urls_paths[11]=https://zenodo.org/records/13293150/files/output005.mp3|.\resource\songs"
|
||||
set "urls_paths[12]=https://zenodo.org/records/13293150/files/output006.mp3|.\resource\songs"
|
||||
set "urls_paths[13]=https://zenodo.org/records/13293150/files/output007.mp3|.\resource\songs"
|
||||
set "urls_paths[14]=https://zenodo.org/records/13293150/files/output008.mp3|.\resource\songs"
|
||||
set "urls_paths[15]=https://zenodo.org/records/13293150/files/output009.mp3|.\resource\songs"
|
||||
set "urls_paths[16]=https://zenodo.org/records/13293150/files/output010.mp3|.\resource\songs"
|
||||
|
||||
rem 循环下载所有文件并保存到指定路径
|
||||
for /L %%i in (0,1,16) do (
|
||||
for /f "tokens=1,2 delims=|" %%a in ("!urls_paths[%%i]!") do (
|
||||
if not exist "%%b" mkdir "%%b"
|
||||
echo 正在下载 %%a 到 %%b
|
||||
curl -o "%%b\%%~nxa" %%a
|
||||
)
|
||||
)
|
||||
|
||||
echo 所有文件已成功下载到指定目录
|
||||
endlocal
|
||||
pause
|
||||
|
||||
|
||||
rem set HF_ENDPOINT=https://hf-mirror.com
|
||||
streamlit run webui.py --browser.serverAddress="127.0.0.1" --server.enableCORS=True --server.maxUploadSize=2048 --browser.gatherUsageStats=False
|
||||
|
||||
streamlit run webui.py --server.maxUploadSize=2048
|
||||
|
||||
请求0:
|
||||
curl -X 'POST' \
|
||||
'http://127.0.0.1:8080/api/v2/youtube/download' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"url": "https://www.youtube.com/watch?v=Kenm35gdqtk",
|
||||
"resolution": "1080p",
|
||||
"output_format": "mp4",
|
||||
"rename": "2024-11-19"
|
||||
}'
|
||||
{
|
||||
"url": "https://www.youtube.com/watch?v=Kenm35gdqtk",
|
||||
"resolution": "1080p",
|
||||
"output_format": "mp4",
|
||||
"rename": "2024-11-19"
|
||||
}
|
||||
|
||||
请求1:
|
||||
curl -X 'POST' \
|
||||
'http://127.0.0.1:8080/api/v2/scripts/generate' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"video_path": "E:\\projects\\NarratoAI\\resource\\videos\\test.mp4",
|
||||
"skip_seconds": 0,
|
||||
"threshold": 30,
|
||||
"vision_batch_size": 10,
|
||||
"vision_llm_provider": "gemini"
|
||||
}'
|
||||
{
|
||||
"video_path": "E:\\projects\\NarratoAI\\resource\\videos\\test.mp4",
|
||||
"skip_seconds": 0,
|
||||
"threshold": 30,
|
||||
"vision_batch_size": 10,
|
||||
"vision_llm_provider": "gemini"
|
||||
}
|
||||
|
||||
请求2:
|
||||
curl -X 'POST' \
|
||||
'http://127.0.0.1:8080/api/v2/scripts/crop' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"video_origin_path": "E:\\projects\\NarratoAI\\resource\\videos\\test.mp4",
|
||||
"video_script": [
|
||||
{
|
||||
"timestamp": "00:10-01:01",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频展现一名留着胡须的男子在森林里挖掘。\n\n画面首先展现男子从后方视角,背着军绿色背包,穿着卡其色长裤和深色T恤,走向一个泥土斜坡。背包上似乎有一个镐头。\n\n下一个镜头特写展现了该背包,一个镐头从背包里伸出来,包里还有一些其他工具。\n\n然后,视频显示该男子用镐头挖掘泥土斜坡。\n\n接下来是一些近景镜头,展现男子的靴子在泥土中行走,以及男子用手清理泥土。\n\n其他镜头从不同角度展现该男子在挖掘,包括从侧面和上方。\n\n可以看到他用工具挖掘,清理泥土,并检查挖出的土壤。\n\n最后,一个镜头展现了挖出的土壤的质地和颜色。",
|
||||
"narration": "好的,接下来就是我们这位“胡须大侠”的精彩冒险了!只见他背着军绿色的背包,迈着比我上班还不情愿的步伐走向那泥土斜坡。哎呀,这个背包可真是个宝贝,里面藏着一把镐头和一些工具,简直像是个随身携带的“建筑工具箱”! \n\n看他挥舞着镐头,挖掘泥土的姿势,仿佛在进行一场“挖土大赛”,结果却比我做饭还要糟糕。泥土飞扬中,他的靴子也成了“泥巴艺术家”。最后,那堆色泽各异的土壤就像他心情的写照——五彩斑斓又略显混乱!真是一次让人捧腹的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:00-00:51"
|
||||
},
|
||||
{
|
||||
"timestamp": "01:07-01:53",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频以一系列森林环境的镜头开头。\n\n第一个镜头是一个特写镜头,镜头中显示的是一些带有水滴的绿色叶子。\n\n第二个镜头显示一个留着胡须的男子在森林中挖掘一个洞。 他跪在地上,用工具挖土。\n\n第三个镜头是一个中等镜头,显示同一个人坐在他挖好的洞边休息。\n\n第四个镜头显示该洞的内部结构,该洞在树根和地面之间。\n\n第五个镜头显示该男子用斧头砍树枝。\n\n第六个镜头显示一堆树枝横跨一个泥泞的小水坑。\n\n第七个镜头显示更多茂盛的树叶和树枝在阳光下。\n\n第八个镜头显示更多茂盛的树叶和树枝。\n\n\n",
|
||||
"narration": "接下来,我们的“挖土大师”又开始了他的森林探险。看这镜头,水滴在叶子上闪烁,仿佛在说:“快来,快来,这里有故事!”他一边挖洞,一边像个新手厨师试图切洋葱——每一下都小心翼翼,生怕自己不小心挖出个“历史遗址”。坐下休息的时候,脸上的表情就像发现新大陆一样!然后,他拿起斧头砍树枝,简直是现代版的“神雕侠侣”,只不过对象是树木。最后,那堆树枝架过泥泞的小水坑,仿佛在说:“我就是不怕湿脚的勇士!”这就是我们的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:51-01:37"
|
||||
}
|
||||
]
|
||||
}'
|
||||
{
|
||||
"video_origin_path": "E:\\projects\\NarratoAI\\resource\\videos\\test.mp4",
|
||||
"video_script": [
|
||||
{
|
||||
"timestamp": "00:10-01:01",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频展现一名留着胡须的男子在森林里挖掘。\n\n画面首先展现男子从后方视角,背着军绿色背包,穿着卡其色长裤和深色T恤,走向一个泥土斜坡。背包上似乎有一个镐头。\n\n下一个镜头特写展现了该背包,一个镐头从背包里伸出来,包里还有一些其他工具。\n\n然后,视频显示该男子用镐头挖掘泥土斜坡。\n\n接下来是一些近景镜头,展现男子的靴子在泥土中行走,以及男子用手清理泥土。\n\n其他镜头从不同角度展现该男子在挖掘,包括从侧面和上方。\n\n可以看到他用工具挖掘,清理泥土,并检查挖出的土壤。\n\n最后,一个镜头展现了挖出的土壤的质地和颜色。",
|
||||
"narration": "好的,接下来就是我们这位“胡须大侠”的精彩冒险了!只见他背着军绿色的背包,迈着比我上班还不情愿的步伐走向那泥土斜坡。哎呀,这个背包可真是个宝贝,里面藏着一把镐头和一些工具,简直像是个随身携带的“建筑工具箱”! \n\n看他挥舞着镐头,挖掘泥土的姿势,仿佛在进行一场“挖土大赛”,结果却比我做饭还要糟糕。泥土飞扬中,他的靴子也成了“泥巴艺术家”。最后,那堆色泽各异的土壤就像他心情的写照——五彩斑斓又略显混乱!真是一次让人捧腹的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:00-00:51"
|
||||
},
|
||||
{
|
||||
"timestamp": "01:07-01:53",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频以一系列森林环境的镜头开头。\n\n第一个镜头是一个特写镜头,镜头中显示的是一些带有水滴的绿色叶子。\n\n第二个镜头显示一个留着胡须的男子在森林中挖掘一个洞。 他跪在地上,用工具挖土。\n\n第三个镜头是一个中等镜头,显示同一个人坐在他挖好的洞边休息。\n\n第四个镜头显示该洞的内部结构,该洞在树根和地面之间。\n\n第五个镜头显示该男子用斧头砍树枝。\n\n第六个镜头显示一堆树枝横跨一个泥泞的小水坑。\n\n第七个镜头显示更多茂盛的树叶和树枝在阳光下。\n\n第八个镜头显示更多茂盛的树叶和树枝。\n\n\n",
|
||||
"narration": "接下来,我们的“挖土大师”又开始了他的森林探险。看这镜头,水滴在叶子上闪烁,仿佛在说:“快来,快来,这里有故事!”他一边挖洞,一边像个新手厨师试图切洋葱——每一下都小心翼翼,生怕自己不小心挖出个“历史遗址”。坐下休息的时候,脸上的表情就像发现新大陆一样!然后,他拿起斧头砍树枝,简直是现代版的“神雕侠侣”,只不过对象是树木。最后,那堆树枝架过泥泞的小水坑,仿佛在说:“我就是不怕湿脚的勇士!”这就是我们的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:51-01:37"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
请求3:
|
||||
curl -X 'POST' \
|
||||
'http://127.0.0.1:8080/api/v2/scripts/start-subclip?task_id=12121' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"request": {
|
||||
"video_clip_json": [
|
||||
{
|
||||
"timestamp": "00:10-01:01",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频展现一名留着胡须的男子在森林里挖掘。\n\n画面首先展现男子从后方视角,背着军绿色背包,穿着卡其色长裤和深色T恤,走向一个泥土斜坡。背包上似乎有一个镐头。\n\n下一个镜头特写展现了该背包,一个镐头从背包里伸出来,包里还有一些其他工具。\n\n然后,视频显示该男子用镐头挖掘泥土斜坡。\n\n接下来是一些近景镜头,展现男子的靴子在泥土中行走,以及男子用手清理泥土。\n\n其他镜头从不同角度展现该男子在挖掘,包括从侧面和上方。\n\n可以看到他用工具挖掘,清理泥土,并检查挖出的土壤。\n\n最后,一个镜头展现了挖出的土壤的质地和颜色。",
|
||||
"narration": "好的,接下来就是我们这位“胡须大侠”的精彩冒险了!只见他背着军绿色的背包,迈着比我上班还不情愿的步伐走向那泥土斜坡。哎呀,这个背包可真是个宝贝,里面藏着一把镐头和一些工具,简直像是个随身携带的“建筑工具箱”! \n\n看他挥舞着镐头,挖掘泥土的姿势,仿佛在进行一场“挖土大赛”,结果却比我做饭还要糟糕。泥土飞扬中,他的靴子也成了“泥巴艺术家”。最后,那堆色泽各异的土壤就像他心情的写照——五彩斑斓又略显混乱!真是一次让人捧腹的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:00-00:51"
|
||||
},
|
||||
{
|
||||
"timestamp": "01:07-01:53",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频以一系列森林环境的镜头开头。\n\n第一个镜头是一个特写镜头,镜头中显示的是一些带有水滴的绿色叶子。\n\n第二个镜头显示一个留着胡须的男子在森林中挖掘一个洞。 他跪在地上,用工具挖土。\n\n第三个镜头是一个中等镜头,显示同一个人坐在他挖好的洞边休息。\n\n第四个镜头显示该洞的内部结构,该洞在树根和地面之间。\n\n第五个镜头显示该男子用斧头砍树枝。\n\n第六个镜头显示一堆树枝横跨一个泥泞的小水坑。\n\n第七个镜头显示更多茂盛的树叶和树枝在阳光下。\n\n第八个镜头显示更多茂盛的树叶和树枝。\n\n\n",
|
||||
"narration": "接下来,我们的“挖土大师”又开始了他的森林探险。看这镜头,水滴在叶子上闪烁,仿佛在说:“快来,快来,这里有故事!”他一边挖洞,一边像个新手厨师试图切洋葱——每一下都小心翼翼,生怕自己不小心挖出个“历史遗址”。坐下休息的时候,脸上的表情就像发现新大陆一样!然后,他拿起斧头砍树枝,简直是现代版的“神雕侠侣”,只不过对象是树木。最后,那堆树枝架过泥泞的小水坑,仿佛在说:“我就是不怕湿脚的勇士!”这就是我们的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:51-01:37"
|
||||
}
|
||||
],
|
||||
"video_clip_json_path": "E:\\projects\\NarratoAI\\resource\\scripts\\2024-1118-230421.json",
|
||||
"video_origin_path": "E:\\projects\\NarratoAI\\resource\\videos\\test.mp4",
|
||||
"video_aspect": "16:9",
|
||||
"video_language": "zh-CN",
|
||||
"voice_name": "zh-CN-YunjianNeural",
|
||||
"voice_volume": 1,
|
||||
"voice_rate": 1.2,
|
||||
"voice_pitch": 1,
|
||||
"bgm_name": "random",
|
||||
"bgm_type": "random",
|
||||
"bgm_file": "",
|
||||
"bgm_volume": 0.3,
|
||||
"subtitle_enabled": true,
|
||||
"subtitle_position": "bottom",
|
||||
"font_name": "STHeitiMedium.ttc",
|
||||
"text_fore_color": "#FFFFFF",
|
||||
"text_background_color": "transparent",
|
||||
"font_size": 75,
|
||||
"stroke_color": "#000000",
|
||||
"stroke_width": 1.5,
|
||||
"custom_position": 70,
|
||||
"n_threads": 8
|
||||
},
|
||||
"subclip_videos": {
|
||||
"00:10-01:01": "E:\\projects\\NarratoAI\\storage\\cache_videos/vid-00_10-01_01.mp4",
|
||||
"01:07-01:53": "E:\\projects\\NarratoAI\\storage\\cache_videos/vid-01_07-01_53.mp4"
|
||||
}
|
||||
}'
|
||||
{
|
||||
"request": {
|
||||
"video_clip_json": [
|
||||
{
|
||||
"timestamp": "00:10-01:01",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频展现一名留着胡须的男子在森林里挖掘。\n\n画面首先展现男子从后方视角,背着军绿色背包,穿着卡其色长裤和深色T恤,走向一个泥土斜坡。背包上似乎有一个镐头。\n\n下一个镜头特写展现了该背包,一个镐头从背包里伸出来,包里还有一些其他工具。\n\n然后,视频显示该男子用镐头挖掘泥土斜坡。\n\n接下来是一些近景镜头,展现男子的靴子在泥土中行走,以及男子用手清理泥土。\n\n其他镜头从不同角度展现该男子在挖掘,包括从侧面和上方。\n\n可以看到他用工具挖掘,清理泥土,并检查挖出的土壤。\n\n最后,一个镜头展现了挖出的土壤的质地和颜色。",
|
||||
"narration": "好的,接下来就是我们这位“胡须大侠”的精彩冒险了!只见他背着军绿色的背包,迈着比我上班还不情愿的步伐走向那泥土斜坡。哎呀,这个背包可真是个宝贝,里面藏着一把镐头和一些工具,简直像是个随身携带的“建筑工具箱”! \n\n看他挥舞着镐头,挖掘泥土的姿势,仿佛在进行一场“挖土大赛”,结果却比我做饭还要糟糕。泥土飞扬中,他的靴子也成了“泥巴艺术家”。最后,那堆色泽各异的土壤就像他心情的写照——五彩斑斓又略显混乱!真是一次让人捧腹的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:00-00:51"
|
||||
},
|
||||
{
|
||||
"timestamp": "01:07-01:53",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频以一系列森林环境的镜头开头。\n\n第一个镜头是一个特写镜头,镜头中显示的是一些带有水滴的绿色叶子。\n\n第二个镜头显示一个留着胡须的男子在森林中挖掘一个洞。 他跪在地上,用工具挖土。\n\n第三个镜头是一个中等镜头,显示同一个人坐在他挖好的洞边休息。\n\n第四个镜头显示该洞的内部结构,该洞在树根和地面之间。\n\n第五个镜头显示该男子用斧头砍树枝。\n\n第六个镜头显示一堆树枝横跨一个泥泞的小水坑。\n\n第七个镜头显示更多茂盛的树叶和树枝在阳光下。\n\n第八个镜头显示更多茂盛的树叶和树枝。\n\n\n",
|
||||
"narration": "接下来,我们的“挖土大师”又开始了他的森林探险。看这镜头,水滴在叶子上闪烁,仿佛在说:“快来,快来,这里有故事!”他一边挖洞,一边像个新手厨师试图切洋葱——每一下都小心翼翼,生怕自己不小心挖出个“历史遗址”。坐下休息的时候,脸上的表情就像发现新大陆一样!然后,他拿起斧头砍树枝,简直是现代版的“神雕侠侣”,只不过对象是树木。最后,那堆树枝架过泥泞的小水坑,仿佛在说:“我就是不怕湿脚的勇士!”这就是我们的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:51-01:37"
|
||||
}
|
||||
],
|
||||
"video_clip_json_path": "E:\\projects\\NarratoAI\\resource\\scripts\\2024-1118-230421.json",
|
||||
"video_origin_path": "E:\\projects\\NarratoAI\\resource\\videos\\test.mp4",
|
||||
"video_aspect": "16:9",
|
||||
"video_language": "zh-CN",
|
||||
"voice_name": "zh-CN-YunjianNeural",
|
||||
"voice_volume": 1,
|
||||
"voice_rate": 1.2,
|
||||
"voice_pitch": 1,
|
||||
"bgm_name": "random",
|
||||
"bgm_type": "random",
|
||||
"bgm_file": "",
|
||||
"bgm_volume": 0.3,
|
||||
"subtitle_enabled": true,
|
||||
"subtitle_position": "bottom",
|
||||
"font_name": "STHeitiMedium.ttc",
|
||||
"text_fore_color": "#FFFFFF",
|
||||
"text_background_color": "transparent",
|
||||
"font_size": 75,
|
||||
"stroke_color": "#000000",
|
||||
"stroke_width": 1.5,
|
||||
"custom_position": 70,
|
||||
"n_threads": 8
|
||||
},
|
||||
"subclip_videos": {
|
||||
"00:10-01:01": "E:\\projects\\NarratoAI\\storage\\cache_videos/vid-00_10-01_01.mp4",
|
||||
"01:07-01:53": "E:\\projects\\NarratoAI\\storage\\cache_videos/vid-01_07-01_53.mp4"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
请在最外层新建一个pipeline 工作流执行逻辑的代码;
|
||||
他会按照下面的顺序请求接口
|
||||
1.下载视频
|
||||
curl -X 'POST' \
|
||||
'http://127.0.0.1:8080/api/v2/youtube/download' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"url": "https://www.youtube.com/watch?v=Kenm35gdqtk",
|
||||
"resolution": "1080p",
|
||||
"output_format": "mp4",
|
||||
"rename": "2024-11-19"
|
||||
}'
|
||||
2.生成脚本
|
||||
curl -X 'POST' \
|
||||
'http://127.0.0.1:8080/api/v2/scripts/generate' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"video_path": "E:\\projects\\NarratoAI\\resource\\videos\\test.mp4",
|
||||
"skip_seconds": 0,
|
||||
"threshold": 30,
|
||||
"vision_batch_size": 10,
|
||||
"vision_llm_provider": "gemini"
|
||||
}'
|
||||
3. 剪辑视频
|
||||
curl -X 'POST' \
|
||||
'http://127.0.0.1:8080/api/v2/scripts/crop' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"video_origin_path": "E:\\projects\\NarratoAI\\resource\\videos\\test.mp4",
|
||||
"video_script": [
|
||||
{
|
||||
"timestamp": "00:10-01:01",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频展现一名留着胡须的男子在森林里挖掘。\n\n画面首先展现男子从后方视角,背着军绿色背包,穿着卡其色长裤和深色T恤,走向一个泥土斜坡。背包上似乎有一个镐头。\n\n下一个镜头特写展现了该背包,一个镐头从背包里伸出来,包里还有一些其他工具。\n\n然后,视频显示该男子用镐头挖掘泥土斜坡。\n\n接下来是一些近景镜头,展现男子的靴子在泥土中行走,以及男子用手清理泥土。\n\n其他镜头从不同角度展现该男子在挖掘,包括从侧面和上方。\n\n可以看到他用工具挖掘,清理泥土,并检查挖出的土壤。\n\n最后,一个镜头展现了挖出的土壤的质地和颜色。",
|
||||
"narration": "好的,接下来就是我们这位“胡须大侠”的精彩冒险了!只见他背着军绿色的背包,迈着比我上班还不情愿的步伐走向那泥土斜坡。哎呀,这个背包可真是个宝贝,里面藏着一把镐头和一些工具,简直像是个随身携带的“建筑工具箱”! \n\n看他挥舞着镐头,挖掘泥土的姿势,仿佛在进行一场“挖土大赛”,结果却比我做饭还要糟糕。泥土飞扬中,他的靴子也成了“泥巴艺术家”。最后,那堆色泽各异的土壤就像他心情的写照——五彩斑斓又略显混乱!真是一次让人捧腹的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:00-00:51"
|
||||
},
|
||||
{
|
||||
"timestamp": "01:07-01:53",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频以一系列森林环境的镜头开头。\n\n第一个镜头是一个特写镜头,镜头中显示的是一些带有水滴的绿色叶子。\n\n第二个镜头显示一个留着胡须的男子在森林中挖掘一个洞。 他跪在地上,用工具挖土。\n\n第三个镜头是一个中等镜头,显示同一个人坐在他挖好的洞边休息。\n\n第四个镜头显示该洞的内部结构,该洞在树根和地面之间。\n\n第五个镜头显示该男子用斧头砍树枝。\n\n第六个镜头显示一堆树枝横跨一个泥泞的小水坑。\n\n第七个镜头显示更多茂盛的树叶和树枝在阳光下。\n\n第八个镜头显示更多茂盛的树叶和树枝。\n\n\n",
|
||||
"narration": "接下来,我们的“挖土大师”又开始了他的森林探险。看这镜头,水滴在叶子上闪烁,仿佛在说:“快来,快来,这里有故事!”他一边挖洞,一边像个新手厨师试图切洋葱——每一下都小心翼翼,生怕自己不小心挖出个“历史遗址”。坐下休息的时候,脸上的表情就像发现新大陆一样!然后,他拿起斧头砍树枝,简直是现代版的“神雕侠侣”,只不过对象是树木。最后,那堆树枝架过泥泞的小水坑,仿佛在说:“我就是不怕湿脚的勇士!”这就是我们的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:51-01:37"
|
||||
}
|
||||
]
|
||||
}'
|
||||
4.生成视频
|
||||
curl -X 'POST' \
|
||||
'http://127.0.0.1:8080/api/v2/scripts/start-subclip?task_id=12121' \
|
||||
-H 'accept: application/json' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"request": {
|
||||
"video_clip_json": [
|
||||
{
|
||||
"timestamp": "00:10-01:01",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频展现一名留着胡须的男子在森林里挖掘。\n\n画面首先展现男子从后方视角,背着军绿色背包,穿着卡其色长裤和深色T恤,走向一个泥土斜坡。背包上似乎有一个镐头。\n\n下一个镜头特写展现了该背包,一个镐头从背包里伸出来,包里还有一些其他工具。\n\n然后,视频显示该男子用镐头挖掘泥土斜坡。\n\n接下来是一些近景镜头,展现男子的靴子在泥土中行走,以及男子用手清理泥土。\n\n其他镜头从不同角度展现该男子在挖掘,包括从侧面和上方。\n\n可以看到他用工具挖掘,清理泥土,并检查挖出的土壤。\n\n最后,一个镜头展现了挖出的土壤的质地和颜色。",
|
||||
"narration": "好的,接下来就是我们这位“胡须大侠”的精彩冒险了!只见他背着军绿色的背包,迈着比我上班还不情愿的步伐走向那泥土斜坡。哎呀,这个背包可真是个宝贝,里面藏着一把镐头和一些工具,简直像是个随身携带的“建筑工具箱”! \n\n看他挥舞着镐头,挖掘泥土的姿势,仿佛在进行一场“挖土大赛”,结果却比我做饭还要糟糕。泥土飞扬中,他的靴子也成了“泥巴艺术家”。最后,那堆色泽各异的土壤就像他心情的写照——五彩斑斓又略显混乱!真是一次让人捧腹的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:00-00:51"
|
||||
},
|
||||
{
|
||||
"timestamp": "01:07-01:53",
|
||||
"picture": "好的,以下是视频画面的客观描述:\n\n视频以一系列森林环境的镜头开头。\n\n第一个镜头是一个特写镜头,镜头中显示的是一些带有水滴的绿色叶子。\n\n第二个镜头显示一个留着胡须的男子在森林中挖掘一个洞。 他跪在地上,用工具挖土。\n\n第三个镜头是一个中等镜头,显示同一个人坐在他挖好的洞边休息。\n\n第四个镜头显示该洞的内部结构,该洞在树根和地面之间。\n\n第五个镜头显示该男子用斧头砍树枝。\n\n第六个镜头显示一堆树枝横跨一个泥泞的小水坑。\n\n第七个镜头显示更多茂盛的树叶和树枝在阳光下。\n\n第八个镜头显示更多茂盛的树叶和树枝。\n\n\n",
|
||||
"narration": "接下来,我们的“挖土大师”又开始了他的森林探险。看这镜头,水滴在叶子上闪烁,仿佛在说:“快来,快来,这里有故事!”他一边挖洞,一边像个新手厨师试图切洋葱——每一下都小心翼翼,生怕自己不小心挖出个“历史遗址”。坐下休息的时候,脸上的表情就像发现新大陆一样!然后,他拿起斧头砍树枝,简直是现代版的“神雕侠侣”,只不过对象是树木。最后,那堆树枝架过泥泞的小水坑,仿佛在说:“我就是不怕湿脚的勇士!”这就是我们的建造之旅!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:51-01:37"
|
||||
}
|
||||
],
|
||||
"video_clip_json_path": "E:\\projects\\NarratoAI\\resource\\scripts\\2024-1118-230421.json",
|
||||
"video_origin_path": "E:\\projects\\NarratoAI\\resource\\videos\\test.mp4",
|
||||
"video_aspect": "16:9",
|
||||
"video_language": "zh-CN",
|
||||
"voice_name": "zh-CN-YunjianNeural",
|
||||
"voice_volume": 1,
|
||||
"voice_rate": 1.2,
|
||||
"voice_pitch": 1,
|
||||
"bgm_name": "random",
|
||||
"bgm_type": "random",
|
||||
"bgm_file": "",
|
||||
"bgm_volume": 0.3,
|
||||
"subtitle_enabled": true,
|
||||
"subtitle_position": "bottom",
|
||||
"font_name": "STHeitiMedium.ttc",
|
||||
"text_fore_color": "#FFFFFF",
|
||||
"text_background_color": "transparent",
|
||||
"font_size": 75,
|
||||
"stroke_color": "#000000",
|
||||
"stroke_width": 1.5,
|
||||
"custom_position": 70,
|
||||
"n_threads": 8
|
||||
},
|
||||
"subclip_videos": {
|
||||
"00:10-01:01": "E:\\projects\\NarratoAI\\storage\\cache_videos/vid-00_10-01_01.mp4",
|
||||
"01:07-01:53": "E:\\projects\\NarratoAI\\storage\\cache_videos/vid-01_07-01_53.mp4"
|
||||
}
|
||||
}'
|
||||
|
||||
请求1,返回的参数是:
|
||||
{
|
||||
"task_id": "4e9b575f-68c0-4ae1-b218-db42b67993d0",
|
||||
"output_path": "E:\\projects\\NarratoAI\\resource\\videos\\2024-11-19.mp4",
|
||||
"resolution": "1080p",
|
||||
"format": "mp4",
|
||||
"filename": "2024-11-19.mp4"
|
||||
}
|
||||
output_path需要传递给请求2
|
||||
请求2,返回数据为:
|
||||
{
|
||||
"task_id": "04497017-953c-44b4-bf1d-9d8ed3ebbbce",
|
||||
"script": [
|
||||
{
|
||||
"timestamp": "00:10-01:01",
|
||||
"picture": "好的,以下是對影片畫面的客觀描述:\n\n影片顯示一名留著鬍鬚的男子在一處樹林茂密的斜坡上挖掘。\n\n畫面一:男子從後方出現,背著一個軍綠色的背包,背包裡似乎裝有工具。他穿著卡其色的長褲和深色的登山鞋。\n\n畫面二:特寫鏡頭顯示男子的背包,一個舊的鎬頭從包裡露出來,包裡還有其他工具,包括一個鏟子。\n\n畫面三:男子用鎬頭在斜坡上挖土,背包放在他旁邊。\n\n畫面四:特寫鏡頭顯示男子的登山鞋在泥土中。\n\n畫面五:男子坐在斜坡上,用手清理樹根和泥土。\n\n畫面六:地上有一些鬆動的泥土和落葉。\n\n畫面七:男子的背包近景鏡頭,他正在挖掘。\n\n畫面八:男子在斜坡上挖掘,揚起一陣塵土。\n\n畫面九:特寫鏡頭顯示男子用手清理泥土。\n\n畫面十:特寫鏡頭顯示挖出的泥土剖面,可以看到土壤的層次。",
|
||||
"narration": "上一个画面是我在绝美的自然中,准备开启我的“土豪”挖掘之旅。现在,你们看到这位留着胡子的“大哥”,他背着个军绿色的包,里面装的可不仅仅是工具,还有我对生活的无限热爱(以及一丝不安)。看!这把旧镐头就像我的前任——用起来费劲,但又舍不得扔掉。\n\n他在斜坡上挖土,泥土飞扬,仿佛在跟大地进行一场“泥巴大战”。每一铲下去,都能听到大地微微的呻吟:哎呀,我这颗小树根可比我当年的情感纠葛还难处理呢!别担心,这些泥土层次分明,简直可以开个“泥土博物馆”。所以,朋友们,跟着我一起享受这场泥泞中的乐趣吧!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:00-00:51"
|
||||
},
|
||||
{
|
||||
"timestamp": "01:07-01:53",
|
||||
"picture": "好的,以下是對影片畫面內容的客觀描述:\n\n影片以一系列森林環境的鏡頭開始。第一個鏡頭展示了綠葉植物的特寫鏡頭,葉子上有一些水珠。接下來的鏡頭是一個男人在森林裡挖掘一個小坑,他跪在地上,用鏟子挖土。\n\n接下來的鏡頭是同一個男人坐在他挖的坑旁邊,望著前方。然後,鏡頭顯示該坑的廣角鏡頭,顯示其結構和大小。\n\n之後的鏡頭,同一個男人在樹林裡劈柴。鏡頭最後呈現出一潭渾濁的水,周圍環繞著樹枝。然後鏡頭又回到了森林裡生長茂盛的植物特寫鏡頭。",
|
||||
"narration": "好嘞,朋友们,我们已经在泥土博物馆里捣鼓了一阵子,现在是时候跟大自然亲密接触了!看看这片森林,绿叶上水珠闪闪发光,就像我曾经的爱情,虽然短暂,却美得让人心碎。\n\n现在,我在这里挖个小坑,感觉自己就像是一位新晋“挖土大王”,不过说实话,这手艺真不敢恭维,连铲子都快对我崩溃了。再说劈柴,这动作简直比我前任的情绪波动还要激烈!最后这一潭浑浊的水,别担心,它只是告诉我:生活就像这水,总有些杂质,但也别忘了,要勇敢面对哦!",
|
||||
"OST": 2,
|
||||
"new_timestamp": "00:51-01:37"
|
||||
}
|
||||
]
|
||||
}
|
||||
output_path和script参数需要传递给请求3
|
||||
请求3返回参数是
|
||||
{
|
||||
"task_id": "b6f5a98a-b2e0-4e3d-89c5-64fb90db2ec1",
|
||||
"subclip_videos": {
|
||||
"00:10-01:01": "E:\\projects\\NarratoAI\\storage\\cache_videos/vid-00_10-01_01.mp4",
|
||||
"01:07-01:53": "E:\\projects\\NarratoAI\\storage\\cache_videos/vid-01_07-01_53.mp4"
|
||||
}
|
||||
}
|
||||
subclip_videos和 output_path和script参数需要传递给请求4
|
||||
最后完成工作流
|
||||
|
||||
0代表只播放文案音频,禁用视频原声;1代表只播放视频原声,不需要播放文案音频和字幕;2代表即播放文案音频也要播放视频原声;
|
||||
@ -112,6 +112,7 @@ def render_tts_settings(tr):
|
||||
|
||||
# 保存TTS引擎选择
|
||||
config.ui["tts_engine"] = selected_engine
|
||||
st.session_state['tts_engine'] = selected_engine
|
||||
|
||||
# 2. 显示引擎详细说明
|
||||
if selected_engine in engine_descriptions:
|
||||
@ -490,17 +491,14 @@ def render_soulvoice_engine_settings(tr):
|
||||
# 音色 URI 输入
|
||||
voice_uri = st.text_input(
|
||||
"音色URI",
|
||||
value=config.soulvoice.get("voice_uri", "speech:mcg3fdnx:clzkyf4vy00e5qr6hywum4u84:bzznlkuhcjzpbosexitr"),
|
||||
value=config.soulvoice.get("voice_uri", "speech:2c2hp73s:clzkyf4vy00e5qr6hywum4u84:itjmezhxyynkyzrhhjav"),
|
||||
help="请输入 SoulVoice 音色标识符",
|
||||
placeholder="speech:mcg3fdnx:clzkyf4vy00e5qr6hywum4u84:bzznlkuhcjzpbosexitr"
|
||||
placeholder="speech:2c2hp73s:clzkyf4vy00e5qr6hywum4u84:itjmezhxyynkyzrhhjav"
|
||||
)
|
||||
|
||||
# 模型名称选择
|
||||
model_options = [
|
||||
"FunAudioLLM/CosyVoice2-0.5B",
|
||||
"FunAudioLLM/CosyVoice-300M",
|
||||
"FunAudioLLM/CosyVoice-300M-SFT",
|
||||
"FunAudioLLM/CosyVoice-300M-Instruct"
|
||||
"FunAudioLLM/CosyVoice2-0.5B"
|
||||
]
|
||||
|
||||
saved_model = config.soulvoice.get("model", "FunAudioLLM/CosyVoice2-0.5B")
|
||||
@ -636,7 +634,7 @@ def render_soulvoice_settings(tr):
|
||||
saved_api_key = config.soulvoice.get("api_key", "")
|
||||
saved_api_url = config.soulvoice.get("api_url", "https://tts.scsmtech.cn/tts")
|
||||
saved_model = config.soulvoice.get("model", "FunAudioLLM/CosyVoice2-0.5B")
|
||||
saved_voice_uri = config.soulvoice.get("voice_uri", "speech:mcg3fdnx:clzkyf4vy00e5qr6hywum4u84:bzznlkuhcjzpbosexitr")
|
||||
saved_voice_uri = config.soulvoice.get("voice_uri", "speech:2c2hp73s:clzkyf4vy00e5qr6hywum4u84:itjmezhxyynkyzrhhjav")
|
||||
|
||||
# API Key 输入
|
||||
api_key = st.text_input(
|
||||
@ -650,8 +648,8 @@ def render_soulvoice_settings(tr):
|
||||
voice_uri = st.text_input(
|
||||
"音色 URI",
|
||||
value=saved_voice_uri,
|
||||
help="请输入 SoulVoice 音色标识符,格式如:speech:mcg3fdnx:clzkyf4vy00e5qr6hywum4u84:bzznlkuhcjzpbosexitr",
|
||||
placeholder="speech:mcg3fdnx:clzkyf4vy00e5qr6hywum4u84:bzznlkuhcjzpbosexitr"
|
||||
help="请输入 SoulVoice 音色标识符,格式如:speech:2c2hp73s:clzkyf4vy00e5qr6hywum4u84:itjmezhxyynkyzrhhjav",
|
||||
placeholder="speech:2c2hp73s:clzkyf4vy00e5qr6hywum4u84:itjmezhxyynkyzrhhjav"
|
||||
)
|
||||
|
||||
# API URL 输入(可选)
|
||||
@ -822,4 +820,5 @@ def get_audio_params():
|
||||
'bgm_type': st.session_state.get('bgm_type', 'random'),
|
||||
'bgm_file': st.session_state.get('bgm_file', ''),
|
||||
'bgm_volume': st.session_state.get('bgm_volume', AudioVolumeDefaults.BGM_VOLUME),
|
||||
'tts_engine': st.session_state.get('tts_engine', "edge_tts"),
|
||||
}
|
||||
|
||||
@ -138,6 +138,7 @@ def test_vision_model_connection(api_key, base_url, model_name, provider, tr):
|
||||
str: 测试结果消息
|
||||
"""
|
||||
import requests
|
||||
logger.debug(f"大模型连通性测试: {base_url} 模型: {model_name} apikey: {api_key}")
|
||||
if provider.lower() == 'gemini':
|
||||
# 原生Gemini API测试
|
||||
try:
|
||||
@ -145,43 +146,21 @@ def test_vision_model_connection(api_key, base_url, model_name, provider, tr):
|
||||
request_data = {
|
||||
"contents": [{
|
||||
"parts": [{"text": "直接回复我文本'当前网络可用'"}]
|
||||
}],
|
||||
"generationConfig": {
|
||||
"temperature": 1.0,
|
||||
"topK": 40,
|
||||
"topP": 0.95,
|
||||
"maxOutputTokens": 100,
|
||||
},
|
||||
"safetySettings": [
|
||||
{
|
||||
"category": "HARM_CATEGORY_HARASSMENT",
|
||||
"threshold": "BLOCK_NONE"
|
||||
},
|
||||
{
|
||||
"category": "HARM_CATEGORY_HATE_SPEECH",
|
||||
"threshold": "BLOCK_NONE"
|
||||
},
|
||||
{
|
||||
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
|
||||
"threshold": "BLOCK_NONE"
|
||||
},
|
||||
{
|
||||
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
|
||||
"threshold": "BLOCK_NONE"
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
# 构建请求URL
|
||||
api_base_url = base_url or "https://generativelanguage.googleapis.com/v1beta"
|
||||
url = f"{api_base_url}/models/{model_name}:generateContent?key={api_key}"
|
||||
|
||||
api_base_url = base_url
|
||||
url = f"{api_base_url}/models/{model_name}:generateContent"
|
||||
# 发送请求
|
||||
response = requests.post(
|
||||
url,
|
||||
json=request_data,
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=30
|
||||
headers={
|
||||
"x-goog-api-key": api_key,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
timeout=10
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
@ -190,7 +169,6 @@ def test_vision_model_connection(api_key, base_url, model_name, provider, tr):
|
||||
return False, f"{tr('原生Gemini模型连接失败')}: HTTP {response.status_code}"
|
||||
except Exception as e:
|
||||
return False, f"{tr('原生Gemini模型连接失败')}: {str(e)}"
|
||||
|
||||
elif provider.lower() == 'gemini(openai)':
|
||||
# OpenAI兼容的Gemini代理测试
|
||||
try:
|
||||
@ -215,23 +193,6 @@ def test_vision_model_connection(api_key, base_url, model_name, provider, tr):
|
||||
return False, f"{tr('OpenAI兼容Gemini代理连接失败')}: HTTP {response.status_code}"
|
||||
except Exception as e:
|
||||
return False, f"{tr('OpenAI兼容Gemini代理连接失败')}: {str(e)}"
|
||||
elif provider.lower() == 'narratoapi':
|
||||
try:
|
||||
# 构建测试请求
|
||||
headers = {
|
||||
"Authorization": f"Bearer {api_key}"
|
||||
}
|
||||
|
||||
test_url = f"{base_url.rstrip('/')}/health"
|
||||
response = requests.get(test_url, headers=headers, timeout=10)
|
||||
|
||||
if response.status_code == 200:
|
||||
return True, tr("NarratoAPI is available")
|
||||
else:
|
||||
return False, f"{tr('NarratoAPI is not available')}: HTTP {response.status_code}"
|
||||
except Exception as e:
|
||||
return False, f"{tr('NarratoAPI is not available')}: {str(e)}"
|
||||
|
||||
else:
|
||||
from openai import OpenAI
|
||||
try:
|
||||
@ -441,7 +402,8 @@ def test_text_model_connection(api_key, base_url, model_name, provider, tr):
|
||||
str: 测试结果消息
|
||||
"""
|
||||
import requests
|
||||
|
||||
logger.debug(f"大模型连通性测试: {base_url} 模型: {model_name} apikey: {api_key}")
|
||||
|
||||
try:
|
||||
# 构建统一的测试请求(遵循OpenAI格式)
|
||||
headers = {
|
||||
@ -457,43 +419,22 @@ def test_text_model_connection(api_key, base_url, model_name, provider, tr):
|
||||
request_data = {
|
||||
"contents": [{
|
||||
"parts": [{"text": "直接回复我文本'当前网络可用'"}]
|
||||
}],
|
||||
"generationConfig": {
|
||||
"temperature": 1.0,
|
||||
"topK": 40,
|
||||
"topP": 0.95,
|
||||
"maxOutputTokens": 100,
|
||||
},
|
||||
"safetySettings": [
|
||||
{
|
||||
"category": "HARM_CATEGORY_HARASSMENT",
|
||||
"threshold": "BLOCK_NONE"
|
||||
},
|
||||
{
|
||||
"category": "HARM_CATEGORY_HATE_SPEECH",
|
||||
"threshold": "BLOCK_NONE"
|
||||
},
|
||||
{
|
||||
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
|
||||
"threshold": "BLOCK_NONE"
|
||||
},
|
||||
{
|
||||
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
|
||||
"threshold": "BLOCK_NONE"
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
# 构建请求URL
|
||||
api_base_url = base_url or "https://generativelanguage.googleapis.com/v1beta"
|
||||
url = f"{api_base_url}/models/{model_name}:generateContent?key={api_key}"
|
||||
api_base_url = base_url
|
||||
url = f"{api_base_url}/models/{model_name}:generateContent"
|
||||
|
||||
# 发送请求
|
||||
response = requests.post(
|
||||
url,
|
||||
json=request_data,
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=30
|
||||
headers={
|
||||
"x-goog-api-key": api_key,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
timeout=10
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user