> ## Documentation Index
> Fetch the complete documentation index at: https://docs.insforge.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 模型網關

> 使用 OpenAI SDK 和 InsForge 配置的 OpenRouter 密鑰構建 AI 功能

## 概述

InsForge 為模型網關項目配置了 OpenRouter API 密鑰。對於新的 AI 功能，請直接使用該密鑰與 OpenRouter 的 OpenAI 相容 API 一起使用，而不是已停用的 InsForge AI 代理方法。

使用 InsForge 儀表板複製活動的 OpenRouter 密鑰，將其儲存在 `OPENROUTER_API_KEY` 中，然後從受信任的伺服器端程式碼呼叫 OpenRouter。

<Warning>
  不要在瀏覽器套件中公開 `OPENROUTER_API_KEY`。在 React、Next.js、Vue、Svelte 和類似應用中，將 OpenRouter 呼叫放在後端路由、伺服器動作、函數或其他僅伺服器的邊界後面。
</Warning>

## 安裝

```bash theme={null}
npm install openai
```

對於本機指令碼，您可能還想要：

```bash theme={null}
npm install dotenv
```

## 環境

```bash theme={null}
OPENROUTER_API_KEY=<your-openrouter-api-key>
```

## 建立用戶端

```typescript theme={null}
import OpenAI from 'openai';

export const openai = new OpenAI({
  baseURL: 'https://openrouter.ai/api/v1',
  apiKey: process.env.OPENROUTER_API_KEY,
  defaultHeaders: {
    'HTTP-Referer': 'https://your-app.example',
    'X-Title': 'Your App',
  },
});
```

`HTTP-Referer` 和 `X-Title` 標頭是選用的 OpenRouter 中繼資料標頭。如果您想要 OpenRouter 歸屬和應用程式排名，請保留它們。

## 聊天完成

```typescript theme={null}
const completion = await openai.chat.completions.create({
  model: 'openai/gpt-4o',
  messages: [
    { role: 'system', content: 'You are a concise assistant.' },
    { role: 'user', content: 'What is the capital of France?' },
  ],
});

console.log(completion.choices[0]?.message?.content);
```

## 流式傳輸

```typescript theme={null}
const stream = await openai.chat.completions.create({
  model: 'anthropic/claude-3.5-haiku',
  messages: [{ role: 'user', content: 'Write a short product update.' }],
  stream: true,
});

for await (const chunk of stream) {
  const text = chunk.choices[0]?.delta?.content;
  if (text) process.stdout.write(text);
}
```

## 工具呼叫

```typescript theme={null}
const completion = await openai.chat.completions.create({
  model: 'openai/gpt-4o-mini',
  messages: [{ role: 'user', content: 'Look up order 123 and summarize it.' }],
  tools: [
    {
      type: 'function',
      function: {
        name: 'get_order',
        description: 'Fetch an order by ID',
        parameters: {
          type: 'object',
          properties: {
            orderId: { type: 'string' },
          },
          required: ['orderId'],
        },
      },
    },
  ],
});

console.log(completion.choices[0]?.message?.tool_calls);
```

## 圖像輸入

```typescript theme={null}
const completion = await openai.chat.completions.create({
  model: 'openai/gpt-4o',
  messages: [
    {
      role: 'user',
      content: [
        { type: 'text', text: 'Describe this image.' },
        {
          type: 'image_url',
          image_url: {
            url: 'https://example.com/photo.jpg',
          },
        },
      ],
    },
  ],
});

console.log(completion.choices[0]?.message?.content);
```

## 圖像生成

使用支援圖像輸出的模型並要求圖像形式。OpenRouter 支援 OpenAI SDK 類型表面中可能還沒有的欄位，所以在本機擴充請求和回應類型。

```typescript theme={null}
type OpenRouterImageRequest =
  OpenAI.Chat.ChatCompletionCreateParamsNonStreaming & {
    modalities?: Array<'image' | 'text'>;
  };

type OpenRouterImage = {
  type: 'image_url';
  image_url: {
    url: string;
  };
};

type OpenRouterImageMessage = OpenAI.Chat.ChatCompletionMessage & {
  images?: OpenRouterImage[];
};

const request: OpenRouterImageRequest = {
  model: 'google/gemini-2.5-flash-image',
  modalities: ['image', 'text'],
  messages: [
    { role: 'user', content: 'Generate a clean product mockup on a white background.' },
  ],
};

const completion = await openai.chat.completions.create(request);

const message = completion.choices[0]?.message as OpenRouterImageMessage | undefined;
console.log(message?.content);
console.log(message?.images?.[0]?.image_url?.url);
```

## 嵌入

```typescript theme={null}
const response = await openai.embeddings.create({
  model: 'openai/text-embedding-3-small',
  input: 'Your text here',
});

console.log(response.data[0].embedding);
```

## 視訊生成

OpenRouter 視訊生成直接使用 OpenRouter HTTP 端點。

```typescript theme={null}
const response = await fetch('https://openrouter.ai/api/v1/videos', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'google/veo-3.1',
    prompt: 'A golden retriever playing fetch on a sunny beach.',
  }),
});

if (!response.ok) {
  const body = await response.text();
  throw new Error(`OpenRouter video request failed: ${response.status} ${body}`);
}

const job = await response.json();
console.log(job);
```

## Next.js 路由範例

用您的應用的身分驗證提供者或工作階段驗證器取代 `verifySessionToken`。

```typescript theme={null}
// app/api/chat/route.ts
import OpenAI from 'openai';

const openai = new OpenAI({
  baseURL: 'https://openrouter.ai/api/v1',
  apiKey: process.env.OPENROUTER_API_KEY,
});

declare function verifySessionToken(token: string): Promise<boolean>;

export async function POST(request: Request) {
  const authorization = request.headers.get('Authorization');
  const sessionToken = authorization?.startsWith('Bearer ')
    ? authorization.slice('Bearer '.length)
    : undefined;

  if (!sessionToken || !(await verifySessionToken(sessionToken))) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const body = await request.json().catch(() => ({}));
  const prompt = typeof body.prompt === 'string' ? body.prompt.trim() : '';

  if (!prompt || prompt.length > 4000) {
    return Response.json(
      { error: 'Prompt must be between 1 and 4000 characters.' },
      { status: 400 }
    );
  }

  const completion = await openai.chat.completions.create({
    model: 'openai/gpt-4o-mini',
    messages: [{ role: 'user', content: prompt }],
  });

  return Response.json({
    text: completion.choices[0]?.message?.content ?? '',
  });
}
```

## 將 InsForge 資料與 AI 結合使用

使用 InsForge SDK 進行資料庫、身分驗證、儲存、函數和即時操作。直接使用 OpenRouter 進行模型呼叫。

```typescript theme={null}
import { createClient } from '@insforge/sdk';
import OpenAI from 'openai';

const insforge = createClient({
  baseUrl: process.env.INSFORGE_BASE_URL!,
  anonKey: process.env.INSFORGE_ANON_KEY!,
});

const openai = new OpenAI({
  baseURL: 'https://openrouter.ai/api/v1',
  apiKey: process.env.OPENROUTER_API_KEY,
});

const { data: documents } = await insforge.database
  .from('documents')
  .select()
  .limit(5);

const completion = await openai.chat.completions.create({
  model: 'openai/gpt-4o-mini',
  messages: [
    {
      role: 'user',
      content: `Summarize these records:\n${JSON.stringify(documents)}`,
    },
  ],
});

console.log(completion.choices[0]?.message?.content);
```

## 舊版 InsForge AI 代理

之前的 InsForge AI SDK 方法已停用：

* `insforge.ai.chat.completions.create()`
* `insforge.ai.images.generate()`
* `insforge.ai.embeddings.create()`

它們對應到仍然存在以實現相容性的後端代理路由，但新的整合應該直接使用 OpenRouter。直接路由提供了對 OpenRouter 完整和不斷演進的 API 表面的存取，無需等待 InsForge SDK 包裝函式更新。

## 模型目錄

使用 InsForge 儀表板或 OpenRouter 模型目錄來選擇模型。模型 ID 使用 `provider/model` 格式，如 `openai/gpt-4o`、`anthropic/claude-3.5-haiku` 和 `google/gemini-2.5-flash-image`。
