An open API service indexing awesome lists of open source software.

https://github.com/nlink-jp/gem-transcribe

Audio transcription CLI built on Vertex AI Gemini — speaker name inference, multi-language output, structured JSON
https://github.com/nlink-jp/gem-transcribe

audio-transcription cli gemini multilingual python speaker-diarization srt subtitles vertex-ai webvtt

Last synced: 8 days ago
JSON representation

Audio transcription CLI built on Vertex AI Gemini — speaker name inference, multi-language output, structured JSON

Awesome Lists containing this project

README

          

# gem-transcribe

Vertex AI Gemini を活用した音声文字起こし CLI。話者推論、マルチランゲージ出力、構造化 JSON に対応します。

`gem-transcribe` は「文字起こし基盤」に特化した単機能ツールです。議事録の構造化、要約、アクションアイテム抽出は下流の
[meeting-note](https://github.com/nlink-jp/meeting-note) などに任せます。

## 主な機能

- **話者推論** — デフォルトで音声内の自己紹介・呼びかけ・第三者言及から話者の名前を抽出します。名前が特定できない話者は `Speaker A`, `Speaker B`, ... のラベルにフォールバック。`--speaker-hint="山田,佐藤"` を渡すと候補名を限定できます
- **マルチランゲージ出力** — `--lang=en,ja` のように指定すると、原文と翻訳を 1 回の API 呼び出しで同時生成
- **長尺音声対応** — ローカルファイルは GCS ステージングバケットに自動アップロードされ、処理後に削除されます。事前アップロード済みの `gs://` URI もそのまま受け付けます
- **複数の出力フォーマット** — デフォルトは stdout への JSON。`--format text|md|srt|vtt` で他形式に切り替え可能。SRT/VTT を `--output-file=meeting.srt --lang=en,ja` のように多言語指定すると `meeting.en.srt` と `meeting.ja.srt` が自動生成されます。`--output-dir` は `.json` と `.txt` の両方を一括出力
- **stderr への進捗表示** — アップロード開始・転記開始・所要時間など、節目ごとに1行ずつ stderr に出力。長時間の API 呼び出し中に「フリーズしているのか動いているのか」分からなくなるのを防ぎます。`--quiet` で抑制、`--verbose` で INFO レベルの詳細ログ

## インストール

```bash
uv tool install git+https://github.com/nlink-jp/gem-transcribe.git
# または、クローンから
uv sync --all-extras
```

Python 3.11+ が必要です。

## セットアップ

1. **GCS バケットの作成**(ステージング用):

```bash
gsutil mb -l us-central1 gs://your-bucket
```

2. **ADC(Application Default Credentials)の設定**:

```bash
gcloud auth application-default login
```

3. **設定ファイルの作成** — `~/.config/gem-transcribe/config.toml`
(テンプレートは `config.example.toml` 参照):

```toml
[gcp]
project = "your-gcp-project"
location = "us-central1"

[model]
name = "gemini-2.5-flash"

[storage]
staging_bucket = "gs://your-bucket/gem-transcribe/"
```

IAM プリンシパルには `roles/aiplatform.user` と、ステージングバケットへの `roles/storage.objectAdmin` が必要です。

## 使い方

```bash
# JSON を stdout に出力(デフォルト)
gem-transcribe meeting.mp3

# 多言語出力
gem-transcribe interview.m4a --lang=en,ja

# 話者名の割り当て
gem-transcribe meeting.mp3 --speaker-hint="山田,佐藤,田中"

# JSON とプレーンテキストの両方をディレクトリに出力
gem-transcribe meeting.mp3 --output-dir=./transcripts/

# Markdown タイムライン
gem-transcribe meeting.mp3 --format=md --output-file=meeting.md

# SRT 字幕
gem-transcribe meeting.mp3 --format=srt --output-file=meeting.srt

# 多言語 SRT — meeting.en.srt と meeting.ja.srt が生成される
gem-transcribe meeting.mp3 --lang=en,ja --format=srt --output-file=meeting.srt

# WebVTT 字幕( voice タグ付き)
gem-transcribe meeting.mp3 --format=vtt --output-file=meeting.vtt

# 事前アップロード済みの GCS 音声
gem-transcribe gs://your-bucket/recordings/2026-05-15.mp3
```

## 既知の制約

### タイムスタンプ精度

セグメントの `start` / `end` は Gemini が音声トークンから推定した値で、サンプル単位の正確なデコードに基づくものではありません。**おおまかな目印として扱い、同期精度が必要な用途には使用しないでください。**

- **長尺音声でドリフトが累積する。** 20分以上の連続音声を1回で転記すると、後半になるほどズレが大きくなる傾向があります。数分程度の音声であれば誤差は通常1〜2秒以内。
- **タイムスタンプが実際の音声長を超えることがある。** 実機検証で、25分の録音を `gemini-2.5-pro` で転記したところ、セグメントのタイムスタンプが30分超に達しました。`gemini-2.5-flash` でも `gemini-2.5-pro` でもこの現象は観測されており、モデル変更で確実には解決しません。
- **`end` が duration(相対秒数)として出力される既知の癖** が Gemini 2.5 にあります。orchestrator はこれを検出して `end = start + end` に書き換え、`--verbose` で警告ログを出します。

サンプル単位の精度が必要な場合(動画への字幕焼き込みなど)、これらのタイムスタンプを直接使用しないでください。下流パイプライン側での回避策(本ツールの責務外):

- `ffprobe` 等でローカルに実 duration を計測し、セグメントタイムスタンプをそれに合わせてクリップ/スケーリングする
- 音声を短いチャンクに分割してから転記し、各チャンクのタイムスタンプを再オフセットする(ドリフトをチャンク長以内に抑制)
- WhisperX 等のフォーストアライメントを別パスで実行し、出力テキストを元音声に再アラインする

### 壊れたセグメント(部分結果)

特に長尺録音で、モデルが構造的に壊れたセグメントを稀に出力します。レスポンス
スキーマで生成を制約して稀にしていますが、安全網として各セグメントを個別に
検証します:

- **既定(サルベージ):** 無効なセグメントはドロップし、件数(と概算位置)を
警告で報告し、**部分的な文字起こし**を返します。JSON 出力の
`metadata.dropped_segments` に件数を記録します。数秒を失う方が、数分の
文字起こしを丸ごと捨てるよりましです。
- **`--strict`:** ドロップが1件でもあれば実行全体を失敗させます(従来の
全か無かの挙動)。完全な文字起こしを必要とするパイプライン向け。
- 空の文字起こし(有効セグメント0件)は常にエラーです。

既定は `config.toml` の `[transcribe] strict = true|false` で設定し、実行ごとに
`--strict` / `--no-strict` で上書きできます(CLI が config より優先)。

## 設定の優先順位

高 → 低:

1. CLI フラグ
2. 環境変数(`GEM_TRANSCRIBE_*`)
3. `.env` ファイル
4. `~/.config/gem-transcribe/config.toml`
5. 組み込みデフォルト値

## ビルドとテスト

```bash
make test # uv run pytest tests/ -v
make lint # ruff check + format check
make build # uv build --out-dir dist/
```

## ドキュメント

- [docs/ja/gem-transcribe-rfp.ja.md](docs/ja/gem-transcribe-rfp.ja.md) — 設計 RFP
- [docs/en/gem-transcribe-rfp.md](docs/en/gem-transcribe-rfp.md) — design RFP

## ライセンス

MIT