メインコンテンツへスキップ

開発者向け

HushscriptのSDKとCLI

TypeScript、Python、Go、PHP向けの公式ライブラリとコマンドラインツールです。録音ファイルを1回の呼び出しで文字起こし結果に変換します。

公式SDKは、サーバーコードやスクリプトから使えるようREST APIをラップしています。1回の呼び出しでファイルを文字起こしします。録音をアップロードし、ジョブの完了を待ち、文字起こし結果を返します。その間にSDKは、分数が確保される前にファイルを検査し、安全に再試行できる処理を再試行し、長いアップロードを維持し、すべてのアップロードと購入に冪等キーを付けるため、再試行しても二重に課金されることはありません。CLIはTypeScript SDKをベースにしており、ターミナルから同じ操作ができます。

パッケージ

言語 パッケージ レジストリ ソース
TypeScript @hushscript/sdk npm: www.npmjs.com/package/@hushscript/sdk github.com/Hushscript/hushscript-sdk-typescript
Python hushscript PyPI: pypi.org/project/hushscript github.com/Hushscript/hushscript-sdk-python
Go github.com/Hushscript/hushscript-sdk-go pkg.go.dev: pkg.go.dev/github.com/Hushscript/hushscript-sdk-go github.com/Hushscript/hushscript-sdk-go
PHP hushscript/sdk Packagist: packagist.org/packages/hushscript/sdk github.com/Hushscript/hushscript-sdk-php
CLI @hushscript/cli npm: www.npmjs.com/package/@hushscript/cli github.com/Hushscript/hushscript-cli

必要なランタイムのバージョン:

SDKはサーバーとスクリプト向けです。APIはブラウザのオリジンを受け付けません。ブラウザ向けバンドルにトークンを入れると、そのトークンが漏えいします。そのためTypeScript SDKは、windowとdocumentが存在する環境では起動を拒否します。

トークンの取得

すべてのSDKとCLIは、パーソナルアクセストークンで認証します。アカウント内のMCPページの新しいトークンを作成から発行し、コードに必要なスコープを選び、分数の購入を許可するかどうかを決めます。トークンは一度だけ表示され、hsr1:<region>:pat.<id>.<secret>の形式です。スコープとトークンの仕組みはAPIのページで説明しています。

トークンを渡さない場合、SDKはHUSHSCRIPT_TOKENから読み取ります。

export HUSHSCRIPT_TOKEN=hsr1:...

エージェントは、自分のアカウントを開設し、ホスト型のチェックアウトページで支払いを済ませ、最初のトークンをコードから取得することもできます。TypeScriptではHushscript.agent.signup()とHushscript.agent.claim()、PythonではHushscript.agent_signup()とHushscript.agent_claim()、GoではAgentSignupとAgentClaim、PHPではClient::agentSignup()とClient::agentClaim()を使います。流れとルールは自動文字起こしで説明しています。

TypeScript

npm install @hushscript/sdk
import { writeFile } from "node:fs/promises";
import { Hushscript } from "@hushscript/sdk";

const hs = new Hushscript(); // reads HUSHSCRIPT_TOKEN
const transcript = await hs.transcribe("meeting.mp3");
console.log(transcript.text);
await writeFile("meeting.srt", transcript.toSRT());

transcribe()には、パス、Blob、Uint8Array、ReadableStream<Uint8Array>を渡せます。ストリームには、正確なsizeとdurationSecondsが必要です。hs.balance()は利用できる分数を返し、hs.transcripts.list()は完了した文字起こしをページ単位で取得し、hs.buy("300min", { acknowledgeNoRefund: true })はパックを購入します。/v1のすべての操作はhs.apiとしても利用でき、再試行、タイムアウト、秘匿化は同じです。

Python

pip install hushscript
from pathlib import Path

from hushscript import Hushscript

with Hushscript() as hs:  # reads HUSHSCRIPT_TOKEN
    transcript = hs.transcribe("meeting.mp3")
    print(transcript.text)
    Path("meeting.srt").write_text(transcript.to_srt(), encoding="utf-8")

すべての呼び出しには、同じ名前のasyncio版がAsyncHushscriptに用意されています。transcribe()には、パス、bytes、バイナリのファイルオブジェクトを渡せます。シークできないファイルオブジェクトにはsizeとduration_secondsが必要です。残高、文字起こしの一覧、購入には、それぞれhs.balance()、hs.transcripts.list()、hs.buy("300min", acknowledge_no_refund=True)を使います。

Go

go get github.com/Hushscript/hushscript-sdk-go
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	hushscript "github.com/Hushscript/hushscript-sdk-go"
)

func main() {
	client, err := hushscript.New() // reads HUSHSCRIPT_TOKEN
	if err != nil {
		log.Fatal(err)
	}
	transcript, err := client.Transcribe(context.Background(), "meeting.mp3", nil)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(transcript.Text(nil))
	if err := os.WriteFile("meeting.srt", []byte(transcript.SRT(nil)), 0o600); err != nil {
		log.Fatal(err)
	}
}

Transcribeはパスを受け取ります。TranscribeReaderはio.ReaderAtとその正確なサイズを、TranscribeStreamは前方にのみ読めるリーダーと、そのサイズおよびDurationSecondsを受け取ります。残高、文字起こしの一覧、購入には、それぞれclient.Balance、client.Transcripts.List、client.Buyを使います。オン、オフ、未設定を区別できるオプションは*boolで、hushscript.Boolで作成します。

PHP

composer require hushscript/sdk
<?php

require __DIR__ . '/vendor/autoload.php';

use Hushscript\Client;

$hs = new Client(); // reads HUSHSCRIPT_TOKEN

$transcript = $hs->transcribe('meeting.mp3');
echo $transcript->text();
file_put_contents('meeting.srt', $transcript->toSrt());

transcribe()には、パスまたは開いたストリームを渡せます。シークできないストリームには、sizeとduration_secondsオプションが必要です。オプションにはsnake_caseの配列キーを使い、結果はcamelCaseのプロパティで返ります。残高、文字起こしの一覧、購入には、それぞれ$hs->balance()、$hs->transcripts()->list()、$hs->buy('300min', true)を使います。Laravelでは、サービスプロバイダーでClientを1つバインドし、固定のidempotency_keyオプションを付けてキュー済みジョブ内で文字起こしを実行してください。

CLI

npm install --global @hushscript/cli
hushscript login
hushscript transcribe meeting.mp3 --format srt --out meeting.srt

CLIは、--token、HUSHSCRIPT_TOKEN、hushscript loginで保存されたトークンの順にトークンを探します。loginは入力を画面に表示せずにトークンを受け取り、ユーザー本人だけが読めるファイルに保存します。hushscript logoutで削除できます。CIでは環境変数の利用をおすすめします。

コマンド 内容
login トークンの入力を求めて保存します。
logout 保存したトークンを削除します。
balance 利用できる分数を表示します。
transcribe <file> 録音をアップロードし、完了を待って文字起こし結果を出力します。フラグ: --language、--translate、--format srt|vtt|txt|json、--out、--key。
resume <token> <file> transcribeが途中で終わった文字起こしを完了させます。
transcripts 完了した文字起こしを新しい順に一覧表示します。
transcript <id> 文字起こしを1件出力します。
jobs ジョブを一覧表示します。--activeで未完了のジョブのみ表示します。
packs 購入できる分数パックを価格とともに一覧表示します。
buy <pack> 保存済みの既定のカードでパックを購入します。フラグ: --yes、--key。

--jsonを指定すると、標準出力にJSONドキュメントを1つだけ出力し、標準エラー出力はJSON Linesになります。終了コードは、成功が0、APIまたはSDKがエラーを報告した場合が1、使い方の誤り(何も送信されていない)が2、実行が中断された場合が130です。

対応ファイル

MP3、M4A、MP4、MOV(動画は音声トラックを使用)、WAV、FLAC、VorbisまたはOpusのOGGで、長さは15秒から10時間です。SDKはファイルのバイト列から形式を確認し、分数が確保される前に長さを調べます。メディアの変換は行わないため、それ以外の形式は先に変換してください。

ffmpeg -i input -vn -c:a libopus output.opus

エラー

SDKが発生させるエラーはすべて1つの系統に属するため、1つのcatchですべてを処理できます。TypeScriptとPythonではHushscriptError、Goでは*hushscript.Error、PHPではHushscriptExceptionです。エラーには、insufficient_balanceのようなスラッグ形式のcode、数値コード、HTTPステータス、メッセージ、次に何をすべきかを示すhint、詳細、retryAfter(PHPではスラッグがerrorCode、PythonではretryAfterがretry_after)が含まれます。

import { HushscriptError, InsufficientBalanceError } from "@hushscript/sdk";

try {
  await hs.transcribe("meeting.mp3");
} catch (error) {
  if (error instanceof InsufficientBalanceError) console.log(error.hint);
  else if (error instanceof HushscriptError) console.log(error.code, error.hint ?? error.message);
  else throw error;
}

PreflightErrorは、クレジットが確保される前にSDKがファイルを拒否したことを意味します。残高がファイルに足りるかどうかはサーバーが判断します。アップロードの作成時、パートが1つも送信される前に402が返されます。

課金と再試行

すべてのアップロードと購入には冪等キーが付き、再試行でも同じキーが使われます。そのため、再試行した呼び出しは2回目を開始せず、最初の呼び出しの結果を再生します。

buy()は、保存済みの既定のカードに課金します。コードからの購入は、3つの設定がすべて有効になるまでオフです。トークンにbillingスコープがあること、トークンで「このトークンに分数の購入を許可」がオンになっていること、アカウントで「連携済みアプリの分数購入を許可」がオンになっていることです。1つでも欠けていると、呼び出しはpat_scope_missingで失敗します。呼び出す前に、返金不可の通知を購入者に表示してください。

購入の再試行は、ネットワークエラー、502、503の場合に、同じキーで最大1回です。何も課金されていないことが確実な応答もあります。400、402、404、422と、コード4021(pat_purchase_requires_app、カードが拒否された、またはユーザーの操作なしには課金できない)または4023(pat_purchase_requires_authentication、銀行が支払いの確認を求めている)の403です。4021または4023の後は、アプリでパックを購入してください。リクエストの送信後に起きたそれ以外の失敗は、401や429も含め、カードに課金された可能性があります。そのエラーには冪等キーが含まれます。同じキーでもう一度実行すれば、購入が二重に行われることはありません。Pythonの例です。

from hushscript import HushscriptError

try:
    purchase = hs.buy("300min", acknowledge_no_refund=True)
except HushscriptError as error:
    refused = error.status in {400, 402, 404, 422} or (
        error.status == 403 and error.numeric_code in {4021, 4023}
    )
    if error.idempotency_key is None or refused:
        raise  # only these refusals charged nothing; any other failure keeps the key for a retry
    purchase = hs.buy("300min", acknowledge_no_refund=True, idempotency_key=error.idempotency_key)

リクエストの送信前に失敗した購入にはキーが付いておらず、何も課金されていません。自分で渡すキーは、A-Za-z0-9_-の1〜128文字にしてください。別のパックに同じキーを再利用しないでください。購入リクエストが送信された可能性がある場合、CLIはキーを出力します。

hushscript buy 300min --yes --key <key>

再開トークン

ジョブが作成された後は、エラーに冪等キーと並んで再開トークンが含まれます。待機がタイムアウトすると、トークン付きのWaitTimeoutErrorが発生しますが、ジョブは実行され続けます。トークンをresume()に渡せば、二重に課金されることなく処理を続行できます。アップロードを終えたジョブにはファイルは不要で、アップロード中のジョブは同じファイルで続行します。PHPの例です。

try {
    $hs->transcribe($path, ['wait_timeout' => 60]);
} catch (\Hushscript\Exception\WaitTimeoutError $timeout) {
    $transcript = $hs->resume($timeout->resumeToken, $path);
}

CLIでは、transcribeの実行中にCtrl-Cを押すと、ジョブの再開トークンと、続行するためのコマンドが表示されます。

hushscript resume <token> meeting.mp3 --format srt --out meeting.srt

ログと秘匿化

SDKはテレメトリーを送信しません。クライアントを識別する情報はUser-Agentヘッダーだけです。ログは既定でオフです。HUSHSCRIPT_LOG=debugを指定すると、リクエストごとに、メソッド、パス、ステータス、所要時間を1行で標準エラー出力に書き込みます。ヘッダー、本文、タイトル、文字起こしのテキストは書き込まれません。

トークンは、すべてのエラー、ログ行、クライアントの出力表示から秘匿化されます。エラーメッセージ、ヒント、原因では、URLのホストとパスは残り、クエリ文字列は?[redacted]になるため、署名付きアップロードURLが出力されることはありません。クレームシークレットや新しいトークンのように秘密の値を返す結果では、フィールドとしては読み取れますが、出力表示では[redacted]になります。JSONエクスポートはご自身のデータなので、値がそのまま含まれます。CLIは、把握しているすべてのトークンを標準エラー出力から除去します。標準出力の結果はご自身の出力であり、除去されません。

設定

設定 環境変数 既定値
トークン HUSHSCRIPT_TOKEN なし
ベースURL HUSHSCRIPT_BASE_URL https://api.hushscript.com
ログレベル HUSHSCRIPT_LOG off
リクエストのタイムアウト なし 60秒
再試行 なし 3回

コードで渡したオプションは環境変数より優先され、空の値は未設定として扱われます。分数はアプリと同じ残高から使われます。パックと価格は料金ページをご覧ください。

30分お試しで文字起こしをはじめる

アカウント作成前に最大5分をプレビューでき、新規の個人アカウントでは、アプリで初めてアップロードしたファイルも無料でプレビューできます。全体の文字起こしにはアカウントと分数が必要です。対象の個人アカウントは、カード確認の後、または初回購入時に、30分の無料分を1回限り受け取れます。サブスクなし。

無料30分ではじめる