feat: channel kling support New API - #1412
Conversation
WalkthroughThis update introduces new GET endpoints for querying Kling video generation tasks by task ID, adds corresponding handler stubs and routes, and adjusts both backend and frontend logic to support a unified API key format for the Kling adaptor. The response parsing logic is updated to handle multiple formats, and related user prompts are clarified. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Frontend
participant Router
participant Controller
participant Adaptor
participant UpstreamAPI
User->>Frontend: Request task status (GET /videos/text2video/:task_id)
Frontend->>Router: Forward GET request
Router->>Controller: Call RelayTask handler
Controller->>Adaptor: Prepare request, parse API key
Adaptor->>UpstreamAPI: Query task status/result
UpstreamAPI-->>Adaptor: Respond with task status/result
Adaptor->>Controller: Parse response (new or old format)
Controller->>Frontend: Return task status/result
Frontend->>User: Display task status/result
Estimated code review effort4 (60–120 minutes) Possibly related PRs
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
relay/channel/task/kling/adaptor.go (3)
53-53: Consider documenting the purpose of the redundant TaskId field.The addition of a top-level
TaskIdfield duplicates the existing nestedData.TaskId. While this may be necessary for API compatibility, it would be helpful to add a comment explaining why both fields exist to prevent confusion for future maintainers.type responsePayload struct { Code int `json:"code"` Message string `json:"message"` - TaskId string `json:"task_id"` + TaskId string `json:"task_id"` // Top-level task ID for New API compatibility RequestId string `json:"request_id"`
84-86: Update or remove the misleading comment about API key format.The comment on line 86 suggests a specific format
"access_key|secret_key", but the Init method doesn't validate or enforce this format. Consider either:
- Removing the comment since the actual parsing happens in
createJWTTokenWithKey- Updating it to reflect that both formats are supported
a.apiKey = info.ApiKey - - // apiKey format: "access_key|secret_key" + // apiKey can be either "access_key|secret_key" (official) or direct API key (New API)
282-288: Remove commented-out code.The commented-out code adds no value and creates confusion. Please remove it to improve code readability.
func (a *TaskAdaptor) createJWTToken() (string, error) { return a.createJWTTokenWithKey(a.apiKey) } -//func (a *TaskAdaptor) createJWTTokenWithKey(apiKey string) (string, error) { -// parts := strings.Split(apiKey, "|") -// if len(parts) != 2 { -// return "", fmt.Errorf("invalid API key format, expected 'access_key,secret_key'") -// } -// return a.createJWTTokenWithKey(strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])) -//} - func (a *TaskAdaptor) createJWTTokenWithKey(apiKey string) (string, error) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
controller/swag_video.go(1 hunks)controller/task_video.go(2 hunks)relay/channel/task/kling/adaptor.go(5 hunks)relay/constant/relay_mode.go(1 hunks)router/video-router.go(1 hunks)web/src/pages/Channel/EditChannel.js(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
relay/channel/task/kling/adaptor.go (1)
Learnt from: 9Ninety
PR: #1273
File: relay/channel/gemini/relay-gemini.go:97-116
Timestamp: 2025-06-21T03:37:41.726Z
Learning: In relay/channel/gemini/relay-gemini.go, the thinking budget calculation logic (including the MaxOutputTokens multiplication) was introduced in PR #1247. PR #1273 focused specifically on decoupling the thoughts summary feature from thinking budget settings and did not modify the existing thinking budget behavior.
🧬 Code Graph Analysis (1)
controller/task_video.go (2)
relay/common/relay_info.go (1)
TaskInfo(337-344)common/json.go (1)
Unmarshal(8-10)
🔇 Additional comments (8)
relay/constant/relay_mode.go (1)
153-153: LGTM: Path matching updated to support task ID endpoints.The change from
HasSuffixtoContainscorrectly enables routing for the new GET endpoints/videos/text2video/:task_idand/videos/image2video/:task_idby matching paths that contain "/video/generations" anywhere in the string.web/src/pages/Channel/EditChannel.js (1)
71-71: LGTM: User prompt updated for dual API key support.The updated prompt clearly informs users about the two authentication formats:
- Official Kling API:
AccessKey|SecretKey- New API proxy: Direct
ApiKeyinputThis aligns perfectly with the PR objective of supporting both interfaces simultaneously.
router/video-router.go (1)
23-24: LGTM: GET endpoints added for task status queries.The new routes properly complement the existing POST endpoints by enabling task status retrieval:
/videos/text2video/:task_idand/videos/image2video/:task_id- Consistent middleware usage and controller reuse
- Follows RESTful patterns for resource querying
These align with the Swagger documentation added in
controller/swag_video.go.controller/swag_video.go (1)
118-136: LGTM: Swagger documentation added for new GET endpoints.The empty handler functions serve as proper Swagger documentation stubs for the new task query endpoints:
- Clear summaries and descriptions in both Chinese and English
- Correct HTTP method and path parameter specification
- Appropriate categorization with Tags
Since the actual implementation is handled by
controller.RelayTask(as configured in the router), these documentation stubs are sufficient.relay/channel/task/kling/adaptor.go (4)
77-77: Good simplification of API key handling.Consolidating the separate access/secret keys into a single
apiKeyfield improves flexibility and aligns well with the PR objective of supporting both official and New API formats.
166-177: LGTM! Simplified response handling.The streamlined response parsing removes unnecessary complexity while maintaining proper error handling. The direct JSON response aligns well with the New API support objective.
290-297: Well-implemented dual API key format support.The logic correctly handles both API key formats as described in the PR objectives:
- Direct API key (New API): Returns the key as-is
- "AccessKey|SecretKey" format (Official): Generates JWT token
This implementation provides the flexibility needed for supporting both interfaces.
310-310:
| taskResult := &relaycommon.TaskInfo{} | ||
| // try parse as New API response format | ||
| var responseItems dto.TaskResponse[model.Task] | ||
| if err = json.Unmarshal(responseBody, &responseItems); err == nil { | ||
| t := responseItems.Data | ||
| taskResult.TaskID = t.TaskID | ||
| taskResult.Status = string(t.Status) | ||
| taskResult.Url = t.FailReason | ||
| taskResult.Progress = t.Progress | ||
| taskResult.Reason = t.FailReason | ||
| } else if taskResult, err = adaptor.ParseTaskResult(responseBody); err != nil { | ||
| return fmt.Errorf("parseTaskResult failed for task %s: %w", taskId, err) | ||
| } else { | ||
| task.Data = responseBody | ||
| } |
There was a problem hiding this comment.
Fix field mapping errors in New API response parsing.
The new dual-format parsing approach is good for compatibility, but there are several issues with the field mapping:
- Incorrect URL assignment: Line 90 assigns
t.FailReasontotaskResult.Url, which should likely be a URL field from the response - Duplicate assignment: Both
taskResult.UrlandtaskResult.Reasonare assigned the samet.FailReasonvalue - Missing task data:
task.Data = responseBodyis only set in the fallback branch (line 96), but may be needed for both parsing paths
Please verify the correct field mappings from the model.Task struct and apply this correction:
// try parse as New API response format
var responseItems dto.TaskResponse[model.Task]
if err = json.Unmarshal(responseBody, &responseItems); err == nil {
t := responseItems.Data
taskResult.TaskID = t.TaskID
taskResult.Status = string(t.Status)
- taskResult.Url = t.FailReason
+ taskResult.Url = t.ResultURL // or appropriate URL field
taskResult.Progress = t.Progress
taskResult.Reason = t.FailReason
+ task.Data = responseBody
} else if taskResult, err = adaptor.ParseTaskResult(responseBody); err != nil {📝 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.
| taskResult := &relaycommon.TaskInfo{} | |
| // try parse as New API response format | |
| var responseItems dto.TaskResponse[model.Task] | |
| if err = json.Unmarshal(responseBody, &responseItems); err == nil { | |
| t := responseItems.Data | |
| taskResult.TaskID = t.TaskID | |
| taskResult.Status = string(t.Status) | |
| taskResult.Url = t.FailReason | |
| taskResult.Progress = t.Progress | |
| taskResult.Reason = t.FailReason | |
| } else if taskResult, err = adaptor.ParseTaskResult(responseBody); err != nil { | |
| return fmt.Errorf("parseTaskResult failed for task %s: %w", taskId, err) | |
| } else { | |
| task.Data = responseBody | |
| } | |
| taskResult := &relaycommon.TaskInfo{} | |
| // try parse as New API response format | |
| var responseItems dto.TaskResponse[model.Task] | |
| if err = json.Unmarshal(responseBody, &responseItems); err == nil { | |
| t := responseItems.Data | |
| taskResult.TaskID = t.TaskID | |
| taskResult.Status = string(t.Status) | |
| taskResult.Url = t.ResultURL // or appropriate URL field | |
| taskResult.Progress = t.Progress | |
| taskResult.Reason = t.FailReason | |
| task.Data = responseBody | |
| } else if taskResult, err = adaptor.ParseTaskResult(responseBody); err != nil { | |
| return fmt.Errorf("parseTaskResult failed for task %s: %w", taskId, err) | |
| } else { | |
| task.Data = responseBody | |
| } |
🤖 Prompt for AI Agents
In controller/task_video.go around lines 83 to 97, fix the incorrect field
mappings when parsing the new API response: assign the correct URL field from
the response (not FailReason) to taskResult.Url, avoid duplicating FailReason in
both Url and Reason fields, and ensure task.Data is set to responseBody in both
successful parsing branches, not just the fallback. Review the model.Task struct
to identify the proper URL field and update the assignments accordingly.
支持New API代理可灵渠道
可灵渠道同时支持官方接口和New API接口
ApiKey如果是可灵官方输入: AccessKey|SecretKey
如果上游是New API,则直接输ApiKey
Summary by CodeRabbit
New Features
Improvements
Bug Fixes