sophhub 0.4.44 → 0.4.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/image-classify/skill.json +9 -2
- package/skills/image-classify/src/pyproject.toml +2 -2
- package/skills/image-description/skill.json +9 -2
- package/skills/image-description/src/pyproject.toml +2 -2
- package/skills/image-identify-world/skill.json +9 -2
- package/skills/image-identify-world/src/pyproject.toml +2 -2
- package/skills/online-bug-report/skill.json +9 -2
- package/skills/online-bug-report/src/pyproject.toml +1 -1
- package/skills/sophnet-age-appearance/skill.json +16 -2
- package/skills/sophnet-age-appearance/src/pyproject.toml +2 -2
- package/skills/sophnet-age-appearance/src/scripts/age_appearance.py +8 -10
- package/skills/sophnet-customized-marketing/skill.json +9 -2
- package/skills/sophnet-customized-marketing/src/pyproject.toml +1 -1
- package/skills/sophnet-docx/skill.json +9 -2
- package/skills/sophnet-docx/src/pyproject.toml +1 -1
- package/skills/sophnet-face-search/skill.json +9 -2
- package/skills/sophnet-face-search/src/pyproject.toml +2 -2
- package/skills/sophnet-id-photo/skill.json +16 -2
- package/skills/sophnet-id-photo/src/pyproject.toml +2 -2
- package/skills/sophnet-id-photo/src/scripts/id_photo.py +5 -7
- package/skills/sophnet-image-edit/skill.json +16 -2
- package/skills/sophnet-image-edit/src/pyproject.toml +2 -2
- package/skills/sophnet-image-edit/src/scripts/edit_image.py +5 -7
- package/skills/sophnet-image-generate/skill.json +16 -2
- package/skills/sophnet-image-generate/src/pyproject.toml +2 -2
- package/skills/sophnet-image-generate/src/scripts/generate_image.py +51 -1
- package/skills/sophnet-image-ocr/skill.json +9 -2
- package/skills/sophnet-image-ocr/src/pyproject.toml +2 -2
- package/skills/sophnet-image-ocr/src/references/api-details.md +1 -1
- package/skills/sophnet-infinite-talk/skill.json +16 -2
- package/skills/sophnet-infinite-talk/src/pyproject.toml +1 -1
- package/skills/sophnet-infinite-talk/src/scripts/gen.py +39 -0
- package/skills/sophnet-pdf/skill.json +9 -2
- package/skills/sophnet-pdf/src/pyproject.toml +1 -1
- package/skills/sophnet-sticker-edit/skill.json +16 -2
- package/skills/sophnet-sticker-edit/src/pyproject.toml +2 -2
- package/skills/sophnet-sticker-edit/src/scripts/edit_sticker_image.py +5 -7
- package/skills/sophnet-tts/skill.json +9 -2
- package/skills/sophnet-tts/src/pyproject.toml +1 -1
- package/skills/sophnet-video-generate/skill.json +16 -2
- package/skills/sophnet-video-generate/src/SKILL.md +21 -12
- package/skills/sophnet-video-generate/src/pyproject.toml +2 -2
- package/skills/sophnet-video-generate/src/scripts/gen_video.py +10 -15
- package/skills/sophnet-xlsx/skill.json +9 -2
- package/skills/sophnet-xlsx/src/pyproject.toml +1 -1
- package/skills/store-marketing/skill.json +16 -2
- package/skills/store-marketing/src/pyproject.toml +2 -2
- package/skills/store-marketing/src/scripts/generate_poster.py +39 -1
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "image-classify",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"types": [
|
|
5
5
|
"store"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "照片分类器",
|
|
8
8
|
"description": "照片分类器:注册人脸、按人搜索/一键分类相册。当用户说用照片分类器查找或搜索某人、对文件夹分类、添加/删除照片分类器用户时使用。",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.7",
|
|
12
|
+
"date": "2026-06-17",
|
|
13
|
+
"changes": [
|
|
14
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
10
17
|
{
|
|
11
18
|
"version": "1.0.6",
|
|
12
19
|
"date": "2026-05-20",
|
|
@@ -59,5 +66,5 @@
|
|
|
59
66
|
}
|
|
60
67
|
],
|
|
61
68
|
"createdAt": "2026-04-10",
|
|
62
|
-
"updatedAt": "2026-
|
|
69
|
+
"updatedAt": "2026-06-17"
|
|
63
70
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "image-classify"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.7"
|
|
4
4
|
description = "Photo classifier by face embedding similarity"
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
dependencies = [
|
|
7
7
|
"opencv-python-headless>=4.8.0",
|
|
8
8
|
"numpy>=1.24.0",
|
|
9
9
|
"requests>=2.28.0",
|
|
10
|
-
"sophnet-tools>=0.0.
|
|
10
|
+
"sophnet-tools>=0.0.2",
|
|
11
11
|
]
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "image-description",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"types": [
|
|
5
5
|
"store"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "图片描述",
|
|
8
8
|
"description": "生成图片描述",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.4",
|
|
12
|
+
"date": "2026-06-17",
|
|
13
|
+
"changes": [
|
|
14
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
10
17
|
{
|
|
11
18
|
"changes": [
|
|
12
19
|
"ana_image.py:HTTP 200 但无法提取非空 content 时 stderr 报错并 exit 1,移除 json.dumps fallback"
|
|
@@ -37,5 +44,5 @@
|
|
|
37
44
|
}
|
|
38
45
|
],
|
|
39
46
|
"createdAt": "2026-04-21",
|
|
40
|
-
"updatedAt": "2026-06-
|
|
47
|
+
"updatedAt": "2026-06-17"
|
|
41
48
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "image-description"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.4"
|
|
4
4
|
description = "Generate image descriptions with Sophnet via chat/completions"
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
dependencies = [
|
|
7
|
-
"sophnet-tools>=0.0.
|
|
7
|
+
"sophnet-tools>=0.0.2",
|
|
8
8
|
]
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "image-identify-world",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"types": [
|
|
5
5
|
"store"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "识万物",
|
|
8
8
|
"description": "图像主体识别与科普说明,专业审慎地描述可能名称、特征、分布习性、安全提醒和不确定性。",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.1",
|
|
12
|
+
"date": "2026-06-17",
|
|
13
|
+
"changes": [
|
|
14
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
10
17
|
{
|
|
11
18
|
"changes": [
|
|
12
19
|
"初次提交:VLM 识图 + 结构化百科输出"
|
|
@@ -16,5 +23,5 @@
|
|
|
16
23
|
}
|
|
17
24
|
],
|
|
18
25
|
"createdAt": "2026-05-13",
|
|
19
|
-
"updatedAt": "2026-
|
|
26
|
+
"updatedAt": "2026-06-17"
|
|
20
27
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "image-identify-world"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.1"
|
|
4
4
|
description = "Identify image subjects with cautious explanatory detail via Sophnet VLM"
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
dependencies = [
|
|
7
|
-
"sophnet-tools>=0.0.
|
|
7
|
+
"sophnet-tools>=0.0.2",
|
|
8
8
|
]
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "online-bug-report",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"types": [
|
|
5
5
|
"store"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "在线提Bug",
|
|
8
8
|
"description": "当用户说「在线提交bug」时,收集问题描述并通过虾友 DM 提交工单。",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.11",
|
|
12
|
+
"date": "2026-06-17",
|
|
13
|
+
"changes": [
|
|
14
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
10
17
|
{
|
|
11
18
|
"changes": [
|
|
12
19
|
"evals 断言改为引擎可识别的 contains/不包含 规则",
|
|
@@ -98,5 +105,5 @@
|
|
|
98
105
|
}
|
|
99
106
|
],
|
|
100
107
|
"createdAt": "2026-05-18",
|
|
101
|
-
"updatedAt": "2026-06-
|
|
108
|
+
"updatedAt": "2026-06-17"
|
|
102
109
|
}
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-age-appearance",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"types": [
|
|
5
5
|
"store"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "年龄相貌模拟",
|
|
8
8
|
"description": "仅支持单张人物图:用 AI 模拟指定年龄的长相(幼年、青少年或成年以后等推演)。用户问「10 岁 / 20 岁长什么样」「变老变年轻」「年龄推演」「小时候或以后样子」并希望出图时使用;多图需分次调用。",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.2",
|
|
12
|
+
"date": "2026-06-24",
|
|
13
|
+
"changes": [
|
|
14
|
+
"修复 upload_oss 失败时临时文件泄漏;移除 PREVIEW_PATH 回退"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"version": "1.0.1",
|
|
19
|
+
"date": "2026-06-17",
|
|
20
|
+
"changes": [
|
|
21
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
10
24
|
{
|
|
11
25
|
"changes": [
|
|
12
26
|
"初版:单人参考图;支持单个或多个目标年龄;输出 IMAGE_URL"
|
|
@@ -16,5 +30,5 @@
|
|
|
16
30
|
}
|
|
17
31
|
],
|
|
18
32
|
"createdAt": "2026-05-13",
|
|
19
|
-
"updatedAt": "2026-
|
|
33
|
+
"updatedAt": "2026-06-24"
|
|
20
34
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sophnet-age-appearance"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.1"
|
|
4
4
|
description = "Sophnet portrait age-appearance simulation via image-edit"
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
dependencies = [
|
|
7
7
|
"requests>=2.28.0",
|
|
8
|
-
"sophnet-tools>=0.0.
|
|
8
|
+
"sophnet-tools>=0.0.2",
|
|
9
9
|
"pillow>=9.5.0",
|
|
10
10
|
]
|
|
@@ -216,8 +216,9 @@ def reupload_for_signed_url(api_key, raw_url):
|
|
|
216
216
|
|
|
217
217
|
signed_url = sophnet_tools.upload_oss(tmp_path)
|
|
218
218
|
if not signed_url:
|
|
219
|
-
print("Warning: upload_oss returned no signed URL
|
|
220
|
-
|
|
219
|
+
print("Warning: upload_oss returned no signed URL", file=sys.stderr)
|
|
220
|
+
os.unlink(tmp_path)
|
|
221
|
+
return None, None
|
|
221
222
|
|
|
222
223
|
return signed_url, tmp_path
|
|
223
224
|
|
|
@@ -246,14 +247,11 @@ def emit_one_age_image(api_key, args, ages_list, idx, edit_refs):
|
|
|
246
247
|
print(f"TARGET_AGE={age}", flush=True)
|
|
247
248
|
signed_url, local_path = reupload_for_signed_url(api_key, raw_url)
|
|
248
249
|
print(f"IMAGE_URL={signed_url or raw_url}", flush=True)
|
|
249
|
-
if local_path:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
pass
|
|
255
|
-
else:
|
|
256
|
-
print(f"PREVIEW_PATH={local_path}", flush=True)
|
|
250
|
+
if signed_url and local_path:
|
|
251
|
+
try:
|
|
252
|
+
os.unlink(local_path)
|
|
253
|
+
except OSError:
|
|
254
|
+
pass
|
|
257
255
|
if idx + 1 < len(ages_list):
|
|
258
256
|
time.sleep(max(0, args.pause_between_calls))
|
|
259
257
|
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-customized-marketing",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"types": [
|
|
5
5
|
"builtin"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "个性化营销助手",
|
|
8
8
|
"description": "个性化营销助手:为中小商户策划营销活动,生成贴合业务的营销文案、宣传图片、海报、卡片和其他营销视觉物料,支持多渠道分发与老板风格定制。",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.2",
|
|
12
|
+
"date": "2026-06-17",
|
|
13
|
+
"changes": [
|
|
14
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
10
17
|
{
|
|
11
18
|
"version": "1.0.1",
|
|
12
19
|
"date": "2026-04-10",
|
|
@@ -24,5 +31,5 @@
|
|
|
24
31
|
}
|
|
25
32
|
],
|
|
26
33
|
"createdAt": "2026-04-09",
|
|
27
|
-
"updatedAt": "2026-
|
|
34
|
+
"updatedAt": "2026-06-17"
|
|
28
35
|
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-docx",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"types": [
|
|
5
5
|
"builtin"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "",
|
|
8
8
|
"description": "",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.1.1",
|
|
12
|
+
"date": "2026-06-17",
|
|
13
|
+
"changes": [
|
|
14
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
10
17
|
{
|
|
11
18
|
"version": "1.1.0",
|
|
12
19
|
"date": "2026-06-08",
|
|
@@ -29,5 +36,5 @@
|
|
|
29
36
|
}
|
|
30
37
|
],
|
|
31
38
|
"createdAt": "2026-04-14",
|
|
32
|
-
"updatedAt": "2026-06-
|
|
39
|
+
"updatedAt": "2026-06-17"
|
|
33
40
|
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-face-search",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"types": [
|
|
5
5
|
"builtin"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "",
|
|
8
8
|
"description": "",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.1",
|
|
12
|
+
"date": "2026-06-17",
|
|
13
|
+
"changes": [
|
|
14
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
10
17
|
{
|
|
11
18
|
"version": "1.0.0",
|
|
12
19
|
"date": "2026-04-09",
|
|
@@ -16,5 +23,5 @@
|
|
|
16
23
|
}
|
|
17
24
|
],
|
|
18
25
|
"createdAt": "2026-04-09",
|
|
19
|
-
"updatedAt": "2026-
|
|
26
|
+
"updatedAt": "2026-06-17"
|
|
20
27
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sophnet-face-search"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.1"
|
|
4
4
|
description = "Face search using Sophnet face detection and embedding API"
|
|
5
5
|
requires-python = ">=3.8"
|
|
6
6
|
dependencies = [
|
|
7
7
|
"opencv-python-headless>=4.8.0",
|
|
8
8
|
"numpy>=1.24.0",
|
|
9
9
|
"requests>=2.28.0",
|
|
10
|
-
"sophnet-tools>=0.0.
|
|
10
|
+
"sophnet-tools>=0.0.2",
|
|
11
11
|
]
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-id-photo",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"types": [
|
|
5
5
|
"store"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "一键证件照",
|
|
8
8
|
"description": "Sophnet 证件照:人脸检测后在多张达标脸中取面积最大者裁切头肩,VL 预审后换纯色底(白/蓝/红)并微调体态与角度。用户要证件照、换证件照底色、一寸/二寸/报名或电子证照底色时使用。",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.2",
|
|
12
|
+
"date": "2026-06-24",
|
|
13
|
+
"changes": [
|
|
14
|
+
"修复 upload_oss 失败时临时文件泄漏;移除 PREVIEW_PATH 回退"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"version": "1.0.1",
|
|
19
|
+
"date": "2026-06-17",
|
|
20
|
+
"changes": [
|
|
21
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
10
24
|
{
|
|
11
25
|
"changes": [
|
|
12
26
|
"初版:白/蓝/红底,默认白底;输出 ALL_BG_TIP"
|
|
@@ -16,5 +30,5 @@
|
|
|
16
30
|
}
|
|
17
31
|
],
|
|
18
32
|
"createdAt": "2026-05-13",
|
|
19
|
-
"updatedAt": "2026-
|
|
33
|
+
"updatedAt": "2026-06-24"
|
|
20
34
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sophnet-id-photo"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.1"
|
|
4
4
|
description = "Sophnet ID photo: solid background + corrections; optional compliance gate; preserve identity"
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
dependencies = [
|
|
7
7
|
"requests>=2.28.0",
|
|
8
|
-
"sophnet-tools>=0.0.
|
|
8
|
+
"sophnet-tools>=0.0.2",
|
|
9
9
|
"opencv-python-headless>=4.8.0",
|
|
10
10
|
]
|
|
@@ -323,8 +323,9 @@ def reupload_for_signed_url(api_key, raw_url):
|
|
|
323
323
|
|
|
324
324
|
signed_url = sophnet_tools.upload_oss(tmp_path)
|
|
325
325
|
if not signed_url:
|
|
326
|
-
print("Warning: upload_oss returned no signed URL
|
|
327
|
-
|
|
326
|
+
print("Warning: upload_oss returned no signed URL", file=sys.stderr)
|
|
327
|
+
os.unlink(tmp_path)
|
|
328
|
+
return None, None
|
|
328
329
|
|
|
329
330
|
return signed_url, tmp_path
|
|
330
331
|
|
|
@@ -527,11 +528,8 @@ def main():
|
|
|
527
528
|
for i, raw_url in enumerate(raw_urls, 1):
|
|
528
529
|
signed_url, local_path = reupload_for_signed_url(api_key, raw_url)
|
|
529
530
|
print(f"IMAGE_URL={signed_url or raw_url}")
|
|
530
|
-
if local_path:
|
|
531
|
-
|
|
532
|
-
os.unlink(local_path)
|
|
533
|
-
else:
|
|
534
|
-
print(f"PREVIEW_PATH={local_path}")
|
|
531
|
+
if signed_url and local_path:
|
|
532
|
+
os.unlink(local_path)
|
|
535
533
|
|
|
536
534
|
print(f"ALL_BG_TIP={ALL_BG_TIP}", flush=True)
|
|
537
535
|
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-image-edit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"types": [
|
|
5
5
|
"builtin"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "",
|
|
8
8
|
"description": "",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.3",
|
|
12
|
+
"date": "2026-06-24",
|
|
13
|
+
"changes": [
|
|
14
|
+
"修复 upload_oss 失败时临时文件泄漏;移除 PREVIEW_PATH 回退"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"version": "1.0.2",
|
|
19
|
+
"date": "2026-06-17",
|
|
20
|
+
"changes": [
|
|
21
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
10
24
|
{
|
|
11
25
|
"version": "1.0.1",
|
|
12
26
|
"date": "2026-06-09",
|
|
@@ -23,5 +37,5 @@
|
|
|
23
37
|
}
|
|
24
38
|
],
|
|
25
39
|
"createdAt": "2026-04-09",
|
|
26
|
-
"updatedAt": "2026-06-
|
|
40
|
+
"updatedAt": "2026-06-24"
|
|
27
41
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sophnet-image-edit"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.2"
|
|
4
4
|
description = "Sophnet image editing (image-to-image) with task polling"
|
|
5
5
|
requires-python = ">=3.8"
|
|
6
6
|
dependencies = [
|
|
7
7
|
"requests>=2.28.0",
|
|
8
|
-
"sophnet-tools>=0.0.
|
|
8
|
+
"sophnet-tools>=0.0.2",
|
|
9
9
|
]
|
|
10
10
|
|
|
11
11
|
[[tool.uv.index]]
|
|
@@ -194,8 +194,9 @@ def reupload_for_signed_url(api_key, raw_url):
|
|
|
194
194
|
|
|
195
195
|
signed_url = sophnet_tools.upload_oss(tmp_path)
|
|
196
196
|
if not signed_url:
|
|
197
|
-
print("Warning: upload_oss returned no signed URL
|
|
198
|
-
|
|
197
|
+
print("Warning: upload_oss returned no signed URL", file=sys.stderr)
|
|
198
|
+
os.unlink(tmp_path)
|
|
199
|
+
return None, None
|
|
199
200
|
|
|
200
201
|
return signed_url, tmp_path
|
|
201
202
|
|
|
@@ -268,11 +269,8 @@ def main():
|
|
|
268
269
|
for i, raw_url in enumerate(raw_urls, 1):
|
|
269
270
|
signed_url, local_path = reupload_for_signed_url(api_key, raw_url)
|
|
270
271
|
print(f"IMAGE_URL={signed_url or raw_url}")
|
|
271
|
-
if local_path:
|
|
272
|
-
|
|
273
|
-
os.unlink(local_path)
|
|
274
|
-
else:
|
|
275
|
-
print(f"PREVIEW_PATH={local_path}")
|
|
272
|
+
if signed_url and local_path:
|
|
273
|
+
os.unlink(local_path)
|
|
276
274
|
|
|
277
275
|
|
|
278
276
|
if __name__ == "__main__":
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-image-generate",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"types": [
|
|
5
5
|
"builtin"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "",
|
|
8
8
|
"description": "",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.3",
|
|
12
|
+
"date": "2026-06-24",
|
|
13
|
+
"changes": [
|
|
14
|
+
"生成图片后通过 sophnet_tools.upload_oss 重新上传,输出短链接避免被 Openclaw 截断"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"version": "1.0.2",
|
|
19
|
+
"date": "2026-06-17",
|
|
20
|
+
"changes": [
|
|
21
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
10
24
|
{
|
|
11
25
|
"version": "1.0.1",
|
|
12
26
|
"date": "2026-06-09",
|
|
@@ -23,5 +37,5 @@
|
|
|
23
37
|
}
|
|
24
38
|
],
|
|
25
39
|
"createdAt": "2026-04-09",
|
|
26
|
-
"updatedAt": "2026-06-
|
|
40
|
+
"updatedAt": "2026-06-24"
|
|
27
41
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sophnet-image-generate"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.2"
|
|
4
4
|
description = "Sophnet text-to-image generation with task polling"
|
|
5
5
|
requires-python = ">=3.8"
|
|
6
6
|
dependencies = [
|
|
7
7
|
"requests>=2.28.0",
|
|
8
|
-
"sophnet-tools>=0.0.
|
|
8
|
+
"sophnet-tools>=0.0.2",
|
|
9
9
|
]
|
|
10
10
|
|
|
11
11
|
[[tool.uv.index]]
|
|
@@ -6,7 +6,9 @@ Outputs machine-friendly TASK_ID, STATUS, and IMAGE_URL lines.
|
|
|
6
6
|
|
|
7
7
|
import argparse
|
|
8
8
|
import json
|
|
9
|
+
import os
|
|
9
10
|
import sys
|
|
11
|
+
import tempfile
|
|
10
12
|
import time
|
|
11
13
|
|
|
12
14
|
import requests
|
|
@@ -111,6 +113,49 @@ def extract_urls(data):
|
|
|
111
113
|
return urls
|
|
112
114
|
|
|
113
115
|
|
|
116
|
+
def reupload_images(api_key, urls):
|
|
117
|
+
"""Download images from URLs and re-upload to OSS for short signed URLs."""
|
|
118
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
119
|
+
new_urls = []
|
|
120
|
+
temp_files = []
|
|
121
|
+
|
|
122
|
+
for url in urls:
|
|
123
|
+
try:
|
|
124
|
+
resp = requests.get(url, headers=headers, timeout=120, stream=True)
|
|
125
|
+
resp.raise_for_status()
|
|
126
|
+
except requests.RequestException as e:
|
|
127
|
+
print(f"Warning: failed to download image: {e}", file=sys.stderr)
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
ext = os.path.splitext(url.split("?")[0])[-1] or ".png"
|
|
131
|
+
fd, tmp_path = tempfile.mkstemp(suffix=ext, prefix="img_gen_")
|
|
132
|
+
try:
|
|
133
|
+
with os.fdopen(fd, "wb") as f:
|
|
134
|
+
for chunk in resp.iter_content(8192):
|
|
135
|
+
f.write(chunk)
|
|
136
|
+
except IOError as e:
|
|
137
|
+
print(f"Warning: failed to write temp file: {e}", file=sys.stderr)
|
|
138
|
+
os.unlink(tmp_path)
|
|
139
|
+
continue
|
|
140
|
+
|
|
141
|
+
signed_url = sophnet_tools.upload_oss(tmp_path)
|
|
142
|
+
if signed_url:
|
|
143
|
+
new_urls.append(signed_url)
|
|
144
|
+
else:
|
|
145
|
+
print("Warning: upload_oss failed, using original URL", file=sys.stderr)
|
|
146
|
+
new_urls.append(url)
|
|
147
|
+
|
|
148
|
+
temp_files.append(tmp_path)
|
|
149
|
+
|
|
150
|
+
for f in temp_files:
|
|
151
|
+
try:
|
|
152
|
+
os.unlink(f)
|
|
153
|
+
except OSError:
|
|
154
|
+
pass
|
|
155
|
+
|
|
156
|
+
return new_urls
|
|
157
|
+
|
|
158
|
+
|
|
114
159
|
def main():
|
|
115
160
|
parser = argparse.ArgumentParser(description="SophNet image generation")
|
|
116
161
|
parser.add_argument("--prompt", required=True, help="Image prompt")
|
|
@@ -148,7 +193,12 @@ def main():
|
|
|
148
193
|
print(json.dumps(result, ensure_ascii=False), file=sys.stderr)
|
|
149
194
|
sys.exit(1)
|
|
150
195
|
|
|
151
|
-
|
|
196
|
+
new_urls = reupload_images(api_key, urls)
|
|
197
|
+
if not new_urls:
|
|
198
|
+
print("Error: all image re-uploads failed.", file=sys.stderr)
|
|
199
|
+
sys.exit(1)
|
|
200
|
+
|
|
201
|
+
for u in new_urls:
|
|
152
202
|
print(f"IMAGE_URL={u}")
|
|
153
203
|
|
|
154
204
|
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-image-ocr",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"types": [
|
|
5
5
|
"builtin"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "",
|
|
8
8
|
"description": "Use when the user needs to extract text, tables, or structured content from images or PDF files. Supports local files and URLs via Sophnet OCR API.",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.1.1",
|
|
12
|
+
"date": "2026-06-17",
|
|
13
|
+
"changes": [
|
|
14
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
10
17
|
{
|
|
11
18
|
"version": "1.1.0",
|
|
12
19
|
"date": "2026-05-26",
|
|
@@ -28,5 +35,5 @@
|
|
|
28
35
|
}
|
|
29
36
|
],
|
|
30
37
|
"createdAt": "2026-04-09",
|
|
31
|
-
"updatedAt": "2026-
|
|
38
|
+
"updatedAt": "2026-06-17"
|
|
32
39
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "image-ocr"
|
|
3
|
-
version = "1.1.
|
|
3
|
+
version = "1.1.1"
|
|
4
4
|
description = "OCR text and table extraction using Sophnet PaddleOCR API"
|
|
5
5
|
requires-python = ">=3.8"
|
|
6
6
|
dependencies = [
|
|
7
7
|
"requests>=2.28.0",
|
|
8
|
-
"sophnet-tools>=0.0.
|
|
8
|
+
"sophnet-tools>=0.0.2",
|
|
9
9
|
]
|
|
10
10
|
|
|
11
11
|
[project.optional-dependencies]
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
## Dependencies
|
|
15
15
|
|
|
16
16
|
- `requests>=2.28.0` — HTTP client (always installed)
|
|
17
|
-
- `sophnet-tools>=0.0.
|
|
17
|
+
- `sophnet-tools>=0.0.2` — Sophnet API helpers (always installed)
|
|
18
18
|
- `pymupdf>=1.24.0` — PDF page rendering (auto-installed from Aliyun mirror on first PDF use)
|
|
19
19
|
|
|
20
20
|
## Workflow
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-infinite-talk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"types": [
|
|
5
5
|
"builtin"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "",
|
|
8
8
|
"description": "",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.2",
|
|
12
|
+
"date": "2026-06-24",
|
|
13
|
+
"changes": [
|
|
14
|
+
"query 命令输出 video_url 前通过 sophnet_tools.upload_oss 重新上传,避免长链接被截断"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"version": "1.0.1",
|
|
19
|
+
"date": "2026-06-17",
|
|
20
|
+
"changes": [
|
|
21
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
10
24
|
{
|
|
11
25
|
"version": "1.0.0",
|
|
12
26
|
"date": "2026-04-09",
|
|
@@ -16,5 +30,5 @@
|
|
|
16
30
|
}
|
|
17
31
|
],
|
|
18
32
|
"createdAt": "2026-04-09",
|
|
19
|
-
"updatedAt": "2026-
|
|
33
|
+
"updatedAt": "2026-06-24"
|
|
20
34
|
}
|
|
@@ -14,6 +14,7 @@ import os
|
|
|
14
14
|
import sys
|
|
15
15
|
import argparse
|
|
16
16
|
import json
|
|
17
|
+
import tempfile
|
|
17
18
|
import requests
|
|
18
19
|
from typing import Optional, Any, Dict
|
|
19
20
|
import sophnet_tools
|
|
@@ -120,6 +121,40 @@ def get_task(api_key: str, task_id: str) -> Dict[str, Any]:
|
|
|
120
121
|
return {"status": status, "video_url": video_url}
|
|
121
122
|
|
|
122
123
|
|
|
124
|
+
def reupload_video(api_key, video_url):
|
|
125
|
+
"""Download video from API URL and re-upload to OSS for short signed URL."""
|
|
126
|
+
headers = _headers(api_key)
|
|
127
|
+
try:
|
|
128
|
+
resp = requests.get(video_url, headers=headers, timeout=300, stream=True)
|
|
129
|
+
resp.raise_for_status()
|
|
130
|
+
except requests.RequestException as e:
|
|
131
|
+
print(f"Warning: failed to download video: {e}", file=sys.stderr)
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
ext = os.path.splitext(video_url.split("?")[0])[-1] or ".mp4"
|
|
135
|
+
fd, tmp_path = tempfile.mkstemp(suffix=ext, prefix="inf_talk_")
|
|
136
|
+
try:
|
|
137
|
+
with os.fdopen(fd, "wb") as f:
|
|
138
|
+
for chunk in resp.iter_content(8192):
|
|
139
|
+
f.write(chunk)
|
|
140
|
+
except IOError as e:
|
|
141
|
+
print(f"Warning: failed to write temp file: {e}", file=sys.stderr)
|
|
142
|
+
os.unlink(tmp_path)
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
signed_url = sophnet_tools.upload_oss(tmp_path)
|
|
146
|
+
try:
|
|
147
|
+
os.unlink(tmp_path)
|
|
148
|
+
except OSError:
|
|
149
|
+
pass
|
|
150
|
+
|
|
151
|
+
if not signed_url:
|
|
152
|
+
print("Warning: upload_oss returned no signed URL", file=sys.stderr)
|
|
153
|
+
return None
|
|
154
|
+
|
|
155
|
+
return signed_url
|
|
156
|
+
|
|
157
|
+
|
|
123
158
|
def _json_out(obj: Dict[str, Any]) -> None:
|
|
124
159
|
print(json.dumps(obj, ensure_ascii=False))
|
|
125
160
|
|
|
@@ -167,6 +202,10 @@ if __name__ == "__main__":
|
|
|
167
202
|
|
|
168
203
|
elif args.command == "query":
|
|
169
204
|
result = get_task(api_key, args.task_id)
|
|
205
|
+
if result.get("status") == "succeeded" and result.get("video_url"):
|
|
206
|
+
signed_url = reupload_video(api_key, result["video_url"])
|
|
207
|
+
if signed_url:
|
|
208
|
+
result["video_url"] = signed_url
|
|
170
209
|
_json_out(result)
|
|
171
210
|
if "error" in result:
|
|
172
211
|
sys.exit(1)
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-pdf",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"types": [
|
|
5
5
|
"store"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "PDF处理",
|
|
8
8
|
"description": "PDF文档处理工具,支持创建、编辑和分析 PDF 文档",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.1",
|
|
12
|
+
"date": "2026-06-17",
|
|
13
|
+
"changes": [
|
|
14
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
10
17
|
{
|
|
11
18
|
"version": "1.0.0",
|
|
12
19
|
"date": "2026-04-14",
|
|
@@ -16,5 +23,5 @@
|
|
|
16
23
|
}
|
|
17
24
|
],
|
|
18
25
|
"createdAt": "2026-04-14",
|
|
19
|
-
"updatedAt": "2026-
|
|
26
|
+
"updatedAt": "2026-06-17"
|
|
20
27
|
}
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-sticker-edit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"types": [
|
|
5
5
|
"store"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "表情包生成",
|
|
8
8
|
"description": "根据输入的图片生成表情包",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.3",
|
|
12
|
+
"date": "2026-06-24",
|
|
13
|
+
"changes": [
|
|
14
|
+
"修复 upload_oss 失败时临时文件泄漏;移除 PREVIEW_PATH 回退"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"version": "1.0.2",
|
|
19
|
+
"date": "2026-06-17",
|
|
20
|
+
"changes": [
|
|
21
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
10
24
|
{
|
|
11
25
|
"changes": [
|
|
12
26
|
"pyproject:requires-python 提升至 >=3.10;SKILL 文档删减冗余 `{baseDir}` 说明"
|
|
@@ -23,5 +37,5 @@
|
|
|
23
37
|
}
|
|
24
38
|
],
|
|
25
39
|
"createdAt": "2026-05-13",
|
|
26
|
-
"updatedAt": "2026-
|
|
40
|
+
"updatedAt": "2026-06-24"
|
|
27
41
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sophnet-sticker-edit"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.2"
|
|
4
4
|
description = "Sophnet sticker/emoji image-to-image with random or custom styles (Qwen-Image-Edit-2509)"
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
dependencies = [
|
|
7
7
|
"requests>=2.28.0",
|
|
8
|
-
"sophnet-tools>=0.0.
|
|
8
|
+
"sophnet-tools>=0.0.2",
|
|
9
9
|
]
|
|
@@ -281,8 +281,9 @@ def reupload_for_signed_url(api_key, raw_url):
|
|
|
281
281
|
|
|
282
282
|
signed_url = sophnet_tools.upload_oss(tmp_path)
|
|
283
283
|
if not signed_url:
|
|
284
|
-
print("Warning: upload_oss returned no signed URL
|
|
285
|
-
|
|
284
|
+
print("Warning: upload_oss returned no signed URL", file=sys.stderr)
|
|
285
|
+
os.unlink(tmp_path)
|
|
286
|
+
return None, None
|
|
286
287
|
|
|
287
288
|
return signed_url, tmp_path
|
|
288
289
|
|
|
@@ -392,11 +393,8 @@ def main():
|
|
|
392
393
|
for i, raw_url in enumerate(raw_urls, 1):
|
|
393
394
|
signed_url, local_path = reupload_for_signed_url(api_key, raw_url)
|
|
394
395
|
print(f"IMAGE_URL={signed_url or raw_url}")
|
|
395
|
-
if local_path:
|
|
396
|
-
|
|
397
|
-
os.unlink(local_path)
|
|
398
|
-
else:
|
|
399
|
-
print(f"PREVIEW_PATH={local_path}")
|
|
396
|
+
if signed_url and local_path:
|
|
397
|
+
os.unlink(local_path)
|
|
400
398
|
|
|
401
399
|
|
|
402
400
|
if __name__ == "__main__":
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-tts",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"types": [
|
|
5
5
|
"builtin"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "",
|
|
8
8
|
"description": "",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.1",
|
|
12
|
+
"date": "2026-06-17",
|
|
13
|
+
"changes": [
|
|
14
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
10
17
|
{
|
|
11
18
|
"version": "1.0.0",
|
|
12
19
|
"date": "2026-04-09",
|
|
@@ -16,5 +23,5 @@
|
|
|
16
23
|
}
|
|
17
24
|
],
|
|
18
25
|
"createdAt": "2026-04-09",
|
|
19
|
-
"updatedAt": "2026-
|
|
26
|
+
"updatedAt": "2026-06-17"
|
|
20
27
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-video-generate",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"types": [
|
|
5
5
|
"builtin",
|
|
6
6
|
"store"
|
|
@@ -8,6 +8,20 @@
|
|
|
8
8
|
"displayName": "视频生成",
|
|
9
9
|
"description": "通过 Sophnet API 生成视频,支持文生视频和图生视频",
|
|
10
10
|
"changelog": [
|
|
11
|
+
{
|
|
12
|
+
"version": "1.0.5",
|
|
13
|
+
"date": "2026-06-24",
|
|
14
|
+
"changes": [
|
|
15
|
+
"输出格式改为结构化 key=value(STATUS/VIDEO_URL/VIDEO_LOCAL_PATH);上传成功后清理本地视频文件"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"version": "1.0.4",
|
|
20
|
+
"date": "2026-06-17",
|
|
21
|
+
"changes": [
|
|
22
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
11
25
|
{
|
|
12
26
|
"version": "1.0.3",
|
|
13
27
|
"date": "2026-06-09",
|
|
@@ -41,5 +55,5 @@
|
|
|
41
55
|
}
|
|
42
56
|
],
|
|
43
57
|
"createdAt": "2026-04-09",
|
|
44
|
-
"updatedAt": "2026-
|
|
58
|
+
"updatedAt": "2026-06-24"
|
|
45
59
|
}
|
|
@@ -65,23 +65,32 @@ The script will:
|
|
|
65
65
|
1. Upload local images to OSS if needed
|
|
66
66
|
2. Submit the video generation request
|
|
67
67
|
3. Poll the API until completion
|
|
68
|
-
4.
|
|
69
|
-
5.
|
|
70
|
-
6. Lists other common models in console output; any documented Sophnet video model name can be passed via `--model`.
|
|
68
|
+
4. Re-upload the video to OSS for a short signed URL, then clean up the local file
|
|
69
|
+
5. Output structured key-value lines for machine parsing
|
|
71
70
|
|
|
72
|
-
Example output:
|
|
71
|
+
Example output (success):
|
|
73
72
|
|
|
74
73
|
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
📥 **视频本地保存路径**: /path/to/xyz789.mp4
|
|
78
|
-
💬 **提示**:
|
|
79
|
-
⚠️ 本内容有AI生成,视频保存24小时,请及时下载保存!
|
|
80
|
-
🤖 当前使用的模型为 [model],还支持 [other models]
|
|
81
|
-
🧠 如果想要指定模型,可以直接对我说:使用 [模型名称] 模型,生成 [视频描述]
|
|
74
|
+
STATUS=succeeded
|
|
75
|
+
VIDEO_URL=https://www.sophnet.com/api/open-apis/files/abc123
|
|
82
76
|
```
|
|
83
77
|
|
|
84
|
-
|
|
78
|
+
If re-upload fails, an additional local path is provided:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
STATUS=succeeded
|
|
82
|
+
VIDEO_URL=https://raw-api.example.com/video/xyz789
|
|
83
|
+
VIDEO_LOCAL_PATH=/home/node/.openclaw/workspace/media/inbound/videos/task_id.mp4
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
On failure:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
STATUS=failed
|
|
90
|
+
视频生成失败
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Present the video to the user using the `VIDEO_URL` value. If `VIDEO_LOCAL_PATH` is present, mention the local backup location.
|
|
85
94
|
|
|
86
95
|
## Examples
|
|
87
96
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sophnet-video-generate"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.4"
|
|
4
4
|
description = "Sophnet video generation with task polling"
|
|
5
5
|
requires-python = ">=3.8"
|
|
6
6
|
dependencies = [
|
|
7
7
|
"requests>=2.28.0",
|
|
8
|
-
"sophnet-tools>=0.0.
|
|
8
|
+
"sophnet-tools>=0.0.2",
|
|
9
9
|
]
|
|
10
10
|
|
|
11
11
|
[[tool.uv.index]]
|
|
@@ -236,7 +236,11 @@ def gen_video(
|
|
|
236
236
|
# Re-upload to get a persistent URL
|
|
237
237
|
result_video_url = sophnet_tools.upload_oss(local_video_url)
|
|
238
238
|
if result_video_url:
|
|
239
|
-
|
|
239
|
+
try:
|
|
240
|
+
os.unlink(local_video_url)
|
|
241
|
+
except OSError:
|
|
242
|
+
pass
|
|
243
|
+
return result_video_url, None
|
|
240
244
|
else:
|
|
241
245
|
return video_url, local_video_url
|
|
242
246
|
else:
|
|
@@ -302,20 +306,11 @@ if __name__ == "__main__":
|
|
|
302
306
|
)
|
|
303
307
|
|
|
304
308
|
if result_url:
|
|
305
|
-
print(f"
|
|
306
|
-
print(f"
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
# 生成支持的模型列表(排除当前使用的模型)
|
|
311
|
-
other_models = [m for m in supported_models if m != model]
|
|
312
|
-
other_models_str = "、".join(other_models)
|
|
313
|
-
print(f"当前使用的模型为 {model},还支持 {other_models_str}")
|
|
314
|
-
print(f"如果想要指定模型,可以直接对我说:使用 [模型名称] 模型,生成 [视频描述]")
|
|
315
|
-
print(
|
|
316
|
-
"提示: 常用模型示例: happyhorse-1.0-t2v、happyhorse-1.0-i2v、"
|
|
317
|
-
"Wan2.6-T2V、Wan2.6-I2V、ViduQ2-pro、Seedance-2.0、Seedance-2.0-Fast、Seedance-1.5-Pro(也可传入文档中的其他模型名)"
|
|
318
|
-
)
|
|
309
|
+
print(f"STATUS=succeeded")
|
|
310
|
+
print(f"VIDEO_URL={result_url}")
|
|
311
|
+
if local_video_url:
|
|
312
|
+
print(f"VIDEO_LOCAL_PATH={local_video_url}")
|
|
319
313
|
else:
|
|
314
|
+
print(f"STATUS=failed")
|
|
320
315
|
print("\n视频生成失败")
|
|
321
316
|
sys.exit(1)
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sophnet-xlsx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"types": [
|
|
5
5
|
"store"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "Excel表格处理",
|
|
8
8
|
"description": "",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.0.1",
|
|
12
|
+
"date": "2026-06-17",
|
|
13
|
+
"changes": [
|
|
14
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
10
17
|
{
|
|
11
18
|
"version": "1.0.0",
|
|
12
19
|
"date": "2026-04-14",
|
|
@@ -16,5 +23,5 @@
|
|
|
16
23
|
}
|
|
17
24
|
],
|
|
18
25
|
"createdAt": "2026-04-14",
|
|
19
|
-
"updatedAt": "2026-
|
|
26
|
+
"updatedAt": "2026-06-17"
|
|
20
27
|
}
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "store-marketing",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"types": [
|
|
5
5
|
"store"
|
|
6
6
|
],
|
|
7
7
|
"displayName": "门店营销辅助",
|
|
8
8
|
"description": "门店营销助手:为通用门店策划活动、分群触达、生成多渠道文案与海报。结合会员分群、目录价格、节日热点与老板风格。触发:营销/推广/促销/文案/海报/沉睡客户/活动方案/朋友圈/小红书/营销日历。",
|
|
9
9
|
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"version": "1.1.5",
|
|
12
|
+
"date": "2026-06-24",
|
|
13
|
+
"changes": [
|
|
14
|
+
"海报生成后通过 sophnet_tools.upload_oss 重新上传,输出短链接避免被截断"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"version": "1.1.4",
|
|
19
|
+
"date": "2026-06-17",
|
|
20
|
+
"changes": [
|
|
21
|
+
"升级 sophnet-tools 依赖版本 >=0.0.1 → >=0.0.2"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
10
24
|
{
|
|
11
25
|
"version": "1.1.3",
|
|
12
26
|
"date": "2026-06-03",
|
|
@@ -63,7 +77,7 @@
|
|
|
63
77
|
}
|
|
64
78
|
],
|
|
65
79
|
"createdAt": "2026-05-29",
|
|
66
|
-
"updatedAt": "2026-
|
|
80
|
+
"updatedAt": "2026-06-24",
|
|
67
81
|
"resources": [
|
|
68
82
|
"references",
|
|
69
83
|
"playbooks"
|
|
@@ -19,7 +19,9 @@ from __future__ import annotations
|
|
|
19
19
|
import argparse
|
|
20
20
|
import json
|
|
21
21
|
import math
|
|
22
|
+
import os
|
|
22
23
|
import sys
|
|
24
|
+
import tempfile
|
|
23
25
|
import time
|
|
24
26
|
from typing import Any, Dict, List, Optional, Tuple
|
|
25
27
|
|
|
@@ -375,6 +377,41 @@ def extract_image_urls(data: Dict[str, Any]) -> List[str]:
|
|
|
375
377
|
return urls
|
|
376
378
|
|
|
377
379
|
|
|
380
|
+
def reupload_image(api_key: str, raw_url: str) -> str:
|
|
381
|
+
"""Download image from API URL and re-upload to OSS for short signed URL."""
|
|
382
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
383
|
+
try:
|
|
384
|
+
resp = requests.get(raw_url, headers=headers, timeout=120, stream=True)
|
|
385
|
+
resp.raise_for_status()
|
|
386
|
+
except requests.RequestException as e:
|
|
387
|
+
print(f"Warning: failed to download image: {e}", file=sys.stderr)
|
|
388
|
+
return raw_url
|
|
389
|
+
|
|
390
|
+
ext = os.path.splitext(raw_url.split("?")[0])[-1] or ".png"
|
|
391
|
+
fd, tmp_path = tempfile.mkstemp(suffix=ext, prefix="poster_gen_")
|
|
392
|
+
try:
|
|
393
|
+
with os.fdopen(fd, "wb") as f:
|
|
394
|
+
for chunk in resp.iter_content(8192):
|
|
395
|
+
f.write(chunk)
|
|
396
|
+
except IOError as e:
|
|
397
|
+
print(f"Warning: failed to write temp file: {e}", file=sys.stderr)
|
|
398
|
+
os.unlink(tmp_path)
|
|
399
|
+
return raw_url
|
|
400
|
+
|
|
401
|
+
import sophnet_tools as _st
|
|
402
|
+
signed_url = _st.upload_oss(tmp_path)
|
|
403
|
+
try:
|
|
404
|
+
os.unlink(tmp_path)
|
|
405
|
+
except OSError:
|
|
406
|
+
pass
|
|
407
|
+
|
|
408
|
+
if not signed_url:
|
|
409
|
+
print("Warning: upload_oss failed, using original URL", file=sys.stderr)
|
|
410
|
+
return raw_url
|
|
411
|
+
|
|
412
|
+
return signed_url
|
|
413
|
+
|
|
414
|
+
|
|
378
415
|
def generate_image(
|
|
379
416
|
api_key: str,
|
|
380
417
|
prompt: str,
|
|
@@ -390,7 +427,8 @@ def generate_image(
|
|
|
390
427
|
urls = extract_image_urls(result)
|
|
391
428
|
if not urls:
|
|
392
429
|
raise ValueError(f"url not found in response: {json.dumps(result, ensure_ascii=False)}")
|
|
393
|
-
|
|
430
|
+
image_url = reupload_image(api_key, urls[0])
|
|
431
|
+
return task_id, image_url
|
|
394
432
|
|
|
395
433
|
|
|
396
434
|
def handle_http_error(e: requests.HTTPError) -> None:
|