Dictionaries
Per-project pronunciation and replacement lists for brand names and domain vocabulary
Custom dictionaries are per-project pronunciation and replacement lists. Each entry maps a written word to the text or IPA the TTS pipeline should pronounce instead. Use them for brand names, product names, acronyms, and domain vocabulary that should sound consistent across requests. The concept is covered in Dictionaries.
Generating speech with a key of the dictionary's project applies it without a project ID; see Dictionaries at synthesis. Changes are available to synthesis after the dictionary mutation finishes.
For the full HTTP contract, field limits, master-key project_id rules,
and error codes, see the Dictionaries API reference.
Create a dictionary
import os
from kugelaudio import KugelAudio
client = KugelAudio(api_key=os.environ["KUGELAUDIO_API_KEY"])
dictionary = client.dictionaries.create(
name="Brand names",
description="Product and company names",
language="en",
)
print(dictionary.id)import { KugelAudio } from 'kugelaudio';
const client = new KugelAudio({ apiKey: process.env.KUGELAUDIO_API_KEY! });
const dictionary = await client.dictionaries.create({
name: 'Brand names',
description: 'Product and company names',
language: 'en',
});
console.log(dictionary.id);import com.kugelaudio.sdk.Dictionary;
import com.kugelaudio.sdk.KugelAudio;
KugelAudio client = KugelAudio.fromEnv();
Dictionary dictionary = client.dictionaries().create(
"Brand names",
"Product and company names",
"en"
);
System.out.println(dictionary.getId());use kugelaudio::{DictionaryCreate, KugelAudio};
let client = KugelAudio::new(std::env::var("KUGELAUDIO_API_KEY").unwrap_or_default())?;
let dictionary = client
.dictionaries()
.create(
&DictionaryCreate::new("Brand names")
.description("Product and company names")
.language("en"),
None, // project_id
)
.await?;
println!("{}", dictionary.id);kugelaudio::Client client{std::getenv("KUGELAUDIO_API_KEY")};
kugelaudio::DictionaryCreate request;
request.name = "Brand names";
request.description = "Product and company names";
request.language = "en";
kugelaudio::Dictionary dictionary = client.dictionaries().create(request);
std::cout << dictionary.id << '\n';import 'dart:io';
import 'package:kugelaudio/kugelaudio.dart';
final client = KugelAudio(apiKey: Platform.environment['KUGELAUDIO_API_KEY']!);
final dictionary = await client.dictionaries.create(
name: 'Brand names',
description: 'Product and company names',
language: 'en',
);
print(dictionary.id);Manage dictionaries
# List every dictionary in the project
dictionaries = client.dictionaries.list()
# Fetch one
dictionary = client.dictionaries.get(dictionary.id)
# Update name / description / language / is_active (only provided fields change)
dictionary = client.dictionaries.update(
dictionary.id,
description="Updated description",
)// List every dictionary in the project
const dictionaries = await client.dictionaries.list();
// Fetch one
const dict = await client.dictionaries.get(dictionary.id);
// Update name / description / language / isActive (only provided fields change)
await client.dictionaries.update(dictionary.id, {
description: 'Updated description',
});// List every dictionary in the project
List<Dictionary> dictionaries = client.dictionaries().list();
// Fetch one
Dictionary dict = client.dictionaries().get(dictionary.getId());
// Update name / description / language / isActive (null leaves a field unchanged)
client.dictionaries().update(
dictionary.getId(),
null, // name
"Updated description", // description
null, // language
false // isActive
);use kugelaudio::DictionaryUpdate;
// List every dictionary in the project
let dictionaries = client.dictionaries().list(None).await?;
// Fetch one
let dict = client.dictionaries().get(dictionary.id, None).await?;
// Update name / description / language / is_active (only set fields change)
let dict = client
.dictionaries()
.update(
dictionary.id,
&DictionaryUpdate::new().description("Updated description"),
None,
)
.await?;// List every dictionary in the project
std::vector<kugelaudio::Dictionary> dictionaries = client.dictionaries().list();
// Fetch one
kugelaudio::Dictionary dict = client.dictionaries().get(dictionary.id);
// Update name / description / language / is_active (only set fields change)
kugelaudio::DictionaryUpdate update;
update.description = "Updated description";
dict = client.dictionaries().update(dictionary.id, update);// List every dictionary in the project
final dictionaries = await client.dictionaries.list();
// Fetch one
final dict = await client.dictionaries.get(dictionary.id);
// Update name / description / language / isActive (only given fields change)
await client.dictionaries.update(
dictionary.id,
description: 'Updated description',
);Add and manage entries
Use replacement for normal spelling-based fixes. Use ipa when you need
an exact phonetic pronunciation; IPA takes precedence over replacement.
created_entry = client.dictionaries.entries.add(
dictionary.id,
word="Postgres",
replacement="post-gres",
)
page = client.dictionaries.entries.list(
dictionary.id,
search="post",
limit=50,
)
for entry in page.entries:
print(f"{entry.word} → {entry.replacement}")
client.dictionaries.entries.update(
dictionary.id,
page.entries[0].id,
replacement="postgres",
)
client.dictionaries.entries.delete(dictionary.id, page.entries[0].id)const createdEntry = await client.dictionaries.entries.add(dictionary.id, {
word: 'Postgres',
replacement: 'post-gres',
});
const page = await client.dictionaries.entries.list(dictionary.id, {
search: 'post',
limit: 50,
});
for (const entry of page.entries) {
console.log(`${entry.word} → ${entry.replacement}`);
}
await client.dictionaries.entries.update(
dictionary.id,
page.entries[0].id,
{ replacement: 'postgres' }
);
await client.dictionaries.entries.delete(dictionary.id, createdEntry.id);import com.kugelaudio.sdk.DictionaryEntry;
import com.kugelaudio.sdk.DictionaryEntryInput;
import com.kugelaudio.sdk.DictionaryEntryListResponse;
DictionaryEntry createdEntry = client.dictionaries().entries().add(
dictionary.getId(),
new DictionaryEntryInput("Postgres", "post-gres")
);
DictionaryEntryListResponse page = client.dictionaries().entries().list(
dictionary.getId(),
"post", // search
50, // limit
null, // offset
null // projectId
);
for (DictionaryEntry entry : page.getEntries()) {
System.out.println(entry.getWord() + " → " + entry.getReplacement());
}
// update(dictionaryId, entryId, word, replacement, ipa, caseSensitive); null leaves a field unchanged
client.dictionaries().entries().update(
dictionary.getId(),
page.getEntries().get(0).getId(),
null,
"postgres",
null,
null
);
client.dictionaries().entries().delete(
dictionary.getId(),
createdEntry.getId()
);use kugelaudio::{DictionaryEntryUpdate, EntryListOptions, NewDictionaryEntry};
let entries = client.dictionaries().entries();
let created_entry = entries
.add(dictionary.id, &NewDictionaryEntry::new("Postgres", "post-gres"), None)
.await?;
let page = entries
.list(dictionary.id, &EntryListOptions::default().search("post").limit(50))
.await?;
for entry in &page.entries {
println!("{} → {}", entry.word, entry.replacement);
}
entries
.update(
dictionary.id,
page.entries[0].id,
&DictionaryEntryUpdate::new().replacement("postgres"),
None,
)
.await?;
entries.delete(dictionary.id, created_entry.id, None).await?;const kugelaudio::DictionaryEntriesResource& entries = client.dictionaries().entries();
kugelaudio::DictionaryEntry created_entry = entries.add(dictionary.id, {"Postgres", "post-gres"});
kugelaudio::DictionaryEntryListOptions options;
options.search = "post";
options.limit = 50;
kugelaudio::DictionaryEntryList page = entries.list(dictionary.id, options);
for (const auto& entry : page.entries) {
std::cout << entry.word << " → " << entry.replacement << '\n';
}
kugelaudio::DictionaryEntryUpdate update;
update.replacement = "postgres";
entries.update(dictionary.id, page.entries[0].id, update);
entries.remove(dictionary.id, created_entry.id);final createdEntry = await client.dictionaries.entries.add(
dictionary.id,
word: 'Postgres',
replacement: 'post-gres',
);
final page = await client.dictionaries.entries.list(
dictionary.id,
search: 'post',
limit: 50,
);
for (final entry in page.entries) {
print('${entry.word} → ${entry.replacement}');
}
await client.dictionaries.entries.update(
dictionary.id,
page.entries[0].id,
replacement: 'postgres',
);
await client.dictionaries.entries.delete(dictionary.id, createdEntry.id);Atomic bulk sync
The bulk replace (replace_all in Python, Rust and C++, replaceAll in TypeScript,
Java and Dart) upserts every entry in one transaction and deletes entries currently in the
dictionary whose word is not in the payload. Use it to sync from a CMS, PIM, or
internal glossary.
result = client.dictionaries.entries.replace_all(
dictionary.id,
entries=[
{"word": "Postgres", "replacement": "post-gres"},
{"word": "Kubernetes", "replacement": "koo-ber-net-eez"},
],
)
print(f"upserted={result.upserted} deleted={result.deleted}")const result = await client.dictionaries.entries.replaceAll(dictionary.id, [
{ word: 'Postgres', replacement: 'post-gres' },
{ word: 'Kubernetes', replacement: 'koo-ber-net-eez' },
]);
console.log(`upserted=${result.upserted} deleted=${result.deleted}`);import com.kugelaudio.sdk.BulkReplaceResult;
import java.util.List;
BulkReplaceResult result = client.dictionaries().entries().replaceAll(
dictionary.getId(),
List.of(
new DictionaryEntryInput("Postgres", "post-gres"),
new DictionaryEntryInput("Kubernetes", "koo-ber-net-eez")
)
);
System.out.printf(
"upserted=%d deleted=%d%n",
result.getUpserted(),
result.getDeleted()
);use kugelaudio::DictionaryEntryInput;
let result = client
.dictionaries()
.entries()
.replace_all(
dictionary.id,
&[
DictionaryEntryInput::new("Postgres", "post-gres"),
DictionaryEntryInput::new("Kubernetes", "koo-ber-net-eez"),
],
None,
)
.await?;
println!("upserted={} deleted={}", result.upserted, result.deleted);kugelaudio::BulkReplaceResult result = client.dictionaries().entries().replace_all(
dictionary.id,
{
{"Postgres", "post-gres"},
{"Kubernetes", "koo-ber-net-eez"},
});
std::cout << "upserted=" << result.upserted << " deleted=" << result.deleted << '\n';final result = await client.dictionaries.entries.replaceAll(dictionary.id, const [
DictionaryEntryInput(word: 'Postgres', replacement: 'post-gres'),
DictionaryEntryInput(word: 'Kubernetes', replacement: 'koo-ber-net-eez'),
]);
print('upserted=${result.upserted} deleted=${result.deleted}');Dictionaries at synthesis
Dictionaries apply from the request's project: the project ID you pass, or, when you omit it, the project of your API key. The project's active dictionaries for the request language apply. Add dictionary IDs for an exact selection (inactive ones included), or pass an empty list to disable dictionaries for the request. A non-empty dictionary-ID list from a caller without a project is rejected. If you serve many end customers, give each its own project and key with the Projects API. Keep normalization enabled unless you have a specific reason to bypass it.
audio = client.tts.generate(
text="Willkommen bei Kugel Audio.",
voice_id=1071,
language="de",
project_id=dictionary.project_id,
dictionary_ids=[dictionary.id], # optional: exactly this dictionary
)const audio = await client.tts.generate({
text: 'Postgres runs our product analytics.',
modelId: 'kugel-3.5',
voiceId: 1071,
language: 'en',
normalize: true,
projectId: dictionary.projectId,
dictionaryIds: [dictionary.id], // optional: exactly this dictionary
});AudioResponse audio = client.tts().generate(
GenerateRequest.builder("Willkommen bei Kugel Audio.")
.voiceId(1071)
.language("de")
.projectId(dictionary.getProjectId())
.dictionaryIds(List.of((int) dictionary.getId())) // optional: exactly this dictionary
.build()
);let audio = client
.tts()
.generate(
&TtsRequest::new("Willkommen bei Kugel Audio.")
.voice_id(1071)
.language("de")
.project_id(dictionary.project_id)
.dictionary_ids(vec![dictionary.id]), // optional: exactly this dictionary
)
.await?;kugelaudio::GenerateRequest request;
request.text = "Willkommen bei Kugel Audio.";
request.voice_id = 1071;
request.language = "de";
request.project_id = dictionary.project_id;
request.dictionary_ids = std::vector<std::int64_t>{dictionary.id}; // optional: exactly this dictionary
kugelaudio::AudioResponse audio = client.tts().generate(request);final audio = await client.tts.generate(
text: 'Willkommen bei Kugel Audio.',
voiceId: 1071,
language: 'de',
projectId: dictionary.projectId,
dictionaryIds: [dictionary.id], // optional: exactly this dictionary
);Streaming and multi-context sessions take the same two settings in their configuration and send them with the session configuration; they apply to every turn or context on that connection:
Every generation and session method accepts project_id and dictionary_ids:
generate(), generate_async(), stream(), stream_async(),
streaming_session(), streaming_session_sync() and multi_context_session().
async with client.tts.streaming_session(
voice_id=1071, language="en", project_id=dictionary.project_id
) as session:
...GenerateOptions, StreamConfig and MultiContextConfig take projectId and
dictionaryIds:
const session = client.tts.streamingSession(
{ voiceId: 1071, language: 'en', projectId: dictionary.projectId },
{ onChunk: (chunk) => playAudio(chunk.audio) },
);
const multi = client.tts.createMultiContextSession({
defaultVoiceId: 1071,
language: 'en',
projectId: dictionary.projectId,
dictionaryIds: [dictionary.id],
});GenerateRequest, StreamConfig and MultiContextConfig builders take
.projectId(long) and .dictionaryIds(List<Integer>) (List.of() disables
dictionaries):
StreamConfig config = StreamConfig.builder()
.voiceId(1071)
.language("en")
.projectId(dictionary.getProjectId())
.build();TtsRequest, StreamConfig and MultiContextConfig take .project_id(i64) and
.dictionary_ids(Vec<i64>) (vec![] disables dictionaries):
let session = client.tts().streaming_session(
StreamConfig::new(1071)
.language("en")
.project_id(dictionary.project_id),
);
let multi = client.tts().multi_context_session(
MultiContextConfig::default()
.default_voice_id(1071)
.language("en")
.project_id(dictionary.project_id)
.dictionary_ids(vec![dictionary.id]),
);GenerateRequest, StreamConfig and MultiContextConfig have project_id and
dictionary_ids fields (an empty vector disables dictionaries):
kugelaudio::StreamConfig config;
config.voice_id = 1071;
config.language = "en";
config.project_id = dictionary.project_id;
auto session = client.tts().streaming_session(config);generate(), stream(), StreamConfig and MultiContextConfig take projectId
and dictionaryIds ([] disables dictionaries):
final session = client.tts.streamingSession(
StreamConfig(voiceId: 1071, language: 'en', projectId: dictionary.projectId),
);
final multi = client.tts.multiContextSession(MultiContextConfig(
defaultVoiceId: 1071,
language: 'en',
projectId: dictionary.projectId,
dictionaryIds: [dictionary.id],
));Delete a dictionary
Deleting a dictionary also deletes its entries:
client.dictionaries.delete(dictionary.id)await client.dictionaries.delete(dictionary.id);client.dictionaries().delete(dictionary.getId());client.dictionaries().delete(dictionary.id, None).await?;client.dictionaries().remove(dictionary.id);await client.dictionaries.delete(dictionary.id);Next steps
- Types and errors:
Dictionary,DictionaryEntry, and result models - Text normalization: how normalization interacts with dictionaries
- Dictionaries API reference: the HTTP contract and field limits