Skip to content

Commit 80317a8

Browse files
authored
Merge pull request #29 from iOrange-ZR/main
feat: 增加 APIMart GPT Image 2 官方通道
2 parents 11caaee + 33d7d99 commit 80317a8

9 files changed

Lines changed: 570 additions & 24 deletions

File tree

__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,12 @@ async def on_batch_complete(batch_idx, total, batch_previews):
12221222
)
12231223

12241224
_usage_duration = _time.monotonic() - _usage_t0
1225+
result["duration_seconds"] = _usage_duration
1226+
_preview_count = len(result.get("preview_images", []))
1227+
print(
1228+
f"[Independent] ✅ 完成: {model} | {_preview_count} 张 | 耗时 {_usage_duration:.1f}s",
1229+
flush=True,
1230+
)
12251231

12261232
# --- Usage Tracking ---
12271233
try:

adapters/generic.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,13 @@ def _build_openai_request(self, params: Dict, mode: str = "text2img") -> Dict:
191191
# Frontend handles api_name mapping, so params already have correct keys
192192
# When payload has "messages" (Chat API), skip prompt/seed — they're inside messages
193193
chat_mode = "messages" in payload
194+
excluded_params = set(self.endpoint.get("exclude_params") or [])
195+
excluded_params.update(self.mode_config.get("exclude_params") or [])
194196
for param_name, value in params.items():
195197
if param_name.startswith("_"):
196198
continue
199+
if param_name in excluded_params:
200+
continue
197201
if chat_mode and param_name in ("prompt", "seed"):
198202
continue
199203
if param_name in ("endpoint_override",):
@@ -1115,6 +1119,11 @@ def _poll_for_result(self, task_id: str, timeout: int = 600) -> APIResponse:
11151119
status_path = self.mode_config.get("status_path", "data.status")
11161120
success_value = self.mode_config.get("success_value", "SUCCESS")
11171121
response_path = self.mode_config.get("response_path", "data.data.data[*].url")
1122+
poll_interval = self.mode_config.get("poll_interval", 2)
1123+
try:
1124+
poll_interval = max(float(poll_interval), 0)
1125+
except (TypeError, ValueError):
1126+
poll_interval = 2
11181127

11191128
poll_url = f"{self.base_url}{polling_endpoint}"
11201129

@@ -1130,7 +1139,7 @@ def _poll_for_result(self, task_id: str, timeout: int = 600) -> APIResponse:
11301139
start_time = time.time()
11311140

11321141
while time.time() - start_time < timeout:
1133-
time.sleep(2)
1142+
time.sleep(poll_interval)
11341143

11351144
try:
11361145
resp = requests.get(

api_config.yaml

Lines changed: 157 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ models:
106106
display_name: 🖼️ GPT-Image-2 (旗舰·图像生成)
107107
category: image
108108
description: OpenAI 最新旗舰图像生成模型,文字渲染能力强(最大长边 3840px,2K以上为实验性功能)
109-
show_seed_widget: true
109+
show_seed_widget: false
110110
dynamic_inputs:
111111
image:
112112
max: 16
@@ -117,45 +117,116 @@ models:
117117
prompt:
118118
type: string
119119
default: ''
120+
resolution:
121+
type: select
122+
default: 1k
123+
options:
124+
- value: 1k
125+
label: 1K (1024 基准)
126+
- value: 2k
127+
label: 2K (高清海报)
128+
- value: 4k
129+
label: 4K (仅限部分比例)
120130
size:
121131
type: select
122132
default: auto
123133
options:
124134
- value: auto
125-
label: 自动 (模型决定)
126-
- value: 1024x1024
127-
label: 1024×1024 (1:1)
128-
- value: 1536x1024
129-
label: 1536×1024 (3:2 横版)
130-
- value: 1024x1536
131-
label: 1024×1536 (2:3 竖版)
132-
- value: 1792x1024
133-
label: 1792×1024 (16:9 横版)
134-
- value: 1024x1792
135-
label: 1024×1792 (9:16 竖版)
136-
- value: 2048x2048
137-
label: 2048×2048 (2K 1:1)
138-
- value: 2048x1152
139-
label: 2048×1152 (2K 横版)
140-
- value: 3840x2160
141-
label: 3840×2160 (4K 横版)
142-
- value: 2160x3840
143-
label: 2160×3840 (4K 竖版)
135+
label: 自动 (服务端选择比例)
136+
- value: '1:1'
137+
label: 1:1 正方形
138+
- value: '3:2'
139+
label: 3:2 横构图
140+
- value: '2:3'
141+
label: 2:3 竖构图
142+
- value: '4:3'
143+
label: 4:3 横构图
144+
- value: '3:4'
145+
label: 3:4 竖构图
146+
- value: '5:4'
147+
label: 5:4 横构图
148+
- value: '4:5'
149+
label: 4:5 竖构图
150+
- value: '16:9'
151+
label: 16:9 宽屏横版
152+
- value: '9:16'
153+
label: 9:16 手机竖版
154+
- value: '2:1'
155+
label: 2:1 横向 Banner
156+
- value: '1:2'
157+
label: 1:2 竖向长图
158+
- value: '21:9'
159+
label: 21:9 电影超宽屏
160+
- value: '9:21'
161+
label: 9:21 竖向超长图
144162
quality:
145163
type: select
146-
default: medium
164+
default: auto
147165
options:
166+
- value: auto
167+
label: 自动
148168
- value: low
149169
label: 低质量 (快速)
150170
- value: medium
151171
label: 中等
152172
- value: high
153173
label: 高质量
154-
advanced: {}
174+
output_format:
175+
type: select
176+
default: png
177+
options:
178+
- value: png
179+
label: PNG
180+
- value: jpeg
181+
label: JPEG
182+
- value: webp
183+
label: WebP
184+
n:
185+
type: number
186+
default: 1
187+
min: 1
188+
max: 4
189+
step: 1
190+
advanced:
191+
background:
192+
type: select
193+
default: auto
194+
options:
195+
- value: auto
196+
label: 自动
197+
- value: opaque
198+
label: 不透明
199+
- value: transparent
200+
label: 透明 (官方会降级为 auto)
201+
moderation:
202+
type: select
203+
default: auto
204+
options:
205+
- value: auto
206+
label: 默认审核
207+
- value: low
208+
label: 宽松审核
209+
output_compression:
210+
type: string
211+
default: ''
212+
mask_url:
213+
type: string
214+
default: ''
155215
api_endpoints:
156216
- provider: openrouter
157217
priority: 2
158218
model_name: openai/gpt-5.4-image-2
219+
exclude_params:
220+
- seed
221+
- size
222+
- quality
223+
- resolution
224+
- background
225+
- moderation
226+
- output_format
227+
- output_compression
228+
- n
229+
- mask_url
159230
extra_params:
160231
modalities:
161232
- image
@@ -187,6 +258,17 @@ models:
187258
- provider: 柏拉图
188259
priority: 1
189260
model_name: gpt-image-2
261+
exclude_params:
262+
- seed
263+
- size
264+
- quality
265+
- resolution
266+
- background
267+
- moderation
268+
- output_format
269+
- output_compression
270+
- n
271+
- mask_url
190272
modes:
191273
text2img:
192274
endpoint: /v1/images/generations
@@ -204,6 +286,59 @@ models:
204286
model: gpt-image-2
205287
prompt: '{{prompt}}'
206288
image: '{{_images_b64}}'
289+
- provider: apimart
290+
display_name: APIMart 官方
291+
priority: 3
292+
model_name: gpt-image-2-official
293+
use_oss_cache: true
294+
modes:
295+
text2img:
296+
endpoint: /v1/images/generations
297+
method: POST
298+
content_type: application/json
299+
response_type: async
300+
task_id_path: data.0.task_id
301+
polling_endpoint: /v1/tasks/{{task_id}}
302+
poll_interval: 5
303+
status_path: data.status
304+
success_value: completed
305+
response_path: data.result.images[*].url[0]
306+
exclude_params:
307+
- seed
308+
payload_template:
309+
model: gpt-image-2-official
310+
prompt: '{{prompt}}'
311+
size: '{{size}}'
312+
resolution: '{{resolution}}'
313+
quality: '{{quality}}'
314+
background: '{{background}}'
315+
moderation: '{{moderation}}'
316+
output_format: '{{output_format}}'
317+
n: '{{n}}'
318+
img2img:
319+
endpoint: /v1/images/generations
320+
oss_endpoint: /v1/images/generations
321+
method: POST
322+
content_type: multipart/form-data
323+
response_type: async
324+
task_id_path: data.0.task_id
325+
polling_endpoint: /v1/tasks/{{task_id}}
326+
poll_interval: 5
327+
status_path: data.status
328+
success_value: completed
329+
response_path: data.result.images[*].url[0]
330+
exclude_params:
331+
- seed
332+
payload_template:
333+
model: gpt-image-2-official
334+
prompt: '{{prompt}}'
335+
size: '{{size}}'
336+
resolution: '{{resolution}}'
337+
quality: '{{quality}}'
338+
background: '{{background}}'
339+
moderation: '{{moderation}}'
340+
output_format: '{{output_format}}'
341+
n: '{{n}}'
207342
sora_image(文生图):
208343
display_name: 🖼️ Sora-Image (视觉先锋·文生图)
209344
category: image

deployment/Deploy_Install.bat

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
@echo off
2+
3+
echo ======================================
4+
echo ComfyUI Portable - Deployment
5+
echo ======================================
6+
echo.
7+
8+
rem ===== Auto-detect NAS Drive =====
9+
echo Searching for NAS drive...
10+
11+
set NAS_FOLDER=ComfyUI_Master\ComfyUI_windows_portable
12+
set NAS_DRIVE=
13+
14+
for %%d in (Z P N M L K J I H G F E D X W) do (
15+
if exist "%%d:\%NAS_FOLDER%\" (
16+
set NAS_DRIVE=%%d:
17+
goto :found
18+
)
19+
)
20+
21+
echo ERROR: Cannot find NAS!
22+
echo Searched for: %NAS_FOLDER%
23+
echo Please ensure NAS is mapped and contains the ComfyUI_Master folder.
24+
pause
25+
goto :eof
26+
27+
:found
28+
echo Found NAS at: %NAS_DRIVE%
29+
30+
rem ===== Path Configuration =====
31+
set NAS_SOURCE=%NAS_DRIVE%\ComfyUI_Master\ComfyUI_windows_portable
32+
set NAS_SCRIPTS=%NAS_DRIVE%\ComfyUI_Master
33+
set LOCAL_DIR=C:\ComfyUI_Portable
34+
35+
rem ===== Copy Files =====
36+
echo.
37+
echo Copying ComfyUI to local drive...
38+
echo This may take a few minutes...
39+
echo.
40+
41+
robocopy "%NAS_SOURCE%" "%LOCAL_DIR%" /E /XO /FFT /R:3 /W:1 /NJH /NJS /XD "output" "temp"
42+
43+
if %ERRORLEVEL% GEQ 8 (
44+
echo ERROR: Copy failed!
45+
pause
46+
goto :eof
47+
)
48+
echo Copy complete!
49+
50+
rem ===== Copy Start Script =====
51+
echo.
52+
echo Setting up launcher script...
53+
copy /Y "%NAS_SCRIPTS%\Start_Client.bat" "%LOCAL_DIR%\Start_Client.bat" >nul
54+
55+
rem ===== Create Desktop Shortcut =====
56+
echo Creating desktop shortcut...
57+
58+
set DESKTOP_LNK=%USERPROFILE%\Desktop\ComfyUI.lnk
59+
set TARGET_BAT=%LOCAL_DIR%\Start_Client.bat
60+
set ICON_EXE=%LOCAL_DIR%\ComfyUI.exe
61+
62+
if exist "%ICON_EXE%" (
63+
powershell -Command "$s=(New-Object -COM WScript.Shell).CreateShortcut('%DESKTOP_LNK%');$s.TargetPath='%TARGET_BAT%';$s.WorkingDirectory='%LOCAL_DIR%';$s.IconLocation='%ICON_EXE%,0';$s.Save()"
64+
) else (
65+
powershell -Command "$s=(New-Object -COM WScript.Shell).CreateShortcut('%DESKTOP_LNK%');$s.TargetPath='%TARGET_BAT%';$s.WorkingDirectory='%LOCAL_DIR%';$s.Save()"
66+
)
67+
68+
echo.
69+
echo ======================================
70+
echo Deployment Complete!
71+
echo ======================================
72+
echo.
73+
echo NAS Drive: %NAS_DRIVE%
74+
echo Local folder: %LOCAL_DIR%
75+
echo.
76+
pause

deployment/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Student Deployment Scripts
2+
3+
This directory stores the student-side deployment scripts that are copied to the NAS root:
4+
5+
- `Start_Client.bat`: launcher used by student desktop shortcuts. It checks the NAS, self-updates from the NAS root, verifies `ComfyUI-Custom-Batchbox` against the NAS copy, mirrors the plugin when needed, then starts ComfyUI.
6+
- `Deploy_Install.bat`: first-time or repair install script. It copies the portable ComfyUI bundle from NAS to `C:\ComfyUI_Portable`, installs the local launcher, and creates the desktop shortcut.
7+
- `Uninstall.bat`: local cleanup script for removing `C:\ComfyUI_Portable` and the desktop shortcut before a reinstall.
8+
9+
## NAS Placement
10+
11+
Copy these files to:
12+
13+
```text
14+
Z:\ComfyUI_Master\Start_Client.bat
15+
Z:\ComfyUI_Master\Deploy_Install.bat
16+
Z:\ComfyUI_Master\Uninstall.bat
17+
```
18+
19+
Student machines may map the same NAS as another drive letter, such as `P:`. Both scripts auto-detect mapped drives by checking for:
20+
21+
```text
22+
ComfyUI_Master\ComfyUI_windows_portable
23+
```
24+
25+
## BatchBox Sync Policy
26+
27+
`Start_Client.bat` does not try to kill running Python or ComfyUI processes. It compares the local BatchBox plugin against the NAS copy first:
28+
29+
- If every file matches by relative path, size, and modified time, it starts ComfyUI immediately.
30+
- If anything differs, it runs `robocopy /MIR` for `ComfyUI-Custom-Batchbox`, which also removes local extra files.
31+
- If `.pyd` files are locked and cannot be mirrored, startup stops and the user should reboot, then run the launcher again.

0 commit comments

Comments
 (0)