Ka Pa Lik.
← all writing

2024.06.12

A Node.js Wrapper for the Gemini API.

Building a clean abstraction over Google's Gemini API before the official SDK existed.

GeminiNode.jsLLMAPI

Before Google released the official @google/generative-ai Node SDK, I built a lightweight wrapper for a news aggregation project. The core insight: Gemini's REST API is clean enough that you don't need much abstraction.

Minimal wrapper

const BASE = 'https://generativelanguage.googleapis.com/v1beta';

async function generate(prompt, { model = 'gemini-pro', temp = 0.7 } = {}) {
  const res = await fetch(
    `${BASE}/models/${model}:generateContent?key=${process.env.GEMINI_KEY}`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        contents: [{ parts: [{ text: prompt }] }],
        generationConfig: { temperature: temp },
      }),
    }
  );
  const data = await res.json();
  return data.candidates?.[0]?.content?.parts?.[0]?.text ?? null;
}

What I used it for

  • Summarizing Nepali and English news articles into 3-sentence briefs
  • Tagging articles by topic (Politics, Tech, Sports) for the aggregator
  • Generating search-optimized titles from raw article text
  • Detecting near-duplicate stories across sources

Rate limiting and retries

async function generateWithRetry(prompt, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try { return await generate(prompt); }
    catch (err) {
      if (err.status === 429) await sleep(1000 * 2 ** i);
      else throw err;
    }
  }
}

The official SDK is now the right call for new projects. But rolling your own for a week taught me the shape of the API better than any documentation would have. Worth doing once.

Always stream for long outputs — buffering 2000-token responses adds visible latency.

Building a Nepali Text-to-Speech APIBuilding HOWL, a voice agent for the G1