-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Nano #333
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Nano #333
Conversation
|
@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. |
|
11 |
There was a problem hiding this 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") |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
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.
| }, "image/png") | |
| }, "image/png") | |
| } else { | |
| throw new Error("Canvas 2D context not available") |
| > | ||
| <SelectTrigger | ||
| id="resolution-select" | ||
| className="w-16 h-4 text-xs" |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
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.
| > | ||
| <SelectTrigger | ||
| id="aspect-ratio-select" | ||
| className="w-20 h-4 text-xs" |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
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.
| @@ -0,0 +1,132 @@ | |||
| "use client" | |||
|
|
|||
| import { ImageIcon } from "lucide-react" | |||
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
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.
| import { ImageIcon } from "lucide-react" |
| 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 | ||
| }) |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
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.
| 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"/> |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
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.
| 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"/> |
| 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"/> |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
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.
| 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"/> |
| } | ||
| }, | ||
| "image/png", | ||
| ) |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
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.
| ) | |
| ) | |
| } else { | |
| // Handle the case where the canvas rendering context is unavailable | |
| toast.error( | |
| "无法获取画布上下文,下载失败", | |
| ) | |
| return |
| let model: any | ||
| let providerOptions: any = {} | ||
| let headers: any = {} | ||
| let modelId: string |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
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.
| // Remove data URL prefix if present | ||
| const base64Data = imageUrl.replace( | ||
| /^data:image\/[^;]+;base64,/, | ||
| "", | ||
| ) | ||
|
|
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable base64Data.
| // Remove data URL prefix if present | |
| const base64Data = imageUrl.replace( | |
| /^data:image\/[^;]+;base64,/, | |
| "", | |
| ) |
|
Thanks for the contribution! Could you add a description of what this PR does? |
No description provided.