Aller au contenu principal

Développeurs

SDK et CLI Hushscript

Des bibliothèques officielles pour TypeScript, Python, Go et PHP, et un outil en ligne de commande, qui transforment un fichier enregistré en transcription en un seul appel.

Les SDK officiels encapsulent l’API REST pour le code serveur et les scripts. Un seul appel transcrit un fichier : il envoie l’enregistrement, attend la tâche et vous rend la transcription. En chemin, le SDK vérifie le fichier avant toute réservation de minutes, relance ce qui peut l’être sans risque, maintient en vie un téléversement long et joint une clé d’idempotence à chaque téléversement et à chaque achat, pour qu’une nouvelle tentative ne débite jamais deux fois. La CLI repose sur le SDK TypeScript et fait la même chose depuis un terminal.

Paquets

Langage Paquet Registre Source
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

Versions minimales d’exécution :

Les SDK sont destinés aux serveurs et aux scripts. L’API n’accepte pas les origines de navigateur, et un jeton dans un bundle de navigateur est un jeton divulgué : le SDK TypeScript refuse donc de démarrer là où window et document existent.

Obtenir un jeton

Chaque SDK et la CLI s’authentifient avec un jeton d’accès personnel. Créez-en un sous Créer un nouveau jeton sur la page MCP du compte, choisissez les scopes dont votre code a besoin et décidez s’il peut acheter des minutes. Le jeton n’est affiché qu’une fois et ressemble à hsr1:<region>:pat.<id>.<secret>. Les scopes et le fonctionnement d’un jeton sont décrits sur la page de l’API.

Les SDK lisent le jeton dans HUSHSCRIPT_TOKEN quand vous n’en passez pas :

export HUSHSCRIPT_TOKEN=hsr1:...

Un agent peut aussi ouvrir son propre compte, le faire payer sur une page de paiement hébergée et récupérer son premier jeton depuis le code : Hushscript.agent.signup() et Hushscript.agent.claim() en TypeScript, Hushscript.agent_signup() et Hushscript.agent_claim() en Python, AgentSignup et AgentClaim en Go, et Client::agentSignup() et Client::agentClaim() en PHP. Le parcours et ses règles sont décrits dans Usage automatisé.

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() accepte un chemin, un Blob, un Uint8Array ou un ReadableStream<Uint8Array>. Un flux exige sa size exacte et sa durationSeconds. hs.balance() renvoie les minutes dont vous disposez, hs.transcripts.list() parcourt page par page les transcriptions terminées et hs.buy("300min", { acknowledgeNoRefund: true }) achète un pack. Chaque opération /v1 est aussi disponible via hs.api, avec les mêmes nouvelles tentatives, les mêmes délais d’attente et la même expurgation des secrets.

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")

Chaque appel a un jumeau asyncio sur AsyncHushscript, avec les mêmes noms. transcribe() accepte un chemin, des bytes ou un objet fichier binaire ; un objet fichier qui ne permet pas de se repositionner exige size et duration_seconds. hs.balance(), hs.transcripts.list() et hs.buy("300min", acknowledge_no_refund=True) couvrent le solde, la liste des transcriptions et les achats.

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 accepte un chemin, TranscribeReader un io.ReaderAt et sa taille exacte, et TranscribeStream un lecteur séquentiel avec sa taille et DurationSeconds. client.Balance, client.Transcripts.List et client.Buy couvrent le solde, la liste des transcriptions et les achats. Les options qui peuvent être activées, désactivées ou non définies sont des *bool, créés avec 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() accepte un chemin ou un flux ouvert ; un flux qui ne permet pas de se repositionner exige les options size et duration_seconds. Les options utilisent des clés de tableau en snake_case et les résultats des propriétés en camelCase. $hs->balance(), $hs->transcripts()->list() et $hs->buy('300min', true) couvrent le solde, la liste des transcriptions et les achats. Pour Laravel, liez un seul Client dans un fournisseur de services et exécutez les transcriptions dans un job en file d’attente avec une option idempotency_key stable.

CLI

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

La CLI prend le jeton dans --token, puis dans HUSHSCRIPT_TOKEN, puis dans celui que hushscript login a enregistré. login demande le jeton sans l’afficher et le conserve dans un fichier que seul votre utilisateur peut lire ; hushscript logout le supprime. En CI, préférez la variable d’environnement.

Commande Ce qu’elle fait
login Demande un jeton et l’enregistre.
logout Supprime le jeton enregistré.
balance Affiche les minutes dont vous disposez.
transcribe <file> Envoie un enregistrement, attend et affiche la transcription. Options : --language, --translate, --format srt|vtt|txt|json, --out, --key.
resume <token> <file> Termine une transcription laissée en suspens par transcribe.
transcripts Liste les transcriptions terminées, les plus récentes d’abord.
transcript <id> Affiche une transcription.
jobs Liste les tâches ; --active pour celles qui ne sont pas terminées.
packs Liste les packs de minutes achetables, avec leurs prix.
buy <pack> Achète un pack avec votre carte par défaut enregistrée. Options : --yes, --key.

--json affiche un seul document JSON sur stdout et rien d’autre, et transforme stderr en JSON Lines. Le code de sortie est 0 en cas de succès, 1 quand l’API ou le SDK a signalé une erreur, 2 pour une erreur d’usage (rien n’a été envoyé) et 130 quand l’exécution a été interrompue.

Fichiers acceptés

MP3, M4A, MP4 et MOV (la piste audio d’une vidéo est utilisée), WAV, FLAC et OGG avec Vorbis ou Opus, de 15 secondes à 10 heures. Les SDK vérifient le format à partir des octets du fichier et sondent la durée avant toute réservation de minutes. Ils ne convertissent pas les médias : convertissez d’abord tout autre format :

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

Erreurs

Toutes les erreurs levées par un SDK appartiennent à une même famille, de sorte qu’un seul catch suffit : HushscriptError en TypeScript et en Python, *hushscript.Error en Go et HushscriptException en PHP. Une erreur porte un code sous forme de slug, comme insufficient_balance, le code numérique, le statut HTTP, un message, un hint qui indique quoi faire ensuite, les détails et retryAfter (en PHP le slug s’appelle errorCode ; en Python, retryAfter s’écrit 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;
}

Une PreflightError signifie que le SDK a refusé le fichier avant toute réservation de crédit. C’est le serveur qui décide si votre solde couvre un fichier : un 402 revient à la création du téléversement, avant l’envoi de la moindre partie.

Facturation et nouvelles tentatives

Chaque téléversement et chaque achat porte une clé d’idempotence, que les nouvelles tentatives réutilisent : un appel relancé rejoue donc le premier au lieu d’en démarrer un second.

buy() débite votre carte par défaut enregistrée. L’achat depuis le code est désactivé tant que trois réglages ne l’autorisent pas : le jeton a le scope billing, l’option « Autoriser ce jeton à acheter des minutes » est activée sur le jeton, et « Autoriser les applications connectées à acheter des minutes » est activée pour le compte. S’il en manque un, l’appel échoue avec pat_scope_missing. Montrez à votre acheteur l’avertissement d’absence de remboursement avant de l’appeler.

Un achat est relancé au plus une fois, après une erreur réseau, un 502 ou un 503, avec la même clé. Certaines réponses prouvent que rien n’a été débité : un 400, 402, 404 ou 422, et un 403 avec le code 4021 (pat_purchase_requires_app, la carte a été refusée ou ne peut pas être débitée sans vous) ou 4023 (pat_purchase_requires_authentication, la banque veut confirmer le paiement). Après 4021 ou 4023, achetez le pack dans l’application. Toute autre défaillance survenue une fois la requête envoyée, y compris un 401 ou un 429, signifie que la carte a peut-être été débitée. Cette erreur porte la clé d’idempotence : redemandez avec la même clé, et l’achat ne peut jamais avoir lieu deux fois. En 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)

Un achat qui a échoué avant l’envoi de sa requête ne porte aucune clé : rien n’a été débité. Une clé que vous fournissez vous-même doit comporter de 1 à 128 caractères parmi A-Za-z0-9_- ; ne la réutilisez pas pour un autre pack. La CLI affiche la clé quand un achat a pu être envoyé :

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

Jetons de reprise

Dès qu’une tâche existe, une erreur porte un jeton de reprise à côté de la clé d’idempotence. Une attente qui expire lève WaitTimeoutError avec le jeton, et la tâche continue de s’exécuter. Repassez le jeton à resume() pour continuer sans second débit : une tâche qui a dépassé l’étape de téléversement n’a plus besoin du fichier, et celle qui téléverse encore est poursuivie avec le même fichier. En PHP :

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

Dans la CLI, Ctrl-C pendant transcribe affiche le jeton de reprise de la tâche et la commande qui la poursuit :

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

Journalisation et expurgation

Les SDK n’envoient aucune télémétrie ; l’en-tête User-Agent est la seule identification du client. La journalisation est désactivée par défaut. HUSHSCRIPT_LOG=debug écrit une ligne par requête sur l’erreur standard, avec la méthode, le chemin, le statut et la durée, et jamais un en-tête, un corps, un titre ni le texte d’une transcription.

Le jeton est expurgé de chaque erreur, de chaque ligne de journal et de chaque forme imprimée du client. Dans les messages d’erreur, les indications et les causes, une URL conserve son hôte et son chemin, mais sa chaîne de requête devient ?[redacted] : une URL de téléversement signée ne s’affiche donc jamais. Les résultats qui vous remettent un secret, comme un secret de récupération ou un nouveau jeton, le gardent lisible dans un champ mais affichent [redacted] à l’impression ; un export JSON vous appartient et contient la valeur. La CLI retire de stderr tous les jetons qu’elle connaît ; ses résultats sur stdout sont votre sortie et ne sont pas filtrés.

Configuration

Réglage Variable d’environnement Valeur par défaut
Jeton HUSHSCRIPT_TOKEN aucune
URL de base HUSHSCRIPT_BASE_URL https://api.hushscript.com
Niveau de journalisation HUSHSCRIPT_LOG off
Délai d’attente des requêtes aucune 60 secondes
Nouvelles tentatives aucune 3

Une option passée dans le code l’emporte sur sa variable d’environnement, et une valeur vide compte comme non définie. Les minutes viennent du même solde que l’application ; les packs et les prix figurent sur la page des tarifs.

Commencer à transcrire avec 30 minutes gratuites

Prévisualisez jusqu'à 5 minutes avant de créer un compte, et un nouveau compte personnel bénéficie d'un aperçu gratuit de son premier téléversement dans l'application. La transcription complète nécessite un compte et des minutes ; les comptes personnels éligibles reçoivent 30 minutes gratuites une seule fois, après une vérification de carte ou avec un premier achat. Sans abonnement.

Commencer avec 30 minutes gratuites