Skip to content

Conversation

@Ben11029
Copy link

No description provided.

Copilot AI review requested due to automatic review settings December 20, 2025 07:21
@vercel
Copy link

vercel bot commented Dec 20, 2025

@Ben11029 is attempting to deploy a commit to the dayuanjiang's projects Team on Vercel.

A member of the Team first needs to authorize it.

@Ben11029
Copy link
Author

11

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds AI image generation capabilities to the draw.io application using Google's Gemini 3 Pro Image model (playfully referred to as "Nano Banana" and "Nano Banana Pro" in the documentation). Users can now toggle between diagram creation and AI image generation modes, with configurable resolution (1K/2K/4K) and aspect ratio settings.

Key Changes:

  • Integration of Gemini 3 Pro Image API for AI-powered image generation
  • New UI components for image preview, download, and generation configuration
  • Image generation mode that bypasses diagram tools and uses Google's image model

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 18 comments.

Show a summary per file
File Description
package-lock.json Version bump from 0.4.2 to 0.4.3
gemini-3-pro-image-preview.md Comprehensive Chinese documentation for Gemini image generation features (1011 lines)
components/image-preview-modal.tsx New modal component with zoom controls and PNG download functionality for generated images
components/image-generation-config.tsx New configuration panel for toggling image generation mode and setting resolution/aspect ratio
components/chat-panel.tsx Integration of image generation config, state management, and handling of image parts in responses
components/chat-message-display.tsx Display and interaction handling for AI-generated images within chat messages
app/api/chat/route.ts Backend logic to switch between diagram mode and image generation mode, including Google AI SDK integration
Comments suppressed due to low confidence (1)

components/image-generation-config.tsx:3

  • Unused import ImageIcon.
import { ImageIcon } from "lucide-react"

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

URL.revokeObjectURL(url)
toast.success("图片已下载")
}
}, "image/png")
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

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

The canvas context could be null, but there's only a null check without handling the null case properly. If ctx is null, the code should either throw an error or fall back to the direct download method in the catch block.

Suggested change
}, "image/png")
}, "image/png")
} else {
throw new Error("Canvas 2D context not available")

Copilot uses AI. Check for mistakes.
>
<SelectTrigger
id="resolution-select"
className="w-16 h-4 text-xs"
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

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

The height property is incorrectly set to "4" when it should be "h-7" or similar valid Tailwind class. The value "4" without a unit prefix will not work as expected for the button height.

Copilot uses AI. Check for mistakes.
>
<SelectTrigger
id="aspect-ratio-select"
className="w-20 h-4 text-xs"
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

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

The height property is incorrectly set to "4" when it should be "h-7" or similar valid Tailwind class. The value "4" without a unit prefix will not work as expected for the button height.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,132 @@
"use client"

import { ImageIcon } from "lucide-react"
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

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

The unused import "ImageIcon" is imported from "lucide-react" but never used in this component. This should be removed to keep the code clean.

Suggested change
import { ImageIcon } from "lucide-react"

Copilot uses AI. Check for mistakes.
Comment on lines +333 to +351
const filteredContent = msg.content.filter((part: any) => {
// Remove image parts from assistant messages (multiple checks for different formats)
if (
part.type === "image" ||
part.image ||
part.url ||
part.mimeType?.startsWith("image/") ||
(part.experimental_providerMetadata &&
part.experimental_providerMetadata.anthropic
?.type === "image")
) {
console.log(
"[route.ts] Filtering out image from assistant message",
part.type,
)
return false
}
return true
})
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

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

The condition checks multiple properties with 'any' type assertions to detect image parts. This is fragile and could miss image data or incorrectly filter non-image content. Consider defining a proper type guard function or using a more robust detection method based on the AI SDK's documented response format.

Copilot uses AI. Check for mistakes.
Comment on lines +708 to +709
const imageXml = `<mxCell id="${imageId}" value="AI生成图片" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;verticalAlign=top;aspect=fixed;imageAspect=0;image=${imageUrl};" vertex="1" parent="1">
<mxGeometry x="50" y="50" width="600" height="600" as="geometry"/>
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

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

The hardcoded dimensions "width='600' height='600'" may not be appropriate for all aspect ratios. Consider calculating dimensions based on the configured imageAspectRatio to ensure the image displays with correct proportions.

Suggested change
const imageXml = `<mxCell id="${imageId}" value="AI生成图片" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;verticalAlign=top;aspect=fixed;imageAspect=0;image=${imageUrl};" vertex="1" parent="1">
<mxGeometry x="50" y="50" width="600" height="600" as="geometry"/>
const baseWidth = 600
const aspectRatio =
typeof imageAspectRatio === "number" &&
imageAspectRatio > 0
? imageAspectRatio
: 1
const imageWidth = baseWidth
const imageHeight = Math.round(
baseWidth / aspectRatio,
)
const imageXml = `<mxCell id="${imageId}" value="AI生成图片" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;verticalAlign=top;aspect=fixed;imageAspect=0;image=${imageUrl};" vertex="1" parent="1">
<mxGeometry x="50" y="50" width="${imageWidth}" height="${imageHeight}" as="geometry"/>

Copilot uses AI. Check for mistakes.
Comment on lines +284 to +285
const imageXml = `<mxCell id="${imageId}" value="${description || "AI生成图片"}" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png;base64,${imageData};" vertex="1" parent="1">
<mxGeometry x="50" y="50" width="400" height="400" as="geometry"/>
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

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

The same hardcoded dimensions issue exists here. The width and height should be calculated based on the configured aspect ratio to ensure proper image display.

Suggested change
const imageXml = `<mxCell id="${imageId}" value="${description || "AI生成图片"}" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png;base64,${imageData};" vertex="1" parent="1">
<mxGeometry x="50" y="50" width="400" height="400" as="geometry"/>
// Base geometry computed from a single width and an aspect ratio (width / height).
// Default to a square aspect ratio to preserve current behavior.
const imageAspectRatio = 1 // width / height
const baseWidth = 400
const imageWidth = baseWidth
const imageHeight = Math.round(baseWidth / imageAspectRatio)
const imageXml = `<mxCell id="${imageId}" value="${description || "AI生成图片"}" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png;base64,${imageData};" vertex="1" parent="1">
<mxGeometry x="50" y="50" width="${imageWidth}" height="${imageHeight}" as="geometry"/>

Copilot uses AI. Check for mistakes.
}
},
"image/png",
)
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

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

The canvas context could be null, but there's only a null check without handling the null case properly. If ctx is null, the code should either throw an error or fall back to showing an error toast.

Suggested change
)
)
} else {
// Handle the case where the canvas rendering context is unavailable
toast.error(
"无法获取画布上下文,下载失败",
)
return

Copilot uses AI. Check for mistakes.
Comment on lines +229 to +232
let model: any
let providerOptions: any = {}
let headers: any = {}
let modelId: string
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

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

Variables are declared with 'any' type which defeats TypeScript's type safety. Consider defining proper types for model, providerOptions, headers, and modelId, or use appropriate type annotations from the AI SDK.

Copilot uses AI. Check for mistakes.
Comment on lines +700 to +705
// Remove data URL prefix if present
const base64Data = imageUrl.replace(
/^data:image\/[^;]+;base64,/,
"",
)

Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

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

Unused variable base64Data.

Suggested change
// Remove data URL prefix if present
const base64Data = imageUrl.replace(
/^data:image\/[^;]+;base64,/,
"",
)

Copilot uses AI. Check for mistakes.
@DayuanJiang
Copy link
Owner

Thanks for the contribution! Could you add a description of what this PR does?

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