refactor(pages): one about page per language, no R2 cache by default

- app/[lang]/about/page.tsx renders en, zh and ja (zh-Hant falls back
  to zh) from one JSX tree with per-language texts and generateMetadata;
  delete the cn/ and ja/ copies and redirect their old URLs
- app/[lang]/layout.tsx: use hasLocale, an OG locale table, and real
  zh/ja title and description
- components/icons/github.tsx replaces react-icons and lucide's
  deprecated Github icon
- quota-limit-toast: read the dictionary keys directly, shadow-float
- Cloudflare: defineCloudflareConfig({}) without R2, no r2_buckets, no
  dev-time OpenNext init, cf-typegen script removed,
  @opennextjs/cloudflare moves to devDependencies, docs updated
This commit is contained in:
dayuan.jiang
2026-10-12 08:16:49 +09:00
parent 8ca2d03e7f
commit 3a9168e5b3
14 changed files with 567 additions and 1049 deletions
-336
View File
@@ -1,336 +0,0 @@
import type { Metadata } from "next"
import Link from "next/link"
import { FaGithub } from "react-icons/fa"
import Image from "@/components/image-with-basepath"
export const metadata: Metadata = {
title: "关于 - Next AI Draw.io",
description:
"AI驱动的图表创建工具 - 对话、绘制、可视化。使用自然语言创建AWS、GCP和Azure架构图。",
keywords: ["AI图表", "draw.io", "AWS架构", "GCP图表", "Azure图表", "LLM"],
}
export default function AboutCN() {
return (
<div className="min-h-screen bg-gray-50">
{/* Navigation */}
<header className="bg-white border-b border-gray-200">
<div className="max-w-4xl 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"
>
编辑器
</Link>
<Link
href="/about/cn"
className="text-blue-600 font-semibold"
>
关于
</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="在GitHub上查看"
>
<FaGithub className="w-5 h-5" />
</a>
</nav>
</div>
</div>
</header>
{/* Main Content */}
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<article className="prose prose-lg max-w-none">
{/* Title */}
<div className="text-center mb-8">
<h1 className="text-4xl font-bold text-gray-900 mb-2">
Next AI Draw.io
</h1>
<p className="text-xl text-gray-600 font-medium">
AI驱动的图表创建工具 - 对话、绘制、可视化
</p>
</div>
<div className="relative mb-8 rounded-2xl bg-gradient-to-br from-amber-50 via-orange-50 to-yellow-50 p-[1px] shadow-lg">
<div className="absolute inset-0 rounded-2xl bg-gradient-to-br from-amber-400 via-orange-400 to-yellow-400 opacity-20" />
<div className="relative rounded-2xl bg-white/80 backdrop-blur-sm p-6">
{/* Bring Your Own Key */}
<div className="text-center">
<h4 className="text-base font-bold text-gray-900 mb-2">
使用自己的 API Key
</h4>
<p className="text-sm text-gray-600 mb-2 max-w-md mx-auto">
您也可以使用自己的 API
Key,支持多种服务商。点击聊天面板中的设置图标即可配置。
</p>
<p className="text-xs text-gray-500 max-w-md mx-auto">
您的 Key
仅保存在浏览器本地,不会被存储在服务器上。
</p>
</div>
</div>
</div>
<p className="text-gray-700">
一个集成了AI功能的Next.js网页应用,与draw.io图表无缝结合。通过自然语言命令和AI辅助可视化来创建、修改和增强图表。
</p>
{/* Features */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
功能特性
</h2>
<ul className="list-disc pl-6 text-gray-700 space-y-2">
<li>
<strong>LLM驱动的图表创建</strong>
:利用大语言模型通过自然语言命令直接创建和操作draw.io图表
</li>
<li>
<strong>基于图像的图表复制</strong>
:上传现有图表或图像,让AI自动复制和增强
</li>
<li>
<strong>版本与撤销</strong>
:AI
的每次修改都会成为聊天里的一个版本,可以对比、恢复或撤销;在画布上按
Ctrl+Z 也能撤回
</li>
<li>
<strong>交互式聊天界面</strong>
:与AI实时对话来完善您的图表
</li>
<li>
<strong>AWS架构图支持</strong>
:专门支持生成AWS架构图
</li>
<li>
<strong>动画连接器</strong>
:在图表元素之间创建动态动画连接器,实现更好的可视化效果
</li>
</ul>
{/* Examples */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
示例
</h2>
<p className="text-gray-700 mb-6">
以下是一些示例提示词及其生成的图表:
</p>
<div className="space-y-8">
{/* ResNet50 Architecture */}
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
ResNet50模型架构动画
</h3>
<p className="text-gray-600 mb-4">
<strong>Prompt:</strong> Give me an{" "}
<strong>animated</strong> architecture diagram
of the ResNet50 model.
</p>
<div className="bg-neutral-950 rounded-lg p-4 inline-block">
<Image
src="/resnet50.svg"
alt="ResNet50模型架构图"
width={480}
height={360}
className="mx-auto"
/>
</div>
</div>
{/* Diagram Grid */}
<div className="grid md:grid-cols-2 gap-6">
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
RAG技术图
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Generate a RAG
architecture diagram for{" "}
<strong>chat application</strong>. Use
connected diagram for data ingestion
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/rag_prod.svg"
alt="RAG架构图"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
React和AWS认证流程
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Generate
authentication process using React with{" "}
<strong>AWS</strong>. Use Serverless
architecture.
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/auth.svg"
alt="认证架构图"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
敏捷Scrum流程
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Generate agile
scrum workflow diagram for software
development team.
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/agile_scrum.svg"
alt="敏捷Scrum流程图"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
开放式创新
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Create
visualization of Henry Chesbrough&apos;s
Open Innovation model.
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/inno.svg"
alt="开放式创新图"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
</div>
</div>
{/* How It Works */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
工作原理
</h2>
<p className="text-gray-700 mb-4">本应用使用以下技术:</p>
<ul className="list-disc pl-6 text-gray-700 space-y-2">
<li>
<strong>Next.js</strong>:用于前端框架和路由
</li>
<li>
<strong>Vercel AI SDK</strong>(<code>ai</code> +{" "}
<code>@ai-sdk/*</code>
):用于流式AI响应和多提供商支持
</li>
<li>
<strong>draw.io</strong>
:内置在应用里的编辑器,应用可以直接控制它
</li>
</ul>
<p className="text-gray-700 mt-4">
图表以XML格式表示,可在draw.io中渲染。AI处理您的命令并相应地生成或修改此XML。
</p>
{/* Multi-Provider Support */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
多提供商支持
</h2>
<ul className="list-disc pl-6 text-gray-700 space-y-1">
<li>字节跳动豆包</li>
<li>AWS Bedrock(默认)</li>
<li>
OpenAI / OpenAI兼容API(通过{" "}
<code>OPENAI_BASE_URL</code>)
</li>
<li>Anthropic</li>
<li>Google AI</li>
<li>Google Vertex AI</li>
<li>Azure OpenAI</li>
<li>Ollama</li>
<li>OpenRouter</li>
<li>DeepSeek</li>
<li>SiliconFlow</li>
<li>ModelScope</li>
</ul>
<p className="text-gray-700 mt-4">
注意:<code>claude-sonnet-4-5</code>{" "}
已在带有AWS标志的draw.io图表上进行训练,因此如果您想创建AWS架构图,这是最佳选择。
</p>
{/* Support */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
支持与联系
</h2>
<p className="text-gray-700">
如果您觉得这个项目有用,请考虑{" "}
<a
href="https://github.com/sponsors/DayuanJiang"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:underline"
>
赞助
</a>{" "}
来帮助托管在线演示站点!
</p>
<p className="text-gray-700 mt-2">
如需支持或咨询,请在{" "}
<a
href="https://github.com/DayuanJiang/next-ai-draw-io"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:underline"
>
GitHub仓库
</a>{" "}
上提交issue或联系:me[at]jiang.jp
</p>
{/* CTA */}
<div className="mt-12 text-center">
<Link
href="/"
className="inline-block bg-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:bg-blue-700 transition-colors"
>
打开编辑器
</Link>
</div>
</article>
</main>
{/* Footer */}
<footer className="bg-white border-t border-gray-200 mt-16">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<p className="text-center text-gray-600 text-sm">
Next AI Draw.io - 开源AI驱动的图表生成器
</p>
</div>
</footer>
</div>
)
}
-350
View File
@@ -1,350 +0,0 @@
import type { Metadata } from "next"
import Link from "next/link"
import { FaGithub } from "react-icons/fa"
import Image from "@/components/image-with-basepath"
export const metadata: Metadata = {
title: "概要 - Next AI Draw.io",
description:
"AI搭載のダイアグラム作成ツール - チャット、描画、可視化。自然言語でAWS、GCP、Azureアーキテクチャ図を作成。",
keywords: [
"AIダイアグラム",
"draw.io",
"AWSアーキテクチャ",
"GCPダイアグラム",
"Azureダイアグラム",
"LLM",
],
}
export default function AboutJA() {
return (
<div className="min-h-screen bg-gray-50">
{/* Navigation */}
<header className="bg-white border-b border-gray-200">
<div className="max-w-4xl 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"
>
エディタ
</Link>
<Link
href="/about/ja"
className="text-blue-600 font-semibold"
>
概要
</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="GitHubで見る"
>
<FaGithub className="w-5 h-5" />
</a>
</nav>
</div>
</div>
</header>
{/* Main Content */}
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<article className="prose prose-lg max-w-none">
{/* Title */}
<div className="text-center mb-8">
<h1 className="text-4xl font-bold text-gray-900 mb-2">
Next AI Draw.io
</h1>
<p className="text-xl text-gray-600 font-medium">
AI搭載のダイアグラム作成ツール -
チャット、描画、可視化
</p>
</div>
<div className="relative mb-8 rounded-2xl bg-gradient-to-br from-amber-50 via-orange-50 to-yellow-50 p-[1px] shadow-lg">
<div className="absolute inset-0 rounded-2xl bg-gradient-to-br from-amber-400 via-orange-400 to-yellow-400 opacity-20" />
<div className="relative rounded-2xl bg-white/80 backdrop-blur-sm p-6">
{/* Bring Your Own Key */}
<div className="text-center">
<h4 className="text-base font-bold text-gray-900 mb-2">
自分のAPIキーを使用
</h4>
<p className="text-sm text-gray-600 mb-2 max-w-md mx-auto">
お好みのプロバイダーで自分のAPIキーを使用することもできます。チャットパネルの設定アイコンをクリックして設定してください。
</p>
<p className="text-xs text-gray-500 max-w-md mx-auto">
キーはブラウザのローカルに保存され、サーバーには保存されません。
</p>
</div>
</div>
</div>
<p className="text-gray-700">
AI機能とdraw.ioダイアグラムを統合したNext.jsウェブアプリケーションです。自然言語コマンドとAI支援の可視化により、ダイアグラムを作成、修正、強化できます。
</p>
{/* Features */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
機能
</h2>
<ul className="list-disc pl-6 text-gray-700 space-y-2">
<li>
<strong>LLM搭載のダイアグラム作成</strong>
:大規模言語モデルを活用して、自然言語コマンドで直接draw.ioダイアグラムを作成・操作
</li>
<li>
<strong>画像ベースのダイアグラム複製</strong>
:既存のダイアグラムや画像をアップロードし、AIが自動的に複製・強化
</li>
<li>
<strong>バージョンと取り消し</strong>
:AI
の変更はそれぞれチャット内のバージョンになり、比較・復元・取り消しができます。キャンバスで
Ctrl+Z を押しても元に戻せます
</li>
<li>
<strong>
インタラクティブなチャットインターフェース
</strong>
:AIとリアルタイムでコミュニケーションしてダイアグラムを改善
</li>
<li>
<strong>
AWSアーキテクチャダイアグラムサポート
</strong>
:AWSアーキテクチャダイアグラムの生成を専門的にサポート
</li>
<li>
<strong>アニメーションコネクタ</strong>
:より良い可視化のためにダイアグラム要素間に動的でアニメーション化されたコネクタを作成
</li>
</ul>
{/* Examples */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
例
</h2>
<p className="text-gray-700 mb-6">
以下はいくつかのプロンプト例と生成されたダイアグラムです:
</p>
<div className="space-y-8">
{/* ResNet50 Architecture */}
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
ResNet50モデルアーキテクチャアニメーション
</h3>
<p className="text-gray-600 mb-4">
<strong>Prompt:</strong> Give me an{" "}
<strong>animated</strong> architecture diagram
of the ResNet50 model.
</p>
<div className="bg-neutral-950 rounded-lg p-4 inline-block">
<Image
src="/resnet50.svg"
alt="ResNet50モデルアーキテクチャ図"
width={480}
height={360}
className="mx-auto"
/>
</div>
</div>
{/* Diagram Grid */}
<div className="grid md:grid-cols-2 gap-6">
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
RAG技術ダイアグラム
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Generate a RAG
architecture diagram for{" "}
<strong>chat application</strong>. Use
connected diagram for data ingestion
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/rag_prod.svg"
alt="RAGアーキテクチャ図"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
ReactとAWSによる認証
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Generate
authentication process using React with{" "}
<strong>AWS</strong>. Use Serverless
architecture.
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/auth.svg"
alt="認証アーキテクチャ図"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
アジャイルスクラムプロセス
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Generate agile
scrum workflow diagram for software
development team.
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/agile_scrum.svg"
alt="アジャイルスクラム図"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
オープンイノベーション
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Create
visualization of Henry Chesbrough&apos;s
Open Innovation model.
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/inno.svg"
alt="オープンイノベーション図"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
</div>
</div>
{/* How It Works */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
仕組み
</h2>
<p className="text-gray-700 mb-4">
本アプリケーションは以下の技術を使用しています:
</p>
<ul className="list-disc pl-6 text-gray-700 space-y-2">
<li>
<strong>Next.js</strong>
:フロントエンドフレームワークとルーティング
</li>
<li>
<strong>Vercel AI SDK</strong>(<code>ai</code> +{" "}
<code>@ai-sdk/*</code>
):ストリーミングAIレスポンスとマルチプロバイダーサポート
</li>
<li>
<strong>draw.io</strong>
:アプリに同梱されたエディター。アプリから直接操作できます
</li>
</ul>
<p className="text-gray-700 mt-4">
ダイアグラムはdraw.ioでレンダリングできるXMLとして表現されます。AIがコマンドを処理し、それに応じてこのXMLを生成または変更します。
</p>
{/* Multi-Provider Support */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
マルチプロバイダーサポート
</h2>
<ul className="list-disc pl-6 text-gray-700 space-y-1">
<li>ByteDance Doubao</li>
<li>AWS Bedrock(デフォルト)</li>
<li>
OpenAI / OpenAI互換API(<code>OPENAI_BASE_URL</code>
経由)
</li>
<li>Anthropic</li>
<li>Google AI</li>
<li>Google Vertex AI</li>
<li>Azure OpenAI</li>
<li>Ollama</li>
<li>OpenRouter</li>
<li>DeepSeek</li>
<li>SiliconFlow</li>
<li>ModelScope</li>
</ul>
<p className="text-gray-700 mt-4">
注:<code>claude-sonnet-4-5</code>
はAWSロゴ付きのdraw.ioダイアグラムで学習されているため、AWSアーキテクチャダイアグラムを作成したい場合は最適な選択です。
</p>
{/* Support */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
サポート&お問い合わせ
</h2>
<p className="text-gray-700">
このプロジェクトが役に立ったら、ライブデモサイトのホスティングを支援するために{" "}
<a
href="https://github.com/sponsors/DayuanJiang"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:underline"
>
スポンサー
</a>{" "}
をご検討ください!
</p>
<p className="text-gray-700 mt-2">
サポートやお問い合わせについては、{" "}
<a
href="https://github.com/DayuanJiang/next-ai-draw-io"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:underline"
>
GitHubリポジトリ
</a>{" "}
でissueを開くか、ご連絡ください:me[at]jiang.jp
</p>
{/* CTA */}
<div className="mt-12 text-center">
<Link
href="/"
className="inline-block bg-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:bg-blue-700 transition-colors"
>
エディタを開く
</Link>
</div>
</article>
</main>
{/* Footer */}
<footer className="bg-white border-t border-gray-200 mt-16">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<p className="text-center text-gray-600 text-sm">
Next AI Draw.io -
オープンソースAI搭載ダイアグラムジェネレーター
</p>
</div>
</footer>
</div>
)
}
+491 -194
View File
@@ -1,23 +1,420 @@
import type { Metadata } from "next"
import Link from "next/link"
import { FaGithub } from "react-icons/fa"
import type { ReactNode } from "react"
import { GitHubIcon } from "@/components/icons/github"
import Image from "@/components/image-with-basepath"
import type { Locale } from "@/lib/i18n/config"
import { hasLocale } from "@/lib/i18n/dictionaries"
export const metadata: Metadata = {
title: "About - Next AI Draw.io",
description:
"AI-Powered Diagram Creation Tool - Chat, Draw, Visualize. Create AWS, GCP, and Azure architecture diagrams with natural language.",
keywords: [
"AI diagram",
"draw.io",
"AWS architecture",
"GCP diagram",
"Azure diagram",
"LLM",
],
type ExampleId = "resnet50" | "rag" | "auth" | "scrum" | "inno"
type AboutTexts = {
title: string
description: string
keywords: string[]
nav: { editor: string; about: string; github: string }
tagline: string
byok: { title: string; body: string; note: string }
intro: string
// Punctuation differs between Latin and CJK text
colon: string
parenOpen: string
parenClose: string
featuresHeading: string
features: { title: string; text: string }[]
examplesHeading: string
examplesIntro: string
examples: Record<ExampleId, { title: string; alt: string }>
howHeading: string
howIntro: string
tech: { nextjs: string; aiSdk: string; drawio: string }
howOutro: string
providersHeading: string
doubao: string
bedrock: string
// Text around the OPENAI_BASE_URL code span
openai: { before: string; after: string }
// Text around the claude-sonnet-4-5 code span
modelNote: { before: string; after: string }
supportHeading: string
// Text around the sponsor link
sponsor: { before: string; link: string; after: string }
// Text around the GitHub repository link
contact: { before: string; link: string; after: string }
openEditor: string
footer: string
}
export default function About() {
const texts: Record<"en" | "zh" | "ja", AboutTexts> = {
en: {
title: "About - Next AI Draw.io",
description:
"AI-Powered Diagram Creation Tool - Chat, Draw, Visualize. Create AWS, GCP, and Azure architecture diagrams with natural language.",
keywords: [
"AI diagram",
"draw.io",
"AWS architecture",
"GCP diagram",
"Azure diagram",
"LLM",
],
nav: { editor: "Editor", about: "About", github: "View on GitHub" },
tagline: "AI-Powered Diagram Creation Tool - Chat, Draw, Visualize",
byok: {
title: "Bring Your Own API Key",
body: "You can also use your own API key with any supported provider. Click the Settings icon in the chat panel to configure your provider and API key.",
note: "Your key is stored locally in your browser and is never stored on the server.",
},
intro: "A Next.js web application that integrates AI capabilities with draw.io diagrams. Create, modify, and enhance diagrams through natural language commands and AI-assisted visualization.",
colon: ": ",
parenOpen: " (",
parenClose: ")",
featuresHeading: "Features",
features: [
{
title: "LLM-Powered Diagram Creation",
text: "Leverage Large Language Models to create and manipulate draw.io diagrams directly through natural language commands",
},
{
title: "Image-Based Diagram Replication",
text: "Upload existing diagrams or images and have the AI replicate and enhance them automatically",
},
{
title: "Versions and Undo",
text: "Every AI change becomes a version in the chat that you can compare, restore or undo; Ctrl+Z on the canvas takes it back too",
},
{
title: "Interactive Chat Interface",
text: "Communicate with AI to refine your diagrams in real-time",
},
{
title: "AWS Architecture Diagram Support",
text: "Specialized support for generating AWS architecture diagrams",
},
{
title: "Animated Connectors",
text: "Create dynamic and animated connectors between diagram elements for better visualization",
},
],
examplesHeading: "Examples",
examplesIntro:
"Here are some example prompts and their generated diagrams:",
examples: {
resnet50: {
title: "Animated ResNet50 Model Architecture",
alt: "Architecture diagram for ResNet50 model",
},
rag: {
title: "RAG Technique Diagram",
alt: "RAG Architecture Diagram",
},
auth: {
title: "Authentication using React and AWS",
alt: "Authentication Architecture Diagram",
},
scrum: { title: "Agile Scrum Process", alt: "Agile Scrum Diagram" },
inno: { title: "Open Innovation", alt: "Open Innovation Diagram" },
},
howHeading: "How It Works",
howIntro: "The application uses the following technologies:",
tech: {
nextjs: "For the frontend framework and routing",
aiSdk: "For streaming AI responses and multi-provider support",
drawio: "The editor, bundled with the app so it can be driven directly",
},
howOutro:
"Diagrams are represented as XML that can be rendered in draw.io. The AI processes your commands and generates or modifies this XML accordingly.",
providersHeading: "Multi-Provider Support",
doubao: "ByteDance Doubao",
bedrock: "AWS Bedrock (default)",
openai: { before: "OpenAI / OpenAI-compatible APIs (via ", after: ")" },
modelNote: {
before: "Note that ",
after: " has trained on draw.io diagrams with AWS logos, so if you want to create AWS architecture diagrams, this is the best choice.",
},
supportHeading: "Support & Contact",
sponsor: {
before: "If you find this project useful, please consider",
link: "sponsoring",
after: "to help host the live demo site!",
},
contact: {
before: "For support or inquiries, please open an issue on the",
link: "GitHub repository",
after: "or contact: me[at]jiang.jp",
},
openEditor: "Open Editor",
footer: "Next AI Draw.io - Open Source AI-Powered Diagram Generator",
},
zh: {
title: "关于 - Next AI Draw.io",
description:
"AI驱动的图表创建工具 - 对话、绘制、可视化。使用自然语言创建AWS、GCP和Azure架构图。",
keywords: [
"AI图表",
"draw.io",
"AWS架构",
"GCP图表",
"Azure图表",
"LLM",
],
nav: { editor: "编辑器", about: "关于", github: "在GitHub上查看" },
tagline: "AI驱动的图表创建工具 - 对话、绘制、可视化",
byok: {
title: "使用自己的 API Key",
body: "您也可以使用自己的 API Key,支持多种服务商。点击聊天面板中的设置图标即可配置。",
note: "您的 Key 仅保存在浏览器本地,不会被存储在服务器上。",
},
intro: "一个集成了AI功能的Next.js网页应用,与draw.io图表无缝结合。通过自然语言命令和AI辅助可视化来创建、修改和增强图表。",
colon: ":",
parenOpen: "(",
parenClose: ")",
featuresHeading: "功能特性",
features: [
{
title: "LLM驱动的图表创建",
text: "利用大语言模型通过自然语言命令直接创建和操作draw.io图表",
},
{
title: "基于图像的图表复制",
text: "上传现有图表或图像,让AI自动复制和增强",
},
{
title: "版本与撤销",
text: "AI 的每次修改都会成为聊天里的一个版本,可以对比、恢复或撤销;在画布上按 Ctrl+Z 也能撤回",
},
{
title: "交互式聊天界面",
text: "与AI实时对话来完善您的图表",
},
{ title: "AWS架构图支持", text: "专门支持生成AWS架构图" },
{
title: "动画连接器",
text: "在图表元素之间创建动态动画连接器,实现更好的可视化效果",
},
],
examplesHeading: "示例",
examplesIntro: "以下是一些示例提示词及其生成的图表:",
examples: {
resnet50: {
title: "ResNet50模型架构动画",
alt: "ResNet50模型架构图",
},
rag: { title: "RAG技术图", alt: "RAG架构图" },
auth: { title: "React和AWS认证流程", alt: "认证架构图" },
scrum: { title: "敏捷Scrum流程", alt: "敏捷Scrum流程图" },
inno: { title: "开放式创新", alt: "开放式创新图" },
},
howHeading: "工作原理",
howIntro: "本应用使用以下技术:",
tech: {
nextjs: "用于前端框架和路由",
aiSdk: "用于流式AI响应和多提供商支持",
drawio: "内置在应用里的编辑器,应用可以直接控制它",
},
howOutro:
"图表以XML格式表示,可在draw.io中渲染。AI处理您的命令并相应地生成或修改此XML。",
providersHeading: "多提供商支持",
doubao: "字节跳动豆包",
bedrock: "AWS Bedrock(默认)",
openai: { before: "OpenAI / OpenAI兼容API(通过 ", after: ")" },
modelNote: {
before: "注意:",
after: " 已在带有AWS标志的draw.io图表上进行训练,因此如果您想创建AWS架构图,这是最佳选择。",
},
supportHeading: "支持与联系",
sponsor: {
before: "如果您觉得这个项目有用,请考虑",
link: "赞助",
after: "来帮助托管在线演示站点!",
},
contact: {
before: "如需支持或咨询,请在",
link: "GitHub仓库",
after: "上提交issue或联系:me[at]jiang.jp",
},
openEditor: "打开编辑器",
footer: "Next AI Draw.io - 开源AI驱动的图表生成器",
},
ja: {
title: "概要 - Next AI Draw.io",
description:
"AI搭載のダイアグラム作成ツール - チャット、描画、可視化。自然言語でAWS、GCP、Azureアーキテクチャ図を作成。",
keywords: [
"AIダイアグラム",
"draw.io",
"AWSアーキテクチャ",
"GCPダイアグラム",
"Azureダイアグラム",
"LLM",
],
nav: { editor: "エディタ", about: "概要", github: "GitHubで見る" },
tagline: "AI搭載のダイアグラム作成ツール - チャット、描画、可視化",
byok: {
title: "自分のAPIキーを使用",
body: "お好みのプロバイダーで自分のAPIキーを使用することもできます。チャットパネルの設定アイコンをクリックして設定してください。",
note: "キーはブラウザのローカルに保存され、サーバーには保存されません。",
},
intro: "AI機能とdraw.ioダイアグラムを統合したNext.jsウェブアプリケーションです。自然言語コマンドとAI支援の可視化により、ダイアグラムを作成、修正、強化できます。",
colon: ":",
parenOpen: "(",
parenClose: ")",
featuresHeading: "機能",
features: [
{
title: "LLM搭載のダイアグラム作成",
text: "大規模言語モデルを活用して、自然言語コマンドで直接draw.ioダイアグラムを作成・操作",
},
{
title: "画像ベースのダイアグラム複製",
text: "既存のダイアグラムや画像をアップロードし、AIが自動的に複製・強化",
},
{
title: "バージョンと取り消し",
text: "AI の変更はそれぞれチャット内のバージョンになり、比較・復元・取り消しができます。キャンバスで Ctrl+Z を押しても元に戻せます",
},
{
title: "インタラクティブなチャットインターフェース",
text: "AIとリアルタイムでコミュニケーションしてダイアグラムを改善",
},
{
title: "AWSアーキテクチャダイアグラムサポート",
text: "AWSアーキテクチャダイアグラムの生成を専門的にサポート",
},
{
title: "アニメーションコネクタ",
text: "より良い可視化のためにダイアグラム要素間に動的でアニメーション化されたコネクタを作成",
},
],
examplesHeading: "例",
examplesIntro:
"以下はいくつかのプロンプト例と生成されたダイアグラムです:",
examples: {
resnet50: {
title: "ResNet50モデルアーキテクチャアニメーション",
alt: "ResNet50モデルアーキテクチャ図",
},
rag: { title: "RAG技術ダイアグラム", alt: "RAGアーキテクチャ図" },
auth: {
title: "ReactとAWSによる認証",
alt: "認証アーキテクチャ図",
},
scrum: {
title: "アジャイルスクラムプロセス",
alt: "アジャイルスクラム図",
},
inno: {
title: "オープンイノベーション",
alt: "オープンイノベーション図",
},
},
howHeading: "仕組み",
howIntro: "本アプリケーションは以下の技術を使用しています:",
tech: {
nextjs: "フロントエンドフレームワークとルーティング",
aiSdk: "ストリーミングAIレスポンスとマルチプロバイダーサポート",
drawio: "アプリに同梱されたエディター。アプリから直接操作できます",
},
howOutro:
"ダイアグラムはdraw.ioでレンダリングできるXMLとして表現されます。AIがコマンドを処理し、それに応じてこのXMLを生成または変更します。",
providersHeading: "マルチプロバイダーサポート",
doubao: "ByteDance Doubao",
bedrock: "AWS Bedrock(デフォルト)",
openai: { before: "OpenAI / OpenAI互換API(", after: "経由)" },
modelNote: {
before: "注:",
after: "はAWSロゴ付きのdraw.ioダイアグラムで学習されているため、AWSアーキテクチャダイアグラムを作成したい場合は最適な選択です。",
},
supportHeading: "サポート&お問い合わせ",
sponsor: {
before: "このプロジェクトが役に立ったら、ライブデモサイトのホスティングを支援するために",
link: "スポンサー",
after: "をご検討ください!",
},
contact: {
before: "サポートやお問い合わせについては、",
link: "GitHubリポジトリ",
after: "でissueを開くか、ご連絡ください:me[at]jiang.jp",
},
openEditor: "エディタを開く",
footer: "Next AI Draw.io - オープンソースAI搭載ダイアグラムジェネレーター",
},
}
// The example prompts stay in English in every language
const examples: { id: ExampleId; src: string; prompt: ReactNode }[] = [
{
id: "resnet50",
src: "/resnet50.svg",
prompt: (
<>
Give me an <strong>animated</strong> architecture diagram of the
ResNet50 model.
</>
),
},
{
id: "rag",
src: "/rag_prod.svg",
prompt: (
<>
Generate a RAG architecture diagram for{" "}
<strong>chat application</strong>. Use connected diagram for
data ingestion
</>
),
},
{
id: "auth",
src: "/auth.svg",
prompt: (
<>
Generate authentication process using React with{" "}
<strong>AWS</strong>. Use Serverless architecture.
</>
),
},
{
id: "scrum",
src: "/agile_scrum.svg",
prompt: (
<>
Generate agile scrum workflow diagram for software development
team.
</>
),
},
{
id: "inno",
src: "/inno.svg",
prompt: (
<>
Create visualization of Henry Chesbrough&apos;s Open Innovation
model.
</>
),
},
]
// Traditional Chinese has no About text of its own and shows the Simplified one
function textsFor(rawLang: string): AboutTexts {
const lang: Locale = hasLocale(rawLang) ? rawLang : "en"
return texts[lang === "zh-Hant" ? "zh" : lang]
}
type Props = { params: Promise<{ lang: string }> }
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { lang } = await params
const t = textsFor(lang)
return { title: t.title, description: t.description, keywords: t.keywords }
}
export default async function About({ params }: Props) {
const { lang } = await params
const t = textsFor(lang)
const [hero, ...grid] = examples
return (
<div className="min-h-screen bg-gray-50">
{/* Navigation */}
@@ -25,32 +422,32 @@ export default function About() {
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<div className="flex items-center justify-between">
<Link
href="/"
href={`/${lang}`}
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="/"
href={`/${lang}`}
className="text-gray-600 hover:text-gray-900 transition-colors"
>
Editor
{t.nav.editor}
</Link>
<Link
href="/about"
href={`/${lang}/about`}
className="text-blue-600 font-semibold"
>
About
{t.nav.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"
aria-label={t.nav.github}
>
<FaGithub className="w-5 h-5" />
<GitHubIcon className="w-5 h-5" />
</a>
</nav>
</div>
@@ -66,8 +463,7 @@ export default function About() {
Next AI Draw.io
</h1>
<p className="text-xl text-gray-600 font-medium">
AI-Powered Diagram Creation Tool - Chat, Draw,
Visualize
{t.tagline}
</p>
</div>
@@ -77,92 +473,53 @@ export default function About() {
{/* Bring Your Own Key */}
<div className="text-center">
<h4 className="text-base font-bold text-gray-900 mb-2">
Bring Your Own API Key
{t.byok.title}
</h4>
<p className="text-sm text-gray-600 mb-2 max-w-md mx-auto">
You can also use your own API key with any
supported provider. Click the Settings icon
in the chat panel to configure your provider
and API key.
{t.byok.body}
</p>
<p className="text-xs text-gray-500 max-w-md mx-auto">
Your key is stored locally in your browser
and is never stored on the server.
{t.byok.note}
</p>
</div>
</div>
</div>
<p className="text-gray-700">
A Next.js web application that integrates AI
capabilities with draw.io diagrams. Create, modify, and
enhance diagrams through natural language commands and
AI-assisted visualization.
</p>
<p className="text-gray-700">{t.intro}</p>
{/* Features */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
Features
{t.featuresHeading}
</h2>
<ul className="list-disc pl-6 text-gray-700 space-y-2">
<li>
<strong>LLM-Powered Diagram Creation</strong>:
Leverage Large Language Models to create and
manipulate draw.io diagrams directly through natural
language commands
</li>
<li>
<strong>Image-Based Diagram Replication</strong>:
Upload existing diagrams or images and have the AI
replicate and enhance them automatically
</li>
<li>
<strong>Versions and Undo</strong>: Every AI change
becomes a version in the chat that you can compare,
restore or undo; Ctrl+Z on the canvas takes it back
too
</li>
<li>
<strong>Interactive Chat Interface</strong>:
Communicate with AI to refine your diagrams in
real-time
</li>
<li>
<strong>AWS Architecture Diagram Support</strong>:
Specialized support for generating AWS architecture
diagrams
</li>
<li>
<strong>Animated Connectors</strong>: Create dynamic
and animated connectors between diagram elements for
better visualization
</li>
{t.features.map((feature) => (
<li key={feature.title}>
<strong>{feature.title}</strong>
{t.colon}
{feature.text}
</li>
))}
</ul>
{/* Examples */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
Examples
{t.examplesHeading}
</h2>
<p className="text-gray-700 mb-6">
Here are some example prompts and their generated
diagrams:
</p>
<p className="text-gray-700 mb-6">{t.examplesIntro}</p>
<div className="space-y-8">
{/* ResNet50 Architecture */}
{/* First example on its own */}
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
Animated ResNet50 Model Architecture
{t.examples[hero.id].title}
</h3>
<p className="text-gray-600 mb-4">
<strong>Prompt:</strong> Give me an{" "}
<strong>animated</strong> architecture diagram
of the ResNet50 model.
<strong>Prompt:</strong> {hero.prompt}
</p>
<div className="bg-neutral-950 rounded-lg p-4 inline-block">
<Image
src="/resnet50.svg"
alt="Architecture diagram for ResNet50 model"
src={hero.src}
alt={t.examples[hero.id].alt}
width={480}
height={360}
className="mx-auto"
@@ -172,125 +529,67 @@ export default function About() {
{/* Diagram Grid */}
<div className="grid md:grid-cols-2 gap-6">
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
RAG Technique Diagram
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Generate a RAG
architecture diagram for{" "}
<strong>chat application</strong>. Use
connected diagram for data ingestion
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/rag_prod.svg"
alt="RAG Architecture Diagram"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
{grid.map((example) => (
<div key={example.id} className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
{t.examples[example.id].title}
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong>{" "}
{example.prompt}
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src={example.src}
alt={t.examples[example.id].alt}
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
</div>
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
Authentication using React and AWS
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Generate
authentication process using React with{" "}
<strong>AWS</strong>. Use Serverless
architecture.
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/auth.svg"
alt="Authentication Architecture Diagram"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
Agile Scrum Process
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Generate agile
scrum workflow diagram for software
development team.
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/agile_scrum.svg"
alt="Agile Scrum Diagram"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
<div className="text-center">
<h3 className="text-lg font-semibold text-gray-900 mb-2">
Open Innovation
</h3>
<p className="text-gray-600 text-sm mb-4">
<strong>Prompt:</strong> Create
visualization of Henry Chesbrough&apos;s
Open Innovation model.
</p>
<div className="bg-neutral-950 rounded-lg p-4 flex items-center justify-center w-full h-[400px]">
<Image
src="/inno.svg"
alt="Open Innovation Diagram"
width={480}
height={360}
className="max-w-full max-h-full object-contain"
/>
</div>
</div>
))}
</div>
</div>
{/* How It Works */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
How It Works
{t.howHeading}
</h2>
<p className="text-gray-700 mb-4">
The application uses the following technologies:
</p>
<p className="text-gray-700 mb-4">{t.howIntro}</p>
<ul className="list-disc pl-6 text-gray-700 space-y-2">
<li>
<strong>Next.js</strong>: For the frontend framework
and routing
<strong>Next.js</strong>
{t.colon}
{t.tech.nextjs}
</li>
<li>
<strong>Vercel AI SDK</strong> (<code>ai</code> +{" "}
<code>@ai-sdk/*</code>): For streaming AI responses
and multi-provider support
<strong>Vercel AI SDK</strong>
{t.parenOpen}
<code>ai</code> + <code>@ai-sdk/*</code>
{t.parenClose}
{t.colon}
{t.tech.aiSdk}
</li>
<li>
<strong>draw.io</strong>: The editor, bundled with
the app so it can be driven directly
<strong>draw.io</strong>
{t.colon}
{t.tech.drawio}
</li>
</ul>
<p className="text-gray-700 mt-4">
Diagrams are represented as XML that can be rendered in
draw.io. The AI processes your commands and generates or
modifies this XML accordingly.
</p>
<p className="text-gray-700 mt-4">{t.howOutro}</p>
{/* Multi-Provider Support */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
Multi-Provider Support
{t.providersHeading}
</h2>
<ul className="list-disc pl-6 text-gray-700 space-y-1">
<li>ByteDance Doubao</li>
<li>AWS Bedrock (default)</li>
<li>{t.doubao}</li>
<li>{t.bedrock}</li>
<li>
OpenAI / OpenAI-compatible APIs (via{" "}
<code>OPENAI_BASE_URL</code>)
{t.openai.before}
<code>OPENAI_BASE_URL</code>
{t.openai.after}
</li>
<li>Anthropic</li>
<li>Google AI</li>
@@ -303,48 +602,47 @@ export default function About() {
<li>ModelScope</li>
</ul>
<p className="text-gray-700 mt-4">
Note that <code>claude-sonnet-4-5</code> has trained on
draw.io diagrams with AWS logos, so if you want to
create AWS architecture diagrams, this is the best
choice.
{t.modelNote.before}
<code>claude-sonnet-4-5</code>
{t.modelNote.after}
</p>
{/* Support */}
<h2 className="text-2xl font-semibold text-gray-900 mt-10 mb-4">
Support &amp; Contact
{t.supportHeading}
</h2>
<p className="text-gray-700">
If you find this project useful, please consider{" "}
{t.sponsor.before}{" "}
<a
href="https://github.com/sponsors/DayuanJiang"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:underline"
>
sponsoring
{t.sponsor.link}
</a>{" "}
to help host the live demo site!
{t.sponsor.after}
</p>
<p className="text-gray-700 mt-2">
For support or inquiries, please open an issue on the{" "}
{t.contact.before}{" "}
<a
href="https://github.com/DayuanJiang/next-ai-draw-io"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:underline"
>
GitHub repository
{t.contact.link}
</a>{" "}
or contact: me[at]jiang.jp
{t.contact.after}
</p>
{/* CTA */}
<div className="mt-12 text-center">
<Link
href="/"
href={`/${lang}`}
className="inline-block bg-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:bg-blue-700 transition-colors"
>
Open Editor
{t.openEditor}
</Link>
</div>
</article>
@@ -354,8 +652,7 @@ export default function About() {
<footer className="bg-white border-t border-gray-200 mt-16">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<p className="text-center text-gray-600 text-sm">
Next AI Draw.io - Open Source AI-Powered Diagram
Generator
{t.footer}
</p>
</div>
</footer>
+13 -16
View File
@@ -40,6 +40,13 @@ export async function generateStaticParams() {
return i18n.locales.map((locale) => ({ lang: locale }))
}
const OG_LOCALE: Record<Locale, string> = {
en: "en_US",
zh: "zh_CN",
ja: "ja_JP",
"zh-Hant": "zh_HK",
}
// Generate metadata per locale
export async function generateMetadata({
params,
@@ -47,22 +54,19 @@ export async function generateMetadata({
params: Promise<{ lang: string }>
}): Promise<Metadata> {
const { lang: rawLang } = await params
const lang = (
rawLang in { en: 1, zh: 1, ja: 1, "zh-Hant": 1 } ? rawLang : "en"
) as Locale
const lang: Locale = hasLocale(rawLang) ? rawLang : i18n.defaultLocale
// Default to English metadata
const titles: Record<Locale, string> = {
en: "Next AI Draw.io - AI-Powered Diagram Generator",
zh: "Next AI Draw.io - AI powered diagram generator",
ja: "Next AI Draw.io - AI-powered diagram generator",
zh: "Next AI Draw.io - AI 驱动的图表生成器",
ja: "Next AI Draw.io - AI 搭載ダイアグラム生成ツール",
"zh-Hant": "Next AI Draw.io - AI 驅動的圖表產生器",
}
const descriptions: Record<Locale, string> = {
en: "Create AWS architecture diagrams, flowcharts, and technical diagrams using AI. Free online tool integrating draw.io with AI assistance for professional diagram creation.",
zh: "Use AI to create AWS architecture diagrams, flowcharts, and technical diagrams. Free online tool integrated with draw.io and AI assistance for professional diagram creation.",
ja: "Create AWS architecture diagrams, flowcharts, and technical diagrams using AI. Create professional diagrams with a free online tool that integrates draw.io with an AI assistant.",
zh: "使用 AI 创建 AWS 架构图、流程图和技术图表。免费在线工具,整合 draw.io 与 AI 辅助,轻松创建专业图表。",
ja: "AI で AWS アーキテクチャ図、フローチャート、技術図を作成。draw.io と AI アシスタントを統合した無料オンラインツールで、プロ品質の図を簡単に作成できます。",
"zh-Hant":
"使用 AI 建立 AWS 架構圖、流程圖和技術圖表。免費線上工具整合 draw.io 與 AI 輔助,輕鬆建立專業圖表。",
}
@@ -91,14 +95,7 @@ export async function generateMetadata({
type: "website",
url: "https://next-ai-drawio.jiang.jp",
siteName: "Next AI Draw.io",
locale:
lang === "zh"
? "zh_CN"
: lang === "zh-Hant"
? "zh_HK"
: lang === "ja"
? "ja_JP"
: "en_US",
locale: OG_LOCALE[lang],
images: [
{
url: "/architecture.png",
+13
View File
@@ -0,0 +1,13 @@
// GitHub mark as an inline SVG, so no icon package is needed for one icon
export function GitHubIcon({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 16 16"
fill="currentColor"
aria-hidden="true"
className={className}
>
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" />
</svg>
)
}
+6 -12
View File
@@ -2,7 +2,7 @@
import { Coffee, Settings, X } from "lucide-react"
import type React from "react"
import { FaGithub } from "react-icons/fa"
import { GitHubIcon } from "@/components/icons/github"
import { useDictionary } from "@/hooks/use-dictionary"
import { formatMessage } from "@/lib/i18n/utils"
@@ -28,16 +28,10 @@ export function QuotaLimitToast({
n >= 1000 ? `${(n / 1000).toFixed(1)}k` : n.toString()
const quotaMessage = isTokenLimit
? isSelfHosted
? (dict.quota.messageTokenSelfHosted ?? dict.quota.messageToken)
: dict.quota.messageToken
: isSelfHosted
? (dict.quota.messageApiSelfHosted ?? dict.quota.messageApi)
: dict.quota.messageApi
? dict.quota.messageToken
: dict.quota.messageApi
const tipHtml = isSelfHosted
? (dict.quota.tipSelfHosted ?? dict.quota.tip)
: dict.quota.tip
const tipHtml = isSelfHosted ? dict.quota.tipSelfHosted : dict.quota.tip
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === "Escape") {
@@ -52,7 +46,7 @@ export function QuotaLimitToast({
aria-live="polite"
tabIndex={0}
onKeyDown={handleKeyDown}
className="relative w-[400px] overflow-hidden rounded-xl border border-border/50 bg-card p-5 shadow-soft animate-message-in"
className="relative w-[400px] overflow-hidden rounded-xl border border-border/50 bg-card p-5 shadow-float animate-message-in"
>
{/* Close button */}
<button
@@ -115,7 +109,7 @@ export function QuotaLimitToast({
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-lg border border-border text-foreground hover:bg-muted transition-colors"
>
<FaGithub className="w-3.5 h-3.5" />
<GitHubIcon className="w-3.5 h-3.5" />
{dict.quota.selfHost}
</a>
<a
+3 -3
View File
@@ -1,5 +1,4 @@
import {
Github,
Info,
Monitor,
Moon,
@@ -13,6 +12,7 @@ import { usePathname, useRouter, useSearchParams } from "next/navigation"
import { useEffect, useState } from "react"
import { toast } from "sonner"
import { useChatEngine } from "@/components/chat/chat-engine"
import { GitHubIcon } from "@/components/icons/github"
import { ModelConfigDialog } from "@/components/model-config-dialog"
import { SettingsHeader } from "@/components/settings/settings-header"
import { Button } from "@/components/ui/button"
@@ -510,7 +510,7 @@ function AboutTab() {
const lang = pathname.split("/").filter(Boolean)[0] || i18n.defaultLocale
const showAbout = process.env.NEXT_PUBLIC_SHOW_ABOUT_AND_NOTICE === "true"
const isSelfHosted = process.env.NEXT_PUBLIC_SELFHOSTED === "true"
const aboutPath = `/${lang}/about${lang === "zh" ? "/cn" : lang === "ja" ? "/ja" : ""}`
const aboutPath = `/${lang}/about`
return (
<div className="space-y-5">
@@ -553,7 +553,7 @@ function AboutTab() {
rel="noopener noreferrer"
className="inline-flex h-8 items-center gap-1.5 rounded-lg border border-border px-3 text-xs text-muted-foreground hover:text-foreground"
>
<Github className="size-3.5" />
<GitHubIcon className="size-3.5" />
GitHub
</a>
{showAbout && (
+8 -38
View File
@@ -68,47 +68,15 @@ cp env.example .env.local
## 第三步 — 选择部署类型
### 选项 A:不使用 R2 部署(简单,免费)
### 选项 A:不使用 R2 部署(默认,免费)
如果您不需要 ISR 缓存,可以选择不使用 R2 进行部署:
**1. 使用简单的 `open-next.config.ts`:**
```ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare/config"
export default defineCloudflareConfig({})
```
**2. 使用简单的 `wrangler.jsonc`(不包含 r2_buckets):**
```jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"main": ".open-next/worker.js",
"name": "next-ai-draw-io-worker",
"compatibility_date": "2025-12-08",
"compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
"assets": {
"directory": ".open-next/assets",
"binding": "ASSETS"
},
"services": [
{
"binding": "WORKER_SELF_REFERENCE",
"service": "next-ai-draw-io-worker"
}
]
}
```
直接跳至 **第四步**。
仓库自带的就是这套配置:`open-next.config.ts` 为 `defineCloudflareConfig({})`,`wrangler.jsonc` 中没有 `r2_buckets`。无需改动任何文件,直接跳至 **第四步**。
---
### 选项 B:使用 R2 部署(完整的 ISR 支持)
### 选项 B:使用 R2 部署(可选,用于 ISR 缓存)
R2 开启了 **增量静态再生 (ISR)** 缓存功能。需要在您的 Cloudflare 账户中绑定支付方式。
R2 为 OpenNext 提供存放 **增量静态再生 (ISR)** 页面的空间。本应用目前没有 ISR 页面,只有在您自己添加了此类页面时才需要这一步。需要在您的 Cloudflare 账户中绑定支付方式。
**1. 在 Cloudflare 控制台中创建 R2 存储桶:**
@@ -127,7 +95,7 @@ export default defineCloudflareConfig({
})
```
**3. 配置 `wrangler.jsonc`(包含 R2):**
**3. 在 `wrangler.jsonc` 中加入 `r2_buckets`:**
```jsonc
{
@@ -157,6 +125,8 @@ export default defineCloudflareConfig({
> **重要提示:** `bucket_name` 必须与您在 Cloudflare 控制台中创建的名称完全一致。
> **注意:** 定时重新验证(页面或 fetch 上的 `revalidate`)还需要在 `open-next.config.ts` 中配置 `queue`,请参阅 OpenNext 的 Cloudflare 缓存文档。
---
## 第四步 — 注册 workers.dev 子域名(仅首次需要)
@@ -264,4 +234,4 @@ npm run preview
| API 路由 | 支持 | 支持 |
| 配置复杂度 | 简单 | 中等 |
测试或简单应用请选择 **不使用 R2**。需要 ISR 缓存的生产环境应用请选择 **使用 R2**。
仓库默认 **不使用 R2**。只有当您添加了需要 ISR 缓存的页面时,才选择 **使用 R2**。
+8 -38
View File
@@ -68,47 +68,15 @@ Fill in the same values there.
## Step 3 — Choose your deployment type
### Option A: Deploy WITHOUT R2 (Simple, Free)
### Option A: Deploy WITHOUT R2 (Default, Free)
If you don't need ISR caching, you can deploy without R2:
**1. Use simple `open-next.config.ts`:**
```ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare/config"
export default defineCloudflareConfig({})
```
**2. Use simple `wrangler.jsonc` (without r2_buckets):**
```jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"main": ".open-next/worker.js",
"name": "next-ai-draw-io-worker",
"compatibility_date": "2025-12-08",
"compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
"assets": {
"directory": ".open-next/assets",
"binding": "ASSETS"
},
"services": [
{
"binding": "WORKER_SELF_REFERENCE",
"service": "next-ai-draw-io-worker"
}
]
}
```
Skip to **Step 4**.
This is how the repository is configured: `open-next.config.ts` is `defineCloudflareConfig({})` and `wrangler.jsonc` has no `r2_buckets`. Nothing to change here. Skip to **Step 4**.
---
### Option B: Deploy WITH R2 (Full ISR Support)
### Option B: Deploy WITH R2 (Optional, ISR caching)
R2 enables **Incremental Static Regeneration (ISR)** caching. Requires a payment method on your Cloudflare account.
R2 gives OpenNext a place to store **Incremental Static Regeneration (ISR)** pages. This app currently has no ISR pages, so you only need this step if you add some. Requires a payment method on your Cloudflare account.
**1. Create an R2 bucket** in the Cloudflare Dashboard:
@@ -127,7 +95,7 @@ export default defineCloudflareConfig({
})
```
**3. Configure `wrangler.jsonc` (with R2):**
**3. Add `r2_buckets` to `wrangler.jsonc`:**
```jsonc
{
@@ -157,6 +125,8 @@ export default defineCloudflareConfig({
> **Important:** The `bucket_name` must exactly match the name you created in the Cloudflare dashboard.
> **Note:** Time-based revalidation (`revalidate` on a page or fetch) also needs a `queue` in `open-next.config.ts`. See the OpenNext Cloudflare caching docs.
---
## Step 4 — Register a workers.dev subdomain (first-time only)
@@ -264,4 +234,4 @@ npm run preview
| API Routes | Yes | Yes |
| Setup Complexity | Simple | Moderate |
Choose **without R2** for testing or simple apps. Choose **with R2** for production apps that need ISR caching.
The repository defaults to **without R2**. Choose **with R2** only if you add pages that need ISR caching.
+8 -38
View File
@@ -68,47 +68,15 @@ cp env.example .env.local
## ステップ 3 — デプロイタイプの選択
### オプション A: R2 なしでのデプロイ(シンプル、無料)
### オプション A: R2 なしでのデプロイ(デフォルト、無料)
ISR キャッシュが不要な場合は、R2 なしでデプロイできます:
**1. シンプルな `open-next.config.ts` を使用:**
```ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare/config"
export default defineCloudflareConfig({})
```
**2. シンプルな `wrangler.jsonc` を使用(r2_buckets なし):**
```jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"main": ".open-next/worker.js",
"name": "next-ai-draw-io-worker",
"compatibility_date": "2025-12-08",
"compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
"assets": {
"directory": ".open-next/assets",
"binding": "ASSETS"
},
"services": [
{
"binding": "WORKER_SELF_REFERENCE",
"service": "next-ai-draw-io-worker"
}
]
}
```
**ステップ 4** へ進んでください。
リポジトリはこの構成のままです。`open-next.config.ts` は `defineCloudflareConfig({})` で、`wrangler.jsonc` に `r2_buckets` はありません。ファイルを変更する必要はないので、**ステップ 4** へ進んでください。
---
### オプション B: R2 ありでのデプロイ(完全な ISR サポート)
### オプション B: R2 ありでのデプロイ(オプション、ISR キャッシュ用)
R2 を使用すると **Incremental Static Regeneration (ISR)** キャッシュが有効になります。これには Cloudflare アカウントに支払い方法の登録が必要です。
R2 は OpenNext が **Incremental Static Regeneration (ISR)** ページを保存する場所になります。このアプリには現在 ISR ページがないため、自分で ISR ページを追加した場合にだけ必要です。Cloudflare アカウントに支払い方法の登録が必要です。
**1. R2 バケットの作成**(Cloudflare ダッシュボードにて):
@@ -127,7 +95,7 @@ export default defineCloudflareConfig({
})
```
**3. `wrangler.jsonc` の設定(R2 あり):**
**3. `wrangler.jsonc` に `r2_buckets` を追加:**
```jsonc
{
@@ -157,6 +125,8 @@ export default defineCloudflareConfig({
> **重要:** `bucket_name` は Cloudflare ダッシュボードで作成した名前と完全に一致させる必要があります。
> **注意:** 時間ベースの再検証(ページや fetch の `revalidate`)には、`open-next.config.ts` で `queue` の設定も必要です。OpenNext の Cloudflare キャッシュドキュメントを参照してください。
---
## ステップ 4 — workers.dev サブドメインの登録(初回のみ)
@@ -264,4 +234,4 @@ npm run preview
| API ルート | あり | あり |
| 設定の複雑さ | シンプル | 普通 |
テストやシンプルなアプリには **R2 なし** を選んでください。ISR キャッシュが必要な本番アプリには **R2 あり** を選んでください。
リポジトリのデフォルトは **R2 なし** です。ISR キャッシュが必要なページを追加した場合にだけ **R2 あり** を選んでください。
+15 -10
View File
@@ -16,16 +16,21 @@ const nextConfig: NextConfig = {
"*": ["./instrumentation.ts"],
"/api/chat": ["./docs/shape-libraries/*.md"],
},
// The Chinese and Japanese About pages used to be separate routes
async redirects() {
return [
{
source: "/:lang/about/cn",
destination: "/zh/about",
permanent: true,
},
{
source: "/:lang/about/ja",
destination: "/ja/about",
permanent: true,
},
]
},
}
export default nextConfig
// Initialize OpenNext Cloudflare for local development only
// This must be a dynamic import to avoid loading workerd binary during builds
if (process.env.NODE_ENV === "development") {
import("@opennextjs/cloudflare").then(
({ initOpenNextCloudflareForDev }) => {
initOpenNextCloudflareForDev()
},
)
}
+1 -5
View File
@@ -1,7 +1,3 @@
// default open-next.config.ts file created by @opennextjs/cloudflare
import { defineCloudflareConfig } from "@opennextjs/cloudflare/config"
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache"
export default defineCloudflareConfig({
incrementalCache: r2IncrementalCache,
})
export default defineCloudflareConfig({})
+1 -3
View File
@@ -17,7 +17,6 @@
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
"upload": "opennextjs-cloudflare build && opennextjs-cloudflare upload",
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts",
"electron:dev": "node scripts/electron-dev.mjs",
"electron:build": "npm run build && npm run electron:compile",
"electron:compile": "npx esbuild electron/main/index.ts electron/preload/index.ts --bundle --platform=node --outdir=dist-electron --external:electron --sourcemap",
@@ -51,7 +50,6 @@
"@langfuse/otel": "^4.4.4",
"@langfuse/tracing": "^4.4.9",
"@next/third-parties": "^16.0.6",
"@opennextjs/cloudflare": "^1.17.1",
"@openrouter/ai-sdk-provider": "^2.10.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.222.0",
@@ -83,7 +81,6 @@
"prism-react-renderer": "^2.4.1",
"react": "^19.1.2",
"react-dom": "^19.1.2",
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"saxes": "^6.0.0",
"server-only": "^0.0.1",
@@ -108,6 +105,7 @@
},
"devDependencies": {
"@biomejs/biome": "2.5.15",
"@opennextjs/cloudflare": "^1.17.1",
"@playwright/test": "^1.57.0",
"@tailwindcss/postcss": "^4",
"@tailwindcss/typography": "^0.5.19",
-6
View File
@@ -8,12 +8,6 @@
"directory": ".open-next/assets",
"binding": "ASSETS"
},
"r2_buckets": [
{
"binding": "NEXT_INC_CACHE_R2_BUCKET",
"bucket_name": "next-inc-cache"
}
],
"services": [
{
"binding": "WORKER_SELF_REFERENCE",