use crate::{
codec::Dict,
error::{Error, Result},
value::Value,
};
wire_struct! {
#[derive(Debug, Clone, PartialEq)]
pub struct BatchTokenIDOutSlim: array("BatchTokenIDOutSlim") {
pub rids: Option<Vec<String>> = None,
pub output_ids: Vec<Vec<i32>>,
pub finished_reasons: Vec<String>,
pub prompt_tokens: Vec<i64>,
pub completion_tokens: Vec<i64>,
pub cached_tokens: Vec<i64>,
pub output_token_logprobs_val: Vec<Vec<f64>>,
pub output_token_logprobs_idx: Vec<Vec<i32>>,
pub engine_index: i64 = 0,
pub num_running: i64 = 0,
pub num_waiting: i64 = 0,
pub kv_active_pages: i64 = 0,
pub kv_total_pages: i64 = 0,
pub finish_reason_details: Vec<Option<FinishDetails>> = Vec::new(),
pub spec_verify_ct: Vec<i64> = Vec::new(),
pub accept_draft_tokens: Vec<Option<f64>> = Vec::new(),
pub input_token_logprobs_val: Vec<Vec<Option<f64>>> = Vec::new(),
pub input_token_logprobs_idx: Vec<Vec<i32>> = Vec::new(),
pub input_top_logprobs_val: Vec<Vec<Option<Vec<f64>>>> = Vec::new(),
pub input_top_logprobs_idx: Vec<Vec<Option<Vec<i32>>>> = Vec::new(),
pub output_top_logprobs_val: Vec<Vec<Vec<f64>>> = Vec::new(),
pub output_top_logprobs_idx: Vec<Vec<Vec<i32>>> = Vec::new(),
}
}
pub type FinishDetails = Dict<String, Value>;
pub type TopLogprobs = (Vec<Vec<f64>>, Vec<Vec<i32>>);
pub type PromptTopLogprobs = (Vec<Option<Vec<f64>>>, Vec<Option<Vec<i32>>>);
pub type TopLogprobRows<'a> = (&'a [Vec<f64>], &'a [Vec<i32>]);
pub type PromptTopLogprobRows<'a> = (&'a [Option<Vec<f64>>], &'a [Option<Vec<i32>>]);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct RequestOutput<'a> {
pub rid: &'a str,
pub output_ids: &'a [i32],
pub finish_reason: Option<&'a str>,
pub prompt_tokens: i64,
pub completion_tokens: i64,
pub cached_tokens: i64,
pub output_token_logprobs: &'a [f64],
pub finish_details: Option<&'a FinishDetails>,
pub spec_verify_ct: Option<i64>,
pub accept_draft_tokens: Option<f64>,
pub input_token_logprobs: Option<(&'a [Option<f64>], &'a [i32])>,
pub input_top_logprobs: Option<PromptTopLogprobRows<'a>>,
pub output_top_logprobs: Option<TopLogprobRows<'a>>,
}
impl BatchTokenIDOutSlim {
pub fn requests(&self) -> Result<impl Iterator<Item = RequestOutput<'_>>> {
let rids = self.rids.as_deref().ok_or(Error::MissingField("rids"))?;
let len = rids.len();
let columns = [
("output_ids", self.output_ids.len()),
("finished_reasons", self.finished_reasons.len()),
("prompt_tokens", self.prompt_tokens.len()),
("completion_tokens", self.completion_tokens.len()),
("cached_tokens", self.cached_tokens.len()),
(
"output_token_logprobs_val",
self.output_token_logprobs_val.len(),
),
(
"output_token_logprobs_idx",
self.output_token_logprobs_idx.len(),
),
];
if let Some((name, found)) = columns.iter().find(|(_, found)| *found != len) {
return Err(Error::Invalid(format!(
"column `{name}` has {found} entries for {len} requests"
)));
}
let optional = [
("finish_reason_details", self.finish_reason_details.len()),
("spec_verify_ct", self.spec_verify_ct.len()),
("accept_draft_tokens", self.accept_draft_tokens.len()),
(
"input_token_logprobs_val",
self.input_token_logprobs_val.len(),
),
(
"input_token_logprobs_idx",
self.input_token_logprobs_idx.len(),
),
("input_top_logprobs_val", self.input_top_logprobs_val.len()),
("input_top_logprobs_idx", self.input_top_logprobs_idx.len()),
(
"output_top_logprobs_val",
self.output_top_logprobs_val.len(),
),
(
"output_top_logprobs_idx",
self.output_top_logprobs_idx.len(),
),
];
if let Some((name, found)) = optional
.iter()
.find(|(_, found)| *found != 0 && *found != len)
{
return Err(Error::Invalid(format!(
"column `{name}` has {found} entries for {len} requests"
)));
}
fn pair<'a, A, B>(
values: &'a [Vec<A>],
ids: &'a [Vec<B>],
i: usize,
) -> Option<(&'a [A], &'a [B])> {
Some((values.get(i)?.as_slice(), ids.get(i)?.as_slice())).filter(|(v, _)| !v.is_empty())
}
Ok((0..len).map(move |i| RequestOutput {
rid: &rids[i],
output_ids: &self.output_ids[i],
finish_reason: Some(self.finished_reasons[i].as_str()).filter(|r| !r.is_empty()),
prompt_tokens: self.prompt_tokens[i],
completion_tokens: self.completion_tokens[i],
cached_tokens: self.cached_tokens[i],
output_token_logprobs: &self.output_token_logprobs_val[i],
finish_details: self.finish_reason_details.get(i).and_then(Option::as_ref),
spec_verify_ct: self.spec_verify_ct.get(i).copied(),
accept_draft_tokens: self.accept_draft_tokens.get(i).copied().flatten(),
input_token_logprobs: pair(
&self.input_token_logprobs_val,
&self.input_token_logprobs_idx,
i,
),
input_top_logprobs: pair(
&self.input_top_logprobs_val,
&self.input_top_logprobs_idx,
i,
),
output_top_logprobs: pair(
&self.output_top_logprobs_val,
&self.output_top_logprobs_idx,
i,
),
}))
}
}