Providers

Code language

View this guide and its examples in your language.

Groq

Configuration#

'groq' => [
    'api_key' => env('GROQ_API_KEY', ''),
    'url' => env('GROQ_URL', 'https://api.groq.com/openai/v1'),
],

Text, tools and images#

use Prism\Prism\Facades\Prism;
use Prism\Prism\Facades\Tool;

$tool = Tool::as('multiply')
    ->for('Multiply two numbers')
    ->withNumberParameter('left', 'First factor')
    ->withNumberParameter('right', 'Second factor')
    ->using(fn (float $left, float $right): string => (string) ($left * $right));

$response = Prism::text()
    ->using('groq', 'llama-3.3-70b-versatile')
    ->withTools([$tool])
    ->withMaxSteps(3)
    ->withPrompt('What is 12 times 13?')
    ->asText();

Groq tool choice accepts ToolChoice::Auto, ToolChoice::Any or a tool name. ToolChoice::None is rejected by this integration. Approval-required and client-executed tools are supported; see Human-in-the-Loop.

With a vision-capable model, pass Image::fromUrl(), local image bytes or base64 in a user message as described in Images. URLs are passed to Groq as references. Choose models from Groq's model catalog for the capability you need.

Structured output#

use Prism\Prism\Schema\ObjectSchema;
use Prism\Prism\Schema\StringSchema;

$response = Prism::structured()
    ->using('groq', 'llama-3.3-70b-versatile')
    ->withSchema(new ObjectSchema(
        'answer', 'An answer', [new StringSchema('text', 'Answer text')],
        requiredFields: ['text'],
    ))
    ->withPrompt('Describe a database index.')
    ->asStructured();

The structured handler sends json_object mode and schema instructions. Validate application constraints after decoding; this path does not send a native JSON Schema constraint.

Errors#

HTTP 429 raises PrismRateLimitedException with parsed rate-limit buckets and retry-after information; 413 raises PrismRequestTooLargeException, and 529 raises PrismProviderOverloadedException. Other failed HTTP requests include Groq's error details. See Error Handling.

Streaming#

The Groq integration supports the standard streaming methods:

return Prism::text()
    ->using('groq', 'llama-3.3-70b-versatile')
    ->withPrompt(request('message'))
    ->asEventStreamResponse();

For complete streaming documentation, see Streaming Output.

Token Usage#

Groq's prompt_tokens includes the tokens it served from the cache, so Prism takes them out to keep the input buckets apart (see Token Usage). Text, structured and streamed responses all report usage like this:

Usage field What it holds
promptTokens prompt_tokens minus prompt_tokens_details.cached_tokens
cacheReadInputTokens prompt_tokens_details.cached_tokens, null when Groq leaves it out
cacheWriteInputTokens Always null, Groq doesn't report cache writes
completionTokens completion_tokens, reasoning included
thoughtTokens completion_tokens_details.reasoning_tokens, already part of completionTokens

Live responses show reasoning tokens inside completion_tokens. The cache split follows Groq's prompt caching docs, which describe cached_tokens as part of prompt_tokens.

Streams can carry usage in more than one place: at the top level, under x_groq.usage, and again in a trailing chunk with no choices. They're all the same totals, so Prism reads one of them per response and counts it once. The StreamEndEvent adds up every step of a tool loop, and each StepFinishEvent carries its own step's usage.

Audio Processing#

The Groq integration supports text-to-speech and speech-to-text requests.

Text-to-Speech#

Use Groq's Orpheus TTS models for English or Saudi Arabic speech. Select a voice supported by the chosen model.

Basic TTS Usage

use Prism\Prism\Facades\Prism;

$response = Prism::audio()
    ->using('groq', 'canopylabs/orpheus-v1-english')
    ->withInput('Hello, welcome to our application!')
    ->withVoice('troy')
    ->asAudio();

// Save the audio file
$audioData = base64_decode($response->audio->base64);
file_put_contents('welcome.wav', $audioData);

TTS Configuration Options

Control audio format and quality:

$response = Prism::audio()
    ->using('groq', 'canopylabs/orpheus-v1-english')
    ->withInput('Testing different audio settings.')
    ->withVoice('hannah')
    ->withProviderOptions([
        'response_format' => 'wav',        // wav (default)
    ])
    ->asAudio();

echo "Audio type: " . ($response->audio->mimeType() ?? 'unknown');

Arabic Text-to-Speech

$response = Prism::audio()
    ->using('groq', 'canopylabs/orpheus-arabic-saudi')
    ->withInput('مرحبا بكم في تطبيقنا')
    ->withVoice('fahad')
    ->asAudio();

file_put_contents('arabic_speech.wav', base64_decode($response->audio->base64));

Speech-to-Text#

Use a supported Whisper model to transcribe audio:

Basic STT Usage

use Prism\Prism\ValueObjects\Media\Audio;

$audioFile = Audio::fromLocalPath('/path/to/recording.mp3');

$response = Prism::audio()
    ->using('groq', 'whisper-large-v3')
    ->withInput($audioFile)
    ->asText();

echo "Transcription: " . $response->text;

Model Selection Guide

Choose the right model for your use case:

$response = Prism::audio()
    ->using('groq', 'whisper-large-v3')
    ->withInput($audioFile)
    ->asText();

// For fastest English-only transcription
$response = Prism::audio()
    ->using('groq', 'distil-whisper-large-v3-en')
    ->withInput($audioFile)
    ->asText();

// For balanced speed and multilingual capability
$response = Prism::audio()
    ->using('groq', 'whisper-large-v3-turbo')
    ->withInput($audioFile)
    ->asText();

Language Detection and Specification

Whisper can automatically detect languages or you can specify them:

$response = Prism::audio()
    ->using('groq', 'whisper-large-v3')
    ->withInput($audioFile)
    ->withProviderOptions([
        'language' => 'es',           // ISO-639-1 code (optional)
        'temperature' => 0.2,         // Lower for more focused results
    ])
    ->asText();

Response Formats

Get transcriptions in different formats:

// Standard JSON response
$response = Prism::audio()
    ->using('groq', 'whisper-large-v3')
    ->withInput($audioFile)
    ->withProviderOptions([
        'response_format' => 'json',  // json, text, verbose_json
    ])
    ->asText();

// Verbose JSON includes timestamps and segments
$response = Prism::audio()
    ->using('groq', 'whisper-large-v3')
    ->withInput($audioFile)
    ->withProviderOptions([
        'response_format' => 'verbose_json',
    ])
    ->asText();

// Access detailed segment information
$segments = $response->additionalContent['segments'] ?? [];
foreach ($segments as $segment) {
    echo "Text: " . $segment['text'] . "\n";
    echo "Start: " . $segment['start'] . "s\n";
    echo "End: " . $segment['end'] . "s\n";
}

Prism does not forward timestamp_granularities to Groq. Use the segment information returned by verbose_json when available.

Transcription Usage

Groq bills transcription by the length of the audio, and its transcription responses don't include a usage object. So $response->usage is null rather than zero tokens. If you need the audio length, verbose_json responses carry it in $response->additionalContent['duration']. Keep in mind that's the audio length, not necessarily what Groq bills (it has a minimum billed length per request).

If a response does include token counts, Prism maps them the same way as text responses (see Token Usage). A duration-style usage object (type: duration) leaves usage as null and puts the seconds in $response->additionalContent['usage_seconds'], matching the OpenAI provider.

Context and Prompts

Improve transcription accuracy with context:

$response = Prism::audio()
    ->using('groq', 'whisper-large-v3')
    ->withInput($audioFile)
    ->withProviderOptions([
        'prompt' => 'This is a technical discussion about machine learning and artificial intelligence.',
        'language' => 'en',
        'temperature' => 0.1,         // Lower temperature for technical content
    ])
    ->asText();

Creating Audio Objects

use Prism\Prism\ValueObjects\Media\Audio;

// From local file path
$audio = Audio::fromLocalPath('/path/to/audio.mp3');

// From remote URL (recommended for large files)
$audio = Audio::fromUrl('https://example.com/recording.wav')->fetchUrlContent(); // a URL you trust

// From base64 encoded data
$audio = Audio::fromBase64($base64AudioData, 'audio/mpeg');

// From binary content
$audioContent = file_get_contents('/path/to/audio.wav');
$audio = Audio::fromRawContent($audioContent, 'audio/wav');