mirror of
https://github.com/sun-guannan/CapCutAPI.git
synced 2025-11-25 03:15:00 +08:00
@@ -246,6 +246,9 @@ mcp_client.call_tool("add_text", {
|
||||
|
||||
调用 `save_draft` 会在`capcut_server.py`当前目录下生成一个 `dfd_` 开头的文件夹,将其复制到剪映/CapCut 草稿目录,即可在应用中看到生成的草稿。
|
||||
|
||||
## 模版
|
||||
我们汇总了一些模版,放在`pattern`文件夹下。
|
||||
|
||||
## 社区与支持
|
||||
|
||||
我们欢迎各种形式的贡献!我们的迭代规则:
|
||||
|
||||
11
README.md
11
README.md
@@ -29,12 +29,15 @@ Enjoy It! 😀😀😀
|
||||
|
||||
**Combine AI-generated images and videos using CapCutAPI**
|
||||
|
||||
[More](pattern)
|
||||
|
||||
[](https://www.youtube.com/watch?v=1zmQWt13Dx0)
|
||||
|
||||
[](https://www.youtube.com/watch?v=IF1RDFGOtEU)
|
||||
|
||||
[](https://www.youtube.com/watch?v=rGNLE_slAJ8)
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
## Key Features
|
||||
@@ -156,7 +159,7 @@ response = requests.post("http://localhost:9001/add_text", json={
|
||||
"text": "Welcome to CapCutAPI",
|
||||
"start": 0,
|
||||
"end": 5,
|
||||
"font": "Source Han Sans",
|
||||
"font": "Source Han Sans",read
|
||||
"font_color": "#FFD700",
|
||||
"font_size": 48,
|
||||
"shadow_enabled": True,
|
||||
@@ -243,6 +246,10 @@ mcp_client.call_tool("add_text", {
|
||||
|
||||
Calling `save_draft` will generate a folder starting with `dfd_` in the current directory of `capcut_server.py`. Copy this to the CapCut/Jianying drafts directory to see the generated draft in the application.
|
||||
|
||||
## Pattern
|
||||
|
||||
You can find a lot of pattern in the `pattern` directory.
|
||||
|
||||
## Community & Support
|
||||
|
||||
We welcome contributions of all forms\! Our iteration rules are:
|
||||
@@ -282,4 +289,4 @@ If you want to:
|
||||
|
||||
</div>
|
||||
|
||||
*Made with ❤️ by the CapCutAPI Community*
|
||||
*Made with ❤️ by the CapCutAPI Community*
|
||||
|
||||
@@ -14,7 +14,7 @@ def add_text_impl(
|
||||
draft_id: str | None = None, # Python 3.10+ 新语法
|
||||
transform_y: float = -0.8,
|
||||
transform_x: float = 0,
|
||||
font: str = "文轩体",
|
||||
font: Optional[str] = None,
|
||||
font_color: str = "#ffffff",
|
||||
font_size: float = 8.0,
|
||||
track_name: str = "text_main",
|
||||
@@ -102,11 +102,14 @@ def add_text_impl(
|
||||
:return: Updated draft information
|
||||
"""
|
||||
# Validate if font is in Font_type
|
||||
try:
|
||||
font_type = getattr(Font_type, font)
|
||||
except:
|
||||
available_fonts = [attr for attr in dir(Font_type) if not attr.startswith('_')]
|
||||
raise ValueError(f"Unsupported font: {font}, please use one of the fonts in Font_type: {available_fonts}")
|
||||
if font is None:
|
||||
font_type = None
|
||||
else:
|
||||
try:
|
||||
font_type = getattr(Font_type, font)
|
||||
except:
|
||||
available_fonts = [attr for attr in dir(Font_type) if not attr.startswith('_')]
|
||||
raise ValueError(f"Unsupported font: {font}, please use one of the fonts in Font_type: {available_fonts}")
|
||||
|
||||
# Validate alpha value range
|
||||
if not 0.0 <= font_alpha <= 1.0:
|
||||
|
||||
@@ -162,7 +162,7 @@ def add_text_impl(text, start, end, font, font_color, font_size, track_name, dra
|
||||
|
||||
return make_request("add_text", data)
|
||||
|
||||
def add_image_impl(image_url, width, height, start, end, track_name, draft_id=None,
|
||||
def add_image_impl(image_url, start, end, width=None, height=None, track_name="image_main", draft_id=None,
|
||||
transform_x=0, transform_y=0, scale_x=1.0, scale_y=1.0, transition=None, transition_duration=None,
|
||||
mask_type=None, mask_center_x=0.0, mask_center_y=0.0, mask_size=0.5,
|
||||
mask_rotation=0.0, mask_feather=0.0, mask_invert=False,
|
||||
|
||||
12
pattern/001-words-coze.md
Normal file
12
pattern/001-words-coze.md
Normal file
File diff suppressed because one or more lines are too long
626
pattern/001-words.py
Normal file
626
pattern/001-words.py
Normal file
@@ -0,0 +1,626 @@
|
||||
import requests
|
||||
import json
|
||||
from flask import Flask, request, jsonify, Response
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
|
||||
sys.path.append('/Users/sunguannan/capcutapi')
|
||||
from example import add_image_impl
|
||||
|
||||
PORT=9001 #端口
|
||||
BASE_URL = f"http://localhost:{PORT}"
|
||||
draft_folder = "/Users/sunguannan/Movies/JianyingPro/User Data/Projects/com.lveditor.draft"
|
||||
|
||||
|
||||
|
||||
|
||||
def make_request(endpoint, data, method='POST'):
|
||||
"""Send HTTP request to the server and handle the response"""
|
||||
url = f"{BASE_URL}/{endpoint}"
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
try:
|
||||
if method == 'POST':
|
||||
response = requests.post(url, data=json.dumps(data), headers=headers)
|
||||
elif method == 'GET':
|
||||
response = requests.get(url, params=data, headers=headers)
|
||||
else:
|
||||
raise ValueError(f"Unsupported HTTP method: {method}")
|
||||
|
||||
response.raise_for_status() # Raise an exception if the request fails
|
||||
return response.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Request error: {e}")
|
||||
sys.exit(1)
|
||||
except json.JSONDecodeError:
|
||||
print("Unable to parse server response")
|
||||
sys.exit(1)
|
||||
|
||||
def save_draft_impl(draft_id, draft_folder):
|
||||
"""API wrapper for save_draft service"""
|
||||
data = {
|
||||
"draft_id": draft_id,
|
||||
"draft_folder": draft_folder
|
||||
}
|
||||
return make_request("save_draft", data)
|
||||
|
||||
def query_script_impl(draft_id):
|
||||
"""API wrapper for query_script service"""
|
||||
data = {
|
||||
"draft_id": draft_id
|
||||
}
|
||||
return make_request("query_script", data)
|
||||
|
||||
def add_text_impl(text, start, end, font, font_color, font_size, track_name, draft_folder="123", draft_id=None,
|
||||
vertical=False, transform_x=0, transform_y=0, font_alpha=1.0,
|
||||
border_color=None, border_width=0.0, border_alpha=1.0,
|
||||
background_color=None, background_alpha=1.0, background_style=None,
|
||||
background_round_radius=0.0, background_height=0.14, background_width=0.14,
|
||||
background_horizontal_offset=0.5, background_vertical_offset=0.5,
|
||||
shadow_enabled=False, shadow_alpha=0.9, shadow_angle=-45.0,
|
||||
shadow_color="#000000", shadow_distance=5.0, shadow_smoothing=0.15,
|
||||
bubble_effect_id=None, bubble_resource_id=None,
|
||||
effect_effect_id=None,
|
||||
intro_animation=None, intro_duration=0.5,
|
||||
outro_animation=None, outro_duration=0.5,
|
||||
width=1080, height=1920,
|
||||
fixed_width=-1, fixed_height=-1,
|
||||
text_styles=None):
|
||||
"""Add text with support for multiple styles, shadows, and backgrounds"""
|
||||
data = {
|
||||
"draft_folder": draft_folder,
|
||||
"text": text,
|
||||
"start": start,
|
||||
"end": end,
|
||||
"font": font,
|
||||
"font_color": font_color,
|
||||
"font_size": font_size,
|
||||
"alpha": font_alpha,
|
||||
"track_name": track_name,
|
||||
"vertical": vertical,
|
||||
"transform_x": transform_x,
|
||||
"transform_y": transform_y
|
||||
}
|
||||
|
||||
# Add border parameters
|
||||
if border_color:
|
||||
data["border_color"] = border_color
|
||||
data["border_width"] = border_width
|
||||
data["border_alpha"] = border_alpha
|
||||
|
||||
# Add background parameters
|
||||
if background_color:
|
||||
data["background_color"] = background_color
|
||||
data["background_alpha"] = background_alpha
|
||||
if background_style:
|
||||
data["background_style"] = background_style
|
||||
data["background_round_radius"] = background_round_radius
|
||||
data["background_height"] = background_height
|
||||
data["background_width"] = background_width
|
||||
data["background_horizontal_offset"] = background_horizontal_offset
|
||||
data["background_vertical_offset"] = background_vertical_offset
|
||||
|
||||
# Add shadow parameters
|
||||
if shadow_enabled:
|
||||
data["shadow_enabled"] = shadow_enabled
|
||||
data["shadow_alpha"] = shadow_alpha
|
||||
data["shadow_angle"] = shadow_angle
|
||||
data["shadow_color"] = shadow_color
|
||||
data["shadow_distance"] = shadow_distance
|
||||
data["shadow_smoothing"] = shadow_smoothing
|
||||
|
||||
|
||||
# Add bubble effect parameters
|
||||
if bubble_effect_id:
|
||||
data["bubble_effect_id"] = bubble_effect_id
|
||||
if bubble_resource_id:
|
||||
data["bubble_resource_id"] = bubble_resource_id
|
||||
|
||||
# Add text effect parameters
|
||||
if effect_effect_id:
|
||||
data["effect_effect_id"] = effect_effect_id
|
||||
|
||||
# Add intro animation parameters
|
||||
if intro_animation:
|
||||
data["intro_animation"] = intro_animation
|
||||
data["intro_duration"] = intro_duration
|
||||
|
||||
# Add outro animation parameters
|
||||
if outro_animation:
|
||||
data["outro_animation"] = outro_animation
|
||||
data["outro_duration"] = outro_duration
|
||||
|
||||
# Add size parameters
|
||||
data["width"] = width
|
||||
data["height"] = height
|
||||
|
||||
# Add fixed size parameters
|
||||
if fixed_width > 0:
|
||||
data["fixed_width"] = fixed_width
|
||||
if fixed_height > 0:
|
||||
data["fixed_height"] = fixed_height
|
||||
|
||||
if draft_id:
|
||||
data["draft_id"] = draft_id
|
||||
|
||||
# Add text styles parameters
|
||||
if text_styles:
|
||||
data["text_styles"] = text_styles
|
||||
|
||||
if draft_id:
|
||||
data["draft_id"] = draft_id
|
||||
|
||||
return make_request("add_text", data)
|
||||
|
||||
|
||||
def group_sentences(corrected_srt, threshold=1.0):
|
||||
"""按时间间隔分句"""
|
||||
if not corrected_srt:
|
||||
return []
|
||||
sentences = []
|
||||
current_sentence = [corrected_srt[0]]
|
||||
for i in range(1, len(corrected_srt)):
|
||||
prev_end = corrected_srt[i-1]["end"]
|
||||
curr_start = corrected_srt[i]["start"]
|
||||
if curr_start - prev_end > threshold:
|
||||
sentences.append(current_sentence)
|
||||
current_sentence = [corrected_srt[i]]
|
||||
else:
|
||||
current_sentence.append(corrected_srt[i])
|
||||
sentences.append(current_sentence)
|
||||
return sentences
|
||||
|
||||
|
||||
def adjust_sentence_timing(sentences, gap_adjust=1, time_precision=3):
|
||||
"""调整句子间的时间间隔,并保留原始时间"""
|
||||
def round_time(t):
|
||||
return round(t, time_precision) if time_precision is not None else t
|
||||
|
||||
adjusted_sentences = []
|
||||
total_offset = 0.0
|
||||
prev_end = sentences[0][-1]["end"]
|
||||
|
||||
# 第一句保持原时间
|
||||
first_sentence = [
|
||||
{
|
||||
"word": w["word"],
|
||||
"start": w["start"],
|
||||
"end": w["end"],
|
||||
"original_start": w["start"],
|
||||
"original_end": w["end"]
|
||||
}
|
||||
for w in sentences[0]
|
||||
]
|
||||
adjusted_sentences.append(first_sentence)
|
||||
|
||||
for i in range(1, len(sentences)):
|
||||
sentence = sentences[i]
|
||||
curr_start = sentence[0]["start"]
|
||||
natural_gap = curr_start - prev_end
|
||||
adjusted_gap = natural_gap if gap_adjust == 0 else (1.0 if natural_gap > 1.0 else natural_gap)
|
||||
move_amount = natural_gap - adjusted_gap
|
||||
total_offset += move_amount
|
||||
|
||||
adjusted_sentence = []
|
||||
for w in sentence:
|
||||
adjusted_sentence.append({
|
||||
"word": w["word"],
|
||||
"start": round_time(w["start"] - total_offset),
|
||||
"end": round_time(w["end"] - total_offset),
|
||||
"original_start": w["start"],
|
||||
"original_end": w["end"]
|
||||
})
|
||||
adjusted_sentences.append(adjusted_sentence)
|
||||
prev_end = sentence[-1]["end"]
|
||||
return adjusted_sentences
|
||||
|
||||
|
||||
def split_into_paragraphs(sentence, max_words=5, max_chunk_duration=1.5):
|
||||
"""把句子按词数和时长分段"""
|
||||
paragraphs = []
|
||||
i = 0
|
||||
n = len(sentence)
|
||||
while i < n:
|
||||
paragraph = [sentence[i]]
|
||||
current_start = sentence[i]["start"]
|
||||
current_end = sentence[i]["end"]
|
||||
i += 1
|
||||
while i < n:
|
||||
current_word = sentence[i]
|
||||
is_continuous = abs(current_word["start"] - current_end) < 0.001
|
||||
if (len(paragraph) >= max_words or
|
||||
(current_word["end"] - current_start) >= max_chunk_duration or
|
||||
not is_continuous):
|
||||
break
|
||||
paragraph.append(current_word)
|
||||
current_end = current_word["end"]
|
||||
i += 1
|
||||
paragraphs.append(paragraph)
|
||||
|
||||
return paragraphs
|
||||
|
||||
|
||||
def build_segments_by_mode(
|
||||
mode,
|
||||
paragraph,
|
||||
track_name,
|
||||
font,
|
||||
font_size,
|
||||
highlight_color,
|
||||
normal_color,
|
||||
transform_x,
|
||||
transform_y,
|
||||
fixed_width,
|
||||
shadow_enabled,
|
||||
shadow_color,
|
||||
border_color,
|
||||
border_width,
|
||||
border_alpha,
|
||||
background_color,
|
||||
):
|
||||
|
||||
"""根据模式生成字幕片段"""
|
||||
segments = []
|
||||
#print("二级代码返回调试fx", fixed_width)
|
||||
|
||||
if mode == "word_pop":
|
||||
# 单词跳出
|
||||
for w in paragraph:
|
||||
text_styles = []
|
||||
word_count = len(w["word"].replace(" ", "")) #统计有多少个字
|
||||
text_styles.append({
|
||||
"start": 0,
|
||||
"end": word_count,
|
||||
"border": {
|
||||
"alpha": border_alpha,
|
||||
"color": border_color,
|
||||
"width": border_width
|
||||
}
|
||||
})
|
||||
segments.append({
|
||||
"text": w["word"],
|
||||
"start": w["start"],
|
||||
"end": w["end"],
|
||||
"font": font,
|
||||
"track_name": track_name,
|
||||
"font_color": normal_color,
|
||||
"font_size": font_size,
|
||||
"transform_x": transform_x,
|
||||
"transform_y": transform_y,
|
||||
"shadow_enabled": shadow_enabled,
|
||||
"fixed_width": fixed_width,
|
||||
"text_styles": text_styles,
|
||||
|
||||
"shadow_color": shadow_color,
|
||||
"border_color": border_color,
|
||||
"border_width": border_width,
|
||||
"border_alpha": border_alpha,
|
||||
|
||||
"background_color": background_color,
|
||||
})
|
||||
|
||||
elif mode == "word_highlight":
|
||||
# 单词高亮:当前词亮,其他灰
|
||||
paragraph_text = " ".join(w["word"] for w in paragraph)
|
||||
offsets = []
|
||||
ci = 0
|
||||
for w in paragraph:
|
||||
offsets.append((ci, ci + len(w["word"])))
|
||||
ci += len(w["word"]) + 1
|
||||
for idx, w in enumerate(paragraph):
|
||||
text_styles = []
|
||||
for k, (s, e) in enumerate(offsets):
|
||||
color = highlight_color if k == idx else normal_color
|
||||
text_styles.append({
|
||||
"start": s,
|
||||
"end": e,
|
||||
"style": {
|
||||
"color": color,
|
||||
"size": font_size,
|
||||
},
|
||||
"border": {
|
||||
"alpha": border_alpha,
|
||||
"color": border_color,
|
||||
"width": border_width
|
||||
}
|
||||
})
|
||||
print("text_styles", text_styles)
|
||||
|
||||
segments.append({
|
||||
"text": paragraph_text,
|
||||
"start": w["start"],
|
||||
"end": w["end"],
|
||||
"font": font,
|
||||
"track_name": track_name,
|
||||
"font_color": normal_color,
|
||||
"font_size": font_size,
|
||||
"text_styles": text_styles,
|
||||
"transform_x": transform_x,
|
||||
"transform_y": transform_y,
|
||||
"shadow_enabled": shadow_enabled,
|
||||
"fixed_width": fixed_width,
|
||||
|
||||
|
||||
"shadow_color": shadow_color,
|
||||
"border_color": border_color,
|
||||
"border_width": border_width,
|
||||
"border_alpha": border_alpha,
|
||||
|
||||
"background_color": background_color,
|
||||
})
|
||||
|
||||
elif mode == "sentence_fade":
|
||||
# 句子渐显:已亮过的词继续保持亮
|
||||
paragraph_text = " ".join(w["word"] for w in paragraph)
|
||||
offsets = []
|
||||
ci = 0
|
||||
for w in paragraph:
|
||||
offsets.append((ci, ci + len(w["word"])))
|
||||
ci += len(w["word"]) + 1
|
||||
for idx, w in enumerate(paragraph):
|
||||
text_styles = []
|
||||
for k, (s, e) in enumerate(offsets):
|
||||
color = highlight_color if k <= idx else normal_color
|
||||
text_styles.append({
|
||||
"start": s,
|
||||
"end": e,
|
||||
"style": {"color": color, "size": font_size},
|
||||
"border": {
|
||||
"alpha": border_alpha,
|
||||
"color": border_color,
|
||||
"width": border_width
|
||||
}
|
||||
})
|
||||
segments.append({
|
||||
"text": paragraph_text,
|
||||
"start": w["start"],
|
||||
"end": w["end"],
|
||||
"font": font,
|
||||
"track_name": track_name,
|
||||
"font_color": normal_color,
|
||||
"font_size": font_size,
|
||||
"text_styles": text_styles,
|
||||
"transform_x": transform_x,
|
||||
"transform_y": transform_y,
|
||||
"shadow_enabled": shadow_enabled,
|
||||
"fixed_width": fixed_width,
|
||||
|
||||
|
||||
"shadow_color": shadow_color,
|
||||
"border_color": border_color,
|
||||
"border_width": border_width,
|
||||
"border_alpha": border_alpha,
|
||||
|
||||
"background_color": background_color,
|
||||
})
|
||||
|
||||
elif mode == "sentence_pop":
|
||||
# 句子跳出
|
||||
text = " ".join(w["word"] for w in paragraph)
|
||||
start_time = paragraph[0]["start"]
|
||||
end_time = paragraph[-1]["end"]
|
||||
text_styles = []
|
||||
word_count = len(text.replace(" ", "")) #统计有多少个字
|
||||
text_styles.append({
|
||||
"start": 0,
|
||||
"end": word_count,
|
||||
"border": {
|
||||
"alpha": border_alpha,
|
||||
"color": border_color,
|
||||
"width": border_width
|
||||
}
|
||||
})
|
||||
segments.append({
|
||||
"text": text,
|
||||
"start": start_time,
|
||||
"end": end_time,
|
||||
"font": font,
|
||||
"track_name": track_name,
|
||||
"font_color": normal_color,
|
||||
"font_size": font_size,
|
||||
"transform_x": transform_x,
|
||||
"transform_y": transform_y,
|
||||
"shadow_enabled": shadow_enabled,
|
||||
"fixed_width": fixed_width,
|
||||
"text_styles": text_styles,
|
||||
|
||||
|
||||
"shadow_color": shadow_color,
|
||||
"border_color": border_color,
|
||||
"border_width": border_width,
|
||||
"border_alpha": border_alpha,
|
||||
|
||||
"background_color": background_color,
|
||||
})
|
||||
|
||||
else:
|
||||
raise ValueError(f"未知模式: {mode}")
|
||||
"""segments.append({
|
||||
"file_name": file_name,
|
||||
})"""
|
||||
|
||||
return segments
|
||||
|
||||
corrected_srt = [{
|
||||
"word": "Hello",
|
||||
"start": 0.0,
|
||||
"end": 0.64,
|
||||
"confidence": 0.93917525
|
||||
},
|
||||
{
|
||||
"word": "I'm",
|
||||
"start": 0.64,
|
||||
"end": 0.79999995,
|
||||
"confidence": 0.9976464
|
||||
},
|
||||
{
|
||||
"word": "PAWA",
|
||||
"start": 0.79999995,
|
||||
"end": 1.36,
|
||||
"confidence": 0.6848311
|
||||
},
|
||||
{
|
||||
"word": "Nice",
|
||||
"start": 1.36,
|
||||
"end": 1.52,
|
||||
"confidence": 0.9850389
|
||||
},
|
||||
{
|
||||
"word": "To",
|
||||
"start": 1.52,
|
||||
"end": 1.68,
|
||||
"confidence": 0.9926886
|
||||
},
|
||||
{
|
||||
"word": "Meet",
|
||||
"start": 1.68,
|
||||
"end": 2.08,
|
||||
"confidence": 0.9972697
|
||||
},
|
||||
{
|
||||
"word": "You",
|
||||
"start": 2.08,
|
||||
"end": 2.72,
|
||||
"confidence": 0.9845563
|
||||
},
|
||||
{
|
||||
"word": "Enjoy",
|
||||
"start": 2.72,
|
||||
"end": 3.04,
|
||||
"confidence": 0.99794894
|
||||
},
|
||||
{
|
||||
"word": "My",
|
||||
"start": 3.04,
|
||||
"end": 3.1999998,
|
||||
"confidence": 0.9970203
|
||||
},
|
||||
{
|
||||
"word": "Parttern",
|
||||
"start": 3.1999998,
|
||||
"end": 3.36,
|
||||
"confidence": 0.9970235
|
||||
},
|
||||
{
|
||||
"word": "Thank",
|
||||
"start": 3.36,
|
||||
"end": 3.6799998,
|
||||
"confidence": 0.98627764
|
||||
},
|
||||
{
|
||||
"word": "You",
|
||||
"start": 3.6799998,
|
||||
"end": 4.0,
|
||||
"confidence": 0.9939551
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def add_koubo_from_srt(
|
||||
corrected_srt,
|
||||
track_name,
|
||||
mode="word_pop",
|
||||
font="ZY_Modern",
|
||||
font_size=32,
|
||||
highlight_color="#FFD700",
|
||||
normal_color="#AAAAAA", max_chunk_duration=1.5, max_words=5,
|
||||
gap_adjust=1,
|
||||
time_precision=3,
|
||||
transform_x=0.5,
|
||||
transform_y=0.3,
|
||||
fixed_width=-1,
|
||||
shadow_enabled=True,
|
||||
shadow_color="#000000",
|
||||
border_color="#000000",
|
||||
border_width=0.5,
|
||||
border_alpha=1.0,
|
||||
background_color="#000000",
|
||||
|
||||
):
|
||||
"""统一入口:根据 mode 选择字幕效果"""
|
||||
sentences = group_sentences(corrected_srt)
|
||||
adjusted_sentences = adjust_sentence_timing(sentences, gap_adjust, time_precision)
|
||||
all_paragraphs = [split_into_paragraphs(s, max_words, max_chunk_duration) for s in adjusted_sentences]
|
||||
|
||||
draft_id_ret = None
|
||||
for sentence_paragraphs in all_paragraphs:
|
||||
for paragraph in sentence_paragraphs:
|
||||
segments = build_segments_by_mode(
|
||||
mode,
|
||||
paragraph,
|
||||
track_name,
|
||||
font,
|
||||
font_size,
|
||||
highlight_color,
|
||||
normal_color,
|
||||
transform_x,
|
||||
transform_y,
|
||||
fixed_width,
|
||||
shadow_enabled,
|
||||
shadow_color,
|
||||
border_color,
|
||||
border_width,
|
||||
border_alpha,
|
||||
background_color,
|
||||
|
||||
)
|
||||
#print("segments", segments)
|
||||
|
||||
for seg in segments:
|
||||
#print("二级代码返回调试fx", seg)
|
||||
if draft_id_ret:
|
||||
seg["draft_id"] = draft_id_ret
|
||||
print("seg", seg)
|
||||
|
||||
res = add_text_impl(**seg)
|
||||
if draft_id_ret is None and isinstance(res, dict):
|
||||
try:
|
||||
draft_id_ret = res["output"]["draft_id"]
|
||||
except:
|
||||
pass
|
||||
return draft_id_ret
|
||||
|
||||
colors = {
|
||||
"shadow_color": "#000000",
|
||||
"border_color": "#FFD700",
|
||||
"background_color": "#000000",
|
||||
"normal_color": "#FFFFFF",
|
||||
"highlight_color": "#DA70D6" # 紫色
|
||||
}
|
||||
|
||||
draft_id = add_koubo_from_srt(
|
||||
corrected_srt,
|
||||
track_name="main_text",
|
||||
font_size=15,
|
||||
gap_adjust=0,
|
||||
transform_x=0,
|
||||
transform_y=-0.45,# 0=保持原间隔,1=调整>1s的间隔
|
||||
fixed_width = 0.6,
|
||||
mode="word_highlight",
|
||||
shadow_enabled=True,
|
||||
border_width=10,
|
||||
border_alpha=1.0,
|
||||
|
||||
**colors,
|
||||
|
||||
font="ZY_Modern", #设置自己的字体,需要在字体库中添加
|
||||
|
||||
|
||||
)
|
||||
|
||||
add_image_impl(image_url="https://pic1.imgdb.cn/item/689aff2758cb8da5c81e64a2.png", start = 0, end = 4, draft_id=draft_id)
|
||||
|
||||
save_result = save_draft_impl(draft_id, draft_folder)
|
||||
|
||||
print(save_result)
|
||||
"""
|
||||
# 单词高亮
|
||||
mode="word_highlight"
|
||||
# 单词跳出
|
||||
mode="word_pop"
|
||||
# 句子渐显
|
||||
mode="sentence_fade"
|
||||
# 句子跳出
|
||||
mode="sentence_pop"
|
||||
"""
|
||||
606
pattern/002-relationship.py
Normal file
606
pattern/002-relationship.py
Normal file
@@ -0,0 +1,606 @@
|
||||
import json
|
||||
import random
|
||||
import requests
|
||||
|
||||
# Set API keys
|
||||
QWEN_API_KEY = "your qwen api key"
|
||||
PEXELS_API_KEY = "your pexels api key"
|
||||
CAPCUT_API_KEY = "your capcut api key"
|
||||
LICENSE_KEY="your capcut license key",
|
||||
|
||||
|
||||
def llm(query = ""):
|
||||
"""
|
||||
Call the Tongyi Qianwen large language model
|
||||
|
||||
Parameters:
|
||||
|
||||
Returns:
|
||||
dict: Dictionary containing title and list of sentences
|
||||
"""
|
||||
|
||||
# Build system prompt
|
||||
system_prompt = """
|
||||
* **Context:** You are an AI expert specializing in modern interpersonal relationships and emotional communication. Your knowledge base is built on a deep understanding of popular emotional content on social media, and you excel at interpreting the dynamics and perspectives of relationships in a relaxed, colloquial style.
|
||||
|
||||
* **Objective:** When the user inputs "Give me some random returns", your goal is to **randomly create** advice about male-female emotions, behavioral habits, or relationship guidance. Your content must strictly mimic the unique style shown in the examples below.
|
||||
|
||||
* **Style:** Your generated content should have the following characteristics:
|
||||
|
||||
* **Structure:** Use a list format, with each point being a short, independent sentence.
|
||||
* **Wording:** Use colloquial language, often using the "When..." sentence pattern to describe a scenario.
|
||||
* **Theme:** Content should revolve around "how to understand the other person", "which behaviors are attractive", or "advice for a specific gender".
|
||||
|
||||
* **Tone:** Your tone should be friendly, sincere, slightly teasing, like a friend sharing experiences on social media.
|
||||
|
||||
* **Audience:** Your audience is anyone interested in modern emotional relationships who wants to get advice in a relaxed way.
|
||||
|
||||
* **Response:** When you receive the instruction "Give me some random returns", please **randomly select one** from the following examples as your response. Or, you can **randomly generate** a new one with a completely consistent style, and return it in the same JSON format:
|
||||
|
||||
**Example 1 (How to understand girls):**
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "How to understand girls",
|
||||
"sentences": [
|
||||
"Hands on her stomach (Insecure)",
|
||||
"She leans on you (Feels safe)",
|
||||
"Covers her smile (Thinks your going to judge)",
|
||||
"Stops texting you (Feels like she is annoying you)",
|
||||
"Says she is fine (She is everything but fine)",
|
||||
"When she hugs you (You mean a lot to her)"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Example 2 (Tips for girls):**
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Tips for the girls (From the guys)",
|
||||
"sentences": [
|
||||
"99/100 guys dont know what hip dips are and actually love your stretch marks",
|
||||
"We can't tell that you like us by just viewing our story, just message us",
|
||||
"When he's out with his boys, let him have this time (this is very important)",
|
||||
"'I'm not ready for a relationship' - unless your the luckiest girl in the world your not getting cuffed",
|
||||
"As Bruno mars said, 'your perfect just the way you are' so just be you, it'll work"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Example 3 (Things guys find attractive in girls):**
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Things girls do that guys find attractive",
|
||||
"sentences": [
|
||||
"Bed hair when it's all messy >>>",
|
||||
"When you come work out with us",
|
||||
"Your sleepy voice in the morning or after a nap",
|
||||
"When you wear our t-shirts as pyjamas",
|
||||
"When you have a funny or really bad laugh",
|
||||
"When you initiate ...",
|
||||
"When your good with animals or animals like you"
|
||||
]
|
||||
}
|
||||
```
|
||||
"""
|
||||
|
||||
# Build user prompt
|
||||
user_prompt = f"Randomly create advice about male-female emotions, behavioral habits, or relationship guidance, based on user input: {query}"
|
||||
|
||||
# Prepare request data
|
||||
url = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {QWEN_API_KEY}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
data = {
|
||||
"model": "qwen-plus",
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": system_prompt
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": user_prompt
|
||||
}
|
||||
],
|
||||
"temperature": 0.7,
|
||||
"max_tokens": 16384,
|
||||
"response_format": {"type": "json_object"}
|
||||
}
|
||||
|
||||
try:
|
||||
# Send HTTP request
|
||||
response = requests.post(url, headers=headers, json=data, timeout=30)
|
||||
|
||||
# Check response status
|
||||
if response.status_code == 200:
|
||||
response_data = response.json()
|
||||
|
||||
# Extract content from response
|
||||
if 'choices' in response_data and len(response_data['choices']) > 0:
|
||||
content = response_data['choices'][0]['message']['content']
|
||||
|
||||
try:
|
||||
# Parse JSON response
|
||||
result = json.loads(content)
|
||||
|
||||
# Ensure result contains necessary fields
|
||||
if "title" in result and "sentences" in result:
|
||||
return result
|
||||
except json.JSONDecodeError:
|
||||
pass # If JSON parsing fails, will return predefined example
|
||||
|
||||
# If API call fails or parsing fails, print error message
|
||||
print(f"Error: {response.status_code}, {response.text if hasattr(response, 'text') else 'No response text'}")
|
||||
except Exception as e:
|
||||
# Catch all possible exceptions
|
||||
print(f"Exception occurred: {str(e)}")
|
||||
|
||||
|
||||
def search_pexels_videos(query="twilight", min_duration=10, orientation="portrait", per_page=15):
|
||||
"""
|
||||
Call Pexels API to search for videos
|
||||
|
||||
Parameters:
|
||||
query (str): Search keyword, default is "twilight"
|
||||
min_duration (int): Minimum video duration (seconds), default is 10 seconds
|
||||
orientation (str): Video orientation, default is "portrait"
|
||||
per_page (int): Number of results per page, default is 15
|
||||
|
||||
Returns:
|
||||
list: List containing video information
|
||||
"""
|
||||
url = "https://api.pexels.com/videos/search"
|
||||
headers = {
|
||||
"Authorization": PEXELS_API_KEY
|
||||
}
|
||||
params = {
|
||||
"query": query,
|
||||
"orientation": orientation,
|
||||
"per_page": per_page,
|
||||
"min_duration": min_duration
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.get(url, headers=headers, params=params)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
videos = []
|
||||
|
||||
for video in data.get("videos", []):
|
||||
# Get video file information
|
||||
video_files = video.get("video_files", [])
|
||||
# Filter out 16:9 ratio video files
|
||||
portrait_videos = [file for file in video_files
|
||||
if file.get("width") and file.get("height") and
|
||||
file.get("height") / file.get("width") > 1.7] # Close to 16:9 ratio
|
||||
|
||||
if portrait_videos:
|
||||
# Select highest quality video file
|
||||
best_quality = max(portrait_videos, key=lambda x: x.get("width", 0) * x.get("height", 0))
|
||||
|
||||
videos.append({
|
||||
"id": video.get("id"),
|
||||
"url": video.get("url"),
|
||||
"image": video.get("image"),
|
||||
"duration": video.get("duration"),
|
||||
"user": video.get("user", {}).get("name"),
|
||||
"video_url": best_quality.get("link"),
|
||||
"width": best_quality.get("width"),
|
||||
"height": best_quality.get("height"),
|
||||
"file_type": best_quality.get("file_type")
|
||||
})
|
||||
|
||||
if videos:
|
||||
random_video = random.choice(videos)
|
||||
return random_video['video_url']
|
||||
return []
|
||||
else:
|
||||
print(f"Error: {response.status_code}, {response.text}")
|
||||
return []
|
||||
except Exception as e:
|
||||
print(f"Exception occurred: {str(e)}")
|
||||
return []
|
||||
|
||||
|
||||
def create_capcut_draft(width=1080, height=1920):
|
||||
"""
|
||||
Call CapCut API to create a new draft
|
||||
|
||||
Parameters:
|
||||
width (int): Video width, default is 1080
|
||||
height (int): Video height, default is 1920
|
||||
|
||||
Returns:
|
||||
dict: Dictionary containing draft ID and download URL, or error message if failed
|
||||
"""
|
||||
url = "https://open.capcutapi.top/cut_jianying/create_draft"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {CAPCUT_API_KEY}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
data = {
|
||||
"width": width,
|
||||
"height": height
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=data)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
|
||||
if result.get("success"):
|
||||
return {
|
||||
"success": True,
|
||||
"draft_id": result.get("output", {}).get("draft_id"),
|
||||
"draft_url": result.get("output", {}).get("draft_url")
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": result.get("error", "Unknown error")
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": f"HTTP Error: {response.status_code}",
|
||||
"response": response.text
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"success": False,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
def add_video_to_draft(draft_id, video_url):
|
||||
"""
|
||||
Call CapCut API to add video to draft
|
||||
|
||||
Parameters:
|
||||
draft_id (str): Draft ID
|
||||
video_url (str): Video URL
|
||||
|
||||
Returns:
|
||||
dict: Dictionary containing draft ID and download URL, or error message if failed
|
||||
"""
|
||||
url = "https://open.capcutapi.top/cut_jianying/add_video"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {CAPCUT_API_KEY}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
data = {
|
||||
"video_url": video_url,
|
||||
"draft_id": draft_id,
|
||||
"end": 10 # Set video duration to 10 seconds
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=data)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
|
||||
if result.get("success"):
|
||||
return {
|
||||
"success": True,
|
||||
"draft_id": result.get("output", {}).get("draft_id"),
|
||||
"draft_url": result.get("output", {}).get("draft_url")
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": result.get("error", "Unknown error")
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": f"HTTP Error: {response.status_code}",
|
||||
"response": response.text
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"success": False,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
def add_text_to_draft(draft_id, text, font="ZY_Starry",
|
||||
font_color="#FFFFFF",
|
||||
background_color="#000000",
|
||||
background_alpha=0.5,
|
||||
background_style=2,
|
||||
background_round_radius=10,
|
||||
transform_y=0,
|
||||
transform_x=0,
|
||||
font_size=10.0,
|
||||
fixed_width=0.6,
|
||||
track_name="text_main"):
|
||||
"""
|
||||
Call CapCut API to add text to draft
|
||||
|
||||
Parameters:
|
||||
draft_id (str): Draft ID
|
||||
text (str): Text content
|
||||
start_time (float): Text start time on timeline (seconds), default is 0
|
||||
end_time (float): Text end time on timeline (seconds), default is 5
|
||||
font (str): Font, default is "ZY_Starry"
|
||||
font_color (str): Font color, default is white
|
||||
background_color (str): Background color, default is black
|
||||
background_alpha (float): Background transparency, default is 0.5
|
||||
transform_y (float): Y-axis position offset, default is 0
|
||||
transform_x (float): X-axis position offset, default is 0
|
||||
font_size (float): Font size, default is 10.0
|
||||
|
||||
Returns:
|
||||
dict: Dictionary containing draft ID and download URL, or error message if failed
|
||||
"""
|
||||
url = "https://open.capcutapi.top/cut_jianying/add_text"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {CAPCUT_API_KEY}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
data = {
|
||||
"text": text,
|
||||
"start": 0,
|
||||
"end": 10,
|
||||
"draft_id": draft_id,
|
||||
"font": font,
|
||||
"font_color": font_color,
|
||||
"font_size": font_size,
|
||||
"transform_y": transform_y,
|
||||
"transform_x": transform_x,
|
||||
"fixed_width": fixed_width,
|
||||
"background_color": background_color,
|
||||
"background_alpha": background_alpha,
|
||||
"background_style": background_style,
|
||||
"background_round_radius": background_round_radius,
|
||||
"track_name": track_name
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=data)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
|
||||
if result.get("success"):
|
||||
return {
|
||||
"success": True,
|
||||
"draft_id": result.get("output", {}).get("draft_id"),
|
||||
"draft_url": result.get("output", {}).get("draft_url")
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": result.get("error", "Unknown error")
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": f"HTTP Error: {response.status_code}",
|
||||
"response": response.text
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"success": False,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
def generate_video(draft_id, resolution="720P", framerate="24"):
|
||||
"""
|
||||
Call CapCut API to render video
|
||||
|
||||
Parameters:
|
||||
draft_id (str): Draft ID
|
||||
license_key (str): License key
|
||||
resolution (str): Video resolution, default is "720P"
|
||||
framerate (str): Video frame rate, default is "24"
|
||||
|
||||
Returns:
|
||||
dict: Dictionary containing task ID, or error message if failed
|
||||
"""
|
||||
url = "https://open.capcutapi.top/cut_jianying/generate_video"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {CAPCUT_API_KEY}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
data = {
|
||||
"draft_id": draft_id,
|
||||
"license_key": LICENSE_KEY,
|
||||
"resolution": resolution,
|
||||
"framerate": framerate
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=data)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
|
||||
if result.get("success"):
|
||||
return {
|
||||
"success": True,
|
||||
"task_id": result.get("output", {}).get("task_id")
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": result.get("error", "Unknown error")
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": f"HTTP Error: {response.status_code}",
|
||||
"response": response.text
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"success": False,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
def check_task_status(task_id):
|
||||
"""
|
||||
Call CapCut API to check task status
|
||||
|
||||
Parameters:
|
||||
task_id (str): Task ID
|
||||
|
||||
Returns:
|
||||
dict: Dictionary containing task status and results, or error message if failed
|
||||
"""
|
||||
url = "https://open.capcutapi.top/cut_jianying/task_status"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {CAPCUT_API_KEY}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
data = {
|
||||
"task_id": task_id
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=data)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
|
||||
if result.get("success"):
|
||||
output = result.get("output", {})
|
||||
return {
|
||||
"success": True,
|
||||
"status": output.get("status"),
|
||||
"progress": output.get("progress"),
|
||||
"result": output.get("result"), # Video URL
|
||||
"error": output.get("error")
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": result.get("error", "Unknown error")
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": f"HTTP Error: {response.status_code}",
|
||||
"response": response.text
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"success": False,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
# Example usage
|
||||
if __name__ == "__main__":
|
||||
|
||||
# Call LLM function and print result
|
||||
result = llm()
|
||||
print(json.dumps(result, indent=2, ensure_ascii=False))
|
||||
|
||||
# 1. Create draft
|
||||
draft_result = create_capcut_draft()
|
||||
print("Draft creation result:", json.dumps(draft_result, indent=2, ensure_ascii=False))
|
||||
|
||||
if draft_result.get("success"):
|
||||
|
||||
draft_id = draft_result.get("draft_id")
|
||||
|
||||
# 2. Search Pexels videos
|
||||
video_url = search_pexels_videos()
|
||||
print("Pexels video URL:", video_url)
|
||||
|
||||
# 3. Add video to draft
|
||||
if video_url:
|
||||
add_result = add_video_to_draft(draft_result.get("draft_id"), video_url)
|
||||
print("Add video result:", json.dumps(add_result, indent=2, ensure_ascii=False))
|
||||
|
||||
|
||||
# 5. Add title text
|
||||
title_result = add_text_to_draft(
|
||||
draft_id=draft_id,
|
||||
text=result["title"],
|
||||
font="ZY_Starry", # Use starry font
|
||||
font_color="#FFFFFF", # White font
|
||||
background_color="#000000", # Black background
|
||||
background_alpha=1, # Background transparency
|
||||
background_style=1,
|
||||
background_round_radius=10,
|
||||
transform_y=0.7, # Located at the top of the screen (1 is top edge, -1 is bottom edge)
|
||||
transform_x=0, # Horizontally centered
|
||||
font_size=13.0, # Larger font
|
||||
track_name = "title",
|
||||
fixed_width=0.6
|
||||
)
|
||||
print("Add title result:", json.dumps(title_result, indent=2, ensure_ascii=False))
|
||||
|
||||
# 6. Add sentence text
|
||||
sentence_count = len(result["sentences"])
|
||||
for i, sentence in enumerate(result["sentences"]):
|
||||
# Calculate vertical position - evenly distributed in the middle of the screen
|
||||
transform_y = 0.5 - (1.1 * (i + 1) / (sentence_count + 1))
|
||||
|
||||
# Determine horizontal alignment - odd sentences left-aligned, even sentences right-aligned
|
||||
if i % 2 == 0: # Odd sentences (counting from 0)
|
||||
transform_x = -0.5 # Left-aligned
|
||||
else: # Even sentences
|
||||
transform_x = 0.5 # Right-aligned
|
||||
|
||||
sentence_result = add_text_to_draft(
|
||||
draft_id=draft_id,
|
||||
text=sentence,
|
||||
font="ZY_Fantasy", # Use fantasy font
|
||||
font_color="#FFFFFF", # White font
|
||||
transform_y=transform_y, # Vertical position
|
||||
transform_x=transform_x, # Horizontal position (left-right alignment)
|
||||
background_alpha=0,
|
||||
font_size=7.0, # Smaller font
|
||||
fixed_width=0.3,
|
||||
track_name=f"text_{i}"
|
||||
)
|
||||
print(f"Add sentence {i+1} result:", json.dumps(sentence_result, indent=2, ensure_ascii=False))
|
||||
|
||||
# 7. Render video
|
||||
print("\nStarting video rendering...")
|
||||
generate_result = generate_video(draft_id)
|
||||
print("Video rendering request result:", json.dumps(generate_result, indent=2, ensure_ascii=False))
|
||||
|
||||
if generate_result.get("success"):
|
||||
task_id = generate_result.get("task_id")
|
||||
print(f"Task ID: {task_id}, starting to poll task status...")
|
||||
|
||||
# 8. Poll task status
|
||||
import time
|
||||
max_attempts = 30 # Maximum 30 polling attempts
|
||||
attempt = 0
|
||||
|
||||
while attempt < max_attempts:
|
||||
status_result = check_task_status(task_id)
|
||||
print(f"Poll count {attempt+1}, status:", json.dumps(status_result, indent=2, ensure_ascii=False))
|
||||
|
||||
if not status_result.get("success"):
|
||||
print("Failed to check task status:", status_result.get("error"))
|
||||
break
|
||||
|
||||
status = status_result.get("status")
|
||||
if status == "SUCCESS":
|
||||
print("\nVideo rendering successful!")
|
||||
print("Video URL:", status_result.get("result"))
|
||||
break
|
||||
elif status == "FAILED":
|
||||
print("\nVideo rendering failed:", status_result.get("error"))
|
||||
break
|
||||
|
||||
# Wait 5 seconds before checking again
|
||||
print("Waiting 5 seconds before checking again...")
|
||||
time.sleep(5)
|
||||
attempt += 1
|
||||
|
||||
if attempt >= max_attempts:
|
||||
print("\nPolling timeout, please check task status manually later")
|
||||
13
pattern/README.md
Normal file
13
pattern/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Pattern Gallery
|
||||
|
||||
## 001-words.py
|
||||
|
||||
[source](001-words.py)
|
||||
|
||||
[](https://www.youtube.com/watch?v=HLSHaJuNtBw)
|
||||
|
||||
## 002-relationship.py
|
||||
|
||||
[source](002-relationship.py)
|
||||
|
||||
[](https://www.youtube.com/watch?v=f2Q1OI_SQZo)
|
||||
Reference in New Issue
Block a user