# PyAI TypeScript starter

Use typed requests and native ReadableStream audio in your Node.js backend.

## Requirements

Node.js 22+. A PyAI key. The starter writes speech.pcm; run npm start -- call.wav to also transcribe a recording.

## Run

```sh
npm install
cp .env.example .env
# Fill in .env, then:
npm start
```

The starter runs on Node.js. Keep secret keys on your backend; use the browser voice-agent guide for frontend authentication.

Play the raw audio with FFmpeg installed:

```sh
ffplay -f s16le -ar 24000 -ac 1 speech.pcm
```

Select a voice from `GET https://api.pyai.com/v1/voices`. Use the current voice/language support table rather than assuming every voice supports every language. PCM, WAV and G.711 support streaming; MP3 and Opus are buffered.

Keep `.env` out of Git. These starters use server-side credentials.

[Full guide](https://docs.pyai.com/guides/sdks) · [Agent setup](https://pyai.com/build-with-ai) · [API contract](https://api.pyai.com/openapi.json)

## Download from your terminal

```sh
curl -fSL https://pyai.com/starters/pyai-typescript.tar.gz -o pyai-typescript.tar.gz
tar -xzf pyai-typescript.tar.gz
cd pyai-typescript
npm install
cp .env.example .env
# Fill in .env, then:
npm start
```

## .env.example

```text
PYAI_API_KEY=replace_me
PYAI_VOICE=stock_emma_en_gb
```

## main.ts

```typescript
import { createWriteStream } from "node:fs";
import { readFile } from "node:fs/promises";
import { basename } from "node:path";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
import PyAI from "@pyai/sdk";

const apiKey = process.env.PYAI_API_KEY;
if (!apiKey) throw new Error("Set PYAI_API_KEY in .env");
const client = new PyAI({ apiKey });
const started = performance.now();
let received = 0;
const stream = await client.audio.speechStream({
  input: "Hello! Your PyAI voice integration is ready.",
  voice: process.env.PYAI_VOICE || "stock_emma_en_gb",
  response_format: "pcm", sample_rate: 24000,
});

async function* chunks() {
  const reader = stream.getReader();
  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      if (value.length && !received) {
        console.log(`First audio bytes: ${Math.round(performance.now() - started)} ms`);
      }
      received += value.length;
      yield value; // Forward to your live player here; pipeline preserves backpressure.
    }
  } finally {
    await reader.cancel();
    reader.releaseLock();
  }
}
await pipeline(Readable.from(chunks()), createWriteStream("speech.pcm"));
if (!received) throw new Error("Speak returned no audio");
console.log(`Saved speech.pcm (${received} bytes; mono PCM16LE at 24000 Hz)`);

const recording = process.argv[2];
if (recording) {
  const result = await client.audio.transcriptions.create({
    file: new Blob([await readFile(recording)]), filename: basename(recording),
  }); // Omit language for automatic detection.
  console.log(result.text);
}
```

## package.json

```json
{
  "name": "pyai-typescript-starter",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "engines": {
    "node": ">=22"
  },
  "scripts": {
    "start": "node --env-file=.env --import tsx main.ts"
  },
  "dependencies": {
    "@pyai/sdk": "0.4.0",
    "tsx": "^4.20.0"
  }
}
```
