From 967d63c57e3d4372b4f0d734efaa4e1c914ce516 Mon Sep 17 00:00:00 2001 From: Dayuan Jiang <34411969+DayuanJiang@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:53:59 +0900 Subject: [PATCH] feat: support minimax model (#185) * feat: support minimax model with XML wrapping fix - Add wrapWithMxFile utility to properly wrap XML for draw.io - Fix 'Not a diagram file' error when model generates raw XML - Add supportsPromptCaching check for conditional caching - Only enable Bedrock prompt caching for Claude models * docs: update model mention to minimax-m2 across About pages and READMEs - Update tooltip in chat-panel.tsx to mention minimax-m2 model change - Update English, Chinese, and Japanese About pages with model change info - Update English, Chinese, and Japanese READMEs with demo site model note --------- Co-authored-by: dayuan.jiang --- README.md | 2 +- app/about/cn/page.tsx | 11 +++++++++-- app/about/ja/page.tsx | 12 ++++++++++-- app/about/page.tsx | 12 ++++++++++-- app/api/chat/route.ts | 26 ++++++++++++++++++-------- components/chat-panel.tsx | 9 ++++++--- docs/README_CN.md | 2 ++ docs/README_JA.md | 2 ++ lib/ai-providers.ts | 14 ++++++++++++++ lib/utils.ts | 26 ++++++++++++++++++++++++++ 10 files changed, 98 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 21e40db..7322875 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ No installation needed! Try the app directly on our demo site: [![Live Demo](./public/live-demo-button.svg)](https://next-ai-drawio.jiang.jp/) -> Note: Due to high traffic, the demo site currently uses Claude Haiku 4.5. For best results, we recommend self-hosting with Claude Opus 4.5. +> Note: Due to high traffic, the demo site currently uses minimax-m2. For best results, we recommend self-hosting with Claude Sonnet 4.5 or Claude Opus 4.5. ### Run with Docker (Recommended) diff --git a/app/about/cn/page.tsx b/app/about/cn/page.tsx index 3339436..f2941e7 100644 --- a/app/about/cn/page.tsx +++ b/app/about/cn/page.tsx @@ -102,7 +102,7 @@ export default function AboutCN() { {/* Header */}

- 关于扩容与限制{" "} + 模型变更与用量限制{" "} (或者说:我的钱包顶不住了) @@ -116,13 +116,20 @@ export default function AboutCN() { AI 接口的频率限制 (TPS/TPM)。一旦超限,系统就会暂停,导致请求失败。

+

+ 由于使用量过高,我已将模型从 Claude 更换为{" "} + + minimax-m2 + + ,以降低成本。 +

作为一个 独立开发者 ,目前的 API - 费用全是我自己在掏腰包(纯属为爱发电)。为了保证服务能细水长流,同时也为了避免我个人陷入财务危机,我不得不设置以下临时用量限制: + 费用全是我自己在掏腰包(纯属为爱发电)。为了保证服务能细水长流,同时也为了避免我个人陷入财务危机,我还设置了以下临时用量限制:

diff --git a/app/about/ja/page.tsx b/app/about/ja/page.tsx index 3b6d70d..f4ef4a1 100644 --- a/app/about/ja/page.tsx +++ b/app/about/ja/page.tsx @@ -110,7 +110,7 @@ export default function AboutJA() { {/* Header */}

- 利用制限とスケーリングについて{" "} + モデル変更と利用制限について{" "} (別名:お財布が悲鳴を上げています) @@ -124,13 +124,21 @@ export default function AboutJA() { AI API のレート制限 (TPS/TPM) に頻繁に引っかかってしまっています。制限に達するとシステムが一時停止し、エラーが発生してしまいます。

+

+ 利用量の増加に伴い、コスト削減のためモデルを + Claude から{" "} + + minimax-m2 + {" "} + に変更しました。 +

私は現在、 個人開発者 として API - 費用を全額自腹で負担しています。サービスを継続し、かつ私自身が借金を背負わないようにするため(笑)、一時的に以下の利用制限を設けさせていただきました。 + 費用を全額自腹で負担しています。サービスを継続し、かつ私自身が借金を背負わないようにするため(笑)、一時的に以下の利用制限も設けさせていただきました。

diff --git a/app/about/page.tsx b/app/about/page.tsx index 74fbf89..36080f4 100644 --- a/app/about/page.tsx +++ b/app/about/page.tsx @@ -110,7 +110,7 @@ export default function About() { {/* Header */}

- Usage Limits & Scaling{" "} + Model Change & Usage Limits{" "} (Or: Why My Wallet is Crying) @@ -127,6 +127,14 @@ export default function About() { (TPS/TPM). When this happens, the system pauses, leading to failed requests.

+

+ Due to the high usage, I have changed the + model from Claude to{" "} + + minimax-m2 + + , which is more cost-effective. +

As an{" "} @@ -135,7 +143,7 @@ export default function About() { , I am currently footing the entire API bill. To keep the lights on and ensure the service remains available to everyone - without sending me into debt, I have + without sending me into debt, I have also implemented the following temporary caps:

diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts index ff073cf..778ce9a 100644 --- a/app/api/chat/route.ts +++ b/app/api/chat/route.ts @@ -8,7 +8,7 @@ import { streamText, } from "ai" import { z } from "zod" -import { getAIModel } from "@/lib/ai-providers" +import { getAIModel, supportsPromptCaching } from "@/lib/ai-providers" import { findCachedResponse } from "@/lib/cached-responses" import { getTelemetryConfig, @@ -202,6 +202,12 @@ async function handleChatRequest(req: Request): Promise { // Get AI model from environment configuration const { model, providerOptions, headers, modelId } = getAIModel() + // Check if model supports prompt caching + const shouldCache = supportsPromptCaching(modelId) + console.log( + `[Prompt Caching] ${shouldCache ? "ENABLED" : "DISABLED"} for model: ${modelId}`, + ) + // Get the appropriate system prompt based on model (extended for Opus/Haiku 4.5) const systemMessage = getSystemPrompt(modelId) @@ -262,7 +268,7 @@ ${lastMessageText} // 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) { + if (shouldCache && 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") { @@ -287,17 +293,21 @@ ${lastMessageText} { role: "system" as const, content: systemMessage, - providerOptions: { - bedrock: { cachePoint: { type: "default" } }, - }, + ...(shouldCache && { + providerOptions: { + bedrock: { cachePoint: { type: "default" } }, + }, + }), }, // Cache breakpoint 2: Current diagram XML context { role: "system" as const, content: `Current diagram XML:\n"""xml\n${xml || ""}\n"""\nWhen using edit_diagram, COPY search patterns exactly from this XML - attribute order matters!`, - providerOptions: { - bedrock: { cachePoint: { type: "default" } }, - }, + ...(shouldCache && { + providerOptions: { + bedrock: { cachePoint: { type: "default" } }, + }, + }), }, ] diff --git a/components/chat-panel.tsx b/components/chat-panel.tsx index 7377c22..0cd83e8 100644 --- a/components/chat-panel.tsx +++ b/components/chat-panel.tsx @@ -40,7 +40,7 @@ const STORAGE_TPM_MINUTE_KEY = "next-ai-draw-io-tpm-minute" import { useDiagram } from "@/contexts/diagram-context" import { findCachedResponse } from "@/lib/cached-responses" -import { formatXML } from "@/lib/utils" +import { formatXML, wrapWithMxFile } from "@/lib/utils" import { ChatMessageDisplay } from "./chat-message-display" interface ChatPanelProps { @@ -340,8 +340,11 @@ export default function ChatPanel({ if (toolCall.toolName === "display_diagram") { const { xml } = toolCall.input as { xml: string } + // Wrap raw XML with full mxfile structure for draw.io + const fullXml = wrapWithMxFile(xml) + // loadDiagram validates and returns error if invalid - const validationError = onDisplayChart(xml) + const validationError = onDisplayChart(fullXml) if (validationError) { console.warn( @@ -1058,7 +1061,7 @@ Please retry with an adjusted search pattern or use display_diagram if retries a rel="noopener noreferrer" > 注意:由于访问量较大,演示站点目前使用 minimax-m2 模型。如需获得最佳效果,建议使用 Claude Sonnet 4.5 或 Claude Opus 4.5 自行部署。 + 一个集成了AI功能的Next.js网页应用,与draw.io图表无缝结合。通过自然语言命令和AI辅助可视化来创建、修改和增强图表。 diff --git a/docs/README_JA.md b/docs/README_JA.md index b82c549..ef35743 100644 --- a/docs/README_JA.md +++ b/docs/README_JA.md @@ -13,6 +13,8 @@ [🚀 ライブデモ](https://next-ai-drawio.jiang.jp/) +> 注意:アクセス数が多いため、デモサイトでは現在 minimax-m2 モデルを使用しています。最高の結果を得るには、Claude Sonnet 4.5 または Claude Opus 4.5 でのセルフホスティングをお勧めします。 + AI機能とdraw.ioダイアグラムを統合したNext.jsウェブアプリケーションです。自然言語コマンドとAI支援の可視化により、ダイアグラムを作成、修正、強化できます。 diff --git a/lib/ai-providers.ts b/lib/ai-providers.ts index 04778f4..8efd8e8 100644 --- a/lib/ai-providers.ts +++ b/lib/ai-providers.ts @@ -283,3 +283,17 @@ export function getAIModel(): ModelConfig { return { model, providerOptions, headers, modelId } } + +/** + * Check if a model supports prompt caching. + * Currently only Claude models on Bedrock support prompt caching. + */ +export function supportsPromptCaching(modelId: string): boolean { + // Bedrock prompt caching is supported for Claude models + return ( + modelId.includes("claude") || + modelId.includes("anthropic") || + modelId.startsWith("us.anthropic") || + modelId.startsWith("eu.anthropic") + ) +} diff --git a/lib/utils.ts b/lib/utils.ts index e179cd0..8c4d4eb 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -106,6 +106,32 @@ export function convertToLegalXml(xmlString: string): string { return result } +/** + * Wrap XML content with the full mxfile structure required by draw.io. + * Handles cases where XML is just , , or already has . + * @param xml - The XML string (may be partial or complete) + * @returns Full mxfile-wrapped XML string + */ +export function wrapWithMxFile(xml: string): string { + if (!xml) { + return `` + } + + // Already has full structure + if (xml.includes("${xml}` + } + + // Just content - extract inner content and wrap fully + const rootContent = xml.replace(/<\/?root>/g, "").trim() + return `${rootContent}` +} + /** * Replace nodes in a Draw.io XML diagram * @param currentXML - The original Draw.io XML string