Skip to content

Conversation

@thewindwillstop
Copy link

@gemini-code-assist
Copy link

Summary of Changes

Hello @thewindwillstop, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant new feature that enables users to change the style of a character image while ensuring the character's identity is preserved. It involves adding a new API endpoint, implementing the core logic in the backend controller, integrating with the Recraft AI service for image processing, and providing thorough validation and testing for the new functionality.

Highlights

  • New API Endpoint: Introduced a new API endpoint, POST /character/style/change, allowing users to modify character styling while preserving their core identity.
  • Recraft Integration: Integrated with the Recraft provider to power the character style change functionality, leveraging its image-to-image capabilities.
  • Robust Validation: Implemented comprehensive validation for character style change requests, including checks for image data presence, size limits (5MB), PNG format, style prompt length, and strength parameters.
  • Character Identity Preservation: Developed logic to construct specific prompts and negative prompts for the Recraft API to ensure that character's facial features, body shape, and basic appearance remain consistent during style transformations.
  • Updated Documentation and Examples: The SVG_GENERATION_CONFIG.md file has been updated to include detailed documentation for the new endpoint, its request/response formats, and a curl example for easy testing.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new feature to change a character's style while preserving its identity, primarily leveraging the Recraft API. The changes include a new API endpoint, controller logic, service implementation, and extensive tests. The implementation is solid, but I've identified a few areas for improvement regarding error handling, a logic bug in parameter validation, and code maintainability. Specifically, there's a bug that prevents users from setting preserve_identity to false, and another issue where PNG images are incorrectly saved with an .svg extension. Addressing these points will enhance the robustness and correctness of the new feature.

Comment on lines +54 to +56
if strength, err := strconv.ParseFloat(strengthStr, 64); err == nil {
params.Strength = strength
}

Choose a reason for hiding this comment

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

medium

Parsing for the strength parameter silently ignores errors. If a user provides a non-numeric value (e.g., strength=abc), the error from strconv.ParseFloat is ignored, and the default value is used without notifying the user. This can be confusing. It's better to return an error for invalid input.

if strength, err := strconv.ParseFloat(strengthStr, 64); err == nil {
		params.Strength = strength
	} else {
		replyWithCodeMsg(ctx, errorInvalidArgs, "Invalid value for strength parameter")
		return
	}

}

// ChangeCharacterStyle changes character styling while preserving character identity and returns the styled image metadata.
func (ctrl *Controller) ChangeCharacterStyle(ctx context.Context, params *ChangeCharacterStyleParams, imageData []byte) (*ChangeCharacterStyleResponse, error) {

Choose a reason for hiding this comment

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

medium

The public method ChangeCharacterStyle should validate its input parameters. Currently, it relies on the caller to perform validation. It's a good practice for public methods to validate their arguments to ensure robustness and prevent misuse. Please add a call to params.Validate() at the beginning of this function.

For example:

if ok, msg := params.Validate(); !ok {
    return nil, errors.New(msg)
}

Comment on lines +470 to +472
var errResp map[string]interface{}
_ = json.NewDecoder(resp.Body).Decode(&errResp)
logger.Printf("[RECRAFT] Error response body: %+v", errResp)

Choose a reason for hiding this comment

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

medium

When handling a non-2xx response from the Recraft API, the error from decoding the JSON error response is ignored. If the error response is not valid JSON, the log message for errResp will be empty or misleading. It would be more robust to read the raw response body into a string and log that, ensuring you always capture the error details from the upstream service. You will need to import the io package.

Suggested change
var errResp map[string]interface{}
_ = json.NewDecoder(resp.Body).Decode(&errResp)
logger.Printf("[RECRAFT] Error response body: %+v", errResp)
bodyBytes, _ := io.ReadAll(resp.Body)
logger.Printf("[RECRAFT] Error response body: %s", string(bodyBytes))

Comment on lines +509 to +541
// buildCharacterPreservationPrompt builds a prompt that emphasizes character preservation during style changes.
func (s *RecraftService) buildCharacterPreservationPrompt(stylePrompt string, preserveIdentity bool) string {
var promptBuilder strings.Builder

if preserveIdentity {
// Add character preservation instructions
promptBuilder.WriteString("保持角色的面部特征、体型和基本外观不变,")
promptBuilder.WriteString("只改变")
}

promptBuilder.WriteString(stylePrompt)

if preserveIdentity {
promptBuilder.WriteString(",确保角色身份完全保持不变,面部特征和体型必须保持一致")
}

return promptBuilder.String()
}

// buildCharacterPreservationNegativePrompt builds negative prompts to avoid unwanted character changes.
func (s *RecraftService) buildCharacterPreservationNegativePrompt(negativePrompt string) string {
var negativeBuilder strings.Builder

if negativePrompt != "" {
negativeBuilder.WriteString(negativePrompt)
negativeBuilder.WriteString(", ")
}

// Add character preservation negative prompts
negativeBuilder.WriteString("改变面部特征, 改变角色身份, 不同的人, 面部变形, 体型改变, 性别改变, 年龄变化")

return negativeBuilder.String()
}

Choose a reason for hiding this comment

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

medium

The Chinese strings used to build the character preservation prompt and negative prompt are hardcoded inline within the buildCharacterPreservationPrompt and buildCharacterPreservationNegativePrompt functions. It's better to define these as constants at the top of the file. This improves readability and makes them easier to manage or change in the future.

For example:

const (
    characterPreservationInstruction = "保持角色的面部特征、体型和基本外观不变,"
    characterStyleChangeInstruction  = "只改变"
    // ... and so on for other strings
)

// Default to preserve identity if not specified
if !p.PreserveIdentity {
p.PreserveIdentity = true // Default to preserve identity
}
Copy link

Choose a reason for hiding this comment

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

🐛 Critical Bug - Broken Default Logic

This condition is always true when PreserveIdentity is false (zero value for bool), making it impossible to explicitly set it to false.

Suggested change
}
// PreserveIdentity defaults to true if not set
// Note: To support explicit false, consider using *bool instead

Alternatively, remove this block and document that default is false, or use a pointer type *bool to distinguish between unset and explicitly false.

)

ctx := &Context
if _, ok := ensureAuthenticatedUser(ctx); !ok {
Copy link

Choose a reason for hiding this comment

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

🔒 Security - Missing Quota/Rate Limiting

Unlike copilot endpoints, this doesn't enforce any quota limits. This could allow abuse of expensive Recraft API calls.

Consider adding quota enforcement similar to post_copilot_message.yap:

if err := authz.ConsumeQuota(ctx.Context(), authz.ResourceAIImageGen, 1); err != nil {
	replyWithCodeMsg(ctx, errorTooManyRequests, "Image generation quota exceeded")
	return
}

@niupilot
Copy link

niupilot bot commented Oct 10, 2025

🔍 Code Review Summary

Reviewed by specialized agents for code quality, performance, documentation, and security. Overall solid implementation with good test coverage, but critical issues require attention before merge.

🚨 Must Fix

  • PreserveIdentity default logic is broken (svg.go:147)
  • Unbounded file read enables memory DoS (post_character_style_change.yap:35)
  • Missing rate limiting allows API abuse (post_character_style_change.yap:15)

⚠️ Should Address

  • Extract duplicated validation logic
  • Add max prompt length (500 chars)
  • Make vector service async (-500-2000ms response time)
  • Pre-allocate multipart buffer

📊 Metrics

Lines: +1276 / -1
Security: 2 high, 2 medium issues
Performance: 700ms-2.5s potential improvement
Test Coverage: ✅ Comprehensive unit tests (761 new test lines)

✨ Positives

Strong architecture, consistent error handling, good separation of concerns, proper authentication enforcement.

See inline comments for specific fixes.

@qiniu-ci
Copy link

This PR has been deployed to the preview environment. You can explore it using the preview URL.

Warning

Please note that deployments in the preview environment are temporary and will be automatically cleaned up after a certain period. Make sure to explore it before it is removed. For any questions, contact the Go+ Builder team.

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