← back to Dw Activation Debug TK11314

scripts/diagnose-vision-project.js

42 lines

#!/usr/bin/env node
'use strict';
// Existing Google Cloud credentials; metadata and quota reads only. No generation,
// credential writes, billing changes, quota changes, or full keys in output.
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { execFileSync } = require('node:child_process');
const { redact } = require('../lib/vision-http');
const account = process.argv[2];
if (!account) throw new Error('Usage: diagnose-vision-project.js <existing-gcloud-account>');
const env = fs.readFileSync(path.join(os.homedir(), 'Projects/secrets-manager/.env'), 'utf8');
const aliases = ['GEMINI_API_KEY', 'GEMINI_API_KEY_WALLCO'];
const keys = aliases.map(alias => (env.match(new RegExp(`^${alias}=(.*)$`, 'm')) || [])[1]?.trim().replace(/^['"]|['"]$/g, ''));
async function main() {
  const token = execFileSync('gcloud', ['auth', 'print-access-token', `--account=${account}`], { encoding: 'utf8', stdio: ['ignore','pipe','pipe'] }).trim();
  async function read(url) {
    const response = await fetch(url, { headers: { Authorization: `Bearer ${token}` }, signal: AbortSignal.timeout(30000) });
    return { http: response.status, data: await response.json() };
  }
  for (let i = 0; i < keys.length; i++) {
    if (!keys[i]) { console.log(JSON.stringify({ alias: aliases[i], missing: true })); continue; }
    const modelResponse = await fetch('https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash', {
      headers: { 'x-goog-api-key': keys[i] }, signal: AbortSignal.timeout(30000),
    });
    const model = await modelResponse.json();
    console.log(JSON.stringify({ alias: aliases[i], nonbillable_model_lookup_http: modelResponse.status,
      model: model.name || null, error: redact(model.error?.message, keys) }));
    const lookup = await read(`https://apikeys.googleapis.com/v2/keys:lookupKey?keyString=${encodeURIComponent(keys[i])}`);
    if (lookup.http !== 200) { console.log(JSON.stringify({ alias: aliases[i], http: lookup.http, error: redact(lookup.data.error?.message, keys) })); continue; }
    const parent = lookup.data.parent;
    const project = parent?.match(/^projects\/(\d+)/)?.[1];
    const info = await read(`https://cloudresourcemanager.googleapis.com/v1/projects/${project}`);
    const quota = await read(`https://serviceusage.googleapis.com/v1beta1/projects/${project}/services/generativelanguage.googleapis.com/consumerQuotaMetrics?view=FULL`);
    const metrics = (quota.data.metrics || []).filter(metric => /generate|content|spend|bill/i.test(JSON.stringify(metric)));
    console.log(JSON.stringify({ alias: aliases[i], projectNumber: project, projectId: info.data.projectId,
      projectName: info.data.name, metadataHttp: info.http, quotaHttp: quota.http,
      quotaError: redact(quota.data.error?.message, keys), metrics }));
  }
}
main().catch(error => { console.error(redact(error.message, keys)); process.exitCode = 1; });