From 4909a78acaf662ce4c6971902eaedf889ee2f101 Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 10 Jun 2026 10:58:37 -0600 Subject: [PATCH] stops import: swap OpenAI for MiniMax as default AI provider --- src/app/api/stops/import/route.ts | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/app/api/stops/import/route.ts b/src/app/api/stops/import/route.ts index 2b6600c..73eb9af 100644 --- a/src/app/api/stops/import/route.ts +++ b/src/app/api/stops/import/route.ts @@ -9,19 +9,25 @@ type RequestBody = { /** Raw file content (CSV text). AI parsing is attempted if useAI=true. */ text: string; brandId: string; - /** If true and OPENAI_API_KEY is set, parse unstructured text with AI. */ + /** If true and an AI API key is set, parse unstructured text with AI. */ useAI?: boolean; }; -const AI_MODEL = "gpt-4o-mini"; - -async function parseWithAI(text: string, brandId: string): Promise<{ +async function parseWithAI(text: string, _brandId: string): Promise<{ stops: ParsedStop[]; warnings: string[]; }> { - const apiKey = process.env.OPENAI_API_KEY; + // Prefer MiniMax (env-level) — fall back to OpenAI. + const provider: "minimax" | "openai" = + process.env.MINIMAX_API_KEY ? "minimax" : process.env.OPENAI_API_KEY ? "openai" : "openai"; + const apiKey = provider === "minimax" ? process.env.MINIMAX_API_KEY! : process.env.OPENAI_API_KEY!; + const baseURL = provider === "minimax" + ? (process.env.MINIMAX_BASE_URL || "https://api.minimax.io/v1") + : "https://api.openai.com/v1"; + const model = provider === "minimax" ? "MiniMax-M3" : "gpt-4o-mini"; + if (!apiKey) { - throw new Error("OPENAI_API_KEY is not configured. Use CSV format for reliable parsing."); + throw new Error("MINIMAX_API_KEY or OPENAI_API_KEY is not configured. Use CSV format for reliable parsing."); } const systemPrompt = `You are a schedule extraction assistant. Given raw schedule text, extract all stop entries. @@ -37,26 +43,27 @@ Return a JSON array where each entry has: If a row lacks required fields (city, state, location), omit it and add a warning.`; - const res = await fetch("https://api.openai.com/v1/chat/completions", { + const res = await fetch(`${baseURL}/chat/completions`, { method: "POST", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify({ - model: AI_MODEL, + model, messages: [ { role: "system", content: systemPrompt }, { role: "user", content: `Extract stops from this schedule:\n\n${text.slice(0, 8000)}` }, ], - response_format: { type: "json_object" }, + // response_format is OpenAI-specific. MiniMax /v1/chat/completions may not honor it. + ...(provider === "openai" ? { response_format: { type: "json_object" } } : {}), temperature: 0.1, }), }); if (!res.ok) { const err = await res.text(); - throw new Error(`OpenAI API error: ${res.status} — ${err}`); + throw new Error(`${provider} API error: ${res.status} — ${err}`); } const data = await res.json();