github-actions[bot]
deploy from github actions 2026-06-18
c8ae75d
Raw
History Blame Contribute Delete
5.4 kB
"use server";
import { NextResponse } from "next/server";
import { exec } from "child_process";
import { promisify } from "util";
import fs from "fs/promises";
import path from "path";
import os from "os";
const execAsync = promisify(exec);
const PROVIDER_NAME = "9router";
const getDeepSeekDir = () => path.join(os.homedir(), ".deepseek");
const getDeepSeekConfigPath = () => path.join(getDeepSeekDir(), "config.toml");
// Simple TOML parser for key = "value" and [section] patterns
const parseToml = (content) => {
const result = {};
let currentSection = result;
const lines = content.split(/\r?\n/);
for (const line of lines) {
const trimmed = line.trim();
// Skip empty lines and comments
if (!trimmed || trimmed.startsWith("#")) continue;
// Section header: [section] or [section.subsection]
const sectionMatch = trimmed.match(/^\[([^\]]+)\]$/);
if (sectionMatch) {
const sectionName = sectionMatch[1];
if (!result[sectionName]) result[sectionName] = {};
currentSection = result[sectionName];
continue;
}
// Key = "value" or key = value
const keyValueMatch = trimmed.match(/^(\w+)\s*=\s*"([^"]*)"$/);
if (keyValueMatch) {
currentSection[keyValueMatch[1]] = keyValueMatch[2];
continue;
}
// Key = value (unquoted)
const unquotedMatch = trimmed.match(/^(\w+)\s*=\s*(.+)$/);
if (unquotedMatch) {
currentSection[unquotedMatch[1]] = unquotedMatch[2].trim();
}
}
return result;
};
// Build TOML config for 9Router (openai provider mode)
const build9RouterConfig = (baseUrl, apiKey, model) => {
const normalizedBaseUrl = baseUrl.endsWith("/v1") ? baseUrl : `${baseUrl}/v1`;
return `provider = "openai"
[providers.openai]
base_url = "${normalizedBaseUrl}"
api_key = "${apiKey}"
model = "${model}"
`;
};
// Default DeepSeek config (reset state)
const DEFAULT_CONFIG = `provider = "deepseek"
`;
const checkDeepSeekInstalled = async () => {
try {
const isWindows = os.platform() === "win32";
const command = isWindows ? "where deepseek" : "which deepseek";
await execAsync(command, { windowsHide: true });
return true;
} catch {
try {
await fs.access(getDeepSeekConfigPath());
return true;
} catch {
return false;
}
}
};
const readConfigToml = async () => {
try {
return await fs.readFile(getDeepSeekConfigPath(), "utf-8");
} catch (error) {
if (error.code === "ENOENT") return "";
throw error;
}
};
// Detect 9Router by checking if provider is "openai" and base_url points to localhost/127.0.0.1
const has9RouterConfig = (config) => {
if (!config) return false;
const provider = config.provider;
if (provider !== "openai") return false;
const openaiSection = config["providers.openai"];
if (!openaiSection?.base_url) return false;
return /localhost|127\.0\.0\.1|0\.0\.0\.0/.test(openaiSection.base_url);
};
export async function GET() {
try {
const installed = await checkDeepSeekInstalled();
if (!installed) {
return NextResponse.json({ installed: false, settings: null, message: "DeepSeek TUI is not installed" });
}
const toml = await readConfigToml();
const config = parseToml(toml);
return NextResponse.json({
installed: true,
settings: config,
has9Router: has9RouterConfig(config),
configPath: getDeepSeekConfigPath(),
});
} catch (error) {
console.log("Error checking deepseek-tui settings:", error);
return NextResponse.json({ error: "Failed to check deepseek-tui settings" }, { status: 500 });
}
}
export async function POST(request) {
try {
const { baseUrl, apiKey, model } = await request.json();
if (!baseUrl || !model) {
return NextResponse.json({ error: "baseUrl and model are required" }, { status: 400 });
}
const dir = getDeepSeekDir();
await fs.mkdir(dir, { recursive: true });
const newConfig = build9RouterConfig(baseUrl, apiKey || "sk_9router", model);
await fs.writeFile(getDeepSeekConfigPath(), newConfig);
return NextResponse.json({
success: true,
message: "DeepSeek TUI settings applied successfully!",
configPath: getDeepSeekConfigPath(),
});
} catch (error) {
console.log("Error updating deepseek-tui settings:", error);
return NextResponse.json({ error: "Failed to update deepseek-tui settings" }, { status: 500 });
}
}
export async function DELETE() {
try {
const configPath = getDeepSeekConfigPath();
try {
await fs.access(configPath);
} catch {
return NextResponse.json({ success: true, message: "No config file to reset" });
}
await fs.writeFile(configPath, DEFAULT_CONFIG);
return NextResponse.json({ success: true, message: `${PROVIDER_NAME} config reset to DeepSeek defaults` });
} catch (error) {
console.log("Error resetting deepseek-tui settings:", error);
return NextResponse.json({ error: "Failed to reset deepseek-tui settings" }, { status: 500 });
}
}