| 1 | import { NextRequest, NextResponse } from 'next/server'; |
| 2 | import { generateText } from 'ai'; |
| 3 | import { glmModel } from '@/lib/glm'; |
| 4 | import { runSSH } from '@/lib/workers/ssh'; |
| 5 | import { setCap } from '@/lib/db'; |
| 6 | |
| 7 | export const runtime = 'nodejs'; |
| 8 | export const dynamic = 'force-dynamic'; |
| 9 | export const maxDuration = 120; |
| 10 | |
| 11 | const OLLAMA = process.env.ZPM_OLLAMA_URL || 'http://REDACTED-IP:11434'; |
| 12 | |
| 13 | async function pingModel(model: string): Promise<{ ok: boolean; latencyMs: number; detail: string }> { |
| 14 | const start = Date.now(); |
| 15 | try { |
| 16 | if (model === 'glm') { |
| 17 | const r = await generateText({ model: glmModel, prompt: 'Reply with exactly: OK' }); |
| 18 | return { ok: /ok/i.test(r.text), latencyMs: Date.now() - start, detail: r.text.trim().slice(0, 40) }; |
| 19 | } |
| 20 | if (model === 'claude') { |
| 21 | const r = await runSSH('REDACTED-IP', 'zion', 'echo ok', 15_000); |
| 22 | return { ok: r.stdout.trim() === 'ok', latencyMs: Date.now() - start, detail: 'CT215 reachable' }; |
| 23 | } |
| 24 | if (model === 'codex') { |
| 25 | const r = await runSSH('REDACTED-IP', 'zion', 'echo ok', 15_000); |
| 26 | return { ok: r.stdout.trim() === 'ok', latencyMs: Date.now() - start, detail: 'CT241 reachable' }; |
| 27 | } |
| 28 | if (model === 'ollama') { |
| 29 | const ctrl = new AbortController(); |
| 30 | const t = setTimeout(() => ctrl.abort(), 10_000); |
| 31 | const res = await fetch(`${OLLAMA}/api/tags`, { signal: ctrl.signal }); |
| 32 | clearTimeout(t); |
| 33 | return { ok: res.ok, latencyMs: Date.now() - start, detail: res.ok ? '3060 ollama up' : `http ${res.status}` }; |
| 34 | } |
| 35 | return { ok: false, latencyMs: 0, detail: 'unknown model' }; |
| 36 | } catch (e) { |
| 37 | return { ok: false, latencyMs: Date.now() - start, detail: (e as Error).message.slice(0, 80) }; |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | export async function POST(req: NextRequest) { |
| 42 | const { model } = await req.json(); |
| 43 | if (!model) return NextResponse.json({ error: 'model required' }, { status: 400 }); |
| 44 | const res = await pingModel(model); |
| 45 | if (model !== 'glm') setCap(model, res.ok ? 1 : 0, res.ok ? 'ping ok' : `ping fail: ${res.detail}`); |
| 46 | return NextResponse.json({ model, ...res }); |
| 47 | } |