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.
Files changed (49) hide show
  1. package/package.json +1 -1
  2. package/skills/image-classify/skill.json +9 -2
  3. package/skills/image-classify/src/pyproject.toml +2 -2
  4. package/skills/image-description/skill.json +9 -2
  5. package/skills/image-description/src/pyproject.toml +2 -2
  6. package/skills/image-identify-world/skill.json +9 -2
  7. package/skills/image-identify-world/src/pyproject.toml +2 -2
  8. package/skills/online-bug-report/skill.json +9 -2
  9. package/skills/online-bug-report/src/pyproject.toml +1 -1
  10. package/skills/sophnet-age-appearance/skill.json +16 -2
  11. package/skills/sophnet-age-appearance/src/pyproject.toml +2 -2
  12. package/skills/sophnet-age-appearance/src/scripts/age_appearance.py +8 -10
  13. package/skills/sophnet-customized-marketing/skill.json +9 -2
  14. package/skills/sophnet-customized-marketing/src/pyproject.toml +1 -1
  15. package/skills/sophnet-docx/skill.json +9 -2
  16. package/skills/sophnet-docx/src/pyproject.toml +1 -1
  17. package/skills/sophnet-face-search/skill.json +9 -2
  18. package/skills/sophnet-face-search/src/pyproject.toml +2 -2
  19. package/skills/sophnet-id-photo/skill.json +16 -2
  20. package/skills/sophnet-id-photo/src/pyproject.toml +2 -2
  21. package/skills/sophnet-id-photo/src/scripts/id_photo.py +5 -7
  22. package/skills/sophnet-image-edit/skill.json +16 -2
  23. package/skills/sophnet-image-edit/src/pyproject.toml +2 -2
  24. package/skills/sophnet-image-edit/src/scripts/edit_image.py +5 -7
  25. package/skills/sophnet-image-generate/skill.json +16 -2
  26. package/skills/sophnet-image-generate/src/pyproject.toml +2 -2
  27. package/skills/sophnet-image-generate/src/scripts/generate_image.py +51 -1
  28. package/skills/sophnet-image-ocr/skill.json +9 -2
  29. package/skills/sophnet-image-ocr/src/pyproject.toml +2 -2
  30. package/skills/sophnet-image-ocr/src/references/api-details.md +1 -1
  31. package/skills/sophnet-infinite-talk/skill.json +16 -2
  32. package/skills/sophnet-infinite-talk/src/pyproject.toml +1 -1
  33. package/skills/sophnet-infinite-talk/src/scripts/gen.py +39 -0
  34. package/skills/sophnet-pdf/skill.json +9 -2
  35. package/skills/sophnet-pdf/src/pyproject.toml +1 -1
  36. package/skills/sophnet-sticker-edit/skill.json +16 -2
  37. package/skills/sophnet-sticker-edit/src/pyproject.toml +2 -2
  38. package/skills/sophnet-sticker-edit/src/scripts/edit_sticker_image.py +5 -7
  39. package/skills/sophnet-tts/skill.json +9 -2
  40. package/skills/sophnet-tts/src/pyproject.toml +1 -1
  41. package/skills/sophnet-video-generate/skill.json +16 -2
  42. package/skills/sophnet-video-generate/src/SKILL.md +21 -12
  43. package/skills/sophnet-video-generate/src/pyproject.toml +2 -2
  44. package/skills/sophnet-video-generate/src/scripts/gen_video.py +10 -15
  45. package/skills/sophnet-xlsx/skill.json +9 -2
  46. package/skills/sophnet-xlsx/src/pyproject.toml +1 -1
  47. package/skills/store-marketing/skill.json +16 -2
  48. package/skills/store-marketing/src/pyproject.toml +2 -2
  49. package/skills/store-marketing/src/scripts/generate_poster.py +39 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sophhub",
3
- "version": "0.4.44",
3
+ "version": "0.4.46",
4
4
  "description": "SophHub CLI - Manage and download AI Agent skills and agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "image-classify",
3
- "version": "1.0.6",
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-05-19"
69
+ "updatedAt": "2026-06-17"
63
70
  }
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "image-classify"
3
- version = "1.0.6"
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.1",
10
+ "sophnet-tools>=0.0.2",
11
11
  ]
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "image-description",
3
- "version": "1.0.3",
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-10"
47
+ "updatedAt": "2026-06-17"
41
48
  }
@@ -1,8 +1,8 @@
1
1
  [project]
2
2
  name = "image-description"
3
- version = "1.0.3"
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.1",
7
+ "sophnet-tools>=0.0.2",
8
8
  ]
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "image-identify-world",
3
- "version": "1.0.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-05-13"
26
+ "updatedAt": "2026-06-17"
20
27
  }
@@ -1,8 +1,8 @@
1
1
  [project]
2
2
  name = "image-identify-world"
3
- version = "1.0.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.1",
7
+ "sophnet-tools>=0.0.2",
8
8
  ]
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "online-bug-report",
3
- "version": "1.0.10",
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-01"
108
+ "updatedAt": "2026-06-17"
102
109
  }
@@ -5,7 +5,7 @@ description = "Send VIP online bug reports to a Sophclaw friend via IM"
5
5
  requires-python = ">=3.8"
6
6
  dependencies = [
7
7
  "requests>=2.28.0",
8
- "sophnet-tools>=0.0.1",
8
+ "sophnet-tools>=0.0.2",
9
9
  ]
10
10
 
11
11
  [[tool.uv.index]]
@@ -1,12 +1,26 @@
1
1
  {
2
2
  "name": "sophnet-age-appearance",
3
- "version": "1.0.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-05-13"
33
+ "updatedAt": "2026-06-24"
20
34
  }
@@ -1,10 +1,10 @@
1
1
  [project]
2
2
  name = "sophnet-age-appearance"
3
- version = "1.0.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.1",
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, keeping local file", file=sys.stderr)
220
- return None, tmp_path
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
- if signed_url:
251
- try:
252
- os.unlink(local_path)
253
- except OSError:
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.1",
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-04-10"
34
+ "updatedAt": "2026-06-17"
28
35
  }
@@ -5,5 +5,5 @@ description = "Personalized marketing content generation for small business owne
5
5
  requires-python = ">=3.10"
6
6
  dependencies = [
7
7
  "requests>=2.28.0",
8
- "sophnet-tools>=0.0.1",
8
+ "sophnet-tools>=0.0.2",
9
9
  ]
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "sophnet-docx",
3
- "version": "1.1.0",
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-08"
39
+ "updatedAt": "2026-06-17"
33
40
  }
@@ -7,7 +7,7 @@ dependencies = [
7
7
  "defusedxml>=0.7.1",
8
8
  "lxml>=5.2.0",
9
9
  "python-docx>=1.1.0",
10
- "sophnet-tools>=0.0.1",
10
+ "sophnet-tools>=0.0.2",
11
11
  ]
12
12
 
13
13
  [[tool.uv.index]]
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "sophnet-face-search",
3
- "version": "1.0.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-04-09"
26
+ "updatedAt": "2026-06-17"
20
27
  }
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "sophnet-face-search"
3
- version = "1.0.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.1",
10
+ "sophnet-tools>=0.0.2",
11
11
  ]
@@ -1,12 +1,26 @@
1
1
  {
2
2
  "name": "sophnet-id-photo",
3
- "version": "1.0.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-05-13"
33
+ "updatedAt": "2026-06-24"
20
34
  }
@@ -1,10 +1,10 @@
1
1
  [project]
2
2
  name = "sophnet-id-photo"
3
- version = "1.0.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.1",
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, keeping local file", file=sys.stderr)
327
- return None, tmp_path
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
- if signed_url:
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.1",
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-09"
40
+ "updatedAt": "2026-06-24"
27
41
  }
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "sophnet-image-edit"
3
- version = "1.0.1"
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.1",
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, keeping local file", file=sys.stderr)
198
- return None, tmp_path
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
- if signed_url:
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.1",
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-09"
40
+ "updatedAt": "2026-06-24"
27
41
  }
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "sophnet-image-generate"
3
- version = "1.0.1"
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.1",
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
- for u in urls:
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.0",
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-05-26"
38
+ "updatedAt": "2026-06-17"
32
39
  }
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "image-ocr"
3
- version = "1.1.0"
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.1",
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.1` — Sophnet API helpers (always installed)
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.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-04-09"
33
+ "updatedAt": "2026-06-24"
20
34
  }
@@ -5,5 +5,5 @@ description = "Digital human video generation using Sophnet InfiniteTalk API"
5
5
  requires-python = ">=3.10"
6
6
  dependencies = [
7
7
  "requests>=2.28.0",
8
- "sophnet-tools>=0.0.1",
8
+ "sophnet-tools>=0.0.2",
9
9
  ]
@@ -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.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-04-14"
26
+ "updatedAt": "2026-06-17"
20
27
  }
@@ -10,5 +10,5 @@ dependencies = [
10
10
  "pdf2image>=1.17.0",
11
11
  "reportlab>=4.2.0",
12
12
  "pymupdf>=1.26.7",
13
- "sophnet-tools>=0.0.1",
13
+ "sophnet-tools>=0.0.2",
14
14
  ]
@@ -1,12 +1,26 @@
1
1
  {
2
2
  "name": "sophnet-sticker-edit",
3
- "version": "1.0.1",
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-05-14"
40
+ "updatedAt": "2026-06-24"
27
41
  }
@@ -1,9 +1,9 @@
1
1
  [project]
2
2
  name = "sophnet-sticker-edit"
3
- version = "1.0.1"
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.1",
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, keeping local file", file=sys.stderr)
285
- return None, tmp_path
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
- if signed_url:
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.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-04-09"
26
+ "updatedAt": "2026-06-17"
20
27
  }
@@ -5,5 +5,5 @@ description = "Skill-local runtime dependencies for sophnet-tts"
5
5
  requires-python = ">=3.10"
6
6
  dependencies = [
7
7
  "requests>=2.28.0",
8
- "sophnet-tools>=0.0.1",
8
+ "sophnet-tools>=0.0.2",
9
9
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sophnet-video-generate",
3
- "version": "1.0.3",
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-05-11"
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. Display the final video URL and local save path
69
- 5. Prompt the user to download the video
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
- 📹 **您的视频提示词为**: [prompt]
76
- ✅ **视频生成成功**: <video controls width="100%" src="https://www.sophnet.com/api/open-apis/projects/download/xyz789"></video>
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
- Present this information to the user in a clear format.
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"
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.1",
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
- return result_video_url, local_video_url
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"\n您的视频提示词为: {args.prompt}")
306
- print(f"视频生成成功: {result_url}")
307
- print(f"视频本地保存路径: {local_video_url}")
308
- print(f"提示: 视频保存24小时,请及时下载")
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.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-04-14"
26
+ "updatedAt": "2026-06-17"
20
27
  }
@@ -7,5 +7,5 @@ dependencies = [
7
7
  "defusedxml>=0.7.1",
8
8
  "lxml>=5.2.0",
9
9
  "openpyxl>=3.1.0",
10
- "sophnet-tools>=0.0.1",
10
+ "sophnet-tools>=0.0.2",
11
11
  ]
@@ -1,12 +1,26 @@
1
1
  {
2
2
  "name": "store-marketing",
3
- "version": "1.1.3",
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-05-29",
80
+ "updatedAt": "2026-06-24",
67
81
  "resources": [
68
82
  "references",
69
83
  "playbooks"
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "store-marketing"
3
- version = "1.1.3"
3
+ version = "1.1.4"
4
4
  requires-python = ">=3.8"
5
5
  dependencies = [
6
6
  "store-suite>=1.1.0",
7
7
  "requests>=2.28.0",
8
- "sophnet-tools>=0.0.1",
8
+ "sophnet-tools>=0.0.2",
9
9
  ]
10
10
 
11
11
  [project.scripts]
@@ -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
- return task_id, urls[0]
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: