Skip to content

Conversation

@iceljc
Copy link
Collaborator

@iceljc iceljc commented Oct 20, 2025

PR Type

Enhancement


Description

  • Reorganize image-related endpoints from InstructModeController to ImageGenerationController

  • Add four new image operation endpoints: generation, variation, edit, mask-edit

  • Refactor image response helper to accept and pass saved files parameter

  • Add DALL-E and GPT image model configurations to settings


Diagram Walkthrough

flowchart LR
  A["InstructModeController<br/>Image Endpoints"] -->|"Move 279 lines"| B["ImageGenerationController<br/>Consolidated"]
  B --> C["4 Endpoint Groups:<br/>Generation, Variation,<br/>Edit, Mask-Edit"]
  D["Image Functions<br/>ComposeImageFn,<br/>EditImageFn,<br/>GenerateImageFn"] -->|"Pass savedFiles"| E["AiResponseHelper<br/>Enhanced"]
  E --> F["GetImageGenerationResponse<br/>with files parameter"]
  G["appsettings.json"] -->|"Add configs"| H["DALL-E 2/3<br/>GPT-Image 1/1-Mini"]
Loading

File Walkthrough

Relevant files
Enhancement
ImageGenerationController.cs
Consolidate image operations into dedicated controller     

src/Infrastructure/BotSharp.OpenAPI/Controllers/ImageGenerationController.cs

  • Added import for FileUtility from BotSharp.Abstraction.Files.Utilities
  • Organized existing ComposeImages endpoint under #region Image
    composition
  • Added ImageGeneration endpoint for POST /instruct/image-generation
  • Added ImageVariation endpoints for POST /instruct/image-variation and
    /instruct/image-variation/form
  • Added ImageEdit endpoints for POST /instruct/image-edit and
    /instruct/image-edit/form
  • Added ImageMaskEdit endpoints for POST /instruct/image-mask-edit and
    /instruct/image-mask-edit/form
+273/-0 
AiResponseHelper.cs
Enhance image response helper with files parameter             

src/Plugins/BotSharp.Plugin.ImageHandler/Helpers/AiResponseHelper.cs

  • Refactored GetImageGenerationResponse to accept optional files
    parameter
  • Added fallback to GetDefaultResponse when response content is null or
    empty
  • Updated GetDefaultResponse signature to accept nullable files
    parameter
  • Reordered method definitions with GetImageGenerationResponse first
+13/-13 
Refactoring
InstructModeController.cs
Remove migrated image endpoints from controller                   

src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs

  • Removed 279 lines of image-related endpoint code (ImageGeneration,
    ImageVariation, ImageEdit, ImageMaskEdit)
  • Removed #region Generate image section entirely
  • Kept remaining multi-modal and PDF completion functionality intact
+0/-266 
ComposeImageFn.cs
Update image response helper invocation                                   

src/Plugins/BotSharp.Plugin.ImageHandler/Functions/ComposeImageFn.cs

  • Updated GetImageEditGeneration method to pass savedFiles parameter to
    AiResponseHelper
  • Removed private GetImageEditResponse wrapper method
  • Simplified method call to directly use
    AiResponseHelper.GetImageGenerationResponse
+1/-6     
EditImageFn.cs
Update image response helper invocation                                   

src/Plugins/BotSharp.Plugin.ImageHandler/Functions/EditImageFn.cs

  • Updated GetImageEdit method to pass savedFiles parameter to
    AiResponseHelper
  • Removed private GetImageEditResponse wrapper method
  • Simplified method call to directly use
    AiResponseHelper.GetImageGenerationResponse
+1/-6     
GenerateImageFn.cs
Update image response helper invocation                                   

src/Plugins/BotSharp.Plugin.ImageHandler/Functions/GenerateImageFn.cs

  • Updated GetImageGeneration method to pass savedFiles parameter to
    AiResponseHelper
  • Removed private GetImageGenerationResponse wrapper method
  • Simplified method call to directly use
    AiResponseHelper.GetImageGenerationResponse
+1/-6     
Configuration changes
appsettings.json
Add image model provider configurations                                   

src/WebStarter/appsettings.json

  • Added DALL-E 2 image model configuration with generation, edit, and
    variation settings
  • Added DALL-E 3 image model configuration with generation settings and
    quality/style options
  • Added GPT-Image-1 model configuration with generation and edit
    capabilities
  • Added GPT-Image-1-Mini model configuration with generation and edit
    capabilities
  • Cleared MetaGLM ApiKey value from configuration
+182/-1 

@qodo-merge-pro
Copy link

qodo-merge-pro bot commented Oct 20, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
API key handling

Description: The MetaGLM ApiKey value was changed to an empty string; confirm that no valid secret
remains elsewhere and that configuration handling does not fall back to insecure defaults
or log missing keys.
appsettings.json [728-734]

Referred Code
"MetaGLM": {
  "ApiKey": "",
  "BaseAddress": "http://localhost:8100/v1/",
  "ModelId": "chatglm3_6b",
  "Temperature": 0.7,
  "TopP": 0.7
},
Ticket Compliance
🎫 No ticket provided
- [ ] Create ticket/issue <!-- /create_ticket --create_ticket=true -->

</details></td></tr>
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
No custom compliance provided

Follow the guide to enable custom compliance check.

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-merge-pro
Copy link

qodo-merge-pro bot commented Oct 20, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Consolidate duplicated endpoint logic

The ImageGenerationController has duplicate logic for handling the same
operations (e.g., image variation) via two different endpoint types ([FromBody]
and [FromForm]). This should be refactored into a shared private helper method
to reduce redundancy and improve maintainability.

Examples:

src/Infrastructure/BotSharp.OpenAPI/Controllers/ImageGenerationController.cs [92-164]
    [HttpPost("/instruct/image-variation")]
    public async Task<ImageGenerationViewModel> ImageVariation([FromBody] ImageVariationFileRequest request)
    {
        var state = _services.GetRequiredService<IConversationStateService>();
        request.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
        var imageViewModel = new ImageGenerationViewModel();

        try
        {
            if (request.File == null)

 ... (clipped 63 lines)
src/Infrastructure/BotSharp.OpenAPI/Controllers/ImageGenerationController.cs [168-240]
    [HttpPost("/instruct/image-edit")]
    public async Task<ImageGenerationViewModel> ImageEdit([FromBody] ImageEditFileRequest request)
    {
        var fileInstruct = _services.GetRequiredService<IFileInstructService>();
        var state = _services.GetRequiredService<IConversationStateService>();
        request.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
        var imageViewModel = new ImageGenerationViewModel();

        try
        {

 ... (clipped 63 lines)

Solution Walkthrough:

Before:

// Image Variation Endpoints
[HttpPost("/instruct/image-variation")]
public async Task<ImageGenerationViewModel> ImageVariation([FromBody] ImageVariationFileRequest request)
{
    // ... boilerplate setup ...
    try
    {
        // ... logic to call fileInstruct.VaryImage with request.File ...
    }
    catch (Exception ex)
    {
        // ... error handling ...
    }
}

[HttpPost("/instruct/image-variation/form")]
public async Task<ImageGenerationViewModel> ImageVariation(IFormFile file, [FromForm] ImageVariationRequest request)
{
    // ... boilerplate setup ...
    try
    {
        // ... logic to build file model and call fileInstruct.VaryImage ...
    }
    catch (Exception ex)
    {
        // ... error handling ...
    }
}

After:

// Refactored Image Variation Endpoints
[HttpPost("/instruct/image-variation")]
public async Task<ImageGenerationViewModel> ImageVariation([FromBody] ImageVariationFileRequest request)
{
    // ... set state ...
    if (request.File == null) { /* return error */ }
    var options = new InstructOptions { ... };
    return await HandleImageVariation(request.File, options);
}

[HttpPost("/instruct/image-variation/form")]
public async Task<ImageGenerationViewModel> ImageVariation(IFormFile file, [FromForm] ImageVariationRequest request)
{
    // ... set state ...
    var fileModel = FileUtility.BuildFileDataFromFile(file);
    var options = new InstructOptions { ... };
    return await HandleImageVariation(fileModel, options);
}

private async Task<ImageGenerationViewModel> HandleImageVariation(InstructFileModel file, InstructOptions options)
{
    var imageViewModel = new ImageGenerationViewModel();
    try
    {
        var fileInstruct = _services.GetRequiredService<IFileInstructService>();
        var message = await fileInstruct.VaryImage(file, options);
        // ... populate view model ...
    }
    catch (Exception ex)
    {
        // ... error handling ...
    }
    return imageViewModel;
}
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies significant code duplication across endpoint pairs in ImageGenerationController and proposes a valid refactoring strategy to improve maintainability, which is a substantial quality improvement.

Medium
Possible issue
Add null check for file input

Add a null check for the file parameter in the ImageVariation form endpoint to
prevent a NullReferenceException if no file is uploaded, and return a
user-friendly error message.

src/Infrastructure/BotSharp.OpenAPI/Controllers/ImageGenerationController.cs [128-164]

 [HttpPost("/instruct/image-variation/form")]
 public async Task<ImageGenerationViewModel> ImageVariation(IFormFile file, [FromForm] ImageVariationRequest request)
 {
     var state = _services.GetRequiredService<IConversationStateService>();
     request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
     var imageViewModel = new ImageGenerationViewModel();
 
     try
     {
+        if (file == null)
+        {
+            return new ImageGenerationViewModel { Message = "Error! Cannot find an image!" };
+        }
+
         var fileInstruct = _services.GetRequiredService<IFileInstructService>();
         var fileData = FileUtility.BuildFileDataFromFile(file);
         var message = await fileInstruct.VaryImage(new InstructFileModel
         {
             FileData = fileData,
             FileName = Path.GetFileNameWithoutExtension(file.FileName),
             FileExtension = Path.GetExtension(file.FileName)
         },
         new InstructOptions
         {
             Provider = request?.Provider,
             Model = request?.Model,
             AgentId = request?.AgentId,
             ImageConvertProvider = request?.ImageConvertProvider
         });
 
         imageViewModel.Content = message.Content;
         imageViewModel.Images = message.GeneratedImages?.Select(x => ImageViewModel.ToViewModel(x)) ?? [];
         return imageViewModel;
     }
     catch (Exception ex)
     {
         var error = $"Error in image variation upload. {ex.Message}";
         _logger.LogError(ex, error);
         imageViewModel.Message = error;
         return imageViewModel;
     }
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a missing null check for the IFormFile parameter, which would cause a NullReferenceException and result in a generic server error instead of a user-friendly message.

Medium
General
Handle null or empty description

In GetImageGenerationResponse, add a check to handle cases where description is
null or whitespace by returning a default response, thus avoiding a malformed
call to the LLM.

src/Plugins/BotSharp.Plugin.ImageHandler/Helpers/AiResponseHelper.cs [5-15]

 internal static async Task<string> GetImageGenerationResponse(IServiceProvider services, Agent agent, string description, IEnumerable<string>? files = null)
 {
+    if (string.IsNullOrWhiteSpace(description))
+    {
+        return GetDefaultResponse(files);
+    }
+
     var text = $"Please generate a user-friendly response from the following description to " +
                $"inform user that you have completed the required image: {description}";
 
     var provider = agent?.LlmConfig?.Provider ?? "openai";
     var model = agent?.LlmConfig?.Model ?? "gpt-4o-mini";
     var completion = CompletionProvider.GetChatCompletion(services, provider: provider, model: model);
     var response = await completion.GetChatCompletions(agent, [new RoleDialogModel(AgentRole.User, text)]);
     return response.Content.IfNullOrEmptyAs(GetDefaultResponse(files)) ?? string.Empty;
 }
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly points out that a null or empty description will lead to a poor prompt for the LLM, and proposes a valid improvement to return a default response instead, making the function more robust.

Low
Learned
best practice
Add null guards for states

Guard request and request.States before iterating to avoid null reference
exceptions. Provide a safe no-op when states are missing.

src/Infrastructure/BotSharp.OpenAPI/Controllers/ImageGenerationController.cs [64]

-request.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
+request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Ensure nullability guards before property access and return safe fallbacks for potentially missing inputs.

Low
Null-check response before access

Null-check response before accessing Content to avoid potential null
dereference; use a safe fallback when response is null.

src/Plugins/BotSharp.Plugin.ImageHandler/Helpers/AiResponseHelper.cs [14]

-return response.Content.IfNullOrEmptyAs(GetDefaultResponse(files)) ?? string.Empty;
+var content = response?.Content;
+return content.IfNullOrEmptyAs(GetDefaultResponse(files)) ?? string.Empty;
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Ensure nullability guards before property access and default to safe fallbacks when inputs may be null.

Low
  • Update

@iceljc iceljc merged commit 7d020bb into SciSharp:master Oct 21, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant