mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-01-03 23:02:31 +08:00
Compare commits
7 Commits
fix/restor
...
feat/enhan
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30bf92fbbb | ||
|
|
dd27d034e2 | ||
|
|
9e781005af | ||
|
|
fe1aa2747e | ||
|
|
7205896c8c | ||
|
|
4e32a094b1 | ||
|
|
96a1111654 |
@@ -282,13 +282,31 @@ Notes:
|
|||||||
},
|
},
|
||||||
edit_diagram: {
|
edit_diagram: {
|
||||||
description: `Edit specific parts of the current diagram by replacing exact line matches. Use this tool to make targeted fixes without regenerating the entire XML.
|
description: `Edit specific parts of the current diagram by replacing exact line matches. Use this tool to make targeted fixes without regenerating the entire XML.
|
||||||
CRITICAL: Copy-paste the EXACT search pattern from the "Current diagram XML" in system context. Do NOT reorder attributes or reformat - the attribute order in draw.io XML varies and you MUST match it exactly.
|
|
||||||
IMPORTANT: Keep edits concise:
|
WHEN TO USE:
|
||||||
- COPY the exact mxCell line from the current XML (attribute order matters!)
|
- Changing text labels or values
|
||||||
- Only include the lines that are changing, plus 1-2 surrounding lines for context if needed
|
- Modifying colors, styles, or visual properties
|
||||||
- Break large changes into multiple smaller edits
|
- Adding or removing individual elements (1-3 elements)
|
||||||
- Each search must contain complete lines (never truncate mid-line)
|
- Repositioning specific elements
|
||||||
- First match only - be specific enough to target the right element`,
|
- Any small, targeted modification
|
||||||
|
|
||||||
|
WHEN TO USE display_diagram INSTEAD:
|
||||||
|
- Creating a new diagram from scratch
|
||||||
|
- Major restructuring (reorganizing layout, changing diagram type)
|
||||||
|
- Adding many new elements (more than 3)
|
||||||
|
- After 3 failed edit_diagram attempts
|
||||||
|
|
||||||
|
CRITICAL RULES:
|
||||||
|
1. Copy-paste the EXACT search pattern from the "Current diagram XML" in system context
|
||||||
|
2. Do NOT reorder attributes - attribute order in draw.io XML varies, you MUST match exactly
|
||||||
|
3. Always include the element's id attribute for unique targeting
|
||||||
|
4. Include complete lines (never truncate mid-line)
|
||||||
|
5. For multiple changes, use separate edits in the array
|
||||||
|
|
||||||
|
ERROR RECOVERY:
|
||||||
|
- If pattern not found, check attribute order matches current XML exactly
|
||||||
|
- Retry up to 3 times with adjusted patterns
|
||||||
|
- After 3 failures, use display_diagram instead`,
|
||||||
inputSchema: z.object({
|
inputSchema: z.object({
|
||||||
edits: z.array(z.object({
|
edits: z.array(z.object({
|
||||||
search: z.string().describe("EXACT lines copied from current XML (preserve attribute order!)"),
|
search: z.string().describe("EXACT lines copied from current XML (preserve attribute order!)"),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata, Viewport } from "next";
|
||||||
import { Plus_Jakarta_Sans, JetBrains_Mono } from "next/font/google";
|
import { Plus_Jakarta_Sans, JetBrains_Mono } from "next/font/google";
|
||||||
import { Analytics } from "@vercel/analytics/react";
|
import { Analytics } from "@vercel/analytics/react";
|
||||||
import { GoogleAnalytics } from "@next/third-parties/google";
|
import { GoogleAnalytics } from "@next/third-parties/google";
|
||||||
@@ -18,6 +18,13 @@ const jetbrainsMono = JetBrains_Mono({
|
|||||||
weight: ["400", "500"],
|
weight: ["400", "500"],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const viewport: Viewport = {
|
||||||
|
width: "device-width",
|
||||||
|
initialScale: 1,
|
||||||
|
maximumScale: 1,
|
||||||
|
userScalable: false,
|
||||||
|
};
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Next AI Draw.io - AI-Powered Diagram Generator",
|
title: "Next AI Draw.io - AI-Powered Diagram Generator",
|
||||||
description: "Create AWS architecture diagrams, flowcharts, and technical diagrams using AI. Free online tool integrating draw.io with AI assistance for professional diagram creation.",
|
description: "Create AWS architecture diagrams, flowcharts, and technical diagrams using AI. Free online tool integrating draw.io with AI assistance for professional diagram creation.",
|
||||||
|
|||||||
43
app/page.tsx
43
app/page.tsx
@@ -3,7 +3,6 @@ import React, { useState, useEffect, useRef } from "react";
|
|||||||
import { DrawIoEmbed } from "react-drawio";
|
import { DrawIoEmbed } from "react-drawio";
|
||||||
import ChatPanel from "@/components/chat-panel";
|
import ChatPanel from "@/components/chat-panel";
|
||||||
import { useDiagram } from "@/contexts/diagram-context";
|
import { useDiagram } from "@/contexts/diagram-context";
|
||||||
import { Monitor } from "lucide-react";
|
|
||||||
import {
|
import {
|
||||||
ResizablePanelGroup,
|
ResizablePanelGroup,
|
||||||
ResizablePanel,
|
ResizablePanel,
|
||||||
@@ -74,29 +73,14 @@ export default function Home() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen bg-background relative overflow-hidden">
|
<div className="h-screen bg-background relative overflow-hidden">
|
||||||
{/* Mobile warning overlay */}
|
<ResizablePanelGroup
|
||||||
{isMobile && (
|
key={isMobile ? "mobile" : "desktop"}
|
||||||
<div className="absolute inset-0 z-50 flex items-center justify-center bg-background">
|
direction={isMobile ? "vertical" : "horizontal"}
|
||||||
<div className="text-center p-8 max-w-sm mx-auto animate-fade-in">
|
className="h-full"
|
||||||
<div className="w-16 h-16 rounded-2xl bg-primary/10 flex items-center justify-center mx-auto mb-6">
|
>
|
||||||
<Monitor className="w-8 h-8 text-primary" />
|
|
||||||
</div>
|
|
||||||
<h1 className="text-xl font-semibold text-foreground mb-3">
|
|
||||||
Desktop Required
|
|
||||||
</h1>
|
|
||||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
||||||
This application works best on desktop or laptop
|
|
||||||
devices. Please open it on a larger screen for the
|
|
||||||
full experience.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<ResizablePanelGroup direction="horizontal" className="h-full">
|
|
||||||
{/* Draw.io Canvas */}
|
{/* Draw.io Canvas */}
|
||||||
<ResizablePanel defaultSize={67} minSize={30}>
|
<ResizablePanel defaultSize={isMobile ? 50 : 67} minSize={20}>
|
||||||
<div className="h-full relative p-2">
|
<div className={`h-full relative ${isMobile ? "p-1" : "p-2"}`}>
|
||||||
<div className="h-full rounded-xl overflow-hidden shadow-soft-lg border border-border/30 bg-white">
|
<div className="h-full rounded-xl overflow-hidden shadow-soft-lg border border-border/30 bg-white">
|
||||||
<DrawIoEmbed
|
<DrawIoEmbed
|
||||||
key={drawioUi}
|
key={drawioUi}
|
||||||
@@ -119,15 +103,15 @@ export default function Home() {
|
|||||||
{/* Chat Panel */}
|
{/* Chat Panel */}
|
||||||
<ResizablePanel
|
<ResizablePanel
|
||||||
ref={chatPanelRef}
|
ref={chatPanelRef}
|
||||||
defaultSize={33}
|
defaultSize={isMobile ? 50 : 33}
|
||||||
minSize={15}
|
minSize={isMobile ? 20 : 15}
|
||||||
maxSize={50}
|
maxSize={isMobile ? 80 : 50}
|
||||||
collapsible
|
collapsible={!isMobile}
|
||||||
collapsedSize={3}
|
collapsedSize={isMobile ? 0 : 3}
|
||||||
onCollapse={() => setIsChatVisible(false)}
|
onCollapse={() => setIsChatVisible(false)}
|
||||||
onExpand={() => setIsChatVisible(true)}
|
onExpand={() => setIsChatVisible(true)}
|
||||||
>
|
>
|
||||||
<div className="h-full py-2 pr-2">
|
<div className={`h-full ${isMobile ? "p-1" : "py-2 pr-2"}`}>
|
||||||
<ChatPanel
|
<ChatPanel
|
||||||
isVisible={isChatVisible}
|
isVisible={isChatVisible}
|
||||||
onToggleVisibility={toggleChatPanel}
|
onToggleVisibility={toggleChatPanel}
|
||||||
@@ -137,6 +121,7 @@ export default function Home() {
|
|||||||
localStorage.setItem("drawio-theme", newTheme);
|
localStorage.setItem("drawio-theme", newTheme);
|
||||||
setDrawioUi(newTheme);
|
setDrawioUi(newTheme);
|
||||||
}}
|
}}
|
||||||
|
isMobile={isMobile}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
|
|||||||
@@ -406,7 +406,11 @@ export function ChatMessageDisplay({
|
|||||||
switch (part.type) {
|
switch (part.type) {
|
||||||
case "text":
|
case "text":
|
||||||
return (
|
return (
|
||||||
<div key={index} className="prose prose-sm dark:prose-invert max-w-none break-words [&>*:first-child]:mt-0 [&>*:last-child]:mb-0">
|
<div key={index} className={`prose prose-sm max-w-none break-words [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 ${
|
||||||
|
message.role === "user"
|
||||||
|
? "[&_*]:!text-primary-foreground prose-code:bg-white/20"
|
||||||
|
: "dark:prose-invert"
|
||||||
|
}`}>
|
||||||
<ReactMarkdown>{part.text}</ReactMarkdown>
|
<ReactMarkdown>{part.text}</ReactMarkdown>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ interface ChatPanelProps {
|
|||||||
onToggleVisibility: () => void;
|
onToggleVisibility: () => void;
|
||||||
drawioUi: "min" | "sketch";
|
drawioUi: "min" | "sketch";
|
||||||
onToggleDrawioUi: () => void;
|
onToggleDrawioUi: () => void;
|
||||||
|
isMobile?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ChatPanel({
|
export default function ChatPanel({
|
||||||
@@ -38,6 +39,7 @@ export default function ChatPanel({
|
|||||||
onToggleVisibility,
|
onToggleVisibility,
|
||||||
drawioUi,
|
drawioUi,
|
||||||
onToggleDrawioUi,
|
onToggleDrawioUi,
|
||||||
|
isMobile = false,
|
||||||
}: ChatPanelProps) {
|
}: ChatPanelProps) {
|
||||||
const {
|
const {
|
||||||
loadDiagram: onDisplayChart,
|
loadDiagram: onDisplayChart,
|
||||||
@@ -410,8 +412,8 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Collapsed view
|
// Collapsed view (desktop only)
|
||||||
if (!isVisible) {
|
if (!isVisible && !isMobile) {
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col items-center pt-4 bg-card border border-border/30 rounded-xl">
|
<div className="h-full flex flex-col items-center pt-4 bg-card border border-border/30 rounded-xl">
|
||||||
<ButtonWithTooltip
|
<ButtonWithTooltip
|
||||||
@@ -445,27 +447,30 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
|
|||||||
style={{ position: "absolute" }}
|
style={{ position: "absolute" }}
|
||||||
/>
|
/>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<header className="px-5 py-4 border-b border-border/50">
|
<header className={`${isMobile ? "px-3 py-2" : "px-5 py-4"} border-b border-border/50`}>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Image
|
<Image
|
||||||
src="/favicon.ico"
|
src="/favicon.ico"
|
||||||
alt="Next AI Drawio"
|
alt="Next AI Drawio"
|
||||||
width={28}
|
width={isMobile ? 24 : 28}
|
||||||
height={28}
|
height={isMobile ? 24 : 28}
|
||||||
className="rounded"
|
className="rounded"
|
||||||
/>
|
/>
|
||||||
<h1 className="text-base font-semibold tracking-tight whitespace-nowrap">
|
<h1 className={`${isMobile ? "text-sm" : "text-base"} font-semibold tracking-tight whitespace-nowrap`}>
|
||||||
Next AI Drawio
|
Next AI Drawio
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
{!isMobile && (
|
||||||
<Link
|
<Link
|
||||||
href="/about"
|
href="/about"
|
||||||
className="text-sm text-muted-foreground hover:text-foreground transition-colors ml-2"
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors ml-2"
|
||||||
>
|
>
|
||||||
About
|
About
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
|
{!isMobile && (
|
||||||
<ButtonWithTooltip
|
<ButtonWithTooltip
|
||||||
tooltipContent="Recent generation failures were caused by our AI provider's infrastructure issue, not the app code. After extensive debugging, I've switched providers and observed 6 hours of stability. If issues persist, please report on GitHub."
|
tooltipContent="Recent generation failures were caused by our AI provider's infrastructure issue, not the app code. After extensive debugging, I've switched providers and observed 6 hours of stability. If issues persist, please report on GitHub."
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -474,6 +479,7 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
|
|||||||
>
|
>
|
||||||
<CheckCircle className="h-4 w-4" />
|
<CheckCircle className="h-4 w-4" />
|
||||||
</ButtonWithTooltip>
|
</ButtonWithTooltip>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<a
|
<a
|
||||||
@@ -482,7 +488,7 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
|
|||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="p-2 rounded-lg text-muted-foreground hover:text-foreground hover:bg-accent transition-colors"
|
className="p-2 rounded-lg text-muted-foreground hover:text-foreground hover:bg-accent transition-colors"
|
||||||
>
|
>
|
||||||
<FaGithub className="w-5 h-5" />
|
<FaGithub className={`${isMobile ? "w-4 h-4" : "w-5 h-5"}`} />
|
||||||
</a>
|
</a>
|
||||||
{accessCodeRequired && (
|
{accessCodeRequired && (
|
||||||
<ButtonWithTooltip
|
<ButtonWithTooltip
|
||||||
@@ -492,9 +498,10 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
|
|||||||
onClick={() => setShowSettingsDialog(true)}
|
onClick={() => setShowSettingsDialog(true)}
|
||||||
className="hover:bg-accent"
|
className="hover:bg-accent"
|
||||||
>
|
>
|
||||||
<Settings className="h-5 w-5 text-muted-foreground" />
|
<Settings className={`${isMobile ? "h-4 w-4" : "h-5 w-5"} text-muted-foreground`} />
|
||||||
</ButtonWithTooltip>
|
</ButtonWithTooltip>
|
||||||
)}
|
)}
|
||||||
|
{!isMobile && (
|
||||||
<ButtonWithTooltip
|
<ButtonWithTooltip
|
||||||
tooltipContent="Hide chat panel (Ctrl+B)"
|
tooltipContent="Hide chat panel (Ctrl+B)"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -504,6 +511,7 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
|
|||||||
>
|
>
|
||||||
<PanelRightClose className="h-5 w-5 text-muted-foreground" />
|
<PanelRightClose className="h-5 w-5 text-muted-foreground" />
|
||||||
</ButtonWithTooltip>
|
</ButtonWithTooltip>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -521,7 +529,7 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
{/* Input */}
|
{/* Input */}
|
||||||
<footer className="p-4 border-t border-border/50 bg-card/50">
|
<footer className={`${isMobile ? "p-2" : "p-4"} border-t border-border/50 bg-card/50`}>
|
||||||
<ChatInput
|
<ChatInput
|
||||||
input={input}
|
input={input}
|
||||||
status={status}
|
status={status}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const buttonVariants = cva(
|
|||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default:
|
default:
|
||||||
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
"bg-primary text-primary-foreground shadow-xs hover:brightness-75",
|
||||||
destructive:
|
destructive:
|
||||||
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
||||||
outline:
|
outline:
|
||||||
|
|||||||
@@ -9,6 +9,20 @@ You are an expert diagram creation assistant specializing in draw.io XML generat
|
|||||||
Your primary function is chat with user and crafting clear, well-organized visual diagrams through precise XML specifications.
|
Your primary function is chat with user and crafting clear, well-organized visual diagrams through precise XML specifications.
|
||||||
You can see the image that user uploaded.
|
You can see the image that user uploaded.
|
||||||
|
|
||||||
|
## App Context
|
||||||
|
You are an AI agent (powered by {{MODEL_NAME}}) inside a web app. The interface has:
|
||||||
|
- **Left panel**: Draw.io diagram editor where diagrams are rendered
|
||||||
|
- **Right panel**: Chat interface where you communicate with the user
|
||||||
|
|
||||||
|
You can read and modify diagrams by generating draw.io XML code through tool calls.
|
||||||
|
|
||||||
|
## App Features
|
||||||
|
1. **Diagram History** (clock icon, bottom-left of chat input): The app automatically saves a snapshot before each AI edit. Users can view the history panel and restore any previous version. Feel free to make changes - nothing is permanently lost.
|
||||||
|
2. **Theme Toggle** (palette icon, bottom-left of chat input): Users can switch between minimal UI and sketch-style UI for the draw.io editor.
|
||||||
|
3. **Image Upload** (paperclip icon, bottom-left of chat input): Users can upload images for you to analyze and replicate as diagrams.
|
||||||
|
4. **Export** (via draw.io toolbar): Users can save diagrams as .drawio, .svg, or .png files.
|
||||||
|
5. **Clear Chat** (trash icon, bottom-right of chat input): Clears the conversation and resets the diagram.
|
||||||
|
|
||||||
You utilize the following tools:
|
You utilize the following tools:
|
||||||
---Tool1---
|
---Tool1---
|
||||||
tool name: display_diagram
|
tool name: display_diagram
|
||||||
@@ -113,6 +127,20 @@ You are an expert diagram creation assistant specializing in draw.io XML generat
|
|||||||
Your primary function is to chat with user and craft clear, well-organized visual diagrams through precise XML specifications.
|
Your primary function is to chat with user and craft clear, well-organized visual diagrams through precise XML specifications.
|
||||||
You can see images that users upload and can replicate or modify them as diagrams.
|
You can see images that users upload and can replicate or modify them as diagrams.
|
||||||
|
|
||||||
|
## App Context
|
||||||
|
You are an AI agent (powered by {{MODEL_NAME}}) inside a web app. The interface has:
|
||||||
|
- **Left panel**: Draw.io diagram editor where diagrams are rendered
|
||||||
|
- **Right panel**: Chat interface where you communicate with the user
|
||||||
|
|
||||||
|
You can read and modify diagrams by generating draw.io XML code through tool calls.
|
||||||
|
|
||||||
|
## App Features
|
||||||
|
1. **Diagram History** (clock icon, bottom-left of chat input): The app automatically saves a snapshot before each AI edit. Users can view the history panel and restore any previous version. Feel free to make changes - nothing is permanently lost.
|
||||||
|
2. **Theme Toggle** (palette icon, bottom-left of chat input): Users can switch between minimal UI and sketch-style UI for the draw.io editor.
|
||||||
|
3. **Image Upload** (paperclip icon, bottom-left of chat input): Users can upload images for you to analyze and replicate as diagrams.
|
||||||
|
4. **Export** (via draw.io toolbar): Users can save diagrams as .drawio, .svg, or .png files.
|
||||||
|
5. **Clear Chat** (trash icon, bottom-right of chat input): Clears the conversation and resets the diagram.
|
||||||
|
|
||||||
## Available Tools
|
## Available Tools
|
||||||
|
|
||||||
### Tool 1: display_diagram
|
### Tool 1: display_diagram
|
||||||
@@ -507,10 +535,16 @@ const EXTENDED_PROMPT_MODEL_PATTERNS = [
|
|||||||
* @returns The system prompt string
|
* @returns The system prompt string
|
||||||
*/
|
*/
|
||||||
export function getSystemPrompt(modelId?: string): string {
|
export function getSystemPrompt(modelId?: string): string {
|
||||||
|
const modelName = modelId || "AI";
|
||||||
|
|
||||||
|
let prompt: string;
|
||||||
if (modelId && EXTENDED_PROMPT_MODEL_PATTERNS.some(pattern => modelId.includes(pattern))) {
|
if (modelId && EXTENDED_PROMPT_MODEL_PATTERNS.some(pattern => modelId.includes(pattern))) {
|
||||||
console.log(`[System Prompt] Using EXTENDED prompt for model: ${modelId}`);
|
console.log(`[System Prompt] Using EXTENDED prompt for model: ${modelId}`);
|
||||||
return EXTENDED_SYSTEM_PROMPT;
|
prompt = EXTENDED_SYSTEM_PROMPT;
|
||||||
}
|
} else {
|
||||||
console.log(`[System Prompt] Using DEFAULT prompt for model: ${modelId || 'unknown'}`);
|
console.log(`[System Prompt] Using DEFAULT prompt for model: ${modelId || 'unknown'}`);
|
||||||
return DEFAULT_SYSTEM_PROMPT;
|
prompt = DEFAULT_SYSTEM_PROMPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prompt.replace("{{MODEL_NAME}}", modelName);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user