If your function is an async generator (uses yield), the caller receives each value as soon as the worker produces it, without waiting for the generator to finish.

This makes functions a good fit for:

  • Streaming LLM token output.
  • Incremental ETL where downstream consumers start processing early.
  • Long-running jobs that emit progress events.

​
Example: audio transcription

Transcribe an audio file and yield each segment as it’s decoded:

import chalkcompute

@chalkcompute.function(
    image=chalkcompute.Image.base("python:3.12-slim").run_commands(
        "pip install faster-whisper httpx",
    ),
    cpu="4",
    memory="8Gi",
)
async def transcribe(audio_uri: str):
    import httpx
    from faster_whisper import WhisperModel

    async with httpx.AsyncClient() as client:
        resp = await client.get(audio_uri)
        resp.raise_for_status()

    audio_path = "/tmp/audio"
    with open(audio_path, "wb") as f:
        f.write(resp.content)

    model = WhisperModel("base.en", compute_type="int8")
    segments, _info = model.transcribe(audio_path)

    for segment in segments:
        yield {
            "start": segment.start,
            "end": segment.end,
            "text": segment.text,
        }

The caller iterates over segments as they arrive:

import asyncio

transcribe.wait_ready()

async def main():
    async for segment in transcribe.remote("https://example.com/meeting-recording.wav"):
        print(f"[{segment['start']:.1f}s] {segment['text']}")

asyncio.run(main())

Output streams in real time:

[0.0s]  Welcome to the quarterly review.
[3.2s]  Let's start with the revenue numbers.
[6.1s]  Q3 came in at 4.2 million, up 18 percent.
...

The caller receives the first segment as soon as it’s decoded. It does not wait for the full file to finish processing. For a 30-minute recording, the first segment may arrive in seconds.