Skip to main content

Vercel AI SDK

Use the OpenAI-compatible provider.

npm install ai @ai-sdk/openai-compatible
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { generateText } from "ai";

const djelia = createOpenAICompatible({
name: "djelia",
baseURL: "https://api.djelia.cloud/openai/v1",
apiKey: process.env.DJELIA_API_KEY,
});

Speech and transcription

@ai-sdk/openai-compatible covers text generation. For /audio/speech, /audio/transcriptions and /audio/translations, use the OpenAI SDK alongside it.

Translation, and the doubled djelia key

const { text } = await generateText({
model: djelia("banjugu-1"),
prompt: "Bonjour, comment allez-vous ?",
providerOptions: {
djelia: { djelia: { source_language: "fra_Latn", target_language: "bam_Latn" } },
},
});
Nbá, í ni sɔ̀gɔmà ?

The two djelia keys serve different purposes.

The outer djelia is the provider name you passed to createOpenAICompatible. That is how the AI SDK decides which provider a block of options belongs to. It then flattens the contents of that block into the root of the request body rather than sending it as a nested object. So the inner djelia is what survives that flattening and becomes the extension object Djelia reads.

Using one key sends the fields at the top level, and the request fails:

// providerOptions: { djelia: { source_language: ..., target_language: ... } }
{"model":"banjugu-1","source_language":"fra_Latn","target_language":"bam_Latn","messages":[]}
// → 400 djelia: Field required

Using both keys sends the required request body:

// providerOptions: { djelia: { djelia: { source_language: ..., target_language: ... } } }
{"model":"banjugu-1","djelia":{"source_language":"fra_Latn","target_language":"bam_Latn"},"messages":[]}
// → 200

If you rename the provider, rename the outer key only. The inner one is Djelia's wire format and never changes.

caution

Djelia's translation model has no tool use, no system-prompt steering and no conversational memory. It translates the last user message. streamText works, but because translation is not incremental it emits the whole result as a single chunk.