Skip to content

Instantly share code, notes, and snippets.

@bogdan
Created July 15, 2026 16:47
Show Gist options
  • Select an option

  • Save bogdan/2b97e76c50fc06ba61dbb49eb52b2dca to your computer and use it in GitHub Desktop.

Select an option

Save bogdan/2b97e76c50fc06ba61dbb49eb52b2dca to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# frozen_string_literal: true
# Speech-to-Text v2 diarization test (chirp_3 model, Japanese by default).
#
# KEY FINDING: chirp_3 + diarizationConfig only works in the "us" multi-region.
# It is rejected everywhere else tested (global, us-central1, europe-west4,
# asia-southeast1, europe-west3) with either "model does not exist" or
# "Permission denied ... It is no longer generally available." Only the
# "us" multi-region endpoint accepts it, and only via the async
# batch_recognize method (sync recognize never supports diarization, in
# v1 or v2, in any region).
#
# Usage:
# script/gcp_diarize_test.rb <path-to-audio-file> <gcs-bucket-name> [language-code]
#
# Example:
# script/gcp_diarize_test.rb ./recording.mp3 my-project-scratch-bucket ja-JP
#
# Auth: uses local Application Default Credentials.
# gcloud auth application-default login --project <PROJECT_ID>
#
# The GCS bucket must already exist in the same project you're calling the
# Speech API against (cross-project GCS reads commonly hit permission
# errors from the Speech service agent).
require "bundler/inline"
gemfile do
source "https://rubygems.org"
gem "google-cloud-speech-v2"
end
require "google/cloud/speech/v2"
require "open3"
require "json"
audio_file, bucket, language_code = ARGV
if audio_file.nil? || bucket.nil?
warn "Usage: #{$PROGRAM_NAME} <audio-file> <gcs-bucket> [language-code]"
exit 1
end
language_code ||= "ja-JP"
project = `gcloud config get-value project 2>/dev/null`.strip
raise "No active gcloud project. Run: gcloud config set project <PROJECT_ID>" if project.empty?
file_name = File.basename(audio_file)
gcs_audio_uri = "gs://#{bucket}/diarize-test/#{file_name}"
gcs_output_uri = "gs://#{bucket}/diarize-test/output/"
puts "Project: #{project}"
puts "Audio file: #{audio_file}"
puts "Language: #{language_code}"
puts "GCS audio URI: #{gcs_audio_uri}"
puts
puts "==> Uploading audio to GCS..."
system("gcloud", "storage", "cp", audio_file, gcs_audio_uri, "--project", project, exception: true)
client = Google::Cloud::Speech::V2::Speech::Client.new do |config|
config.endpoint = "us-speech.googleapis.com"
end
recognizer = "projects/#{project}/locations/us/recognizers/_"
request = {
recognizer: recognizer,
files: [ { uri: gcs_audio_uri } ],
config: {
auto_decoding_config: {},
model: "chirp_3",
language_codes: [ language_code ],
features: {
enable_automatic_punctuation: true,
enable_word_time_offsets: true,
diarization_config: {}
}
},
recognition_output_config: {
gcs_output_config: { uri: gcs_output_uri }
}
}
puts "==> Submitting batch_recognize (model=chirp_3, location=us)..."
operation = client.batch_recognize(request)
puts "==> Waiting for operation to complete..."
operation.wait_until_done!
raise "Operation failed: #{operation.results}" if operation.error?
result_uri = operation.response.results.values.first.uri
puts "==> Downloading transcript from #{result_uri}"
json_text, status = Open3.capture2("gcloud", "storage", "cat", result_uri, "--project", project)
raise "Failed to download transcript" unless status.success?
data = JSON.parse(json_text)
puts
puts "==================== DIARIZED TRANSCRIPT ===================="
data.fetch("results", []).each do |r|
alt = r.fetch("alternatives", []).first
next unless alt
words = alt.fetch("words", [])
next if words.empty?
current_speaker = nil
line = []
words.each do |w|
speaker = w["speakerLabel"]
if speaker != current_speaker
puts "Speaker #{current_speaker}: #{line.join}" unless line.empty?
current_speaker = speaker
line = []
end
line << w["word"]
end
puts "Speaker #{current_speaker}: #{line.join}" unless line.empty?
end
puts "================================================================"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment