> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fish.audio/llms.txt
> Use this file to discover all available pages before exploring further.

# Batch-transcribe files with a language hint

> Loop over local audio files and transcribe each with an explicit language, collecting text and duration per file

## Prerequisites

<AccordionGroup>
  <Accordion icon="user-plus" title="Create a Fish Audio account">
    Sign up for a free Fish Audio account to get started with our API.

    1. Go to [fish.audio/auth/signup](https://fish.audio/auth/signup)
    2. Fill in your details to create an account, complete steps to verify your account.
    3. Log in to your account and navigate to the [API section](https://fish.audio/app/api-keys)
  </Accordion>

  <Accordion icon="key" title="Get your API key">
    Once you have an account, you'll need an API key to authenticate your requests.

    1. Log in to your [Fish Audio Dashboard](https://fish.audio/app/api-keys/)
    2. Navigate to the API Keys section
    3. Click "Create New Key" and give it a descriptive name, set a expiration if desired
    4. Copy your key and store it securely

    <Warning>Keep your API key secret! Never commit it to version control or share it publicly.</Warning>
  </Accordion>
</AccordionGroup>

## Recipe

Read each file's bytes from disk and pass them to [`asr.transcribe()`](/api-reference/sdk/python/resources#transcribe) with an explicit `language`. A language hint is more reliable than auto-detection when you already know the source language, especially for phonetically similar languages. Collect one result row per file as you go.

<CodeGroup>
  ```python Synchronous theme={null}
  from fishaudio import FishAudio

  client = FishAudio()

  paths = ["speech.wav"]  # add more file paths here
  language = "en"

  results = []
  for path in paths:
      with open(path, "rb") as f:
          audio = f.read()

      transcript = client.asr.transcribe(audio=audio, language=language)
      results.append({
          "file": path,
          "text": transcript.text,
          "duration": transcript.duration,  # seconds
      })

  for row in results:
      print(f"{row['file']} ({row['duration']:.1f}s): {row['text']}")
  ```

  ```python Asynchronous theme={null}
  import asyncio
  from fishaudio import AsyncFishAudio

  async def main():
      async with AsyncFishAudio() as client:
          paths = ["speech.wav"]  # add more file paths here
          language = "en"

          results = []
          for path in paths:
              with open(path, "rb") as f:
                  audio = f.read()

              transcript = await client.asr.transcribe(audio=audio, language=language)
              results.append({
                  "file": path,
                  "text": transcript.text,
                  "duration": transcript.duration,  # seconds
              })

      for row in results:
          print(f"{row['file']} ({row['duration']:.1f}s): {row['text']}")

  asyncio.run(main())
  ```

  ```javascript JavaScript theme={null}
  import { FishAudioClient } from "fish-audio";
  import { readFile } from "fs/promises";

  const client = new FishAudioClient({ apiKey: process.env.FISH_API_KEY });

  const paths = ["speech.wav"]; // add more file paths here
  const language = "en";

  const results = [];
  for (const path of paths) {
    const audio = new File([await readFile(path)], path);

    const transcript = await client.speechToText.convert({ audio, language });
    results.push({
      file: path,
      text: transcript.text,
      duration: transcript.duration, // seconds
    });
  }

  for (const row of results) {
    console.log(`${row.file} (${row.duration.toFixed(1)}s): ${row.text}`);
  }
  ```
</CodeGroup>

Each call returns an [`ASRResponse`](/api-reference/sdk/python/types#asrresponse-objects) with `.text`, a `.duration` in seconds, and per-phrase `.segments`. The loop keeps files independent, so one bad file does not block the rest of the batch.

<Tip>
  Auto-detection (omit `language`) works well, but passing an explicit
  `language` improves accuracy for similar-sounding languages. Use one
  `language` per batch — split mixed-language files into separate lists.
</Tip>

## Related

* [Speech-to-Text guide](/features/speech-to-text)
* [Instant voice cloning](/developer-guide/sdk-guide/cookbook/instant-voice-cloning)
