mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-01-03 06:42:27 +08:00
Compare commits
52 Commits
v0.2.0
...
feat/add-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45ab934288 | ||
|
|
cd012f5e2f | ||
|
|
d4fb635d98 | ||
|
|
14740e35a8 | ||
|
|
5b31216917 | ||
|
|
c7d0260328 | ||
|
|
d2d4dd01cc | ||
|
|
b4679f6598 | ||
|
|
0d0d553e23 | ||
|
|
6e6de1eba6 | ||
|
|
00af87edbe | ||
|
|
468d6c0276 | ||
|
|
14f74b076f | ||
|
|
78d9229ca3 | ||
|
|
d8e0a1daad | ||
|
|
32e75ab556 | ||
|
|
b87e3a2de9 | ||
|
|
b758f63d7f | ||
|
|
b32d42d962 | ||
|
|
603865fdb0 | ||
|
|
4cb4e187b3 | ||
|
|
b4d0c6c18b | ||
|
|
c03c41d320 | ||
|
|
9d248e25ad | ||
|
|
4f4aae0e39 | ||
|
|
b00579b257 | ||
|
|
caf7ffe56c | ||
|
|
50d16cbe47 | ||
|
|
56167d363c | ||
|
|
3e2dbbb541 | ||
|
|
efebcea3ba | ||
|
|
68824bc951 | ||
|
|
794826550d | ||
|
|
de98cf60ae | ||
|
|
b3fc624e13 | ||
|
|
d2dd501f3f | ||
|
|
5964deeff7 | ||
|
|
663e1c8c77 | ||
|
|
455115935c | ||
|
|
8d36e0dfb0 | ||
|
|
60f4694752 | ||
|
|
aa330f74b3 | ||
|
|
7a6a7eaf7c | ||
|
|
7518285e98 | ||
|
|
5c5da397df | ||
|
|
0385818b98 | ||
|
|
5e5c1fc31c | ||
|
|
50b860bdea | ||
|
|
533b3ccace | ||
|
|
8084905711 | ||
|
|
0dffe8cc20 | ||
|
|
065e8f0d62 |
6
.eslintrc.json
Normal file
6
.eslintrc.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": [
|
||||
"next/core-web-vitals",
|
||||
"next/typescript"
|
||||
]
|
||||
}
|
||||
149
README.md
149
README.md
@@ -4,7 +4,7 @@ A next.js web application that integrates AI capabilities with draw.io diagrams.
|
||||
|
||||
https://github.com/user-attachments/assets/b2eef5f3-b335-4e71-a755-dc2e80931979
|
||||
|
||||
Demo site: [https://next-ai-draw-io.vercel.app/](https://next-ai-draw-io.vercel.app/)
|
||||
Demo site: [https://next-ai-draw-io.vercel.app](https://next-ai-draw-io.vercel.app)
|
||||
|
||||
## Features
|
||||
|
||||
@@ -12,9 +12,48 @@ Demo site: [https://next-ai-draw-io.vercel.app/](https://next-ai-draw-io.vercel.
|
||||
- **Image-Based Diagram Replication**: Upload existing diagrams or images and have the AI replicate and enhance them automatically
|
||||
- **Diagram History**: Comprehensive version control that tracks all changes, allowing you to view and restore previous versions of your diagrams before the AI editing.
|
||||
- **Interactive Chat Interface**: Communicate with AI to refine your diagrams in real-time
|
||||
- **Smart Editing**: Modify existing diagrams using simple text prompts
|
||||
- **Targeted XML Editing**: AI can now make precise edits to specific parts of diagrams without regenerating the entire XML, making updates faster and more efficient
|
||||
- **Improved XML Handling**: Automatic formatting of single-line XML for better compatibility and reliability
|
||||
- **AWS Architecture Diagram Support**: Specialized support for generating AWS architecture diagrams
|
||||
- **Animated Connectors**: Create dynamic and animated connectors between diagram elements for better visualization
|
||||
|
||||
## **Examples**
|
||||
|
||||
Here are some example prompts and their generated diagrams:
|
||||
|
||||
<div align="center">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
<strong>GCP architecture diagram</strong><br />
|
||||
<p><strong>Prompt:</strong> Generate a GCP architecture diagram with **GCP icons**. In this diagram, users connect to a frontend hosted on an instance.</p>
|
||||
<img src="./public/gcp_demo.svg" alt="GCP Architecture Diagram" width="480" />
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
<strong>AWS architecture diagram</strong><br />
|
||||
<p><strong>Prompt:</strong> Generate a AWS architecture diagram with **AWS icons**. In this diagram, users connect to a frontend hosted on an instance.</p>
|
||||
<img src="./public/aws_demo.svg" alt="AWS Architecture Diagram" width="480" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
<strong>Azure architecture diagram</strong><br />
|
||||
<p><strong>Prompt:</strong> Generate a Azure architecture diagram with **Azure icons**. In this diagram, users connect to a frontend hosted on an instance.</p>
|
||||
<img src="./public/azure_demo.svg" alt="Azure Architecture Diagram" width="480" />
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
<strong>Animated transformer connectors</strong><br />
|
||||
<p><strong>Prompt:</strong> Give me a **animated connector** diagram of transformer's architecture.</p>
|
||||
<img src="./public/animated_connectors.svg" alt="Transformer Architecture with Animated Connectors" width="480" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" valign="top" align="center">
|
||||
<strong>Cat sketch prompt</strong><br />
|
||||
<p><strong>Prompt:</strong> Draw a cute cat for me.</p>
|
||||
<img src="./public/cat_demo.svg" alt="Cat Drawing" width="260" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
## How It Works
|
||||
|
||||
@@ -28,83 +67,16 @@ Diagrams are represented as XML that can be rendered in draw.io. The AI processe
|
||||
|
||||
## Multi-Provider Support
|
||||
|
||||
This application supports multiple AI providers, making it easy to deploy with your preferred service. Choose from:
|
||||
- AWS Bedrock (default)
|
||||
- OpenAI / OpenAI-compatible APIs (via `OPENAI_BASE_URL`)
|
||||
- Anthropic
|
||||
- Google AI
|
||||
- Azure OpenAI
|
||||
- Ollama
|
||||
- OpenRouter
|
||||
- DeepSeek
|
||||
|
||||
### Supported Providers
|
||||
|
||||
| Provider | Status | Best For |
|
||||
|----------|--------|----------|
|
||||
| **AWS Bedrock** | ✅ Default | Claude models via AWS infrastructure |
|
||||
| **OpenAI** | ✅ Supported | GPT-4, GPT-5, and reasoning models |
|
||||
| **Anthropic** | ✅ Supported | Direct access to Claude models |
|
||||
| **Google AI** | ✅ Supported | Gemini models with multi-modal capabilities |
|
||||
| **Azure OpenAI** | ✅ Supported | Enterprise OpenAI deployments |
|
||||
| **Ollama** | ✅ Supported | Local/self-hosted open source models |
|
||||
|
||||
### Quick Setup by Provider
|
||||
|
||||
#### AWS Bedrock (Default)
|
||||
```bash
|
||||
AI_PROVIDER=bedrock
|
||||
AI_MODEL=global.anthropic.claude-sonnet-4-5-20250929-v1:0
|
||||
AWS_REGION=us-east-1
|
||||
AWS_ACCESS_KEY_ID=your-access-key
|
||||
AWS_SECRET_ACCESS_KEY=your-secret-key
|
||||
```
|
||||
|
||||
#### OpenAI
|
||||
```bash
|
||||
AI_PROVIDER=openai
|
||||
AI_MODEL=gpt-4o
|
||||
OPENAI_API_KEY=sk-...
|
||||
```
|
||||
|
||||
#### Anthropic
|
||||
```bash
|
||||
AI_PROVIDER=anthropic
|
||||
AI_MODEL=claude-sonnet-4-5
|
||||
ANTHROPIC_API_KEY=sk-ant-...
|
||||
```
|
||||
|
||||
#### Google Generative AI
|
||||
```bash
|
||||
AI_PROVIDER=google
|
||||
AI_MODEL=gemini-2.5-flash
|
||||
GOOGLE_GENERATIVE_AI_API_KEY=...
|
||||
```
|
||||
|
||||
#### Azure OpenAI
|
||||
```bash
|
||||
AI_PROVIDER=azure
|
||||
AI_MODEL=your-deployment-name
|
||||
AZURE_RESOURCE_NAME=your-resource
|
||||
AZURE_API_KEY=...
|
||||
```
|
||||
|
||||
#### Ollama (Local)
|
||||
```bash
|
||||
AI_PROVIDER=ollama
|
||||
AI_MODEL=phi3
|
||||
OLLAMA_BASE_URL=http://localhost:11434/api # Optional
|
||||
```
|
||||
Note: Install models locally first with `ollama pull <model-name>`
|
||||
|
||||
### Recommended Models
|
||||
|
||||
**Best Quality:**
|
||||
- AWS Bedrock: `global.anthropic.claude-sonnet-4-5-20250929-v1:0`
|
||||
- Anthropic: `claude-sonnet-4-5`
|
||||
- OpenAI: `gpt-4o` or `gpt-5`
|
||||
|
||||
**Best Speed:**
|
||||
- Google: `gemini-2.5-flash`
|
||||
- OpenAI: `gpt-4o`
|
||||
- Anthropic: `claude-haiku-4-5`
|
||||
|
||||
**Best Cost:**
|
||||
- Ollama: Free (local models)
|
||||
- Google: `gemini-1.5-flash-8b`
|
||||
- OpenAI: `gpt-4o-mini`
|
||||
Note that `claude-sonnet-4-5` has trained on draw.io diagrams with AWS logos, so if you want to create AWS architecture diagrams, this is the best choice.
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -130,13 +102,14 @@ yarn install
|
||||
Create a `.env.local` file in the root directory:
|
||||
|
||||
```bash
|
||||
cp .env.example .env.local
|
||||
cp env.example .env.local
|
||||
```
|
||||
|
||||
Edit `.env.local` and configure your chosen provider:
|
||||
- Set `AI_PROVIDER` to your chosen provider (bedrock, openai, anthropic, google, azure, ollama)
|
||||
- Set `AI_MODEL` to the specific model you want to use
|
||||
- Add the required API keys for your provider
|
||||
|
||||
- Set `AI_PROVIDER` to your chosen provider (bedrock, openai, anthropic, google, azure, ollama, openrouter, deepseek)
|
||||
- Set `AI_MODEL` to the specific model you want to use
|
||||
- Add the required API keys for your provider
|
||||
|
||||
See the [Multi-Provider Support](#multi-provider-support) section above for provider-specific configuration examples.
|
||||
|
||||
@@ -157,6 +130,8 @@ Check out the [Next.js deployment documentation](https://nextjs.org/docs/app/bui
|
||||
Or you can deploy by this button.
|
||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FDayuanJiang%2Fnext-ai-draw-io)
|
||||
|
||||
Be sure to **set the environment variables** in the Vercel dashboard as you did in your local `.env.local` file.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
@@ -176,6 +151,8 @@ public/ # Static assets including example images
|
||||
- [x] Allow the LLM to modify the XML instead of generating it from scratch everytime.
|
||||
- [x] Improve the smoothness of shape streaming updates.
|
||||
- [x] Add multiple AI provider support (OpenAI, Anthropic, Google, Azure, Ollama)
|
||||
- [x] Solve the bug that generation will fail for session that longer than 60s.
|
||||
- [ ] Add API config on the UI.
|
||||
|
||||
## License
|
||||
|
||||
@@ -187,4 +164,8 @@ For support or inquiries, please open an issue on the GitHub repository or conta
|
||||
|
||||
- Email: me[at]jiang.jp
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://www.star-history.com/#DayuanJiang/next-ai-draw-io&type=date&legend=top-left)
|
||||
|
||||
---
|
||||
|
||||
336
app/about/page.tsx
Normal file
336
app/about/page.tsx
Normal file
@@ -0,0 +1,336 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { FaGithub } from "react-icons/fa";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "About - AI-Powered Diagram Generator | Next AI Draw.io",
|
||||
description: "Learn about Next AI Draw.io, a free AI-powered diagram creation tool. Create AWS architecture diagrams, flowcharts, and UML diagrams using Claude Sonnet and GPT-4. No login required.",
|
||||
keywords: ["about AI diagram generator", "diagram tool features", "how to create diagrams", "AI drawing tool capabilities", "draw.io integration"],
|
||||
};
|
||||
|
||||
export default function About() {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
{/* Navigation */}
|
||||
<header className="bg-white border-b border-gray-200">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Link href="/" className="text-xl font-bold text-gray-900 hover:text-gray-700">
|
||||
Next AI Draw.io
|
||||
</Link>
|
||||
<nav className="flex items-center gap-6 text-sm">
|
||||
<Link href="/" className="text-gray-600 hover:text-gray-900 transition-colors">
|
||||
Editor
|
||||
</Link>
|
||||
<Link href="/about" className="text-blue-600 font-semibold">
|
||||
About
|
||||
</Link>
|
||||
<a
|
||||
href="https://github.com/DayuanJiang/next-ai-draw-io"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-gray-600 hover:text-gray-900 transition-colors"
|
||||
aria-label="View on GitHub"
|
||||
>
|
||||
<FaGithub className="w-5 h-5" />
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
<article>
|
||||
{/* Hero Section */}
|
||||
<header className="mb-12">
|
||||
<h1 className="text-4xl font-bold text-gray-900 mb-4">
|
||||
AI-Powered Diagram Generator | Create Professional Diagrams Instantly
|
||||
</h1>
|
||||
<p className="text-xl text-gray-600">
|
||||
Free, open-source diagram creation tool powered by AI. No login required, no installation needed.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
{/* Introduction */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-gray-900 mb-4">What is Next AI Draw.io?</h2>
|
||||
<div className="prose prose-lg max-w-none text-gray-700">
|
||||
<p className="mb-4">
|
||||
<strong>Next AI Draw.io</strong> is a free, AI-powered diagram creation tool that integrates seamlessly with draw.io.
|
||||
Generate AWS architecture diagrams, flowcharts, UML diagrams, and technical documentation diagrams using natural language
|
||||
prompts. No login required, no installation needed—start creating professional diagrams instantly in your browser.
|
||||
</p>
|
||||
<p className="mb-4">
|
||||
Our intelligent diagram generator uses advanced AI models including <strong>Claude Sonnet</strong> and <strong>GPT-4</strong> to
|
||||
understand your requirements and automatically create properly structured diagrams with appropriate symbols, layouts, and connections.
|
||||
Simply describe what you need, upload reference images, or ask the AI to modify existing diagrams with our targeted XML editing feature.
|
||||
</p>
|
||||
<p>
|
||||
Whether you're a software architect designing system infrastructure, a developer documenting APIs, a business analyst creating
|
||||
process flows, or a student working on technical assignments, Next AI Draw.io makes diagram creation fast, accurate, and effortless.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Key Features */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-gray-900 mb-6">Key Features</h2>
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
<div className="bg-white p-6 rounded-lg border border-gray-200 shadow-sm">
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-3 flex items-center">
|
||||
<span className="text-blue-600 mr-2">✓</span>
|
||||
AI-Powered Diagram Creation
|
||||
</h3>
|
||||
<p className="text-gray-700">
|
||||
Generate diagrams from natural language descriptions using Claude Sonnet or GPT-4.
|
||||
Describe your diagram in plain English, and watch the AI create it with proper symbols,
|
||||
layouts, and connections automatically.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white p-6 rounded-lg border border-gray-200 shadow-sm">
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-3 flex items-center">
|
||||
<span className="text-blue-600 mr-2">✓</span>
|
||||
AWS Architecture Diagrams
|
||||
</h3>
|
||||
<p className="text-gray-700">
|
||||
Create professional cloud infrastructure diagrams with AWS-style icons and layouts.
|
||||
Perfect for designing EC2 instances, Lambda functions, S3 buckets, RDS databases, VPCs,
|
||||
and complete AWS solution architectures.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white p-6 rounded-lg border border-gray-200 shadow-sm">
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-3 flex items-center">
|
||||
<span className="text-blue-600 mr-2">✓</span>
|
||||
Image-Based Diagram Replication
|
||||
</h3>
|
||||
<p className="text-gray-700">
|
||||
Upload existing diagrams or sketches, and the AI will automatically recreate them in draw.io format.
|
||||
Modify uploaded images by describing the changes you want—the AI handles the rest.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white p-6 rounded-lg border border-gray-200 shadow-sm">
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-3 flex items-center">
|
||||
<span className="text-blue-600 mr-2">✓</span>
|
||||
Diagram History & Version Control
|
||||
</h3>
|
||||
<p className="text-gray-700">
|
||||
Access previous versions of your diagrams and restore any version from your session history.
|
||||
Never lose work—every AI modification is saved and can be undone with a single click.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white p-6 rounded-lg border border-gray-200 shadow-sm">
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-3 flex items-center">
|
||||
<span className="text-blue-600 mr-2">✓</span>
|
||||
Targeted XML Editing
|
||||
</h3>
|
||||
<p className="text-gray-700">
|
||||
Precise diagram modifications using intelligent XML manipulation. Unlike full diagram regeneration,
|
||||
targeted edits preserve your existing layout while making specific changes, ensuring consistent
|
||||
and predictable results.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-white p-6 rounded-lg border border-gray-200 shadow-sm">
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-3 flex items-center">
|
||||
<span className="text-blue-600 mr-2">✓</span>
|
||||
Multi-Provider AI Support
|
||||
</h3>
|
||||
<p className="text-gray-700">
|
||||
Choose between Claude Sonnet, GPT-4, and other leading AI models for optimal results.
|
||||
Each model has unique strengths—select the one that best fits your diagram complexity and style.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Use Cases */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-gray-900 mb-6">Popular Use Cases</h2>
|
||||
<div className="grid md:grid-cols-3 gap-6">
|
||||
<div className="bg-blue-50 p-6 rounded-lg border border-blue-200">
|
||||
<h3 className="text-xl font-semibold text-gray-900 mb-3">AWS Cloud Architecture</h3>
|
||||
<p className="text-gray-700 mb-4">
|
||||
Design scalable cloud infrastructure with EC2 instances, Lambda functions, S3 storage,
|
||||
RDS databases, and VPC networking. Perfect for solution architects, cloud engineers,
|
||||
and DevOps teams planning AWS deployments.
|
||||
</p>
|
||||
<p className="text-sm text-gray-600 italic">
|
||||
Example: "Create an AWS diagram with an Application Load Balancer, two EC2 instances
|
||||
in different availability zones, an RDS database, and an S3 bucket for static assets."
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-green-50 p-6 rounded-lg border border-green-200">
|
||||
<h3 className="text-xl font-semibold text-gray-900 mb-3">Flowcharts & Process Diagrams</h3>
|
||||
<p className="text-gray-700 mb-4">
|
||||
Create business process flows, decision trees, workflow diagrams, and algorithm flowcharts
|
||||
for documentation, presentations, and process optimization. Ideal for business analysts,
|
||||
project managers, and operations teams.
|
||||
</p>
|
||||
<p className="text-sm text-gray-600 italic">
|
||||
Example: "Draw a flowchart for user authentication: check if user exists, verify password,
|
||||
generate JWT token on success, show error message on failure."
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-purple-50 p-6 rounded-lg border border-purple-200">
|
||||
<h3 className="text-xl font-semibold text-gray-900 mb-3">System Design & UML Diagrams</h3>
|
||||
<p className="text-gray-700 mb-4">
|
||||
Generate system architecture diagrams, class diagrams, sequence diagrams, and
|
||||
entity-relationship diagrams for software projects. Essential for software engineers,
|
||||
system designers, and technical documentation.
|
||||
</p>
|
||||
<p className="text-sm text-gray-600 italic">
|
||||
Example: "Create a class diagram for an e-commerce system with User, Product, Order,
|
||||
and Payment classes showing their relationships and key methods."
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* How It Works */}
|
||||
<section className="mb-12 bg-white p-8 rounded-lg border border-gray-200">
|
||||
<h2 className="text-2xl font-semibold text-gray-900 mb-6">How to Use Next AI Draw.io</h2>
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 w-10 h-10 bg-blue-600 text-white rounded-full flex items-center justify-center font-bold mr-4">
|
||||
1
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Open the Editor</h3>
|
||||
<p className="text-gray-700">
|
||||
Navigate to the main page and you'll see the draw.io editor with an AI chat panel on the right.
|
||||
No account creation or login required—start immediately.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 w-10 h-10 bg-blue-600 text-white rounded-full flex items-center justify-center font-bold mr-4">
|
||||
2
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Describe Your Diagram</h3>
|
||||
<p className="text-gray-700">
|
||||
Type your diagram request in natural language. Be as detailed or as general as you like.
|
||||
You can also upload reference images for the AI to analyze and replicate.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 w-10 h-10 bg-blue-600 text-white rounded-full flex items-center justify-center font-bold mr-4">
|
||||
3
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">AI Generates Your Diagram</h3>
|
||||
<p className="text-gray-700">
|
||||
The AI processes your request and automatically creates your diagram in seconds.
|
||||
Watch as it appears in the editor with proper symbols, layouts, and connections.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 w-10 h-10 bg-blue-600 text-white rounded-full flex items-center justify-center font-bold mr-4">
|
||||
4
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Refine and Export</h3>
|
||||
<p className="text-gray-700">
|
||||
Request modifications using the chat, manually edit in draw.io, or export to PNG, SVG,
|
||||
or XML format. Access diagram history to restore previous versions anytime.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Benefits */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-gray-900 mb-6">Why Choose Next AI Draw.io?</h2>
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 text-blue-600 text-2xl mr-3">⚡</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Save Time</h3>
|
||||
<p className="text-gray-700">
|
||||
Create complex diagrams in seconds instead of hours. No more dragging, aligning,
|
||||
or searching for the right symbols—AI handles it all.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 text-blue-600 text-2xl mr-3">🎯</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Precision Editing</h3>
|
||||
<p className="text-gray-700">
|
||||
Targeted XML editing ensures changes are precise and predictable, unlike tools
|
||||
that regenerate entire diagrams and lose your layout.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 text-blue-600 text-2xl mr-3">🆓</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Completely Free</h3>
|
||||
<p className="text-gray-700">
|
||||
No subscriptions, no usage limits, no hidden costs. Open-source and free forever.
|
||||
Use it for personal projects, work, or education.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 text-blue-600 text-2xl mr-3">🔒</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">Privacy First</h3>
|
||||
<p className="text-gray-700">
|
||||
No account required means your diagrams stay private. Work on sensitive
|
||||
architecture designs without worrying about data storage or privacy policies.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA Section */}
|
||||
<section className="bg-blue-600 text-white p-8 rounded-lg text-center">
|
||||
<h2 className="text-3xl font-bold mb-4">Ready to Create Your First AI Diagram?</h2>
|
||||
<p className="text-xl mb-6">
|
||||
Start generating professional diagrams in seconds. No signup required.
|
||||
</p>
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-block bg-white text-blue-600 px-8 py-3 rounded-lg font-semibold hover:bg-gray-100 transition-colors"
|
||||
>
|
||||
Open Editor
|
||||
</Link>
|
||||
</section>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="bg-white border-t border-gray-200 mt-16">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<div className="text-center text-gray-600 text-sm">
|
||||
<p className="mb-2">
|
||||
Next AI Draw.io - Free AI-Powered Diagram Generator
|
||||
</p>
|
||||
<p>
|
||||
Perfect for developers, architects, students, and business analysts.
|
||||
Open source. No login required.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,13 +1,55 @@
|
||||
import { streamText, convertToModelMessages } from 'ai';
|
||||
import { streamText, convertToModelMessages, createUIMessageStream, createUIMessageStreamResponse } from 'ai';
|
||||
import { getAIModel } from '@/lib/ai-providers';
|
||||
import { findCachedResponse } from '@/lib/cached-responses';
|
||||
import { z } from "zod";
|
||||
|
||||
export const maxDuration = 60;
|
||||
export const maxDuration = 300;
|
||||
|
||||
// Helper function to check if diagram is minimal/empty
|
||||
function isMinimalDiagram(xml: string): boolean {
|
||||
const stripped = xml.replace(/\s/g, '');
|
||||
return !stripped.includes('id="2"');
|
||||
}
|
||||
|
||||
// Helper function to create cached stream response
|
||||
function createCachedStreamResponse(xml: string): Response {
|
||||
const toolCallId = `cached-${Date.now()}`;
|
||||
|
||||
const stream = createUIMessageStream({
|
||||
execute: async ({ writer }) => {
|
||||
writer.write({ type: 'start' });
|
||||
writer.write({ type: 'tool-input-start', toolCallId, toolName: 'display_diagram' });
|
||||
writer.write({ type: 'tool-input-delta', toolCallId, inputTextDelta: xml });
|
||||
writer.write({ type: 'tool-input-available', toolCallId, toolName: 'display_diagram', input: { xml } });
|
||||
writer.write({ type: 'finish' });
|
||||
},
|
||||
});
|
||||
|
||||
return createUIMessageStreamResponse({ stream });
|
||||
}
|
||||
|
||||
export async function POST(req: Request) {
|
||||
try {
|
||||
const { messages, xml } = await req.json();
|
||||
|
||||
// === CACHE CHECK START ===
|
||||
const isFirstMessage = messages.length === 1;
|
||||
const isEmptyDiagram = !xml || xml.trim() === '' || isMinimalDiagram(xml);
|
||||
|
||||
if (isFirstMessage && isEmptyDiagram) {
|
||||
const lastMessage = messages[0];
|
||||
const textPart = lastMessage.parts?.find((p: any) => p.type === 'text');
|
||||
const filePart = lastMessage.parts?.find((p: any) => p.type === 'file');
|
||||
|
||||
const cached = findCachedResponse(textPart?.text || '', !!filePart);
|
||||
|
||||
if (cached) {
|
||||
console.log('[Cache] Returning cached response for:', textPart?.text);
|
||||
return createCachedStreamResponse(cached.xml);
|
||||
}
|
||||
}
|
||||
// === CACHE CHECK END ===
|
||||
|
||||
const systemMessage = `
|
||||
You are an expert diagram creation assistant specializing in draw.io XML generation.
|
||||
Your primary function is crafting clear, well-organized visual diagrams through precise XML specifications.
|
||||
@@ -90,7 +132,30 @@ ${lastMessageText}
|
||||
|
||||
// Convert UIMessages to ModelMessages and add system message
|
||||
const modelMessages = convertToModelMessages(messages);
|
||||
let enhancedMessages = [...modelMessages];
|
||||
|
||||
// Log messages with empty content for debugging (helps identify root cause)
|
||||
const emptyMessages = modelMessages.filter((msg: any) =>
|
||||
!msg.content || !Array.isArray(msg.content) || msg.content.length === 0
|
||||
);
|
||||
if (emptyMessages.length > 0) {
|
||||
console.warn('[Chat API] Messages with empty content detected:',
|
||||
JSON.stringify(emptyMessages.map((m: any) => ({ role: m.role, contentLength: m.content?.length })))
|
||||
);
|
||||
console.warn('[Chat API] Original UI messages structure:',
|
||||
JSON.stringify(messages.map((m: any) => ({
|
||||
id: m.id,
|
||||
role: m.role,
|
||||
partsCount: m.parts?.length,
|
||||
partTypes: m.parts?.map((p: any) => p.type)
|
||||
})))
|
||||
);
|
||||
}
|
||||
|
||||
// Filter out messages with empty content arrays (Bedrock API rejects these)
|
||||
// This is a safety measure - ideally convertToModelMessages should handle all cases
|
||||
let enhancedMessages = modelMessages.filter((msg: any) =>
|
||||
msg.content && Array.isArray(msg.content) && msg.content.length > 0
|
||||
);
|
||||
|
||||
// Update the last message with formatted content if it's a user message
|
||||
if (enhancedMessages.length >= 1) {
|
||||
@@ -117,16 +182,49 @@ ${lastMessageText}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Enhanced messages:", enhancedMessages);
|
||||
// Add cache point to the last assistant message in conversation history
|
||||
// This caches the entire conversation prefix for subsequent requests
|
||||
// Strategy: system (cached) + history with last assistant (cached) + new user message
|
||||
if (enhancedMessages.length >= 2) {
|
||||
// Find the last assistant message (should be second-to-last, before current user message)
|
||||
for (let i = enhancedMessages.length - 2; i >= 0; i--) {
|
||||
if (enhancedMessages[i].role === 'assistant') {
|
||||
enhancedMessages[i] = {
|
||||
...enhancedMessages[i],
|
||||
providerOptions: {
|
||||
bedrock: { cachePoint: { type: 'default' } },
|
||||
},
|
||||
};
|
||||
break; // Only cache the last assistant message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get AI model from environment configuration
|
||||
const { model, providerOptions } = getAIModel();
|
||||
const { model, providerOptions, headers } = getAIModel();
|
||||
|
||||
// System message with cache point for Bedrock (requires 1024+ tokens)
|
||||
const systemMessageWithCache = {
|
||||
role: 'system' as const,
|
||||
content: systemMessage,
|
||||
providerOptions: {
|
||||
bedrock: { cachePoint: { type: 'default' } },
|
||||
},
|
||||
};
|
||||
|
||||
const result = streamText({
|
||||
model,
|
||||
system: systemMessage,
|
||||
messages: enhancedMessages,
|
||||
messages: [systemMessageWithCache, ...enhancedMessages],
|
||||
...(providerOptions && { providerOptions }),
|
||||
...(headers && { headers }),
|
||||
onFinish: ({ usage, providerMetadata }) => {
|
||||
console.log('[Cache] Usage:', JSON.stringify({
|
||||
inputTokens: usage?.inputTokens,
|
||||
outputTokens: usage?.outputTokens,
|
||||
cachedInputTokens: usage?.cachedInputTokens,
|
||||
}, null, 2));
|
||||
console.log('[Cache] Provider metadata:', JSON.stringify(providerMetadata, null, 2));
|
||||
},
|
||||
tools: {
|
||||
// Client-side tool that will be executed on the client
|
||||
display_diagram: {
|
||||
@@ -141,6 +239,7 @@ ${lastMessageText}
|
||||
</mxCell>
|
||||
</root>
|
||||
- Note that when you need to generate diagram about aws architecture, use **AWS 2025 icons**.
|
||||
- If you are asked to generate animated connectors, make sure to include "flowAnimation=1" in the style of the connector elements.
|
||||
`,
|
||||
inputSchema: z.object({
|
||||
xml: z.string().describe("XML string to be displayed on draw.io")
|
||||
|
||||
@@ -16,8 +16,49 @@ const geistMono = Geist_Mono({
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Next-AI-Drawio",
|
||||
description: "An AI-powered drawing tool that integrates with draw.io",
|
||||
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.",
|
||||
keywords: ["AI diagram generator", "AWS architecture", "flowchart creator", "draw.io", "AI drawing tool", "technical diagrams", "diagram automation", "free diagram generator", "online diagram maker"],
|
||||
authors: [{ name: "Next AI Draw.io" }],
|
||||
creator: "Next AI Draw.io",
|
||||
publisher: "Next AI Draw.io",
|
||||
metadataBase: new URL("https://next-ai-drawio.jiang.jp"),
|
||||
openGraph: {
|
||||
title: "Next AI Draw.io - AI Diagram Generator",
|
||||
description: "Create professional diagrams with AI assistance. Supports AWS architecture, flowcharts, and more.",
|
||||
type: "website",
|
||||
url: "https://next-ai-drawio.jiang.jp",
|
||||
siteName: "Next AI Draw.io",
|
||||
locale: "en_US",
|
||||
images: [
|
||||
{
|
||||
url: "/architecture.png",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: "Next AI Draw.io - AI-powered diagram creation tool",
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "Next AI Draw.io - AI Diagram Generator",
|
||||
description: "Create professional diagrams with AI assistance. Free, no login required.",
|
||||
images: ["/architecture.png"],
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: {
|
||||
index: true,
|
||||
follow: true,
|
||||
"max-video-preview": -1,
|
||||
"max-image-preview": "large",
|
||||
"max-snippet": -1,
|
||||
},
|
||||
},
|
||||
icons: {
|
||||
icon: "/favicon.ico",
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
@@ -25,8 +66,29 @@ export default function RootLayout({
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
const jsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'SoftwareApplication',
|
||||
name: 'Next AI Draw.io',
|
||||
applicationCategory: 'DesignApplication',
|
||||
operatingSystem: 'Web Browser',
|
||||
description: 'AI-powered diagram generator with targeted XML editing capabilities that integrates with draw.io for creating AWS architecture diagrams, flowcharts, and technical diagrams. Features diagram history, multi-provider AI support, and real-time collaboration.',
|
||||
url: 'https://next-ai-drawio.jiang.jp',
|
||||
offers: {
|
||||
'@type': 'Offer',
|
||||
price: '0',
|
||||
priceCurrency: 'USD',
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
||||
/>
|
||||
</head>
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
|
||||
25
app/page.tsx
25
app/page.tsx
@@ -40,20 +40,19 @@ export default function Home() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (isMobile) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-screen bg-gray-100">
|
||||
<div className="text-center p-8">
|
||||
<h1 className="text-2xl font-semibold text-gray-800">
|
||||
Please open this application on a desktop or laptop
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-screen bg-gray-100">
|
||||
<div className="flex h-screen bg-gray-100 relative">
|
||||
{/* Mobile warning overlay - keeps components mounted */}
|
||||
{isMobile && (
|
||||
<div className="absolute inset-0 z-50 flex items-center justify-center bg-gray-100">
|
||||
<div className="text-center p-8">
|
||||
<h1 className="text-2xl font-semibold text-gray-800">
|
||||
Please open this application on a desktop or laptop
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={`${isChatVisible ? 'w-2/3' : 'w-full'} p-1 h-full relative transition-all duration-300 ease-in-out`}>
|
||||
<DrawIoEmbed
|
||||
ref={drawioRef}
|
||||
|
||||
12
app/robots.ts
Normal file
12
app/robots.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { MetadataRoute } from 'next'
|
||||
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
return {
|
||||
rules: {
|
||||
userAgent: '*',
|
||||
allow: '/',
|
||||
disallow: '/api/',
|
||||
},
|
||||
sitemap: 'https://next-ai-drawio.jiang.jp/sitemap.xml',
|
||||
}
|
||||
}
|
||||
18
app/sitemap.ts
Normal file
18
app/sitemap.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { MetadataRoute } from 'next'
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
return [
|
||||
{
|
||||
url: 'https://next-ai-drawio.jiang.jp',
|
||||
lastModified: new Date(),
|
||||
changeFrequency: 'weekly',
|
||||
priority: 1,
|
||||
},
|
||||
{
|
||||
url: 'https://next-ai-drawio.jiang.jp/about',
|
||||
lastModified: new Date(),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.8,
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -50,25 +50,34 @@ export default function ExamplePanel({
|
||||
{" "}
|
||||
You can also upload images to use as references.
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 mb-2">Try these examples:</p>
|
||||
<p className="text-sm text-gray-500 mb-2">
|
||||
Try these examples{" "}
|
||||
<span className="text-xs text-gray-400">(cached for instant response)</span>:
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-5">
|
||||
<button
|
||||
className="text-xs bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium py-1 px-2 rounded"
|
||||
onClick={() => setInput("Give me a **animated connector** diagram of transformer's architecture")}
|
||||
>
|
||||
Draw diagram with Animated Connectors
|
||||
</button>
|
||||
<button
|
||||
className="text-xs bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium py-1 px-2 rounded"
|
||||
onClick={handleReplicateArchitecture}
|
||||
>
|
||||
Create this diagram in aws style
|
||||
Create AWS architecture
|
||||
</button>
|
||||
<button
|
||||
className="text-xs bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium py-1 px-2 rounded"
|
||||
onClick={handleReplicateFlowchart}
|
||||
>
|
||||
Replicate this flowchart
|
||||
Replicate flowchart
|
||||
</button>
|
||||
<button
|
||||
className="text-xs bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium py-1 px-2 rounded"
|
||||
onClick={() => setInput("Draw a cat for me")}
|
||||
>
|
||||
Draw a cat for me
|
||||
Draw a cat
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import type React from "react";
|
||||
import { useRef, useEffect, useState, useCallback } from "react";
|
||||
import Image from "next/image";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import ExamplePanel from "./chat-example-panel";
|
||||
import { UIMessage } from "ai";
|
||||
import { convertToLegalXml, replaceNodes } from "@/lib/utils";
|
||||
import { Copy, Check, X } from "lucide-react";
|
||||
|
||||
import { useDiagram } from "@/contexts/diagram-context";
|
||||
|
||||
const getMessageTextContent = (message: UIMessage): string => {
|
||||
if (!message.parts) return "";
|
||||
return message.parts
|
||||
.filter((part: any) => part.type === "text")
|
||||
.map((part: any) => part.text)
|
||||
.join("\n");
|
||||
};
|
||||
|
||||
interface ChatMessageDisplayProps {
|
||||
messages: UIMessage[];
|
||||
error?: Error | null;
|
||||
@@ -30,6 +38,21 @@ export function ChatMessageDisplay({
|
||||
const [expandedTools, setExpandedTools] = useState<Record<string, boolean>>(
|
||||
{}
|
||||
);
|
||||
const [copiedMessageId, setCopiedMessageId] = useState<string | null>(null);
|
||||
const [copyFailedMessageId, setCopyFailedMessageId] = useState<string | null>(null);
|
||||
|
||||
const copyMessageToClipboard = async (messageId: string, text: string) => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
setCopiedMessageId(messageId);
|
||||
setTimeout(() => setCopiedMessageId(null), 2000);
|
||||
} catch (err) {
|
||||
console.error("Failed to copy message:", err);
|
||||
setCopyFailedMessageId(messageId);
|
||||
setTimeout(() => setCopyFailedMessageId(null), 2000);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDisplayChart = useCallback(
|
||||
(xml: string) => {
|
||||
const currentXml = xml || "";
|
||||
@@ -137,16 +160,16 @@ export function ChatMessageDisplay({
|
||||
{output || (toolName === "display_diagram"
|
||||
? "Diagram generated"
|
||||
: toolName === "edit_diagram"
|
||||
? "Diagram edited"
|
||||
: "Tool executed")}
|
||||
? "Diagram edited"
|
||||
: "Tool executed")}
|
||||
</div>
|
||||
) : state === "output-error" ? (
|
||||
<div className="text-red-600">
|
||||
{output || (toolName === "display_diagram"
|
||||
? "Error generating diagram"
|
||||
: toolName === "edit_diagram"
|
||||
? "Error editing diagram"
|
||||
: "Tool error")}
|
||||
? "Error editing diagram"
|
||||
: "Tool error")}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
@@ -160,51 +183,66 @@ export function ChatMessageDisplay({
|
||||
{messages.length === 0 ? (
|
||||
<ExamplePanel setInput={setInput} setFiles={setFiles} />
|
||||
) : (
|
||||
messages.map((message) => (
|
||||
<div
|
||||
key={message.id}
|
||||
className={`mb-4 ${
|
||||
message.role === "user" ? "text-right" : "text-left"
|
||||
}`}
|
||||
>
|
||||
messages.map((message) => {
|
||||
const userMessageText = message.role === "user" ? getMessageTextContent(message) : "";
|
||||
return (
|
||||
<div
|
||||
className={`inline-block px-4 py-2 whitespace-pre-wrap text-sm rounded-lg max-w-[85%] break-words ${
|
||||
message.role === "user"
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "bg-muted text-muted-foreground"
|
||||
}`}
|
||||
key={message.id}
|
||||
className={`mb-4 flex ${message.role === "user" ? "justify-end" : "justify-start"}`}
|
||||
>
|
||||
{message.parts?.map((part: any, index: number) => {
|
||||
switch (part.type) {
|
||||
case "text":
|
||||
return (
|
||||
<div key={index}>{part.text}</div>
|
||||
);
|
||||
case "file":
|
||||
return (
|
||||
<div key={index} className="mt-2">
|
||||
<Image
|
||||
src={part.url}
|
||||
width={200}
|
||||
height={200}
|
||||
alt={`file-${index}`}
|
||||
className="rounded-md border"
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
if (part.type?.startsWith("tool-")) {
|
||||
return renderToolPart(part);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
})}
|
||||
{message.role === "user" && userMessageText && (
|
||||
<button
|
||||
onClick={() => copyMessageToClipboard(message.id, userMessageText)}
|
||||
className="p-1 text-gray-400 hover:text-gray-600 transition-colors self-center mr-1"
|
||||
title={copiedMessageId === message.id ? "Copied!" : copyFailedMessageId === message.id ? "Failed to copy" : "Copy message"}
|
||||
>
|
||||
{copiedMessageId === message.id ? (
|
||||
<Check className="h-3.5 w-3.5 text-green-500" />
|
||||
) : copyFailedMessageId === message.id ? (
|
||||
<X className="h-3.5 w-3.5 text-red-500" />
|
||||
) : (
|
||||
<Copy className="h-3.5 w-3.5" />
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
<div
|
||||
className={`px-4 py-2 whitespace-pre-wrap text-sm rounded-lg max-w-[85%] break-words ${message.role === "user"
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "bg-muted text-muted-foreground"
|
||||
}`}
|
||||
>
|
||||
{message.parts?.map((part: any, index: number) => {
|
||||
switch (part.type) {
|
||||
case "text":
|
||||
return (
|
||||
<div key={index}>{part.text}</div>
|
||||
);
|
||||
case "file":
|
||||
return (
|
||||
<div key={index} className="mt-2">
|
||||
<Image
|
||||
src={part.url}
|
||||
width={200}
|
||||
height={200}
|
||||
alt={`Uploaded diagram or image for AI analysis`}
|
||||
className="rounded-md border"
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
if (part.type?.startsWith("tool-")) {
|
||||
return renderToolPart(part);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
);
|
||||
})
|
||||
)}
|
||||
{error && (
|
||||
<div className="text-red-500 text-sm mt-2">
|
||||
|
||||
@@ -4,6 +4,7 @@ import type React from "react";
|
||||
import { useRef, useEffect, useState } from "react";
|
||||
import { FaGithub } from "react-icons/fa";
|
||||
import { PanelRightClose, PanelRightOpen } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
import {
|
||||
Card,
|
||||
@@ -226,7 +227,12 @@ Please retry with an adjusted search pattern or use display_diagram if retries a
|
||||
return (
|
||||
<Card className="h-full flex flex-col rounded-none py-0 gap-0">
|
||||
<CardHeader className="p-4 flex flex-row justify-between items-center">
|
||||
<CardTitle>Next-AI-Drawio</CardTitle>
|
||||
<div className="flex items-center gap-3">
|
||||
<CardTitle>Next-AI-Drawio</CardTitle>
|
||||
<Link href="/about" className="text-sm text-gray-600 hover:text-gray-900 transition-colors">
|
||||
About
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<ButtonWithTooltip
|
||||
tooltipContent="Hide chat panel (Ctrl+B)"
|
||||
|
||||
@@ -79,7 +79,7 @@ export function FilePreviewList({ files, onRemoveFile }: FilePreviewListProps) {
|
||||
<div className="relative w-auto h-auto max-w-[90vw] max-h-[90vh]">
|
||||
<Image
|
||||
src={selectedImage}
|
||||
alt="Preview"
|
||||
alt="Full size preview of uploaded diagram or image"
|
||||
width={1200}
|
||||
height={900}
|
||||
className="object-contain max-w-full max-h-[90vh] w-auto h-auto"
|
||||
|
||||
11
env.example
11
env.example
@@ -1,6 +1,6 @@
|
||||
# AI Provider Configuration
|
||||
# AI_PROVIDER: Which provider to use
|
||||
# Options: bedrock, openai, anthropic, google, azure, ollama, openrouter
|
||||
# Options: bedrock, openai, anthropic, google, azure, ollama, openrouter, deepseek
|
||||
# Default: bedrock
|
||||
AI_PROVIDER=bedrock
|
||||
|
||||
@@ -14,21 +14,30 @@ AI_MODEL=global.anthropic.claude-sonnet-4-5-20250929-v1:0
|
||||
|
||||
# OpenAI Configuration
|
||||
# OPENAI_API_KEY=sk-...
|
||||
# OPENAI_BASE_URL=https://api.openai.com/v1 # Optional: Custom OpenAI-compatible endpoint
|
||||
# OPENAI_ORGANIZATION=org-... # Optional
|
||||
# OPENAI_PROJECT=proj_... # Optional
|
||||
|
||||
# Anthropic (Direct) Configuration
|
||||
# ANTHROPIC_API_KEY=sk-ant-...
|
||||
# ANTHROPIC_BASE_URL=https://your-custom-anthropic/v1
|
||||
|
||||
# Google Generative AI Configuration
|
||||
# GOOGLE_GENERATIVE_AI_API_KEY=...
|
||||
# GOOGLE_BASE_URL=https://generativelanguage.googleapis.com/v1beta # Optional: Custom endpoint
|
||||
|
||||
# Azure OpenAI Configuration
|
||||
# AZURE_RESOURCE_NAME=your-resource-name
|
||||
# AZURE_API_KEY=...
|
||||
# AZURE_BASE_URL=https://your-resource.openai.azure.com # Optional: Custom endpoint (overrides resourceName)
|
||||
|
||||
# Ollama (Local) Configuration
|
||||
# OLLAMA_BASE_URL=http://localhost:11434/api # Optional, defaults to localhost
|
||||
|
||||
# OpenRouter Configuration
|
||||
# OPENROUTER_API_KEY=sk-or-v1-...
|
||||
# OPENROUTER_BASE_URL=https://openrouter.ai/api/v1 # Optional: Custom endpoint
|
||||
|
||||
# DeepSeek Configuration
|
||||
# DEEPSEEK_API_KEY=sk-...
|
||||
# DEEPSEEK_BASE_URL=https://api.deepseek.com/v1 # Optional: Custom endpoint
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { bedrock } from '@ai-sdk/amazon-bedrock';
|
||||
import { openai } from '@ai-sdk/openai';
|
||||
import { anthropic } from '@ai-sdk/anthropic';
|
||||
import { google } from '@ai-sdk/google';
|
||||
import { azure } from '@ai-sdk/azure';
|
||||
import { ollama } from 'ollama-ai-provider-v2';
|
||||
import { openai, createOpenAI } from '@ai-sdk/openai';
|
||||
import { createAnthropic } from '@ai-sdk/anthropic';
|
||||
import { google, createGoogleGenerativeAI } from '@ai-sdk/google';
|
||||
import { azure, createAzure } from '@ai-sdk/azure';
|
||||
import { ollama, createOllama } from 'ollama-ai-provider-v2';
|
||||
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
|
||||
import { deepseek, createDeepSeek } from '@ai-sdk/deepseek';
|
||||
|
||||
export type ProviderName =
|
||||
| 'bedrock'
|
||||
@@ -13,20 +14,25 @@ export type ProviderName =
|
||||
| 'google'
|
||||
| 'azure'
|
||||
| 'ollama'
|
||||
| 'openrouter';
|
||||
| 'openrouter'
|
||||
| 'deepseek';
|
||||
|
||||
interface ModelConfig {
|
||||
model: any;
|
||||
providerOptions?: any;
|
||||
headers?: Record<string, string>;
|
||||
}
|
||||
|
||||
// Anthropic beta headers for fine-grained tool streaming
|
||||
const ANTHROPIC_BETA_OPTIONS = {
|
||||
anthropic: {
|
||||
additionalModelRequestFields: {
|
||||
anthropic_beta: ['fine-grained-tool-streaming-2025-05-14']
|
||||
}
|
||||
}
|
||||
// Bedrock provider options for Anthropic beta features
|
||||
const BEDROCK_ANTHROPIC_BETA = {
|
||||
bedrock: {
|
||||
anthropicBeta: ['fine-grained-tool-streaming-2025-05-14'],
|
||||
},
|
||||
};
|
||||
|
||||
// Direct Anthropic API headers for beta features
|
||||
const ANTHROPIC_BETA_HEADERS = {
|
||||
'anthropic-beta': 'fine-grained-tool-streaming-2025-05-14',
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -41,6 +47,7 @@ function validateProviderCredentials(provider: ProviderName): void {
|
||||
azure: 'AZURE_API_KEY',
|
||||
ollama: null, // No credentials needed for local Ollama
|
||||
openrouter: 'OPENROUTER_API_KEY',
|
||||
deepseek: 'DEEPSEEK_API_KEY',
|
||||
};
|
||||
|
||||
const requiredVar = requiredEnvVars[provider];
|
||||
@@ -56,17 +63,20 @@ function validateProviderCredentials(provider: ProviderName): void {
|
||||
* Get the AI model based on environment variables
|
||||
*
|
||||
* Environment variables:
|
||||
* - AI_PROVIDER: The provider to use (bedrock, openai, anthropic, google, azure, ollama, openrouter)
|
||||
* - AI_PROVIDER: The provider to use (bedrock, openai, anthropic, google, azure, ollama, openrouter, deepseek)
|
||||
* - AI_MODEL: The model ID/name for the selected provider
|
||||
*
|
||||
* Provider-specific env vars:
|
||||
* - OPENAI_API_KEY: OpenAI API key
|
||||
* - OPENAI_BASE_URL: Custom OpenAI-compatible endpoint (optional)
|
||||
* - ANTHROPIC_API_KEY: Anthropic API key
|
||||
* - GOOGLE_GENERATIVE_AI_API_KEY: Google API key
|
||||
* - AZURE_RESOURCE_NAME, AZURE_API_KEY: Azure OpenAI credentials
|
||||
* - AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY: AWS Bedrock credentials
|
||||
* - OLLAMA_BASE_URL: Ollama server URL (optional, defaults to http://localhost:11434)
|
||||
* - OPENROUTER_API_KEY: OpenRouter API key
|
||||
* - DEEPSEEK_API_KEY: DeepSeek API key
|
||||
* - DEEPSEEK_BASE_URL: DeepSeek endpoint (optional)
|
||||
*/
|
||||
export function getAIModel(): ModelConfig {
|
||||
const provider = (process.env.AI_PROVIDER || 'bedrock') as ProviderName;
|
||||
@@ -86,55 +96,105 @@ export function getAIModel(): ModelConfig {
|
||||
|
||||
let model: any;
|
||||
let providerOptions: any = undefined;
|
||||
let headers: Record<string, string> | undefined = undefined;
|
||||
|
||||
switch (provider) {
|
||||
case 'bedrock':
|
||||
model = bedrock(modelId);
|
||||
// Add Anthropic beta headers if using Claude models via Bedrock
|
||||
// Add Anthropic beta options if using Claude models via Bedrock
|
||||
if (modelId.includes('anthropic.claude')) {
|
||||
providerOptions = ANTHROPIC_BETA_OPTIONS;
|
||||
providerOptions = BEDROCK_ANTHROPIC_BETA;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'openai':
|
||||
model = openai(modelId);
|
||||
if (process.env.OPENAI_BASE_URL) {
|
||||
const customOpenAI = createOpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
baseURL: process.env.OPENAI_BASE_URL,
|
||||
});
|
||||
model = customOpenAI.chat(modelId);
|
||||
} else {
|
||||
model = openai(modelId);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'anthropic':
|
||||
model = anthropic(modelId);
|
||||
const customProvider = createAnthropic({
|
||||
apiKey: process.env.ANTHROPIC_API_KEY,
|
||||
baseURL: process.env.ANTHROPIC_BASE_URL || 'https://api.anthropic.com/v1',
|
||||
headers: ANTHROPIC_BETA_HEADERS,
|
||||
});
|
||||
model = customProvider(modelId);
|
||||
// Add beta headers for fine-grained tool streaming
|
||||
providerOptions = ANTHROPIC_BETA_OPTIONS;
|
||||
headers = ANTHROPIC_BETA_HEADERS;
|
||||
break;
|
||||
|
||||
case 'google':
|
||||
model = google(modelId);
|
||||
if (process.env.GOOGLE_BASE_URL) {
|
||||
const customGoogle = createGoogleGenerativeAI({
|
||||
apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
|
||||
baseURL: process.env.GOOGLE_BASE_URL,
|
||||
});
|
||||
model = customGoogle(modelId);
|
||||
} else {
|
||||
model = google(modelId);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'azure':
|
||||
model = azure(modelId);
|
||||
if (process.env.AZURE_BASE_URL) {
|
||||
const customAzure = createAzure({
|
||||
apiKey: process.env.AZURE_API_KEY,
|
||||
baseURL: process.env.AZURE_BASE_URL,
|
||||
});
|
||||
model = customAzure(modelId);
|
||||
} else {
|
||||
model = azure(modelId);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ollama':
|
||||
model = ollama(modelId);
|
||||
if (process.env.OLLAMA_BASE_URL) {
|
||||
const customOllama = createOllama({
|
||||
baseURL: process.env.OLLAMA_BASE_URL,
|
||||
});
|
||||
model = customOllama(modelId);
|
||||
} else {
|
||||
model = ollama(modelId);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'openrouter':
|
||||
const openrouter = createOpenRouter({
|
||||
apiKey: process.env.OPENROUTER_API_KEY,
|
||||
...(process.env.OPENROUTER_BASE_URL && { baseURL: process.env.OPENROUTER_BASE_URL }),
|
||||
});
|
||||
model = openrouter(modelId);
|
||||
break;
|
||||
|
||||
case 'deepseek':
|
||||
if (process.env.DEEPSEEK_BASE_URL) {
|
||||
const customDeepSeek = createDeepSeek({
|
||||
apiKey: process.env.DEEPSEEK_API_KEY,
|
||||
baseURL: process.env.DEEPSEEK_BASE_URL,
|
||||
});
|
||||
model = customDeepSeek(modelId);
|
||||
} else {
|
||||
model = deepseek(modelId);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown AI provider: ${provider}. Supported providers: bedrock, openai, anthropic, google, azure, ollama, openrouter`
|
||||
`Unknown AI provider: ${provider}. Supported providers: bedrock, openai, anthropic, google, azure, ollama, openrouter, deepseek`
|
||||
);
|
||||
}
|
||||
|
||||
// Log if provider options are being applied
|
||||
if (providerOptions) {
|
||||
console.log('[AI Provider] Applying provider-specific options');
|
||||
// Log if provider options or headers are being applied
|
||||
if (providerOptions || headers) {
|
||||
console.log('[AI Provider] Applying provider-specific options/headers');
|
||||
}
|
||||
|
||||
return { model, providerOptions };
|
||||
return { model, providerOptions, headers };
|
||||
}
|
||||
|
||||
557
lib/cached-responses.ts
Normal file
557
lib/cached-responses.ts
Normal file
@@ -0,0 +1,557 @@
|
||||
export interface CachedResponse {
|
||||
promptText: string;
|
||||
hasImage: boolean;
|
||||
xml: string;
|
||||
}
|
||||
|
||||
export const CACHED_EXAMPLE_RESPONSES: CachedResponse[] = [
|
||||
{
|
||||
promptText: "Give me a **animated connector** diagram of transformer's architecture",
|
||||
hasImage: false,
|
||||
xml: `<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
|
||||
<!-- Title -->
|
||||
<mxCell id="title" value="Transformer Architecture" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=20;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="300" y="20" width="250" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Input Embedding (Left - Encoder Side) -->
|
||||
<mxCell id="input_embed" value="Input Embedding" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="480" width="120" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Positional Encoding (Left) -->
|
||||
<mxCell id="pos_enc_left" value="Positional Encoding" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="420" width="120" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Encoder Stack -->
|
||||
<mxCell id="encoder_box" value="ENCODER" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;verticalAlign=top;fontSize=12;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="60" y="180" width="160" height="220" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Multi-Head Attention (Encoder) -->
|
||||
<mxCell id="mha_enc" value="Multi-Head
Attention" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="330" width="120" height="50" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Add & Norm 1 (Encoder) -->
|
||||
<mxCell id="add_norm1_enc" value="Add & Norm" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="280" width="120" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Feed Forward (Encoder) -->
|
||||
<mxCell id="ff_enc" value="Feed Forward" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="240" width="120" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Add & Norm 2 (Encoder) -->
|
||||
<mxCell id="add_norm2_enc" value="Add & Norm" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="200" width="120" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Nx label for encoder -->
|
||||
<mxCell id="nx_enc" value="Nx" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=11;fontStyle=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="30" y="275" width="30" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Output Embedding (Right - Decoder Side) -->
|
||||
<mxCell id="output_embed" value="Output Embedding" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="650" y="480" width="120" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Positional Encoding (Right) -->
|
||||
<mxCell id="pos_enc_right" value="Positional Encoding" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="650" y="420" width="120" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Decoder Stack -->
|
||||
<mxCell id="decoder_box" value="DECODER" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;verticalAlign=top;fontSize=12;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="630" y="140" width="160" height="260" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Masked Multi-Head Attention (Decoder) -->
|
||||
<mxCell id="masked_mha_dec" value="Masked Multi-Head
Attention" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="650" y="340" width="120" height="50" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Add & Norm 1 (Decoder) -->
|
||||
<mxCell id="add_norm1_dec" value="Add & Norm" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="650" y="290" width="120" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Multi-Head Attention (Decoder - Cross Attention) -->
|
||||
<mxCell id="mha_dec" value="Multi-Head
Attention" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="650" y="240" width="120" height="40" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Add & Norm 2 (Decoder) -->
|
||||
<mxCell id="add_norm2_dec" value="Add & Norm" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="650" y="200" width="120" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Feed Forward (Decoder) -->
|
||||
<mxCell id="ff_dec" value="Feed Forward" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="650" y="160" width="120" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Add & Norm 3 (Decoder) -->
|
||||
<mxCell id="add_norm3_dec" value="Add & Norm" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontSize=10;" vertex="1" parent="1">
|
||||
<mxGeometry x="650" y="120" width="120" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Nx label for decoder -->
|
||||
<mxCell id="nx_dec" value="Nx" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=11;fontStyle=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="790" y="255" width="30" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Linear -->
|
||||
<mxCell id="linear" value="Linear" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="650" y="80" width="120" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Softmax -->
|
||||
<mxCell id="softmax" value="Softmax" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=11;" vertex="1" parent="1">
|
||||
<mxGeometry x="650" y="40" width="120" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Output Probabilities -->
|
||||
<mxCell id="output" value="Output Probabilities" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=11;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="640" y="0" width="140" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Animated Connectors - Encoder Side -->
|
||||
<mxCell id="conn1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#6c8ebf;flowAnimation=1;" edge="1" parent="1" source="input_embed" target="pos_enc_left">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#6c8ebf;flowAnimation=1;" edge="1" parent="1" source="pos_enc_left" target="mha_enc">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#82b366;flowAnimation=1;" edge="1" parent="1" source="mha_enc" target="add_norm1_enc">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#d6b656;flowAnimation=1;" edge="1" parent="1" source="add_norm1_enc" target="ff_enc">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#82b366;flowAnimation=1;" edge="1" parent="1" source="ff_enc" target="add_norm2_enc">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Encoder to Decoder Cross Attention -->
|
||||
<mxCell id="conn_cross" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;strokeColor=#9673a6;flowAnimation=1;dashed=1;" edge="1" parent="1" source="add_norm2_enc" target="mha_dec">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="400" y="215"/>
|
||||
<mxPoint x="400" y="260"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cross_label" value="K, V" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=10;fontStyle=1;fillColor=#ffffff;" vertex="1" connectable="0" parent="conn_cross">
|
||||
<mxGeometry x="-0.1" y="1" relative="1" as="geometry">
|
||||
<mxPoint x="10" y="-9" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Animated Connectors - Decoder Side -->
|
||||
<mxCell id="conn6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#d79b00;flowAnimation=1;" edge="1" parent="1" source="output_embed" target="pos_enc_right">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#d79b00;flowAnimation=1;" edge="1" parent="1" source="pos_enc_right" target="masked_mha_dec">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#82b366;flowAnimation=1;" edge="1" parent="1" source="masked_mha_dec" target="add_norm1_dec">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#d6b656;flowAnimation=1;" edge="1" parent="1" source="add_norm1_dec" target="mha_dec">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#82b366;flowAnimation=1;" edge="1" parent="1" source="mha_dec" target="add_norm2_dec">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#d6b656;flowAnimation=1;" edge="1" parent="1" source="add_norm2_dec" target="ff_dec">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#82b366;flowAnimation=1;" edge="1" parent="1" source="ff_dec" target="add_norm3_dec">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#b85450;flowAnimation=1;" edge="1" parent="1" source="add_norm3_dec" target="linear">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#b85450;flowAnimation=1;" edge="1" parent="1" source="linear" target="softmax">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="conn15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;strokeWidth=2;strokeColor=#6c8ebf;flowAnimation=1;" edge="1" parent="1" source="softmax" target="output">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Residual Connections (Encoder) -->
|
||||
<mxCell id="res1_enc" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=1.5;strokeColor=#999999;dashed=1;flowAnimation=1;" edge="1" parent="1" source="mha_enc" target="add_norm1_enc">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="50" y="355"/>
|
||||
<mxPoint x="50" y="295"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="res2_enc" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=1.5;strokeColor=#999999;dashed=1;flowAnimation=1;" edge="1" parent="1" source="ff_enc" target="add_norm2_enc">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="50" y="255"/>
|
||||
<mxPoint x="50" y="215"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Residual Connections (Decoder) -->
|
||||
<mxCell id="res1_dec" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=1.5;strokeColor=#999999;dashed=1;flowAnimation=1;" edge="1" parent="1" source="masked_mha_dec" target="add_norm1_dec">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="800" y="365"/>
|
||||
<mxPoint x="800" y="305"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="res2_dec" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=1.5;strokeColor=#999999;dashed=1;flowAnimation=1;" edge="1" parent="1" source="mha_dec" target="add_norm2_dec">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="800" y="260"/>
|
||||
<mxPoint x="800" y="215"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="res3_dec" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=1.5;strokeColor=#999999;dashed=1;flowAnimation=1;" edge="1" parent="1" source="ff_dec" target="add_norm3_dec">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="800" y="175"/>
|
||||
<mxPoint x="800" y="135"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Input/Output Labels -->
|
||||
<mxCell id="input_label" value="Inputs" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=12;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="110" y="530" width="60" height="20" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<mxCell id="output_label" value="Outputs
(shifted right)" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=12;fontStyle=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="530" width="100" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
</root>`,
|
||||
},
|
||||
{
|
||||
promptText: "Replicate this in aws style",
|
||||
hasImage: true,
|
||||
xml: `<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
|
||||
<!-- AWS Cloud Container -->
|
||||
<mxCell id="2" value="AWS" style="sketch=0;outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_aws_cloud;strokeColor=#232F3E;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#232F3E;dashed=0;rounded=1;arcSize=5;" vertex="1" parent="1">
|
||||
<mxGeometry x="340" y="40" width="880" height="520" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- User -->
|
||||
<mxCell id="3" value="User" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#232F3D;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.user;rounded=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="240" width="78" height="78" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- EC2 Instance -->
|
||||
<mxCell id="4" value="EC2" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#ED7100;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;rounded=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="560" y="240" width="78" height="78" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- S3 Bucket -->
|
||||
<mxCell id="5" value="S3" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#7AA116;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.s3;rounded=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="960" y="120" width="78" height="78" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Bedrock -->
|
||||
<mxCell id="6" value="bedrock" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#01A88D;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.bedrock;rounded=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="960" y="260" width="78" height="78" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- DynamoDB -->
|
||||
<mxCell id="7" value="DynamoDB" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#C925D1;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.dynamodb;rounded=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="960" y="400" width="78" height="78" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Arrow: User to EC2 -->
|
||||
<mxCell id="8" value="" style="endArrow=classic;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="3" target="4">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="400" y="350" as="sourcePoint"/>
|
||||
<mxPoint x="450" y="300" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Arrow: EC2 to S3 -->
|
||||
<mxCell id="9" value="" style="endArrow=classic;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=1;exitY=0.25;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="4" target="5">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="700" y="350" as="sourcePoint"/>
|
||||
<mxPoint x="750" y="300" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Arrow: EC2 to Bedrock -->
|
||||
<mxCell id="10" value="" style="endArrow=classic;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="4" target="6">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="700" y="350" as="sourcePoint"/>
|
||||
<mxPoint x="750" y="300" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Arrow: EC2 to DynamoDB -->
|
||||
<mxCell id="11" value="" style="endArrow=classic;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;exitX=1;exitY=0.75;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="4" target="7">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="700" y="350" as="sourcePoint"/>
|
||||
<mxPoint x="750" y="300" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>`,
|
||||
},
|
||||
{
|
||||
promptText: "Replicate this flowchart.",
|
||||
hasImage: true,
|
||||
xml: `<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
|
||||
<!-- Start: Lamp doesn't work -->
|
||||
<mxCell id="2" value="Lamp doesn't work" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffcccc;strokeColor=#000000;strokeWidth=2;fontSize=18;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="140" y="40" width="180" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Arrow from start to first decision -->
|
||||
<mxCell id="3" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#000000;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="2" target="4">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Decision: Lamp plugged in? -->
|
||||
<mxCell id="4" value="Lamp<br>plugged in?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#ffff99;strokeColor=#000000;strokeWidth=2;fontSize=18;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="130" y="150" width="200" height="200" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Arrow to Plug in lamp (No) -->
|
||||
<mxCell id="5" value="No" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#000000;strokeWidth=2;endArrow=block;endFill=1;fontSize=16;" edge="1" parent="1" source="4" target="6">
|
||||
<mxGeometry x="-0.2" relative="1" as="geometry">
|
||||
<mxPoint as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Action: Plug in lamp -->
|
||||
<mxCell id="6" value="Plug in lamp" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#99ff99;strokeColor=#000000;strokeWidth=2;fontSize=18;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="420" y="220" width="200" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Arrow down to second decision (Yes) -->
|
||||
<mxCell id="7" value="Yes" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#000000;strokeWidth=2;endArrow=block;endFill=1;fontSize=16;" edge="1" parent="1" source="4" target="8">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Decision: Bulb burned out? -->
|
||||
<mxCell id="8" value="Bulb<br>burned out?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#ffff99;strokeColor=#000000;strokeWidth=2;fontSize=18;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="130" y="400" width="200" height="200" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Arrow to Replace bulb (Yes) -->
|
||||
<mxCell id="9" value="Yes" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#000000;strokeWidth=2;endArrow=block;endFill=1;fontSize=16;" edge="1" parent="1" source="8" target="10">
|
||||
<mxGeometry x="-0.2" relative="1" as="geometry">
|
||||
<mxPoint as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Action: Replace bulb -->
|
||||
<mxCell id="10" value="Replace bulb" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#99ff99;strokeColor=#000000;strokeWidth=2;fontSize=18;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="420" y="470" width="200" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Arrow down to Repair lamp (No) -->
|
||||
<mxCell id="11" value="No" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#000000;strokeWidth=2;endArrow=block;endFill=1;fontSize=16;" edge="1" parent="1" source="8" target="12">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Action: Repair lamp -->
|
||||
<mxCell id="12" value="Repair lamp" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#99ff99;strokeColor=#000000;strokeWidth=2;fontSize=18;fontStyle=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="130" y="650" width="200" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
</root>`,
|
||||
},
|
||||
{
|
||||
promptText: "Draw a cat for me",
|
||||
hasImage: false,
|
||||
xml: `<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
|
||||
<!-- Cat's head -->
|
||||
<mxCell id="2" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#FFE6CC;strokeColor=#000000;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="300" y="150" width="120" height="120" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Left ear -->
|
||||
<mxCell id="3" value="" style="triangle;whiteSpace=wrap;html=1;fillColor=#FFE6CC;strokeColor=#000000;strokeWidth=2;rotation=30;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="120" width="50" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Right ear -->
|
||||
<mxCell id="4" value="" style="triangle;whiteSpace=wrap;html=1;fillColor=#FFE6CC;strokeColor=#000000;strokeWidth=2;rotation=-30;" vertex="1" parent="1">
|
||||
<mxGeometry x="390" y="120" width="50" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Left ear inner -->
|
||||
<mxCell id="5" value="" style="triangle;whiteSpace=wrap;html=1;fillColor=#FFB6C1;strokeColor=none;rotation=30;" vertex="1" parent="1">
|
||||
<mxGeometry x="290" y="135" width="30" height="35" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Right ear inner -->
|
||||
<mxCell id="6" value="" style="triangle;whiteSpace=wrap;html=1;fillColor=#FFB6C1;strokeColor=none;rotation=-30;" vertex="1" parent="1">
|
||||
<mxGeometry x="400" y="135" width="30" height="35" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Left eye -->
|
||||
<mxCell id="7" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#000000;strokeColor=#000000;" vertex="1" parent="1">
|
||||
<mxGeometry x="325" y="185" width="15" height="15" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Right eye -->
|
||||
<mxCell id="8" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#000000;strokeColor=#000000;" vertex="1" parent="1">
|
||||
<mxGeometry x="380" y="185" width="15" height="15" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Nose -->
|
||||
<mxCell id="9" value="" style="triangle;whiteSpace=wrap;html=1;fillColor=#FFB6C1;strokeColor=#000000;strokeWidth=1;rotation=180;" vertex="1" parent="1">
|
||||
<mxGeometry x="350" y="210" width="20" height="15" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Mouth left -->
|
||||
<mxCell id="10" value="" style="curved=1;endArrow=none;html=1;strokeColor=#000000;strokeWidth=2;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="360" y="220" as="sourcePoint"/>
|
||||
<mxPoint x="340" y="235" as="targetPoint"/>
|
||||
<Array as="points">
|
||||
<mxPoint x="355" y="230"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Mouth right -->
|
||||
<mxCell id="11" value="" style="curved=1;endArrow=none;html=1;strokeColor=#000000;strokeWidth=2;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="360" y="220" as="sourcePoint"/>
|
||||
<mxPoint x="380" y="235" as="targetPoint"/>
|
||||
<Array as="points">
|
||||
<mxPoint x="365" y="230"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Left whisker 1 -->
|
||||
<mxCell id="12" value="" style="endArrow=none;html=1;strokeColor=#000000;strokeWidth=1.5;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="310" y="200" as="sourcePoint"/>
|
||||
<mxPoint x="260" y="195" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Left whisker 2 -->
|
||||
<mxCell id="13" value="" style="endArrow=none;html=1;strokeColor=#000000;strokeWidth=1.5;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="310" y="210" as="sourcePoint"/>
|
||||
<mxPoint x="260" y="210" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Left whisker 3 -->
|
||||
<mxCell id="14" value="" style="endArrow=none;html=1;strokeColor=#000000;strokeWidth=1.5;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="310" y="220" as="sourcePoint"/>
|
||||
<mxPoint x="260" y="225" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Right whisker 1 -->
|
||||
<mxCell id="15" value="" style="endArrow=none;html=1;strokeColor=#000000;strokeWidth=1.5;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="410" y="200" as="sourcePoint"/>
|
||||
<mxPoint x="460" y="195" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Right whisker 2 -->
|
||||
<mxCell id="16" value="" style="endArrow=none;html=1;strokeColor=#000000;strokeWidth=1.5;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="410" y="210" as="sourcePoint"/>
|
||||
<mxPoint x="460" y="210" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Right whisker 3 -->
|
||||
<mxCell id="17" value="" style="endArrow=none;html=1;strokeColor=#000000;strokeWidth=1.5;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="410" y="220" as="sourcePoint"/>
|
||||
<mxPoint x="460" y="225" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
<!-- Body -->
|
||||
<mxCell id="18" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=#FFE6CC;strokeColor=#000000;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="285" y="250" width="150" height="180" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Belly -->
|
||||
<mxCell id="19" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=none;" vertex="1" parent="1">
|
||||
<mxGeometry x="315" y="280" width="90" height="120" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Left front paw -->
|
||||
<mxCell id="20" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=#FFE6CC;strokeColor=#000000;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="300" y="410" width="40" height="50" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Right front paw -->
|
||||
<mxCell id="21" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=#FFE6CC;strokeColor=#000000;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="380" y="410" width="40" height="50" as="geometry"/>
|
||||
</mxCell>
|
||||
|
||||
<!-- Tail -->
|
||||
<mxCell id="22" value="" style="curved=1;endArrow=none;html=1;strokeColor=#000000;strokeWidth=3;fillColor=#FFE6CC;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="285" y="340" as="sourcePoint"/>
|
||||
<mxPoint x="240" y="260" as="targetPoint"/>
|
||||
<Array as="points">
|
||||
<mxPoint x="260" y="350"/>
|
||||
<mxPoint x="240" y="320"/>
|
||||
<mxPoint x="235" y="290"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
|
||||
</root>`,
|
||||
},
|
||||
];
|
||||
|
||||
export function findCachedResponse(
|
||||
promptText: string,
|
||||
hasImage: boolean
|
||||
): CachedResponse | undefined {
|
||||
return CACHED_EXAMPLE_RESPONSES.find(
|
||||
(c) => c.promptText === promptText && c.hasImage === hasImage && c.xml !== ''
|
||||
);
|
||||
}
|
||||
4821
package-lock.json
generated
4821
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,9 +9,10 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/amazon-bedrock": "^3.0.52",
|
||||
"@ai-sdk/amazon-bedrock": "^3.0.62",
|
||||
"@ai-sdk/anthropic": "^2.0.44",
|
||||
"@ai-sdk/azure": "^2.0.69",
|
||||
"@ai-sdk/deepseek": "^1.0.30",
|
||||
"@ai-sdk/google": "^2.0.0",
|
||||
"@ai-sdk/openai": "^2.0.19",
|
||||
"@ai-sdk/react": "^2.0.22",
|
||||
@@ -46,6 +47,8 @@
|
||||
"@types/pako": "^2.0.3",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "9.39.1",
|
||||
"eslint-config-next": "16.0.5",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
}
|
||||
|
||||
4
public/animated_connectors.svg
Normal file
4
public/animated_connectors.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 261 KiB |
4
public/aws_demo.svg
Normal file
4
public/aws_demo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 95 KiB |
4
public/azure_demo.svg
Normal file
4
public/azure_demo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 88 KiB |
4
public/cat_demo.svg
Normal file
4
public/cat_demo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 33 KiB |
4
public/gcp_demo.svg
Normal file
4
public/gcp_demo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 100 KiB |
Reference in New Issue
Block a user