Skip to content

增加wan2.5-i2i-preview图生图支持 - #2227

Merged
creamlike1024 merged 1 commit into
QuantumNous:mainfrom
feitianbubu:pr/add-wan2.5-i2i-preview
Nov 15, 2025
Merged

增加wan2.5-i2i-preview图生图支持#2227
creamlike1024 merged 1 commit into
QuantumNous:mainfrom
feitianbubu:pr/add-wan2.5-i2i-preview

Conversation

@feitianbubu

@feitianbubu feitianbubu commented Nov 14, 2025

Copy link
Copy Markdown
Member

官方文档:https://help.aliyun.com/zh/model-studio/wan2-5-image-edit-api-reference?spm=a2c4g.11186623.help-menu-2400256.d_2_2_5.334275acmnKHP4&scm=20140722.H_2982258._.OR_help-T_cn~zh-V_1#4c9724d501qsq
支持模型:wan2.5-i2i-preview
请求示例:

curl http://localhost:3000/v1/images/edits \
  --request POST \
  --header 'Content-Type: multipart/form-data' \
  --form 'image=@avatar.png' \
  --form 'prompt=转个圈' \
  --form 'model=wan2.5-i2i-preview'
image image

Summary by CodeRabbit

  • New Features
    • Added comprehensive support for WAN-based image editing models. Enhanced request handling now intelligently routes WAN model requests through specialized endpoints with async processing. New capabilities include configurable image synthesis parameters (watermark control, seed values, strength settings), negative prompt support, and optimized response handling tailored to WAN model workflows.

@coderabbitai

coderabbitai Bot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

The changes add WAN model support to Alibaba's image editing capability. New types and handlers route WAN-based image edits through different endpoints and async behavior. A helper extracts image data from multipart forms. Conditional logic branches requests based on WAN model detection.

Changes

Cohort / File(s) Summary
New WAN DTO Types
relay/channel/ali/dto.go
Added WanImageInput and WanImageParameters types to support WAN-specific image editing request structure with fields for prompt, images, parameters (N, Watermark, Seed, Strength).
Adaptor Conditional Routing
relay/channel/ali/adaptor.go
Modified GetRequestURL, SetupRequestHeader, ConvertImageRequest, and DoResponse in RelayModeImagesEdits to branch on isWanModel: WAN models use image2image/image-synthesis endpoint with async header; route through oaiFormEdit2WanxImageEdit; dispatch to aliImageHandler.
Image Form Extraction
relay/channel/ali/image.go
Added private getImageBase64sFromForm helper to centralize base64 image extraction from multipart forms supporting "image", "image[]", and "image[...]" fields. Refactored oaiFormEdit2AliImageEdit to use new helper.
WAN Image Handler
relay/channel/ali/image_wan.go
Added oaiFormEdit2WanxImageEdit to construct AliImageRequest for WAN edits by extracting images, unmarshaling WAN parameters, and building WanImageParameters. Introduced isWanModel detection helper.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Adaptor as adaptor.go
    participant FormExt as image.go/<br/>image_wan.go
    participant Backend as ALI Backend

    Client->>Adaptor: Image edit request
    Adaptor->>Adaptor: isWanModel check
    
    alt WAN Model
        Adaptor->>Adaptor: Select image2image/<br/>image-synthesis endpoint
        Adaptor->>Adaptor: Set X-DashScope-Async header
        Adaptor->>FormExt: oaiFormEdit2WanxImageEdit
        FormExt->>FormExt: getImageBase64sFromForm
        FormExt->>FormExt: UnmarshalBodyReusable<br/>(WAN params)
        FormExt-->>Adaptor: AliImageRequest
        Adaptor->>Backend: POST (async)
        Backend-->>Adaptor: Response
        Adaptor->>Adaptor: Route to aliImageHandler
    else Non-WAN Model
        Adaptor->>Adaptor: Select multimodal-generation/<br/>generation endpoint
        Adaptor->>FormExt: oaiFormEdit2AliImageEdit
        FormExt->>FormExt: getImageBase64sFromForm
        FormExt-->>Adaptor: AliImageRequest
        Adaptor->>Backend: POST
        Backend-->>Adaptor: Response
        Adaptor->>Adaptor: Route to aliImageEditHandler
    end
    
    Adaptor-->>Client: Response
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • adaptor.go: Multi-point conditional branching for WAN models across four functions (GetRequestURL, SetupRequestHeader, ConvertImageRequest, DoResponse) requires careful verification of endpoint/handler routing logic
  • image_wan.go: New handler logic with unmarshaling and form extraction—ensure proper error handling and data flow
  • DTO interactions: Verify WanImageInput/WanImageParameters marshaling and field mapping to backend expectations

Possibly Related PRs

Suggested Reviewers

  • creamlike1024

Poem

🐰 A rabbit's verse on WAN's new flight:

WAN models hop to image-synthesis bright,
Async headers set, form-data in sight,
Images base64-ed, parameters unified tight,
Conditional branching done just right! 🎨✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title in Chinese describes adding support for wan2.5-i2i-preview image-to-image functionality, which aligns with the PR objectives and code changes implementing WAN model routing for image editing.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@feitianbubu feitianbubu changed the title 增wan2.5-i2i-preview图生图支持 增加wan2.5-i2i-preview图生图支持 Nov 14, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
relay/channel/ali/image.go (1)

61-127: Fix unused parameter (compile error) and tighten file handling in getImageBase64sFromForm

Two issues here:

  1. The fieldName parameter is never used and is shadowed by the for fieldName, files := range mf.File loop variable. In Go, an unused parameter causes a compile-time error, so this function will not compile as written.
  2. When file.Open() or io.ReadAll(image) fail, the opened file is not closed, which can leak resources under load.

A minimal fix that both uses fieldName meaningfully and avoids shadowing, while improving error handling, could look like this:

-func getImageBase64sFromForm(c *gin.Context, fieldName string) ([]string, error) {
+func getImageBase64sFromForm(c *gin.Context, fieldName string) ([]string, error) {
 	mf := c.Request.MultipartForm
 	if mf == nil {
 		if _, err := c.MultipartForm(); err != nil {
 			return nil, fmt.Errorf("failed to parse image edit form request: %w", err)
 		}
 		mf = c.Request.MultipartForm
 	}
 
 	var imageFiles []*multipart.FileHeader
 	var exists bool
 
-	// First check for standard "image" field
-	if imageFiles, exists = mf.File["image"]; !exists || len(imageFiles) == 0 {
-		// If not found, check for "image[]" field
-		if imageFiles, exists = mf.File["image[]"]; !exists || len(imageFiles) == 0 {
-			// If still not found, iterate through all fields to find any that start with "image["
+	if fieldName == "" {
+		fieldName = "image"
+	}
+
+	// First check for standard fieldName
+	if imageFiles, exists = mf.File[fieldName]; !exists || len(imageFiles) == 0 {
+		// If not found, check for "<field>[]"
+		if imageFiles, exists = mf.File[fieldName+"[]"]; !exists || len(imageFiles) == 0 {
+			// If still not found, iterate through all fields to find any that start with "<field>["
 			foundArrayImages := false
-			for fieldName, files := range mf.File {
-				if strings.HasPrefix(fieldName, "image[") && len(files) > 0 {
+			for formFieldName, files := range mf.File {
+				if strings.HasPrefix(formFieldName, fieldName+"[") && len(files) > 0 {
 					foundArrayImages = true
 					imageFiles = append(imageFiles, files...)
 				}
 			}
@@
-	// 获取base64编码的图片
+	// 获取base64编码的图片
 	var imageBase64s []string
 	for _, file := range imageFiles {
-		image, err := file.Open()
-		if err != nil {
-			return nil, errors.New("failed to open image file")
-		}
-
-		// 读取文件内容
-		imageData, err := io.ReadAll(image)
-		if err != nil {
-			return nil, errors.New("failed to read image file")
-		}
+		image, err := file.Open()
+		if err != nil {
+			return nil, fmt.Errorf("failed to open image file: %w", err)
+		}
+		// Ensure the file is always closed
+		func() {
+			defer image.Close()
+
+			// 读取文件内容
+			imageData, err := io.ReadAll(image)
+			if err != nil {
+				// propagate error out of the loop
+				imageBase64s = nil
+				return
+			}
+
+			// 获取MIME类型
+			mimeType := http.DetectContentType(imageData)
+
+			// 编码为base64
+			base64Data := base64.StdEncoding.EncodeToString(imageData)
+
+			// 构造data URL格式
+			dataURL := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Data)
+			imageBase64s = append(imageBase64s, dataURL)
+		}()
+		if imageBase64s == nil {
+			return nil, fmt.Errorf("failed to read image file")
+		}
-
-		// 获取MIME类型
-		mimeType := http.DetectContentType(imageData)
-
-		// 编码为base64
-		base64Data := base64.StdEncoding.EncodeToString(imageData)
-
-		// 构造data URL格式
-		dataURL := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Data)
-		imageBase64s = append(imageBase64s, dataURL)
-		image.Close()
 	}
 	return imageBase64s, nil
 }

(Exact error-propagation pattern inside the loop is flexible; the key points are: actually using fieldName, avoiding shadowing, and always closing the opened file even on error.)

🧹 Nitpick comments (2)
relay/channel/ali/dto.go (1)

115-126: WAN DTOs look correct; consider enforcing API constraints earlier

WanImageInput/WanImageParameters match the WAN API shape and should serialize fine. To fail fast and return clearer errors before hitting Ali, you might consider:

  • Validating len(Images) <= 2 when building the request.
  • Clamping or validating N to the documented [1,4] range (and possibly Seed / Strength ranges) in the converter.

This can live either in the WAN converter or as small helper validation functions around these DTOs.

relay/channel/ali/image_wan.go (1)

37-39: isWanModel is simple and works; consider tightening matching if more models are added

strings.Contains(modelName, "wan") is a pragmatic way to route WAN models like wan2.5-i2i-preview. If additional non-WAN models containing "wan" are introduced later, you might want to switch to a stricter check (e.g., exact prefix match, allowlist, or regex) to avoid misrouting.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35192e5 and 344a799.

📒 Files selected for processing (4)
  • relay/channel/ali/adaptor.go (4 hunks)
  • relay/channel/ali/dto.go (1 hunks)
  • relay/channel/ali/image.go (2 hunks)
  • relay/channel/ali/image_wan.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
relay/channel/ali/image.go (3)
relay/common/relay_info.go (1)
  • RelayInfo (76-123)
dto/openai_image.go (1)
  • ImageRequest (14-34)
relay/channel/ali/dto.go (1)
  • AliImageRequest (94-99)
relay/channel/ali/image_wan.go (3)
relay/common/relay_info.go (1)
  • RelayInfo (76-123)
relay/channel/ali/dto.go (3)
  • AliImageRequest (94-99)
  • WanImageInput (115-119)
  • WanImageParameters (121-126)
common/gin.go (1)
  • UnmarshalBodyReusable (33-58)
🔇 Additional comments (2)
relay/channel/ali/image.go (1)

129-137: Refactor of oaiFormEdit2AliImageEdit to use shared helper looks good

The switch to getImageBase64sFromForm and wrapping its error with context keeps the edit path consistent with the WAN path and improves error messages. The rest of the function remains unchanged in behavior.

relay/channel/ali/adaptor.go (1)

50-54: WAN edit routing, headers, and handlers are consistent; verify alignment with Ali WAN API

The new WAN-specific branches look coherent:

  • URL selection (Lines 50-54): WAN models under RelayModeImagesEdits now target /api/v1/services/aigc/image2image/image-synthesis, while non-WAN edits still use /multimodal-generation/generation. Good separation of the two APIs.
  • Headers (Lines 78-82): For edit requests with WAN models you enable X-DashScope-Async, matching the async handling used elsewhere, and force Content-Type: application/json for the outgoing request body.
  • Request conversion (Lines 117-119): WAN edit requests are converted via oaiFormEdit2WanxImageEdit, while the existing multipart vs JSON path is preserved for non-WAN edits.
  • Response handling (Lines 174-178): WAN edits now reuse aliImageHandler, which performs async task polling; non-WAN edits remain on aliImageEditHandler.

Assuming Ali’s image2image/image-synthesis endpoint for WAN models indeed uses the same async task contract as the existing text2image path, this wiring should behave correctly. It would be good to double-check against the latest WAN API docs or a live call that:

  • WAN edit responses return a task id compatible with aliImageHandler/asyncTaskWait, and
  • Async mode really is required (or at least supported) when X-DashScope-Async=enable is set.

Also applies to: 78-82, 117-119, 174-178

Comment on lines +14 to +35
func oaiFormEdit2WanxImageEdit(c *gin.Context, info *relaycommon.RelayInfo, request dto.ImageRequest) (*AliImageRequest, error) {
var err error
var imageRequest AliImageRequest
imageRequest.Model = request.Model
imageRequest.ResponseFormat = request.ResponseFormat
wanInput := WanImageInput{
Prompt: request.Prompt,
}

if err := common.UnmarshalBodyReusable(c, &wanInput); err != nil {
return nil, err
}
if wanInput.Images, err = getImageBase64sFromForm(c, "image"); err != nil {
return nil, fmt.Errorf("get image base64s from form failed: %w", err)
}
wanParams := WanImageParameters{
N: int(request.N),
}
imageRequest.Input = wanInput
imageRequest.Parameters = wanParams
return &imageRequest, nil
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Unused info parameter in oaiFormEdit2WanxImageEdit causes compile failure

In Go, function parameters must be used or explicitly ignored. Here info *relaycommon.RelayInfo is never referenced in the body, which will cause a compile-time error.

A minimal fix is to mark the parameter as intentionally unused:

-func oaiFormEdit2WanxImageEdit(c *gin.Context, info *relaycommon.RelayInfo, request dto.ImageRequest) (*AliImageRequest, error) {
+func oaiFormEdit2WanxImageEdit(c *gin.Context, _ *relaycommon.RelayInfo, request dto.ImageRequest) (*AliImageRequest, error) {

A couple of smaller improvements you may also want to consider in this function:

  • Wrap the UnmarshalBodyReusable error with context so callers know which step failed, similar to how you wrap the image helper error:

    if err := common.UnmarshalBodyReusable(c, &wanInput); err != nil {
        return nil, fmt.Errorf("unmarshal WAN input from request failed: %w", err)
    }
  • Optionally validate len(wanInput.Images) and wanParams.N against the documented WAN limits (e.g., max 2 images, N in [1,4]) before sending the request.

🤖 Prompt for AI Agents
In relay/channel/ali/image_wan.go around lines 14 to 35, the parameter info
*relaycommon.RelayInfo is unused and causes a compile error; mark it as
intentionally unused by adding a blank identifier assignment (e.g. _ = info) at
the top of the function, change the UnmarshalBodyReusable error return to wrap
the error with context (e.g. return nil, fmt.Errorf("unmarshal WAN input from
request failed: %w", err)), keep the existing wrapped error for
getImageBase64sFromForm, and (optionally) validate wanInput.Images length and
wanParams.N against expected WAN limits before returning the request.

@creamlike1024
creamlike1024 merged commit 293c027 into QuantumNous:main Nov 15, 2025
1 check passed
ennnnny pushed a commit to ennnnny/new-api that referenced this pull request Mar 17, 2026
…i-preview

增加wan2.5-i2i-preview图生图支持
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