Skip to content

proxy, ui-svelte: add /sdapi/v1 endpoint support#587

Merged
mostlygeek merged 11 commits intomainfrom
claude/add-sdapi-v1-support-o2Y1L
Mar 19, 2026
Merged

proxy, ui-svelte: add /sdapi/v1 endpoint support#587
mostlygeek merged 11 commits intomainfrom
claude/add-sdapi-v1-support-o2Y1L

Conversation

@mostlygeek
Copy link
Copy Markdown
Owner

Add proxy routes for stable-diffusion.cpp's /sdapi/v1/txt2img,
/sdapi/v1/img2img, and /sdapi/v1/loras endpoints. POST endpoints
use proxyInferenceHandler (model in JSON body), GET /loras uses
proxyGETModelHandler (model in query param).

Update the image playground with a dual-mode UI supporting both
OpenAI and SDAPI backends. In SDAPI mode, loras are fetched first
to prime the server-side cache, and all txt2img parameters are
exposed (negative prompt, steps, cfg_scale, seed, batch_size,
clip_skip, sampler, scheduler, lora selection with multipliers).

  • Add 3 sdapi route registrations in proxymanager.go
  • Add sdApi.ts client with generateSdImage and fetchSdLoras
  • Add SDAPI types (SdApiTxt2ImgRequest, SdApiResponse, etc.)
  • Add /sdapi to vite dev proxy config
  • Add backend tests for sdapi routing
  • Support batch image display in gallery grid

https://claude.ai/code/session_0186MGX6NXdHVBTv2KH45fqn

claude added 2 commits March 15, 2026 18:52
Add proxy routes for stable-diffusion.cpp's /sdapi/v1/txt2img,
/sdapi/v1/img2img, and /sdapi/v1/loras endpoints. POST endpoints
use proxyInferenceHandler (model in JSON body), GET /loras uses
proxyGETModelHandler (model in query param).

Update the image playground with a dual-mode UI supporting both
OpenAI and SDAPI backends. In SDAPI mode, loras are fetched first
to prime the server-side cache, and all txt2img parameters are
exposed (negative prompt, steps, cfg_scale, seed, batch_size,
clip_skip, sampler, scheduler, lora selection with multipliers).

- Add 3 sdapi route registrations in proxymanager.go
- Add sdApi.ts client with generateSdImage and fetchSdLoras
- Add SDAPI types (SdApiTxt2ImgRequest, SdApiResponse, etc.)
- Add /sdapi to vite dev proxy config
- Add backend tests for sdapi routing
- Support batch image display in gallery grid

https://claude.ai/code/session_0186MGX6NXdHVBTv2KH45fqn
Replace automatic lora fetching on model change with a manual
"Load LoRAs" button. Once loaded, loras are added via a select
dropdown and displayed as a list with multiplier inputs and
remove buttons.

- Remove auto-fetch $effect for loras
- Remove lora cache priming from generate flow
- Add "Load LoRAs" / "Reload LoRAs" button
- Add select dropdown to pick from available loras
- Show selected loras as list with multiplier and remove controls

https://claude.ai/code/session_0186MGX6NXdHVBTv2KH45fqn
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 15, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds Stable Diffusion API (SDAPI) HTTP routes and tests on the backend; introduces SDAPI client helpers, types, Vite proxy, and Svelte UI support (mode switch, multi-image results, and LoRA management); adds SDAPI stub endpoints in the simple-responder dev server.

Changes

Cohort / File(s) Summary
Backend SDAPI Routing & Tests
proxy/proxymanager.go, proxy/proxymanager_test.go
Register POST /sdapi/v1/txt2img, POST /sdapi/v1/img2img, GET /sdapi/v1/loras (route to existing handlers) and add integration tests validating routing, parameter handling, and error responses.
Dev stub server
cmd/simple-responder/simple-responder.go
Add SDAPI stub endpoints (/sdapi/v1/txt2img, /sdapi/v1/img2img, /sdapi/v1/loras) — duplicate registrations with differing responses exist in the same file.
Frontend types
ui-svelte/src/lib/types.ts
Add SDAPI types: ImageApiMode, SdApiLora, SdApiLoraRef, SdApiTxt2ImgRequest, and SdApiResponse.
Frontend SDAPI client
ui-svelte/src/lib/sdApi.ts
New helpers generateSdImage() and fetchSdLoras() calling backend SDAPI endpoints with JSON parsing, error handling, and optional AbortSignal.
Frontend UI
ui-svelte/src/components/playground/ImageInterface.svelte
Add API mode switch (openai/sdapi), support for multiple generated images, SD-specific settings panel, and LoRA management (load/select/update/remove); adjust UI flows (fullscreen, clear, download).
Dev tooling & config
ui-svelte/vite.config.ts, go.mod
Add Vite proxy /sdapihttp://localhost:8080; change go directive from 1.25.4 to 1.25.1.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Add Event Bus #184 — Modifies proxy/proxymanager.go (routing/ProxyManager fields); overlaps with SDAPI route registrations and proxy manager changes.
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main changes: adding /sdapi/v1 endpoint support to the proxy and UI components.
Description check ✅ Passed The description clearly explains the key changes including proxy routes, UI dual-mode support, and implementation details aligned with the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/add-sdapi-v1-support-o2Y1L
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
ui-svelte/src/components/playground/ImageInterface.svelte (1)

48-63: Consider clearing LoRA state when the model changes.

When the user switches to a different model, the availableLoras, selectedLoras, and lorasLoaded state remain from the previous model. This could lead to using LoRAs that don't exist for the new model.

Add an effect to reset LoRA state on model change
+  // Reset LoRA state when model changes
+  $effect(() => {
+    const _ = $selectedModelStore; // track dependency
+    availableLoras = [];
+    selectedLoras = [];
+    lorasLoaded = false;
+    loraError = null;
+  });
+
   async function loadLoras() {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui-svelte/src/components/playground/ImageInterface.svelte` around lines 48 -
63, When the selected model changes the component must clear LoRA-related state
to avoid carrying over invalid selections; update the component so that on model
change (watching $selectedModelStore) you reset availableLoras = [],
selectedLoras = [], and lorasLoaded = false before (or immediately when) calling
loadLoras; locate the loadLoras function and the reactive/store usage of
selectedModelStore and add a short effect or reactive statement tied to
selectedModelStore that clears those variables and then triggers loadLoras to
fetch the correct list for the new model.
ui-svelte/src/lib/sdApi.ts (1)

16-22: Consider handling JSON parse errors.

If the server returns a non-JSON response (e.g., during maintenance), response.json() will throw an unhandled exception. The same applies to fetchSdLoras.

Proposed defensive handling
   if (!response.ok) {
     const errorText = await response.text();
     throw new Error(`SDAPI error: ${response.status} - ${errorText}`);
   }

-  return response.json();
+  try {
+    return await response.json();
+  } catch {
+    throw new Error("SDAPI error: Invalid JSON response");
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui-svelte/src/lib/sdApi.ts` around lines 16 - 22, Wrap the response.json()
call in a try/catch in this file (the same pattern for fetchSdLoras) so JSON
parse failures are handled: after checking response.ok capture response.text()
inside a try block, attempt JSON.parse via await response.json(), and if that
throws, catch the error, read the raw text (await response.text() if not
already), and throw a new Error that includes response.status and the raw
response body plus the parse error message; apply this change to the function
containing the shown snippet and to fetchSdLoras so both return valid parsed
JSON on success or throw a clear, informative error on non-JSON or malformed
responses.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui-svelte/src/components/playground/ImageInterface.svelte`:
- Around line 100-116: The size parsing for the SD API branch is fragile: when
isSdapi is true the code splits $selectedSizeStore into w and h without
validation, which can yield NaN and break the API request; update the logic
around the isSdapi block to validate $selectedSizeStore (e.g., ensure it matches
/^\d+x\d+$/ or that split results are two numeric values), parse ints safely for
w and h, and handle invalid formats by using a safe default size or
early-return/error (affecting the width/height fields used when building
request) so request.width and request.height are never NaN.

---

Nitpick comments:
In `@ui-svelte/src/components/playground/ImageInterface.svelte`:
- Around line 48-63: When the selected model changes the component must clear
LoRA-related state to avoid carrying over invalid selections; update the
component so that on model change (watching $selectedModelStore) you reset
availableLoras = [], selectedLoras = [], and lorasLoaded = false before (or
immediately when) calling loadLoras; locate the loadLoras function and the
reactive/store usage of selectedModelStore and add a short effect or reactive
statement tied to selectedModelStore that clears those variables and then
triggers loadLoras to fetch the correct list for the new model.

In `@ui-svelte/src/lib/sdApi.ts`:
- Around line 16-22: Wrap the response.json() call in a try/catch in this file
(the same pattern for fetchSdLoras) so JSON parse failures are handled: after
checking response.ok capture response.text() inside a try block, attempt
JSON.parse via await response.json(), and if that throws, catch the error, read
the raw text (await response.text() if not already), and throw a new Error that
includes response.status and the raw response body plus the parse error message;
apply this change to the function containing the shown snippet and to
fetchSdLoras so both return valid parsed JSON on success or throw a clear,
informative error on non-JSON or malformed responses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6f2a93b4-c822-438e-a60f-708320de4592

📥 Commits

Reviewing files that changed from the base of the PR and between c3c258a and f24b4eb.

📒 Files selected for processing (6)
  • proxy/proxymanager.go
  • proxy/proxymanager_test.go
  • ui-svelte/src/components/playground/ImageInterface.svelte
  • ui-svelte/src/lib/sdApi.ts
  • ui-svelte/src/lib/types.ts
  • ui-svelte/vite.config.ts

Comment on lines +100 to +116
if (isSdapi) {
const [w, h] = $selectedSizeStore.split("x").map(Number);
const request = {
model: $selectedModelStore,
prompt: trimmedPrompt,
negative_prompt: $sdNegativePromptStore || undefined,
width: w,
height: h,
steps: $sdStepsStore,
cfg_scale: $sdCfgScaleStore,
seed: $sdSeedStore,
batch_size: $sdBatchSizeStore,
clip_skip: $sdClipSkipStore,
sampler_name: $sdSamplerStore || undefined,
scheduler: $sdSchedulerStore || undefined,
lora: selectedLoras.length > 0 ? selectedLoras : undefined,
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add validation for size parsing.

The size string is split without validation. If $selectedSizeStore has an unexpected format, w and h could be NaN, causing API errors.

Proposed fix with validation
       if (isSdapi) {
         const [w, h] = $selectedSizeStore.split("x").map(Number);
+        if (isNaN(w) || isNaN(h) || w <= 0 || h <= 0) {
+          error = "Invalid image size format";
+          return;
+        }
         const request = {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (isSdapi) {
const [w, h] = $selectedSizeStore.split("x").map(Number);
const request = {
model: $selectedModelStore,
prompt: trimmedPrompt,
negative_prompt: $sdNegativePromptStore || undefined,
width: w,
height: h,
steps: $sdStepsStore,
cfg_scale: $sdCfgScaleStore,
seed: $sdSeedStore,
batch_size: $sdBatchSizeStore,
clip_skip: $sdClipSkipStore,
sampler_name: $sdSamplerStore || undefined,
scheduler: $sdSchedulerStore || undefined,
lora: selectedLoras.length > 0 ? selectedLoras : undefined,
};
if (isSdapi) {
const [w, h] = $selectedSizeStore.split("x").map(Number);
if (isNaN(w) || isNaN(h) || w <= 0 || h <= 0) {
error = "Invalid image size format";
return;
}
const request = {
model: $selectedModelStore,
prompt: trimmedPrompt,
negative_prompt: $sdNegativePromptStore || undefined,
width: w,
height: h,
steps: $sdStepsStore,
cfg_scale: $sdCfgScaleStore,
seed: $sdSeedStore,
batch_size: $sdBatchSizeStore,
clip_skip: $sdClipSkipStore,
sampler_name: $sdSamplerStore || undefined,
scheduler: $sdSchedulerStore || undefined,
lora: selectedLoras.length > 0 ? selectedLoras : undefined,
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui-svelte/src/components/playground/ImageInterface.svelte` around lines 100 -
116, The size parsing for the SD API branch is fragile: when isSdapi is true the
code splits $selectedSizeStore into w and h without validation, which can yield
NaN and break the API request; update the logic around the isSdapi block to
validate $selectedSizeStore (e.g., ensure it matches /^\d+x\d+$/ or that split
results are two numeric values), parse ints safely for w and h, and handle
invalid formats by using a safe default size or early-return/error (affecting
the width/height fields used when building request) so request.width and
request.height are never NaN.

claude added 4 commits March 19, 2026 12:27
Remove clip skip option and replace sampler/scheduler text inputs
with dropdown selects populated with known values from sd.cpp.

- remove clip_skip from SdApiTxt2ImgRequest type and UI
- sampler dropdown: euler_a, euler, heun, dpm2, dpmpp2s_a, dpmpp2m,
  dpmpp2mv2, ipndm, ipndm_v, lcm, ddim_trailing, tcd
- scheduler dropdown: discrete, karras, exponential, ays, gits

https://claude.ai/code/session_0186MGX6NXdHVBTv2KH45fqn
Add /sdapi/v1/txt2img, /sdapi/v1/img2img, and /sdapi/v1/loras
handlers to simple-responder so SD API routing tests can pass.

https://claude.ai/code/session_0186MGX6NXdHVBTv2KH45fqn
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
cmd/simple-responder/simple-responder.go (1)

219-231: Deduplicate the two SDAPI POST echo handlers to avoid behavior drift.

Line 219-231 duplicates identical logic for txt2img and img2img; extracting one shared handler keeps both endpoints consistent and easier to maintain.

Proposed refactor
+echoRequestBody := func(c *gin.Context) {
+	bodyBytes, err := io.ReadAll(c.Request.Body)
+	if err != nil {
+		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("failed to read request body: %s", err)})
+		return
+	}
+	c.JSON(http.StatusOK, gin.H{
+		"request_body": string(bodyBytes),
+	})
+}
+
 // sd.cpp endpoints
-r.POST("/sdapi/v1/txt2img", func(c *gin.Context) {
-	bodyBytes, _ := io.ReadAll(c.Request.Body)
-	c.JSON(http.StatusOK, gin.H{
-		"request_body": string(bodyBytes),
-	})
-})
+r.POST("/sdapi/v1/txt2img", echoRequestBody)

-r.POST("/sdapi/v1/img2img", func(c *gin.Context) {
-	bodyBytes, _ := io.ReadAll(c.Request.Body)
-	c.JSON(http.StatusOK, gin.H{
-		"request_body": string(bodyBytes),
-	})
-})
+r.POST("/sdapi/v1/img2img", echoRequestBody)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/simple-responder/simple-responder.go` around lines 219 - 231, The two
POST route handlers for "/sdapi/v1/txt2img" and "/sdapi/v1/img2img" duplicate
the same request-body echo logic; extract a single handler function (e.g.,
sdapiEchoHandler) that reads c.Request.Body (using io.ReadAll and handling the
error) and returns c.JSON(http.StatusOK, gin.H{"request_body":
string(bodyBytes)}), then register that same sdapiEchoHandler for both
r.POST("/sdapi/v1/txt2img", ...) and r.POST("/sdapi/v1/img2img", ...) to keep
behavior consistent and maintainable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/simple-responder/simple-responder.go`:
- Around line 219-223: The POST handler for "/sdapi/v1/txt2img" currently
ignores errors from io.ReadAll and returns 200 with possibly empty request_body;
update the handler(s) that call io.ReadAll (the "/sdapi/v1/txt2img" route and
the similar handler around lines 226-230) to check the error returned, and if
non-nil respond with an appropriate non-200 status and JSON error (e.g., use
c.AbortWithStatusJSON or c.JSON with
http.StatusBadRequest/http.StatusInternalServerError) including an error
message, otherwise continue to return the request_body; ensure you reference the
bodyBytes and err variables in the handler to guard against nil/partial reads.

---

Nitpick comments:
In `@cmd/simple-responder/simple-responder.go`:
- Around line 219-231: The two POST route handlers for "/sdapi/v1/txt2img" and
"/sdapi/v1/img2img" duplicate the same request-body echo logic; extract a single
handler function (e.g., sdapiEchoHandler) that reads c.Request.Body (using
io.ReadAll and handling the error) and returns c.JSON(http.StatusOK,
gin.H{"request_body": string(bodyBytes)}), then register that same
sdapiEchoHandler for both r.POST("/sdapi/v1/txt2img", ...) and
r.POST("/sdapi/v1/img2img", ...) to keep behavior consistent and maintainable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1a0e6395-2ee5-4670-b3f3-200f0707e025

📥 Commits

Reviewing files that changed from the base of the PR and between faff698 and 8a94244.

📒 Files selected for processing (2)
  • cmd/simple-responder/simple-responder.go
  • go.mod
✅ Files skipped from review due to trivial changes (1)
  • go.mod

mostlygeek and others added 2 commits March 19, 2026 05:52
Add handlers for sdapi/v1 endpoints to support testing.

- POST /sdapi/v1/txt2img
- POST /sdapi/v1/img2img
- GET /sdapi/v1/loras

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/simple-responder/simple-responder.go`:
- Around line 218-236: Remove the duplicate early route registrations for the SD
endpoints by deleting the first r.POST handlers for "/sdapi/v1/txt2img" and
"/sdapi/v1/img2img" and the r.GET handler for "/sdapi/v1/loras" (the handlers
that simply read c.Request.Body without error handling) so only the later
implementations remain (those around the other registration block with proper
io.ReadAll error checks); after removing the duplicate block, run gofmt -w on
simple-responder.go to fix the formatting issues.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5c7e56df-d424-41e8-b73c-78ab227e20b8

📥 Commits

Reviewing files that changed from the base of the PR and between 8a94244 and b0651d3.

📒 Files selected for processing (1)
  • cmd/simple-responder/simple-responder.go

@mostlygeek mostlygeek merged commit 15bd55d into main Mar 19, 2026
4 checks passed
@mostlygeek mostlygeek deleted the claude/add-sdapi-v1-support-o2Y1L branch March 19, 2026 13:08
rohitpaul pushed a commit to rohitpaul/llama-swap that referenced this pull request Mar 29, 2026
Add proxy routes for stable-diffusion.cpp's /sdapi/v1/txt2img,
/sdapi/v1/img2img, and /sdapi/v1/loras endpoints. POST endpoints
use proxyInferenceHandler (model in JSON body), GET /loras uses
proxyGETModelHandler (model in query param).

Update the image playground with a dual-mode UI supporting both
OpenAI and SDAPI backends. In SDAPI mode, loras are fetched first
to prime the server-side cache, and all txt2img parameters are
exposed (negative prompt, steps, cfg_scale, seed, batch_size,
clip_skip, sampler, scheduler, lora selection with multipliers).

- Add 3 sdapi route registrations in proxymanager.go
- Add sdApi.ts client with generateSdImage and fetchSdLoras
- Add SDAPI types (SdApiTxt2ImgRequest, SdApiResponse, etc.)
- Add /sdapi to vite dev proxy config
- Add backend tests for sdapi routing
- Support batch image display in gallery grid

https://claude.ai/code/session_0186MGX6NXdHVBTv2KH45fqn

---------

Co-authored-by: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants