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

# Gemini

# 一、环境变量

在部署环境中设置以下值，不要把密钥写入源代码：

```bash theme={null}
export BASE_URL='https://api.bytedance.mom'
export API_KEY='your-byte-api-key'
export GEMINI_MODEL='gemini-3.7-flash'
```

可以替换 `GEMINI_MODEL`来使用其他 Gemini 系列模型。

请求地址为：

```text theme={null}
POST ${BASE_URL}/v1beta/models/${GEMINI_MODEL}:generateContent
Authorization: Bearer ${API_KEY}
```

# 二、分意图请求说明

## 1、媒体视频识别

通过我们的原生 Gemini 路由，把完整 MP4 以 Base64 `inlineData` 发送给模型进行识别。

> Byte API 的该路由只支持 `inlineData`。不要使用 Google Gemini File API、`fileData.fileUri` 或把视频 URL 直接放入请求体。

### Python

依赖：`pip install requests`

```python theme={null}
import base64
import os
from pathlib import Path

import requests

video_path = Path("/path/to/source.mp4")
video_b64 = base64.b64encode(video_path.read_bytes()).decode("ascii")

base_url = os.environ["BASE_URL"].rstrip("/")
api_key = os.environ["API_KEY"]
model = os.getenv("GEMINI_MODEL", "gemini-3.7-flash")

payload = {
    "contents": [{
        "role": "user",
        "parts": [
            {
                "inlineData": {
                    "mimeType": "video/mp4",
                    "data": video_b64,
                }
            },
            {
                "text": "分析这条视频"
            },
        ],
    }]
}

response = requests.post(
    f"{base_url}/v1beta/models/{model}:generateContent",
    headers={
        "Content-Type": "application/json",
        "Authorization": f"Bearer {api_key}",
    },
    json=payload,
    # connect timeout, read timeout（视频理解通常比纯文本慢，超时时长尽量调高一些）
    timeout=(15, 300),
)
response.raise_for_status()

result = response.json()
print(result["candidates"][0]["content"]["parts"][0]["text"])
```

### Java（JDK 17+）

不需要额外 HTTP 依赖。`jsonString` 用于安全地将提示词写入 JSON；Base64 字符串本身无需再转义。

```java theme={null}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Base64;

public class GeminiVideoExample {
    private static String jsonString(String value) {
        return "\"" + value
                .replace("\\", "\\\\")
                .replace("\"", "\\\"")
                .replace("\n", "\\n")
                .replace("\r", "\\r")
                .replace("\t", "\\t") + "\"";
    }

    public static void main(String[] args) throws Exception {
        String baseUrl = System.getenv("BASE_URL").replaceAll("/+$", "");
        String apiKey = System.getenv("API_KEY");
        String model = System.getenv().getOrDefault("GEMINI_MODEL", "gemini-3.7-flash");

        byte[] videoBytes = Files.readAllBytes(Path.of("/path/to/source.mp4"));
        String videoBase64 = Base64.getEncoder().encodeToString(videoBytes);
        String prompt = "分析这条视频";

        String body = """
                {
                  "contents": [{
                    "role": "user",
                    "parts": [
                      {"inlineData": {"mimeType": "video/mp4", "data": "%s"}},
                      {"text": %s}
                    ]
                  }]
                }
                """.formatted(videoBase64, jsonString(prompt));

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(baseUrl + "/v1beta/models/" + model + ":generateContent"))
                .timeout(Duration.ofMinutes(5))
                .header("Content-Type", "application/json")
                .header("Authorization", "Bearer " + apiKey)
                .POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
                .build();

        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(15))
                .build();
        HttpResponse<String> response = client.send(
                request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));

        if (response.statusCode() / 100 != 2) {
            throw new IllegalStateException("New API error "
                    + response.statusCode() + ": " + response.body());
        }
        System.out.println(response.body());
    }
}
```

生产项目如已使用 Jackson、Gson 等 JSON 库，建议由该库构造请求体，避免手写 JSON。

### JavaScript（Node.js 18+）

Node.js 18 及以上已提供全局 `fetch`。

```js theme={null}
import { readFile } from "node:fs/promises";

const baseUrl = process.env.BASE_URL.replace(/\/+$/, "");
const apiKey = process.env.API_KEY;
const model = process.env.GEMINI_MODEL || "gemini-3.7-flash";

const video = await readFile("/path/to/source.mp4");
const videoBase64 = video.toString("base64");

const response = await fetch(
  `${baseUrl}/v1beta/models/${model}:generateContent`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${apiKey}`,
    },
    body: JSON.stringify({
      contents: [{
        role: "user",
        parts: [
          {
            inlineData: {
              mimeType: "video/mp4",
              data: videoBase64,
            },
          },
          { text: "分析这条视频" },
        ],
      }]
    }),
    signal: AbortSignal.timeout(300_000),
  },
);

if (!response.ok) {
  throw new Error(`New API error ${response.status}: ${await response.text()}`);
}

const result = await response.json();
console.log(result.candidates?.[0]?.content?.parts?.[0]?.text);
```

## 2、文本聊天

文本聊天与视频识别使用相同的 Gemini 原生端点。将系统提示词放在顶层 `systemInstruction`，将用户消息放在 `contents` 中即可；不需要 `inlineData`。

```text theme={null}
POST ${BASE_URL}/v1beta/models/${GEMINI_MODEL}:generateContent
Authorization: Bearer ${API_KEY}
```

以下示例中的系统提示词是“我是一个地理专家”，用户提问是“什么是丹霞地貌”。`generationConfig` 是可选项，不写时使用模型/网关的默认值。

### Python

依赖：`pip install requests`

```python theme={null}
import os

import requests

base_url = os.environ["BASE_URL"].rstrip("/")
api_key = os.environ["API_KEY"]
model = os.getenv("GEMINI_MODEL", "gemini-3.7-flash")

payload = {
    "systemInstruction": {
        "parts": [{"text": "我是一个地理专家"}]
    },
    "contents": [{
        "role": "user",
        "parts": [{"text": "什么是丹霞地貌"}],
    }],
}

response = requests.post(
    f"{base_url}/v1beta/models/{model}:generateContent",
    headers={
        "Content-Type": "application/json",
        "Authorization": f"Bearer {api_key}",
    },
    json=payload,
    timeout=(15, 90),
)
response.raise_for_status()

result = response.json()
print(result["candidates"][0]["content"]["parts"][0]["text"])
```

### Java（JDK 17+）

```java theme={null}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

public class GeminiTextChatExample {
    public static void main(String[] args) throws Exception {
        String baseUrl = System.getenv("BASE_URL").replaceAll("/+$", "");
        String apiKey = System.getenv("API_KEY");
        String model = System.getenv().getOrDefault("GEMINI_MODEL", "gemini-3.7-flash");

        String body = """
                {
                  "systemInstruction": {
                    "parts": [{"text": "我是一个地理专家"}]
                  },
                  "contents": [{
                    "role": "user",
                    "parts": [{"text": "什么是丹霞地貌"}]
                  }]
                }
                """;

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(baseUrl + "/v1beta/models/" + model + ":generateContent"))
                .timeout(Duration.ofSeconds(90))
                .header("Content-Type", "application/json")
                .header("Authorization", "Bearer " + apiKey)
                .POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
                .build();

        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(15))
                .build();
        HttpResponse<String> response = client.send(
                request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));

        if (response.statusCode() / 100 != 2) {
            throw new IllegalStateException("New API error "
                    + response.statusCode() + ": " + response.body());
        }
        System.out.println(response.body());
    }
}
```

### JavaScript（Node.js 18+）

```js theme={null}
const baseUrl = process.env.BASE_URL.replace(/\/+$/, "");
const apiKey = process.env.API_KEY;
const model = process.env.GEMINI_MODEL || "gemini-3.7-flash";

const response = await fetch(
  `${baseUrl}/v1beta/models/${model}:generateContent`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${apiKey}`,
    },
    body: JSON.stringify({
      systemInstruction: {
        parts: [{ text: "我是一个地理专家" }],
      },
      contents: [{
        role: "user",
        parts: [{ text: "什么是丹霞地貌" }],
      }],
    }),
    signal: AbortSignal.timeout(90_000),
  },
);

if (!response.ok) {
  throw new Error(`New API error ${response.status}: ${await response.text()}`);
}

const result = await response.json();
console.log(result.candidates?.[0]?.content?.parts?.[0]?.text);
```

## 生产配置要点

* 认证使用 `Authorization: Bearer <API_KEY>`。
* Base64 后的体积约为原视频的 `4 / 3`；例如 20 MB MP4 约为 26.7 MB，加上 JSON 包装后还会略增。请相应提高生产环境应用和反向代理的请求体大小限制。
* 为视频请求配置至少 300 秒的客户端读取超时与反向代理上游读取超时。不要复用面向普通文本聊天的短超时。
* 由于视频大小不确定，建议按示例代码来，不设置`maxOutputTokens`或设置足够的 `maxOutputTokens`。
