Include start offset in voice-name window tag

Clones that don't start at 0:00 are tagged with where the reference
window begins (grandma-at1m32s-30s), so voices cloned from different
sections of the same source are distinguishable in the voice list.
Zero-start names keep the existing -30s form.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cameron Cordes
2026-06-12 16:21:41 -04:00
parent 1dec34540d
commit 1017fe73af
+58 -16
View File
@@ -177,13 +177,25 @@ fn tts_ref_seconds() -> u32 {
.unwrap_or(30)
}
/// Tag a (sanitized) voice name with the reference-clip cap used to create it,
/// e.g. `grandma` → `grandma-30s`. The tag makes the ref length visible in the
/// voice list so clones of the same source at different caps can be compared.
/// Tag a (sanitized) voice name with the reference window used to create it:
/// `grandma` → `grandma-30s` (from the start), or `grandma-at1m32s-30s` (30s
/// window starting at 1:32). The tag makes the window visible in the voice
/// list so clones of the same source from different sections can be compared.
/// Skips the append when the name already ends in the same tag; keeps the
/// 64-char bound by truncating the base name, never the tag.
fn append_ref_seconds(name: &str, secs: u32) -> String {
let suffix = format!("-{secs}s");
fn append_ref_window(name: &str, start: f64, secs: u32) -> String {
let start_whole = start.round().max(0.0) as u64;
let suffix = if start_whole > 0 {
// ':' isn't in the safe voice-name charset, so 1:32 becomes 1m32s.
let at = if start_whole >= 60 {
format!("at{}m{:02}s", start_whole / 60, start_whole % 60)
} else {
format!("at{start_whole}s")
};
format!("-{at}-{secs}s")
} else {
format!("-{secs}s")
};
if name.ends_with(&suffix) {
return name.to_string();
}
@@ -880,7 +892,7 @@ pub async fn create_voice_upload_handler(
};
// Tag the name with the ref-clip length (e.g. `grandma-30s`) so the
// library shows which reference length produced each clone.
let name = append_ref_seconds(&name, ref_duration.round().max(1.0) as u32);
let name = append_ref_window(&name, ref_start, ref_duration.round().max(1.0) as u32);
if file_bytes.is_empty() {
span.set_status(Status::error("voice_file is required"));
return HttpResponse::BadRequest().json(json!({ "error": "voice_file is required" }));
@@ -970,7 +982,8 @@ pub async fn create_voice_from_library_handler(
};
// Tag the name with the ref-clip length (e.g. `grandma-30s`) so the
// library shows which reference length produced each clone.
let voice_name = append_ref_seconds(&voice_name, ref_duration.round().max(1.0) as u32);
let voice_name =
append_ref_window(&voice_name, ref_start, ref_duration.round().max(1.0) as u32);
let library = match libraries::resolve_library_param(&app_state, req.library.as_deref()) {
Ok(Some(l)) => l,
@@ -1075,24 +1088,53 @@ mod tests {
}
#[test]
fn append_ref_seconds_tags_name() {
assert_eq!(append_ref_seconds("grandma", 30), "grandma-30s");
assert_eq!(append_ref_seconds("voice_01", 15), "voice_01-15s");
fn append_ref_window_tags_name() {
assert_eq!(append_ref_window("grandma", 0.0, 30), "grandma-30s");
assert_eq!(append_ref_window("voice_01", 0.0, 15), "voice_01-15s");
}
#[test]
fn append_ref_seconds_is_idempotent_for_same_cap() {
assert_eq!(append_ref_seconds("grandma-30s", 30), "grandma-30s");
// A different cap still appends — that's the comparison use-case.
assert_eq!(append_ref_seconds("grandma-15s", 30), "grandma-15s-30s");
fn append_ref_window_includes_nonzero_start() {
// Sub-minute starts stay in seconds; longer ones read as XmYYs since
// ':' isn't allowed in voice names.
assert_eq!(append_ref_window("grandma", 45.0, 30), "grandma-at45s-30s");
assert_eq!(
append_ref_window("grandma", 92.4, 30),
"grandma-at1m32s-30s"
);
assert_eq!(
append_ref_window("grandma", 600.0, 12),
"grandma-at10m00s-12s"
);
// A start that rounds to zero is "from the start".
assert_eq!(append_ref_window("grandma", 0.3, 30), "grandma-30s");
}
#[test]
fn append_ref_seconds_keeps_64_char_bound() {
fn append_ref_window_is_idempotent_for_same_window() {
assert_eq!(append_ref_window("grandma-30s", 0.0, 30), "grandma-30s");
assert_eq!(
append_ref_window("grandma-at45s-30s", 45.0, 30),
"grandma-at45s-30s"
);
// A different window still appends — that's the comparison use-case.
assert_eq!(append_ref_window("grandma-15s", 0.0, 30), "grandma-15s-30s");
assert_eq!(
append_ref_window("grandma-30s", 45.0, 30),
"grandma-30s-at45s-30s"
);
}
#[test]
fn append_ref_window_keeps_64_char_bound() {
let long = "a".repeat(64);
let tagged = append_ref_seconds(&long, 30);
let tagged = append_ref_window(&long, 0.0, 30);
assert_eq!(tagged.len(), 64);
assert!(tagged.ends_with("-30s"));
let tagged = append_ref_window(&long, 92.0, 30);
assert_eq!(tagged.len(), 64);
assert!(tagged.ends_with("-at1m32s-30s"));
}
#[test]