unify cargo version and add some ci rules
This commit is contained in:
+18
-25
@@ -1,10 +1,11 @@
|
||||
use std::f64::consts::PI;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use candle_core::{D, Device, Tensor};
|
||||
use candle_nn::{Conv1d, Conv1dConfig, Module};
|
||||
use hound::{SampleFormat, WavReader};
|
||||
use num::integer::gcd;
|
||||
use std::f64::consts::PI;
|
||||
use std::path::Path;
|
||||
|
||||
// 重采样方法枚举
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -13,7 +14,6 @@ pub enum ResamplingMethod {
|
||||
SincInterpKaiser,
|
||||
}
|
||||
|
||||
|
||||
// 零阶修正贝塞尔函数 I0
|
||||
fn i0(x: f32) -> f32 {
|
||||
let mut result = 1.0;
|
||||
@@ -80,7 +80,7 @@ pub fn get_sinc_resample_kernel(
|
||||
window_arg.cos()?.sqr()?
|
||||
}
|
||||
ResamplingMethod::SincInterpKaiser => {
|
||||
let beta_val = beta.unwrap_or(14.769656459379492);
|
||||
let beta_val = beta.unwrap_or(14.769_656_f32);
|
||||
let i0_beta = i0(beta_val);
|
||||
|
||||
let normalized_t = t.affine(1.0 / lowpass_filter_width as f64, 0.0)?;
|
||||
@@ -94,8 +94,7 @@ pub fn get_sinc_resample_kernel(
|
||||
.iter()
|
||||
.map(|x| i0(beta_val * x) / i0_beta)
|
||||
.collect();
|
||||
let window = Tensor::new(window_val, device)?.reshape(sqrt_dims)?;
|
||||
window
|
||||
Tensor::new(window_val, device)?.reshape(sqrt_dims)?
|
||||
}
|
||||
};
|
||||
|
||||
@@ -196,7 +195,7 @@ pub fn resample(
|
||||
rolloff,
|
||||
resampling_method,
|
||||
beta,
|
||||
&device,
|
||||
device,
|
||||
)?;
|
||||
let t = apply_sinc_resample_kernel(waveform, orig_freq, new_freq, gcd_val, &kernel, width)?;
|
||||
Ok(t)
|
||||
@@ -220,35 +219,28 @@ pub fn load_audio<P: AsRef<Path>>(path: P, device: Device) -> Result<(Tensor, us
|
||||
let spec = reader.spec();
|
||||
let samples: Vec<f32> = match spec.sample_format {
|
||||
SampleFormat::Int => {
|
||||
// 将整数样本转换为浮点数 [-1.0, 1.0]
|
||||
// 将整数样本转换为浮点数 [-1.0, 1.0]
|
||||
// println!("spec.bits_per_sample: {}", spec.bits_per_sample);
|
||||
let samples = match spec.bits_per_sample {
|
||||
8 => {
|
||||
reader
|
||||
match spec.bits_per_sample {
|
||||
8 => reader
|
||||
.samples::<i8>()
|
||||
.map(|s| s.map(|sample| sample as f32 / i8::MAX as f32))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
},
|
||||
16 => {
|
||||
reader
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
16 => reader
|
||||
.samples::<i16>()
|
||||
.map(|s| s.map(|sample| sample as f32 / i16::MAX as f32))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
},
|
||||
24 => {
|
||||
reader
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
24 => reader
|
||||
.samples::<i32>()
|
||||
.map(|s| s.map(|sample| sample as f32 / 8388607.0))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
},
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
_ => {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Unsupported bit depth: {}",
|
||||
spec.bits_per_sample
|
||||
));
|
||||
}
|
||||
};
|
||||
samples
|
||||
}
|
||||
}
|
||||
SampleFormat::Float => {
|
||||
// 直接读取浮点数样本
|
||||
@@ -278,8 +270,9 @@ pub fn load_audio_with_resample<P: AsRef<Path>>(
|
||||
target_sample_rate: Option<usize>,
|
||||
) -> Result<Tensor> {
|
||||
let (mut audio, sr) = load_audio(path, device)?;
|
||||
if target_sample_rate.is_some() && target_sample_rate.unwrap() as usize != sr {
|
||||
let target_sample_rate = target_sample_rate.unwrap();
|
||||
if let Some(target_sample_rate) = target_sample_rate
|
||||
&& target_sample_rate != sr
|
||||
{
|
||||
audio = resample_simple(&audio, sr as i64, target_sample_rate as i64)?;
|
||||
}
|
||||
Ok(audio)
|
||||
|
||||
+9
-11
@@ -33,13 +33,13 @@ pub fn load_image_from_base64(base64_data: &str) -> Result<DynamicImage> {
|
||||
Ok(img)
|
||||
}
|
||||
|
||||
pub fn get_image(file: &String) -> Result<DynamicImage> {
|
||||
pub fn get_image(file: &str) -> Result<DynamicImage> {
|
||||
let mut img = None;
|
||||
if file.starts_with("http://") || file.starts_with("https://") {
|
||||
img = Some(load_image_from_url(&file)?);
|
||||
img = Some(load_image_from_url(file)?);
|
||||
}
|
||||
if file.starts_with("file://") {
|
||||
let mut path = file.clone();
|
||||
let mut path = file.to_owned();
|
||||
path = path.split_off(7);
|
||||
img = Some(
|
||||
ImageReader::open(path)
|
||||
@@ -48,15 +48,13 @@ pub fn get_image(file: &String) -> Result<DynamicImage> {
|
||||
.map_err(|e| anyhow!(format!("Failed to decode image: {}", e)))?,
|
||||
);
|
||||
}
|
||||
if file.starts_with("data:image") {
|
||||
if file.contains("base64,") {
|
||||
let data: Vec<&str> = file.split("base64,").collect();
|
||||
let data = data[1];
|
||||
img = Some(load_image_from_base64(data)?);
|
||||
}
|
||||
if file.starts_with("data:image") && file.contains("base64,") {
|
||||
let data: Vec<&str> = file.split("base64,").collect();
|
||||
let data = data[1];
|
||||
img = Some(load_image_from_base64(data)?);
|
||||
}
|
||||
if img.is_some() {
|
||||
return Ok(img.unwrap());
|
||||
if let Some(img) = img {
|
||||
return Ok(img);
|
||||
}
|
||||
Err(anyhow!("get image from message failed".to_string()))
|
||||
}
|
||||
|
||||
+257
-2
@@ -1,5 +1,260 @@
|
||||
pub mod audio_utils;
|
||||
pub mod img_utils;
|
||||
pub mod tensor_utils;
|
||||
pub mod utils;
|
||||
pub mod video_utils;
|
||||
pub mod audio_utils;
|
||||
|
||||
use anyhow::Result;
|
||||
use candle_core::{DType, Device};
|
||||
use candle_transformers::generation::LogitsProcessor;
|
||||
use openai_dive::v1::resources::{
|
||||
chat::{
|
||||
ChatCompletionChoice, ChatCompletionChunkChoice, ChatCompletionChunkResponse,
|
||||
ChatCompletionResponse, ChatMessage, ChatMessageContent, DeltaChatMessage, DeltaFunction,
|
||||
DeltaToolCall, Function, ToolCall,
|
||||
},
|
||||
shared::FinishReason,
|
||||
};
|
||||
|
||||
pub fn get_device(device: Option<&Device>) -> Device {
|
||||
match device {
|
||||
Some(d) => d.clone(),
|
||||
None => {
|
||||
#[cfg(feature = "cuda")]
|
||||
{
|
||||
Device::new_cuda(0).unwrap_or(Device::Cpu)
|
||||
}
|
||||
#[cfg(not(feature = "cuda"))]
|
||||
{
|
||||
Device::Cpu
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_dtype(dtype: Option<DType>, cfg_dtype: &str) -> DType {
|
||||
match dtype {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
#[cfg(feature = "cuda")]
|
||||
{
|
||||
match cfg_dtype {
|
||||
"float32" | "float" => DType::F32,
|
||||
"float64" | "double" => DType::F64,
|
||||
"float16" => DType::F16,
|
||||
"bfloat16" => DType::BF16,
|
||||
"uint8" => DType::U8,
|
||||
"int8" | "int16" | "int32" | "int64" => DType::I64,
|
||||
_ => DType::F32,
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "cuda"))]
|
||||
{
|
||||
match cfg_dtype {
|
||||
"float32" | "float" => DType::F32,
|
||||
"float64" | "double" => DType::F64,
|
||||
"float16" | "bfloat16" => DType::F16, // cpu上bfloat16有问题
|
||||
"uint8" => DType::U8,
|
||||
"int8" | "int16" | "int32" | "int64" => DType::I64,
|
||||
_ => DType::F32,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string_to_static_str(s: String) -> &'static str {
|
||||
Box::leak(s.into_boxed_str())
|
||||
}
|
||||
|
||||
pub fn find_type_files(path: &str, extension_type: &str) -> Result<Vec<String>> {
|
||||
let mut files = Vec::new();
|
||||
|
||||
for entry in std::fs::read_dir(path)? {
|
||||
let entry = entry?;
|
||||
let file_path = entry.path();
|
||||
|
||||
if file_path.is_file()
|
||||
&& let Some(extension) = file_path.extension()
|
||||
&& extension == extension_type
|
||||
{
|
||||
files.push(file_path.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(files)
|
||||
}
|
||||
|
||||
pub fn round_by_factor(num: u32, factor: u32) -> u32 {
|
||||
let round = (num as f32 / factor as f32).round() as u32;
|
||||
round * factor
|
||||
}
|
||||
|
||||
pub fn floor_by_factor(num: f32, factor: u32) -> u32 {
|
||||
let floor = (num / factor as f32).floor() as u32;
|
||||
floor * factor
|
||||
}
|
||||
|
||||
pub fn ceil_by_factor(num: f32, factor: u32) -> u32 {
|
||||
let ceil = (num / factor as f32).ceil() as u32;
|
||||
ceil * factor
|
||||
}
|
||||
|
||||
pub fn build_completion_response(res: String, model_name: &str) -> ChatCompletionResponse {
|
||||
let id = uuid::Uuid::new_v4().to_string();
|
||||
let mut response = ChatCompletionResponse {
|
||||
id: Some(id),
|
||||
choices: vec![],
|
||||
created: chrono::Utc::now().timestamp() as u32,
|
||||
model: model_name.to_string(),
|
||||
service_tier: None,
|
||||
system_fingerprint: None,
|
||||
object: "chat.completion".to_string(),
|
||||
usage: None,
|
||||
};
|
||||
let choice = if res.contains("<tool_call>") {
|
||||
let mes: Vec<&str> = res.split("<tool_call>").collect();
|
||||
let content = mes[0].to_string();
|
||||
let mut tool_vec = Vec::new();
|
||||
for (i, m) in mes.iter().enumerate().skip(1) {
|
||||
let tool_mes = m.replace("</tool_call>", "");
|
||||
let function = match serde_json::from_str::<serde_json::Value>(&tool_mes) {
|
||||
Ok(json_value) => {
|
||||
let name = json_value
|
||||
.get("name")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
let arguments = json_value
|
||||
.get("arguments")
|
||||
.map(|v| v.to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
Function { name, arguments }
|
||||
}
|
||||
Err(_) => Function {
|
||||
name: "".to_string(),
|
||||
arguments: "".to_string(),
|
||||
},
|
||||
};
|
||||
let tool_call = ToolCall {
|
||||
id: (i - 1).to_string(),
|
||||
r#type: "function".to_string(),
|
||||
function,
|
||||
};
|
||||
tool_vec.push(tool_call);
|
||||
}
|
||||
ChatCompletionChoice {
|
||||
index: 0,
|
||||
message: ChatMessage::Assistant {
|
||||
content: Some(ChatMessageContent::Text(content)),
|
||||
reasoning_content: None,
|
||||
refusal: None,
|
||||
name: None,
|
||||
audio: None,
|
||||
tool_calls: Some(tool_vec),
|
||||
},
|
||||
finish_reason: Some(FinishReason::ToolCalls),
|
||||
logprobs: None,
|
||||
}
|
||||
} else {
|
||||
ChatCompletionChoice {
|
||||
index: 0,
|
||||
message: ChatMessage::Assistant {
|
||||
content: Some(ChatMessageContent::Text(res)),
|
||||
reasoning_content: None,
|
||||
refusal: None,
|
||||
name: None,
|
||||
audio: None,
|
||||
tool_calls: None,
|
||||
},
|
||||
finish_reason: Some(FinishReason::StopSequenceReached),
|
||||
logprobs: None,
|
||||
}
|
||||
};
|
||||
response.choices.push(choice);
|
||||
response
|
||||
}
|
||||
|
||||
pub fn build_completion_chunk_response(
|
||||
res: String,
|
||||
model_name: &str,
|
||||
tool_call_id: Option<String>,
|
||||
tool_call_content: Option<String>,
|
||||
) -> ChatCompletionChunkResponse {
|
||||
let id = uuid::Uuid::new_v4().to_string();
|
||||
let mut response = ChatCompletionChunkResponse {
|
||||
id: Some(id),
|
||||
choices: vec![],
|
||||
created: chrono::Utc::now().timestamp() as u32,
|
||||
model: model_name.to_string(),
|
||||
system_fingerprint: None,
|
||||
object: "chat.completion.chunk".to_string(),
|
||||
usage: None,
|
||||
};
|
||||
let choice = if let Some(tool_call_id) = tool_call_id {
|
||||
let function = if let Some(content) = tool_call_content {
|
||||
match serde_json::from_str::<serde_json::Value>(&content) {
|
||||
Ok(json_value) => {
|
||||
let name = json_value
|
||||
.get("name")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_string());
|
||||
|
||||
let arguments = json_value.get("arguments").map(|v| v.to_string());
|
||||
|
||||
DeltaFunction { name, arguments }
|
||||
}
|
||||
Err(_) => DeltaFunction {
|
||||
name: None,
|
||||
arguments: Some(content),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
DeltaFunction {
|
||||
name: None,
|
||||
arguments: None,
|
||||
}
|
||||
};
|
||||
ChatCompletionChunkChoice {
|
||||
index: Some(0),
|
||||
delta: DeltaChatMessage::Assistant {
|
||||
content: None,
|
||||
reasoning_content: None,
|
||||
refusal: None,
|
||||
name: None,
|
||||
tool_calls: Some(vec![DeltaToolCall {
|
||||
index: Some(0),
|
||||
id: Some(tool_call_id),
|
||||
r#type: Some("function".to_string()),
|
||||
function,
|
||||
}]),
|
||||
},
|
||||
finish_reason: None,
|
||||
logprobs: None,
|
||||
}
|
||||
} else {
|
||||
ChatCompletionChunkChoice {
|
||||
index: Some(0),
|
||||
delta: DeltaChatMessage::Assistant {
|
||||
content: Some(ChatMessageContent::Text(res)),
|
||||
reasoning_content: None,
|
||||
refusal: None,
|
||||
name: None,
|
||||
tool_calls: None,
|
||||
},
|
||||
finish_reason: None,
|
||||
logprobs: None,
|
||||
}
|
||||
};
|
||||
response.choices.push(choice);
|
||||
response
|
||||
}
|
||||
|
||||
pub fn get_logit_processor(temperature: Option<f32>, top_p: Option<f32>) -> LogitsProcessor {
|
||||
LogitsProcessor::new(
|
||||
34562,
|
||||
temperature.map(|temp| temp as f64),
|
||||
top_p.map(|tp| tp as f64),
|
||||
)
|
||||
}
|
||||
|
||||
+28
-51
@@ -1,23 +1,15 @@
|
||||
use anyhow::{anyhow, Ok, Result};
|
||||
use anyhow::{Ok, Result, anyhow};
|
||||
use candle_core::{D, DType, Device, IndexOp, Tensor, shape::Dim};
|
||||
|
||||
pub fn prepare_causal_attention_mask(
|
||||
b_size: usize,
|
||||
tgt_len: usize,
|
||||
seqlen_offset: usize,
|
||||
device: &Device
|
||||
device: &Device,
|
||||
) -> Result<Tensor> {
|
||||
// Sliding window mask?
|
||||
let mask: Vec<_> = (0..tgt_len)
|
||||
.flat_map(|i| {
|
||||
(0..tgt_len).map(move |j| {
|
||||
if i < j {
|
||||
f32::NEG_INFINITY
|
||||
} else {
|
||||
0.
|
||||
}
|
||||
})
|
||||
})
|
||||
.flat_map(|i| (0..tgt_len).map(move |j| if i < j { f32::NEG_INFINITY } else { 0. }))
|
||||
.collect();
|
||||
let mask = Tensor::from_slice(&mask, (tgt_len, tgt_len), device)?;
|
||||
let mask = if seqlen_offset > 0 {
|
||||
@@ -84,12 +76,10 @@ pub fn nonzero_index_vec(mask: &Tensor) -> Result<Vec<u32>> {
|
||||
mask = mask.to_dtype(DType::U32)?;
|
||||
}
|
||||
match mask.rank() {
|
||||
0 => {
|
||||
return Err(anyhow!(format!(
|
||||
"input rank must > 0, the input tensor rank: {}",
|
||||
mask.rank()
|
||||
)));
|
||||
}
|
||||
0 => Err(anyhow!(format!(
|
||||
"input rank must > 0, the input tensor rank: {}",
|
||||
mask.rank()
|
||||
))),
|
||||
1 => {
|
||||
let mask_vector = mask.to_vec1::<u32>()?;
|
||||
let indices: Vec<u32> = mask_vector
|
||||
@@ -99,12 +89,10 @@ pub fn nonzero_index_vec(mask: &Tensor) -> Result<Vec<u32>> {
|
||||
.collect();
|
||||
Ok(indices)
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!(format!(
|
||||
"input rank not support, the input tensor rank: {}",
|
||||
mask.rank()
|
||||
)));
|
||||
}
|
||||
_ => Err(anyhow!(format!(
|
||||
"input rank not support, the input tensor rank: {}",
|
||||
mask.rank()
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,8 +107,7 @@ pub fn nonzero_index(mask: &Tensor) -> Result<Tensor> {
|
||||
}
|
||||
1 => {
|
||||
let index_vec = nonzero_index_vec(mask)?;
|
||||
let indices_tensor = Tensor::from_slice(&index_vec, index_vec.len(), mask.device())?;
|
||||
indices_tensor
|
||||
Tensor::from_slice(&index_vec, index_vec.len(), mask.device())?
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!(format!(
|
||||
@@ -140,12 +127,10 @@ pub fn zero_index_vec(mask: &Tensor) -> Result<Vec<u32>> {
|
||||
mask = mask.to_dtype(DType::U32)?;
|
||||
}
|
||||
match mask.rank() {
|
||||
0 => {
|
||||
return Err(anyhow!(format!(
|
||||
"input rank must > 0, the input tensor rank: {}",
|
||||
mask.rank()
|
||||
)));
|
||||
}
|
||||
0 => Err(anyhow!(format!(
|
||||
"input rank must > 0, the input tensor rank: {}",
|
||||
mask.rank()
|
||||
))),
|
||||
1 => {
|
||||
let mask_vector = mask.to_vec1::<u32>()?;
|
||||
let indices: Vec<u32> = mask_vector
|
||||
@@ -155,12 +140,10 @@ pub fn zero_index_vec(mask: &Tensor) -> Result<Vec<u32>> {
|
||||
.collect();
|
||||
Ok(indices)
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!(format!(
|
||||
"input rank not support, the input tensor rank: {}",
|
||||
mask.rank()
|
||||
)));
|
||||
}
|
||||
_ => Err(anyhow!(format!(
|
||||
"input rank not support, the input tensor rank: {}",
|
||||
mask.rank()
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,12 +161,8 @@ pub fn nonzero_slice(mask: &Tensor) -> Result<Vec<(usize, usize)>> {
|
||||
// 索引前闭后开
|
||||
let mut index_vec = nonzero_index_vec(mask)?;
|
||||
match index_vec.len() {
|
||||
0 => {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
1 => {
|
||||
return Ok(vec![(index_vec[0] as usize, (index_vec[0] + 1) as usize)]);
|
||||
}
|
||||
0 => Ok(vec![]),
|
||||
1 => Ok(vec![(index_vec[0] as usize, (index_vec[0] + 1) as usize)]),
|
||||
_ => {
|
||||
let mut vec_slice = vec![];
|
||||
let mut start = index_vec.remove(0);
|
||||
@@ -244,7 +223,7 @@ pub fn get_equal_mask(input_ids: &Tensor, token_ids: u32) -> Result<Tensor> {
|
||||
|
||||
pub fn get_vision_next_indices(input_ids: &Tensor, token_id: u32) -> Result<Tensor> {
|
||||
// input_ids -> shape: (seq_len)
|
||||
let mask = get_equal_mask(&input_ids, token_id)?;
|
||||
let mask = get_equal_mask(input_ids, token_id)?;
|
||||
let indices = nonzero_index(&mask)?;
|
||||
let indices = indices.broadcast_add(&Tensor::new(vec![1u32], input_ids.device())?)?;
|
||||
Ok(indices)
|
||||
@@ -255,12 +234,10 @@ pub fn linspace(start: f32, end: f32, steps: usize, device: &Device) -> Result<T
|
||||
if steps == 1 {
|
||||
let t = Tensor::from_slice(&[start], 1, device)?;
|
||||
return Ok(t);
|
||||
}
|
||||
let step_size = (end - start) / (steps-1) as f32;
|
||||
let data: Vec<f32> = (0..steps)
|
||||
.map(|i| start + i as f32 * step_size)
|
||||
.collect();
|
||||
|
||||
}
|
||||
let step_size = (end - start) / (steps - 1) as f32;
|
||||
let data: Vec<f32> = (0..steps).map(|i| start + i as f32 * step_size).collect();
|
||||
|
||||
let t = Tensor::from_slice(&data, steps, device)?;
|
||||
Ok(t)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
use anyhow::Result;
|
||||
use candle_core::{DType, Device};
|
||||
use candle_transformers::generation::LogitsProcessor;
|
||||
use openai_dive::v1::resources::{
|
||||
chat::{
|
||||
ChatCompletionChoice, ChatCompletionChunkChoice, ChatCompletionChunkResponse,
|
||||
ChatCompletionResponse, ChatMessage, ChatMessageContent, DeltaChatMessage, DeltaFunction,
|
||||
DeltaToolCall, Function, ToolCall,
|
||||
},
|
||||
shared::FinishReason,
|
||||
};
|
||||
|
||||
pub fn get_device(device: Option<&Device>) -> Device {
|
||||
match device {
|
||||
Some(d) => d.clone(),
|
||||
None => {
|
||||
#[cfg(feature = "cuda")]
|
||||
{
|
||||
Device::new_cuda(0).unwrap_or(Device::Cpu)
|
||||
}
|
||||
#[cfg(not(feature = "cuda"))]
|
||||
{
|
||||
Device::Cpu
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_dtype(dtype: Option<DType>, cfg_dtype: &str) -> DType {
|
||||
match dtype {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
#[cfg(feature = "cuda")]
|
||||
{
|
||||
match cfg_dtype {
|
||||
"float32" | "float" => DType::F32,
|
||||
"float64" | "double" => DType::F64,
|
||||
"float16" => DType::F16,
|
||||
"bfloat16" => DType::BF16,
|
||||
"uint8" => DType::U8,
|
||||
"int8" | "int16" | "int32" | "int64" => DType::I64,
|
||||
_ => DType::F32,
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "cuda"))]
|
||||
{
|
||||
match cfg_dtype {
|
||||
"float32" | "float" => DType::F32,
|
||||
"float64" | "double" => DType::F64,
|
||||
"float16" | "bfloat16" => DType::F16, // cpu上bfloat16有问题
|
||||
"uint8" => DType::U8,
|
||||
"int8" | "int16" | "int32" | "int64" => DType::I64,
|
||||
_ => DType::F32,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string_to_static_str(s: String) -> &'static str {
|
||||
Box::leak(s.into_boxed_str())
|
||||
}
|
||||
|
||||
pub fn find_type_files(path: &str, extension_type: &str) -> Result<Vec<String>> {
|
||||
let mut files = Vec::new();
|
||||
|
||||
for entry in std::fs::read_dir(path)? {
|
||||
let entry = entry?;
|
||||
let file_path = entry.path();
|
||||
|
||||
if file_path.is_file() {
|
||||
if let Some(extension) = file_path.extension() {
|
||||
if extension == extension_type {
|
||||
files.push(file_path.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(files)
|
||||
}
|
||||
|
||||
|
||||
pub fn round_by_factor(num: u32, factor: u32) -> u32 {
|
||||
let round = (num as f32 / factor as f32).round() as u32;
|
||||
round * factor
|
||||
}
|
||||
|
||||
pub fn floor_by_factor(num: f32, factor: u32) -> u32 {
|
||||
let floor = (num / factor as f32).floor() as u32;
|
||||
floor * factor
|
||||
}
|
||||
|
||||
pub fn ceil_by_factor(num: f32, factor: u32) -> u32 {
|
||||
let ceil = (num / factor as f32).ceil() as u32;
|
||||
ceil * factor
|
||||
}
|
||||
|
||||
pub fn build_completion_response(res: String, model_name: &str) -> ChatCompletionResponse {
|
||||
let id = uuid::Uuid::new_v4().to_string();
|
||||
let mut response = ChatCompletionResponse {
|
||||
id: Some(id),
|
||||
choices: vec![],
|
||||
created: chrono::Utc::now().timestamp() as u32,
|
||||
model: model_name.to_string(),
|
||||
service_tier: None,
|
||||
system_fingerprint: None,
|
||||
object: "chat.completion".to_string(),
|
||||
usage: None,
|
||||
};
|
||||
let choice = if res.contains("<tool_call>") {
|
||||
let mes: Vec<&str> = res.split("<tool_call>").collect();
|
||||
let content = mes[0].to_string();
|
||||
let mut tool_vec = Vec::new();
|
||||
for i in 1..mes.len() {
|
||||
let tool_mes = mes[i].replace("</tool_call>", "");
|
||||
let function = match serde_json::from_str::<serde_json::Value>(&tool_mes) {
|
||||
Ok(json_value) => {
|
||||
let name = json_value
|
||||
.get("name")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
let arguments = json_value
|
||||
.get("arguments")
|
||||
.map(|v| v.to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
Function { name, arguments }
|
||||
}
|
||||
Err(_) => Function {
|
||||
name: "".to_string(),
|
||||
arguments: "".to_string(),
|
||||
},
|
||||
};
|
||||
let tool_call = ToolCall {
|
||||
id: (i - 1).to_string(),
|
||||
r#type: "function".to_string(),
|
||||
function: function,
|
||||
};
|
||||
tool_vec.push(tool_call);
|
||||
}
|
||||
ChatCompletionChoice {
|
||||
index: 0,
|
||||
message: ChatMessage::Assistant {
|
||||
content: Some(ChatMessageContent::Text(content)),
|
||||
reasoning_content: None,
|
||||
refusal: None,
|
||||
name: None,
|
||||
audio: None,
|
||||
tool_calls: Some(tool_vec),
|
||||
},
|
||||
finish_reason: Some(FinishReason::ToolCalls),
|
||||
logprobs: None,
|
||||
}
|
||||
} else {
|
||||
ChatCompletionChoice {
|
||||
index: 0,
|
||||
message: ChatMessage::Assistant {
|
||||
content: Some(ChatMessageContent::Text(res)),
|
||||
reasoning_content: None,
|
||||
refusal: None,
|
||||
name: None,
|
||||
audio: None,
|
||||
tool_calls: None,
|
||||
},
|
||||
finish_reason: Some(FinishReason::StopSequenceReached),
|
||||
logprobs: None,
|
||||
}
|
||||
};
|
||||
response.choices.push(choice);
|
||||
response
|
||||
}
|
||||
|
||||
pub fn build_completion_chunk_response(
|
||||
res: String,
|
||||
model_name: &str,
|
||||
tool_call_id: Option<String>,
|
||||
tool_call_content: Option<String>,
|
||||
) -> ChatCompletionChunkResponse {
|
||||
let id = uuid::Uuid::new_v4().to_string();
|
||||
let mut response = ChatCompletionChunkResponse {
|
||||
id: Some(id),
|
||||
choices: vec![],
|
||||
created: chrono::Utc::now().timestamp() as u32,
|
||||
model: model_name.to_string(),
|
||||
system_fingerprint: None,
|
||||
object: "chat.completion.chunk".to_string(),
|
||||
usage: None,
|
||||
};
|
||||
let choice = if tool_call_id.is_some() {
|
||||
let tool_call_id = tool_call_id.unwrap();
|
||||
let function = if let Some(content) = tool_call_content {
|
||||
match serde_json::from_str::<serde_json::Value>(&content) {
|
||||
Ok(json_value) => {
|
||||
let name = json_value
|
||||
.get("name")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_string());
|
||||
|
||||
let arguments = json_value.get("arguments").map(|v| v.to_string());
|
||||
|
||||
DeltaFunction { name, arguments }
|
||||
}
|
||||
Err(_) => DeltaFunction {
|
||||
name: None,
|
||||
arguments: Some(content),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
DeltaFunction {
|
||||
name: None,
|
||||
arguments: None,
|
||||
}
|
||||
};
|
||||
ChatCompletionChunkChoice {
|
||||
index: Some(0),
|
||||
delta: DeltaChatMessage::Assistant {
|
||||
content: None,
|
||||
reasoning_content: None,
|
||||
refusal: None,
|
||||
name: None,
|
||||
tool_calls: Some(vec![DeltaToolCall {
|
||||
index: Some(0),
|
||||
id: Some(tool_call_id),
|
||||
r#type: Some("function".to_string()),
|
||||
function,
|
||||
}]),
|
||||
},
|
||||
finish_reason: None,
|
||||
logprobs: None,
|
||||
}
|
||||
} else {
|
||||
ChatCompletionChunkChoice {
|
||||
index: Some(0),
|
||||
delta: DeltaChatMessage::Assistant {
|
||||
content: Some(ChatMessageContent::Text(res)),
|
||||
reasoning_content: None,
|
||||
refusal: None,
|
||||
name: None,
|
||||
tool_calls: None,
|
||||
},
|
||||
finish_reason: None,
|
||||
logprobs: None,
|
||||
}
|
||||
};
|
||||
response.choices.push(choice);
|
||||
response
|
||||
}
|
||||
|
||||
pub fn get_logit_processor(temperature: Option<f32>, top_p: Option<f32>) -> LogitsProcessor {
|
||||
let temperature = match temperature {
|
||||
Some(temp) => Some(temp as f64),
|
||||
None => None,
|
||||
};
|
||||
let top_p = match top_p {
|
||||
Some(tp) => Some(tp as f64),
|
||||
None => None,
|
||||
};
|
||||
LogitsProcessor::new(34562, temperature, top_p)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use ffmpeg_next as ffmpeg;
|
||||
use std::{fs::File, io::Write};
|
||||
|
||||
use ffmpeg_next as ffmpeg;
|
||||
|
||||
#[allow(unused)]
|
||||
fn save_file(
|
||||
frame: &ffmpeg::frame::Video,
|
||||
|
||||
Reference in New Issue
Block a user