Documentation Index
Fetch the complete documentation index at: https://docs.sf-voice.sh/llms.txt
Use this file to discover all available pages before exploring further.
sf_voice_media — async, built on reqwest. Requires tokio.
Use this SDK inside Tokio services or jobs where ingest and polling should be part of the same async runtime.
Install
Add to Cargo.toml:
[dependencies]
sf_voice_media = "0.1.1"
tokio = { version = "1", features = ["full"] }
Create a client
use sf_voice_media::SfVoiceMedia;
let client = SfVoiceMedia::new(
"https://api.sf-voice.com",
std::env::var("SF_VOICE_API_KEY").unwrap(),
)?;
Ingest
use sf_voice_media::{SfVoiceMedia, IngestRequest, MediaType};
let resp = client.ingest(
IngestRequest::from_url("https://storage.example.com/calls/001.mp3")
.asset_id("call_001")
.asset_class("customer_acme")
.media_type(MediaType::Audio)
.build(),
).await?;
let task_id = resp.task_id;
S3:
use sf_voice_media::IngestRequest;
let resp = client.ingest(
IngestRequest::from_s3("calls/customer_acme/001.mp3")
.asset_id("call_001")
.asset_class("customer_acme")
.media_type(MediaType::Audio)
.build(),
).await?;
Poll until ready
use sf_voice_media::TaskStatus;
let task = client.poll_task(&task_id, None).await?;
match task.status {
TaskStatus::Ready => println!("indexed: {}", task.asset_id),
TaskStatus::Failed => eprintln!("failed: {:?}", task.error),
_ => unreachable!(),
}
poll_task takes optional PollOptions { interval_ms, timeout_ms }. Defaults: 1500ms interval, 120s timeout.
Search
use sf_voice_media::SearchRequest;
let resp = client.search(
SearchRequest::new("customer asks about pricing")
.asset_class("customer_acme")
.threshold(0.7)
.limit(10)
.build(),
).await?;
for result in &resp.results {
println!("{} {}–{}ms ({:.2})", result.asset_id, result.start_ms, result.end_ms, result.score);
}
Assets
// list
let resp = client.list_assets(None).await?;
// get one
let asset = client.get_asset("call_001").await?;
// delete
client.delete_asset("call_001").await?;
Errors
use sf_voice_media::SfVoiceMediaError;
match client.search(req).await {
Ok(resp) => { /* use resp */ }
Err(SfVoiceMediaError::Api { code, message, status }) => {
eprintln!("api error {status} [{code}]: {message}");
}
Err(SfVoiceMediaError::Http(e)) => {
eprintln!("transport error: {e}");
}
Err(SfVoiceMediaError::PollTimeout { task_id }) => {
eprintln!("timed out polling {task_id}");
}
}