diff --git a/Cargo.lock b/Cargo.lock index 9c7d449..9d868af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,7 +23,6 @@ dependencies = [ name = "aha" version = "0.2.4" dependencies = [ - "aha_openai_dive", "ahash", "anyhow", "base64 0.22.1", @@ -32,8 +31,8 @@ dependencies = [ "candle-flash-attn", "candle-nn", "candle-transformers", - "chrono", "clap", + "derive_builder", "dirs", "ffmpeg-next", "half", @@ -44,7 +43,7 @@ dependencies = [ "num", "rayon", "realfft", - "reqwest 0.13.2", + "reqwest", "rocket", "sentencepiece", "serde", @@ -59,25 +58,6 @@ dependencies = [ "zip", ] -[[package]] -name = "aha_openai_dive" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06be555744ef37a775e05d920ac6d4e0c5765fdc00a12cd8e221b3a1f2eaf982" -dependencies = [ - "bytes", - "derive_builder", - "futures", - "reqwest 0.12.28", - "reqwest-eventsource", - "serde", - "serde_html_form", - "serde_json", - "tokio", - "tokio-stream", - "tokio-util", -] - [[package]] name = "ahash" version = "0.8.12" @@ -125,15 +105,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anstream" version = "1.0.0" @@ -509,9 +480,6 @@ name = "bytes" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" -dependencies = [ - "serde", -] [[package]] name = "bzip2" @@ -693,19 +661,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "chrono" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-link", -] - [[package]] name = "cipher" version = "0.4.4" @@ -1286,17 +1241,6 @@ dependencies = [ "cc", ] -[[package]] -name = "eventsource-stream" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab" -dependencies = [ - "futures-core", - "nom 7.1.3", - "pin-project-lite", -] - [[package]] name = "exr" version = "1.74.0" @@ -1460,15 +1404,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] - [[package]] name = "foreign-types" version = "0.5.0" @@ -1476,7 +1411,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared 0.3.1", + "foreign-types-shared", ] [[package]] @@ -1490,12 +1425,6 @@ dependencies = [ "syn", ] -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -1525,7 +1454,6 @@ checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1548,17 +1476,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" -[[package]] -name = "futures-executor" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - [[package]] name = "futures-io" version = "0.3.32" @@ -1588,12 +1505,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" - [[package]] name = "futures-util" version = "0.3.32" @@ -2159,22 +2070,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.8.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.20" @@ -2200,30 +2095,6 @@ dependencies = [ "windows-registry", ] -[[package]] -name = "iana-time-zone" -version = "0.1.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core 0.62.2", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "icu_collections" version = "2.1.1" @@ -2745,7 +2616,7 @@ dependencies = [ "bitflags 2.11.0", "block", "core-graphics-types", - "foreign-types 0.5.0", + "foreign-types", "log", "objc", "paste", @@ -2757,16 +2628,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minijinja" version = "2.17.1" @@ -2813,7 +2674,7 @@ dependencies = [ "clap", "futures-util", "indicatif", - "reqwest 0.13.2", + "reqwest", "serde", "serde_json", "tokio", @@ -2870,23 +2731,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "native-tls" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -3134,50 +2978,12 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "openssl" -version = "0.10.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" -dependencies = [ - "bitflags 2.11.0", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "openssl-probe" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" -[[package]] -name = "openssl-sys" -version = "0.9.112" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "option-ext" version = "0.2.0" @@ -3802,46 +3608,6 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" -[[package]] -name = "reqwest" -version = "0.12.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-core", - "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "http-body-util", - "hyper 1.8.1", - "hyper-tls", - "hyper-util", - "js-sys", - "log", - "mime_guess", - "native-tls", - "percent-encoding", - "pin-project-lite", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams 0.4.2", - "web-sys", -] - [[package]] name = "reqwest" version = "0.13.2" @@ -3884,26 +3650,10 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams 0.5.0", + "wasm-streams", "web-sys", ] -[[package]] -name = "reqwest-eventsource" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632c55746dbb44275691640e7b40c907c16a2dc1a5842aa98aaec90da6ec6bde" -dependencies = [ - "eventsource-stream", - "futures-core", - "futures-timer", - "mime", - "nom 7.1.3", - "pin-project-lite", - "reqwest 0.12.28", - "thiserror 1.0.69", -] - [[package]] name = "rgb" version = "0.8.53" @@ -4268,19 +4018,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_html_form" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f" -dependencies = [ - "form_urlencoded", - "indexmap", - "itoa", - "ryu", - "serde_core", -] - [[package]] name = "serde_json" version = "1.0.149" @@ -4312,18 +4049,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_yaml" version = "0.9.34+deprecated" @@ -4917,16 +4642,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.4" @@ -5203,12 +4918,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "unicase" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" - [[package]] name = "unicode-ident" version = "1.0.24" @@ -5454,19 +5163,6 @@ dependencies = [ "wasmparser", ] -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "wasm-streams" version = "0.5.0" @@ -5573,7 +5269,7 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ - "windows-core 0.57.0", + "windows-core", "windows-targets 0.52.6", ] @@ -5583,25 +5279,12 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", + "windows-implement", + "windows-interface", "windows-result 0.1.2", "windows-targets 0.52.6", ] -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement 0.60.2", - "windows-interface 0.59.3", - "windows-link", - "windows-result 0.4.1", - "windows-strings", -] - [[package]] name = "windows-implement" version = "0.57.0" @@ -5613,17 +5296,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-interface" version = "0.57.0" @@ -5635,17 +5307,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-link" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 376fd8f..8a2d4c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,9 +21,9 @@ base64 = "0.22.1" num = "0.4.3" minijinja = "2.12.0" tokenizers = "0.22.1" -aha_openai_dive = { version = "1.4", features = ["stream"] } +# aha_openai_dive = { version = "1.4", features = ["stream"] } uuid = { version = "1.18.1", features = ["v4"] } -chrono = "0.4" +# chrono = "0.4" rocket = { version = "0.5.1", features = ["serde_json", "json"] } tokio = "1.47.1" hound = "3.5.1" @@ -43,6 +43,7 @@ half = "2.7.1" byteorder = "1.5.0" sentencepiece = "0.13.1" ahash = "0.8.12" +derive_builder = "0.20.2" [features] flash-attn = ["candle-flash-attn"] diff --git a/README.md b/README.md index 46483e1..06320d2 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,9 @@ aha is a high-performance, cross-platform AI inference engine built with Rust and the Candle framework. It brings state-of-the-art AI models to your local machine—no API keys, no cloud dependencies, just pure, fast AI running directly on your hardware. ## Changelog +### 2026-03-31 +- dependencies delete aha_openai_dive,chrono + ### v0.2.5 (2026-03-30) - add LFM2.5VL-1.6B - add LFM2VL-1.6B diff --git a/README.zh-CN.md b/README.zh-CN.md index cd6b5ec..42438b6 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -25,6 +25,9 @@ aha 是一款基于 Rust 和 Candle 框架构建的高性能跨平台 AI 推理引擎。将最先进的 AI 模型带到您的本地机器——无需 API 密钥,无需云依赖,纯粹、快速的 AI,直接在您的硬件上运行。 ## 更新日志 +### 2026-03-31 +- 删除 aha_openai_dive,chrono 依赖 + ### v0.2.5 (2026-03-30) - 新增 LFM2.5VL-1.6B - 新增 LFM2VL-1.6B diff --git a/docs/changelog.md b/docs/changelog.md index 967b132..0e3f648 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,6 +5,9 @@ All notable changes to aha will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### 2026-03-31 +- dependencies delete aha_openai_dive,chrono + ### v0.2.5 (2026-03-30) - add LFM2.5VL-1.6B - add LFM2VL-1.6B diff --git a/docs/changelog.zh-CN.md b/docs/changelog.zh-CN.md index 077f597..71309bd 100644 --- a/docs/changelog.zh-CN.md +++ b/docs/changelog.zh-CN.md @@ -5,6 +5,9 @@ 格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), 本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/spec/v2.0.0.html)。 +### 2026-03-31 +- 删除 aha_openai_dive,chrono 依赖 + ### v0.2.5 (2026-03-30) - 新增 LFM2.5VL-1.6B - 新增 LFM2VL-1.6B diff --git a/src/api/asr.rs b/src/api/asr.rs index 22c007b..7d13f39 100644 --- a/src/api/asr.rs +++ b/src/api/asr.rs @@ -1,12 +1,12 @@ // OpenAI-compatible ASR (Automatic Speech Recognition) API endpoint // Implements POST /audio/transcriptions and /v1/audio/transcriptions -use aha::models::GenerateModel; -use aha::utils::{clean_asr_response, map_language_code}; -use aha_openai_dive::v1::resources::chat::{ +use aha::params::chat::{ AudioUrlType, ChatCompletionParameters, ChatMessage, ChatMessageAudioContentPart, ChatMessageContent, ChatMessageContentPart, }; +use aha::models::GenerateModel; +use aha::utils::{clean_asr_response, map_language_code}; use rocket::http::Status; use rocket::serde::json::Json; use rocket::{form::Form, post}; diff --git a/src/api/mod.rs b/src/api/mod.rs index 6cd72cc..0cc6ff0 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -2,10 +2,10 @@ use std::pin::pin; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, OnceLock}; +use aha::params::chat::ChatCompletionParameters; use aha::models::{GenerateModel, ModelInstance, WhichModel, load_model}; use aha::process::cleanup_pid_file; use aha::utils::string_to_static_str; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; use rocket::futures::StreamExt; use rocket::serde::{Serialize, json::Json}; use rocket::{ diff --git a/src/chat_template/mod.rs b/src/chat_template/mod.rs index 4b3b6f0..5a3b269 100644 --- a/src/chat_template/mod.rs +++ b/src/chat_template/mod.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use crate::params::chat::ChatCompletionParameters; use anyhow::{Result, anyhow}; use minijinja::{Environment, Value as MiniJinjaValue, context}; diff --git a/src/lib.rs b/src/lib.rs index e454ceb..543fa9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,5 +5,5 @@ pub mod position_embed; pub mod process; pub mod tokenizer; pub mod utils; +pub mod params; -pub use aha_openai_dive::v1::resources::chat; diff --git a/src/models/deepseek_ocr/generate.rs b/src/models/deepseek_ocr/generate.rs index 9876c15..c070a9c 100644 --- a/src/models/deepseek_ocr/generate.rs +++ b/src/models/deepseek_ocr/generate.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/deepseek_ocr/processor.rs b/src/models/deepseek_ocr/processor.rs index 5bf5d74..0382712 100644 --- a/src/models/deepseek_ocr/processor.rs +++ b/src/models/deepseek_ocr/processor.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use crate::params::chat::ChatCompletionParameters; use anyhow::Result; use candle_core::{DType, Device, Tensor}; diff --git a/src/models/fun_asr_nano/generate.rs b/src/models/fun_asr_nano/generate.rs index 521be97..c7ba044 100644 --- a/src/models/fun_asr_nano/generate.rs +++ b/src/models/fun_asr_nano/generate.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/fun_asr_nano/processor.rs b/src/models/fun_asr_nano/processor.rs index c44b46d..662409b 100644 --- a/src/models/fun_asr_nano/processor.rs +++ b/src/models/fun_asr_nano/processor.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use crate::params::chat::ChatCompletionParameters; use anyhow::Result; use candle_core::{D, Device, Tensor}; diff --git a/src/models/glm_asr_nano/generate.rs b/src/models/glm_asr_nano/generate.rs index 0ac2f05..67cd0e2 100644 --- a/src/models/glm_asr_nano/generate.rs +++ b/src/models/glm_asr_nano/generate.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/glm_asr_nano/processor.rs b/src/models/glm_asr_nano/processor.rs index 2ec3985..7b3f818 100644 --- a/src/models/glm_asr_nano/processor.rs +++ b/src/models/glm_asr_nano/processor.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use crate::params::chat::ChatCompletionParameters; use anyhow::Result; use candle_core::{D, DType, Device, IndexOp, Tensor}; diff --git a/src/models/glm_ocr/generate.rs b/src/models/glm_ocr/generate.rs index ae2f594..6e82a7e 100644 --- a/src/models/glm_ocr/generate.rs +++ b/src/models/glm_ocr/generate.rs @@ -1,5 +1,5 @@ //! GLM-OCR Inference and Generation -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/hunyuan_ocr/generate.rs b/src/models/hunyuan_ocr/generate.rs index fd7fa69..392f1d6 100644 --- a/src/models/hunyuan_ocr/generate.rs +++ b/src/models/hunyuan_ocr/generate.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/hunyuan_ocr/processor.rs b/src/models/hunyuan_ocr/processor.rs index 0865fb5..5d7e6eb 100644 --- a/src/models/hunyuan_ocr/processor.rs +++ b/src/models/hunyuan_ocr/processor.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use crate::params::chat::ChatCompletionParameters; use anyhow::Result; use candle_core::{DType, Device, IndexOp, Shape, Tensor}; use image::DynamicImage; diff --git a/src/models/lfm2/generate.rs b/src/models/lfm2/generate.rs index 72ab927..d0fdf49 100644 --- a/src/models/lfm2/generate.rs +++ b/src/models/lfm2/generate.rs @@ -1,3 +1,4 @@ +use crate::params::chat::{ChatCompletionParameters, ChatCompletionResponse}; use crate::utils::build_completion_chunk_response; use crate::{ chat_template::ChatTemplate, @@ -13,7 +14,6 @@ use crate::{ build_completion_response, find_type_files, get_device, get_dtype, get_logit_processor, }, }; -use aha_openai_dive::v1::resources::chat::{ChatCompletionParameters, ChatCompletionResponse}; use anyhow::Result; use candle_core::{DType, Device, Tensor}; use candle_nn::VarBuilder; @@ -109,10 +109,7 @@ impl<'a> GenerateModel for Lfm2GenerateModel<'a> { ) -> Result< Box< dyn rocket::futures::Stream< - Item = Result< - aha_openai_dive::v1::resources::chat::ChatCompletionChunkResponse, - anyhow::Error, - >, + Item = Result, > + Send + Unpin + '_, diff --git a/src/models/lfm2vl/generate.rs b/src/models/lfm2vl/generate.rs index 8e32718..6992648 100644 --- a/src/models/lfm2vl/generate.rs +++ b/src/models/lfm2vl/generate.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::{ChatCompletionParameters, ChatCompletionResponse}; +use crate::params::chat::{ChatCompletionParameters, ChatCompletionResponse}; use anyhow::Result; use candle_core::{DType, Device, Tensor}; use candle_nn::VarBuilder; @@ -119,10 +119,7 @@ impl<'a> GenerateModel for Lfm2VLGenerateModel<'a> { ) -> Result< Box< dyn rocket::futures::Stream< - Item = Result< - aha_openai_dive::v1::resources::chat::ChatCompletionChunkResponse, - anyhow::Error, - >, + Item = Result, > + Send + Unpin + '_, diff --git a/src/models/lfm2vl/model.rs b/src/models/lfm2vl/model.rs index 1199e96..6fc42de 100644 --- a/src/models/lfm2vl/model.rs +++ b/src/models/lfm2vl/model.rs @@ -287,7 +287,6 @@ impl Lfm2VLModel { && let Some(shapes) = spatial_shapes { let image_embeds = self.vision_tower.forward(pixel, mask, shapes)?; - println!("image_embeds: {}", image_embeds); let bs = image_embeds.dim(0)?; let img_featrure_length = mask.sum(1)?.to_vec1::()?; let mut image_features = vec![]; @@ -306,7 +305,6 @@ impl Lfm2VLModel { image_features.push(img_embedding); } let image_embeds = Tensor::cat(&image_features, 0)?; - println!("image_embeds: {}", image_embeds); let image_mask = get_equal_mask(input_ids, self.img_id)?; inputs_embeds = masked_scatter_dim0(&inputs_embeds, &image_embeds, &image_mask)?; } diff --git a/src/models/lfm2vl/processor.rs b/src/models/lfm2vl/processor.rs index 74236dd..a8010b6 100644 --- a/src/models/lfm2vl/processor.rs +++ b/src/models/lfm2vl/processor.rs @@ -1,3 +1,4 @@ +use crate::params::chat::ChatCompletionParameters; use crate::{ models::lfm2vl::config::{Lfm2ImageConfig, Lfm2ProcessorConfig}, utils::{ @@ -8,7 +9,6 @@ use crate::{ round_by_factor, }, }; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; use anyhow::Result; use candle_core::{DType, Device, Tensor}; use image::DynamicImage; diff --git a/src/models/minicpm4/generate.rs b/src/models/minicpm4/generate.rs index 3fa1af9..0637e6b 100644 --- a/src/models/minicpm4/generate.rs +++ b/src/models/minicpm4/generate.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/mod.rs b/src/models/mod.rs index 200780d..b1bb00d 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -22,7 +22,7 @@ pub mod rmbg2_0; pub mod voxcpm; pub mod w2v_bert_2_0; -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/paddleocr_vl/generate.rs b/src/models/paddleocr_vl/generate.rs index 699a73f..540c59e 100644 --- a/src/models/paddleocr_vl/generate.rs +++ b/src/models/paddleocr_vl/generate.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/paddleocr_vl/processor.rs b/src/models/paddleocr_vl/processor.rs index 594a95c..2af5312 100644 --- a/src/models/paddleocr_vl/processor.rs +++ b/src/models/paddleocr_vl/processor.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use crate::params::chat::ChatCompletionParameters; use anyhow::Result; use candle_core::{DType, Device, IndexOp, Shape, Tensor}; use image::DynamicImage; diff --git a/src/models/qwen2_5vl/generate.rs b/src/models/qwen2_5vl/generate.rs index b521833..28fc793 100644 --- a/src/models/qwen2_5vl/generate.rs +++ b/src/models/qwen2_5vl/generate.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/qwen2_5vl/processor.rs b/src/models/qwen2_5vl/processor.rs index babd8a3..d830f1a 100644 --- a/src/models/qwen2_5vl/processor.rs +++ b/src/models/qwen2_5vl/processor.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionParameters, ChatMessage, ChatMessageContent, ChatMessageContentPart, }; use anyhow::{Result, anyhow}; diff --git a/src/models/qwen3/generate.rs b/src/models/qwen3/generate.rs index 46da4aa..92342bb 100644 --- a/src/models/qwen3/generate.rs +++ b/src/models/qwen3/generate.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/qwen3_5/generate.rs b/src/models/qwen3_5/generate.rs index 1c4cfae..5cd5aac 100644 --- a/src/models/qwen3_5/generate.rs +++ b/src/models/qwen3_5/generate.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/qwen3_asr/generate.rs b/src/models/qwen3_asr/generate.rs index efb8935..ef3f504 100644 --- a/src/models/qwen3_asr/generate.rs +++ b/src/models/qwen3_asr/generate.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/qwen3_asr/processor.rs b/src/models/qwen3_asr/processor.rs index cf894f8..1c7c41b 100644 --- a/src/models/qwen3_asr/processor.rs +++ b/src/models/qwen3_asr/processor.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use crate::params::chat::ChatCompletionParameters; use anyhow::Result; use candle_core::{Device, Tensor}; diff --git a/src/models/qwen3vl/generate.rs b/src/models/qwen3vl/generate.rs index 8544e56..8c1adee 100644 --- a/src/models/qwen3vl/generate.rs +++ b/src/models/qwen3vl/generate.rs @@ -1,4 +1,4 @@ -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Result, anyhow}; diff --git a/src/models/qwen3vl/processor.rs b/src/models/qwen3vl/processor.rs index 81eb2a7..50d000a 100644 --- a/src/models/qwen3vl/processor.rs +++ b/src/models/qwen3vl/processor.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionParameters, ChatMessage, ChatMessageContent, ChatMessageContentPart, }; use anyhow::Result; diff --git a/src/models/rmbg2_0/generate.rs b/src/models/rmbg2_0/generate.rs index 8366d71..8e9c85a 100644 --- a/src/models/rmbg2_0/generate.rs +++ b/src/models/rmbg2_0/generate.rs @@ -1,6 +1,6 @@ use std::io::Cursor; -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::Result; diff --git a/src/models/voxcpm/generate.rs b/src/models/voxcpm/generate.rs index eb82395..43bc06a 100644 --- a/src/models/voxcpm/generate.rs +++ b/src/models/voxcpm/generate.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, }; use anyhow::{Ok, Result}; diff --git a/src/params/chat.rs b/src/params/chat.rs new file mode 100644 index 0000000..4974fe5 --- /dev/null +++ b/src/params/chat.rs @@ -0,0 +1,760 @@ +use super::shared::{ReasoningEffort, WebSearchContextSize}; +use crate::params::shared::StopToken; +use crate::params::shared::{FinishReason, Usage}; +use derive_builder::Builder; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::collections::HashMap; +use std::fmt::Display; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatCompletionResponse { + /// A unique identifier for the chat completion. + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + /// A list of chat completion choices. Can be more than one if n is greater than 1. + pub choices: Vec, + /// The Unix timestamp (in seconds) of when the chat completion was created. + pub created: u32, + /// The model used for the chat completion. + pub model: String, + /// The service tier used for processing the request. + #[serde(skip_serializing_if = "Option::is_none")] + pub service_tier: Option, + /// This fingerprint represents the backend configuration that the model runs with. + #[serde(skip_serializing_if = "Option::is_none")] + pub system_fingerprint: Option, + /// The object type, which is always chat.completion. + pub object: String, + /// Usage statistics for the completion request. + #[serde(skip_serializing_if = "Option::is_none")] + pub usage: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatCompletionChunkResponse { + /// A unique identifier for the chat completion. Each chunk has the same ID. + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + /// A list of chat completion choices. Can be more than one if n is greater than 1. + pub choices: Vec, + /// The Unix timestamp (in seconds) of when the chat completion was created. Each chunk has the same timestamp. + pub created: u32, + /// The model to generate the completion. + pub model: String, + /// This fingerprint represents the backend configuration that the model runs with. + /// Can be used in conjunction with the seed request parameter to understand when backend changes have been made that might impact determinism. + #[serde(skip_serializing_if = "Option::is_none")] + pub system_fingerprint: Option, + /// The object type, which is always chat.completion.chunk. + pub object: String, + /// An optional field that will only be present when you set stream_options: {"include_usage": true} in your request. When present, it contains a null value except for the last chunk which contains the token usage statistics for the entire request. + #[serde(skip_serializing_if = "Option::is_none")] + pub usage: Option, +} + +#[derive(Serialize, Deserialize, Debug, Default, Builder, Clone, PartialEq)] +#[builder(name = "ChatCompletionParametersBuilder")] +#[builder(setter(into, strip_option), default)] +pub struct ChatCompletionParameters { + /// A list of messages comprising the conversation so far. + pub messages: Vec, + /// ID of the model to use. + pub model: String, + /// Whether or not to store the output of this chat completion request for use in our model distillation or evals products. + #[serde(skip_serializing_if = "Option::is_none")] + pub store: Option, + /// Constrains effort on reasoning for reasoning models. + #[serde(skip_serializing_if = "Option::is_none")] + pub reasoning_effort: Option, + /// Developer-defined tags and values used for filtering completions in the dashboard. + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata: Option>, + /// Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, + /// decreasing the model's likelihood to repeat the same line verbatim. + #[serde(skip_serializing_if = "Option::is_none")] + pub frequency_penalty: Option, + /// Modify the likelihood of specified tokens appearing in the completion. + #[serde(skip_serializing_if = "Option::is_none")] + pub logit_bias: Option>, + /// Whether to return log probabilities of the output tokens or not. + /// If true, returns the log probabilities of each output token returned in the 'content' of 'message'. + #[serde(skip_serializing_if = "Option::is_none")] + pub logprobs: Option, + /// An integer between 0 and 5 specifying the number of most likely tokens to return at each token position, + /// each with an associated log probability. 'logprobs' must be set to 'true' if this parameter is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub top_logprobs: Option, + /// Max completion tokens, deprecated (still used by vllm) + #[serde(skip_serializing_if = "Option::is_none")] + pub max_tokens: Option, + /// An upper bound for the number of tokens that can be generated for a completion, including visible output tokens and reasoning tokens. + #[serde(skip_serializing_if = "Option::is_none")] + pub max_completion_tokens: Option, + /// How many chat completion choices to generate for each input message. + #[serde(skip_serializing_if = "Option::is_none")] + pub n: Option, + /// Output types that you would like the model to generate for this request. + #[serde(skip_serializing_if = "Option::is_none")] + pub modalities: Option>, + /// Configuration for a Predicted Output, which can greatly improve response times when large parts of the model response are known ahead of time. + /// This is most common when you are regenerating a file with only minor changes to most of the content. + #[serde(skip_serializing_if = "Option::is_none")] + pub prediction: Option, + /// Parameters for audio output. Required when audio output is requested with modalities: ["audio"]. + #[serde(skip_serializing_if = "Option::is_none")] + pub audio: Option, + /// Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, + /// increasing the model's likelihood to talk about new topics. + #[serde(skip_serializing_if = "Option::is_none")] + pub presence_penalty: Option, + /// An object specifying the format that the model must output. + /// Compatible with GPT-4o, GPT-4o mini, GPT-4 Turbo and all GPT-3.5 Turbo models newer than gpt-3.5-turbo-1106. + /// Setting to { "type": "json_schema", "json_schema": {...} } enables Structured Outputs which ensures the model will match your supplied JSON schema. + /// Setting to { "type": "json_object" } enables JSON mode, which ensures the message the model generates is valid JSON. + #[serde(skip_serializing_if = "Option::is_none")] + pub response_format: Option, + /// Deprecated (still used by vllm) + /// This feature is in Beta. If specified, our system will make a best effort to sample deterministically, + /// such that repeated requests with the same seed and parameters should return the same result. + /// Determinism is not guaranteed, and you should refer to the system_fingerprint response parameter to monitor changes in the backend. + #[serde(skip_serializing_if = "Option::is_none")] + pub seed: Option, + /// Up to 4 sequences where the API will stop generating further tokens. + #[serde(skip_serializing_if = "Option::is_none")] + pub stop: Option, + /// If set, partial messages will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent events + /// as they become available, with the stream terminated by a data: [DONE] message. + #[serde(skip_serializing_if = "Option::is_none")] + pub stream: Option, + /// Options for streaming response. Only set this when you set stream: true. + #[serde(skip_serializing_if = "Option::is_none")] + pub stream_options: Option, + /// What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, + /// while lower values like 0.2 will make it more focused and deterministic. + #[serde(skip_serializing_if = "Option::is_none")] + pub temperature: Option, + /// An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. + /// So 0.1 means only the tokens comprising the top 10% probability mass are considered. + #[serde(skip_serializing_if = "Option::is_none")] + pub top_p: Option, + /// A list of tools the model may call. Currently, only functions are supported as a tool. + /// Use this to provide a list of functions the model may generate JSON inputs for. + #[serde(skip_serializing_if = "Option::is_none")] + pub tools: Option>, + /// Controls which (if any) tool is called by the model. none means the model will not call any tool and instead generates a message. + /// auto means the model can pick between generating a message or calling one or more tools. + /// required means the model must call one or more tools. + /// Specifying a particular tool via {"type": "function", "function": {"name": "my_function"}} forces the model to call that tool. + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_choice: Option, + /// Whether to enable parallel function calling during tool use. + #[serde(skip_serializing_if = "Option::is_none")] + pub parallel_tool_calls: Option, + /// A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. + #[serde(skip_serializing_if = "Option::is_none")] + pub safety_identifier: Option, + /// Used by OpenAI to cache responses for similar requests to optimize your cache hit rates. + #[serde(skip_serializing_if = "Option::is_none")] + pub prompt_cache_key: Option, + /// This tool searches the web for relevant results to use in a response. + #[serde(skip_serializing_if = "Option::is_none")] + pub web_search_options: Option, + /// Allows to pass arbitrary json as an extra_body parameter, for specific features/openai-compatible endpoints. + #[serde(flatten)] + #[serde(skip_serializing_if = "Option::is_none")] + pub extra_body: Option, + /// Azure OpenAI and some other providers may require special query parameters to be set on the request URL. + /// This field allows you to specify those query parameters. + #[serde(skip_serializing_if = "Option::is_none")] + pub query_params: Option>, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatCompletionStreamOptions { + /// If set, an additional chunk will be streamed before the data: [DONE] message. + pub include_usage: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub continuous_usage_stats: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatCompletionToolChoiceFunction { + /// The type of the tool. Currently, only 'function' is supported. + #[serde(skip_serializing_if = "Option::is_none")] + pub r#type: Option, + /// Name of the function. + pub function: ChatCompletionToolChoiceFunctionName, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatCompletionToolChoiceFunctionName { + /// Name of the function. + pub name: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatCompletionFunction { + /// Name of the function. + pub name: String, + /// Optional description of the function. + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + /// The parameters the function takes. The model will generate JSON inputs for these parameters. + pub parameters: serde_json::Value, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ChatCompletionResponseFormat { + Text, + JsonObject, + JsonSchema { json_schema: JsonSchema }, +} + +#[derive(Serialize, Deserialize, Debug, Default, Builder, Clone, PartialEq)] +#[builder(name = "JsonSchemaBuilder")] +#[builder(setter(into, strip_option), default)] +pub struct JsonSchema { + /// A description of what the response format is for, used by the model to determine how to respond in the format. + #[serde(skip_serializing_if = "Option::is_none")] + description: Option, + /// The name of the response format. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64. + name: String, + /// The schema for the response format, described as a JSON Schema object. + #[serde(skip_serializing_if = "Option::is_none")] + schema: Option, + /// Whether to enable strict schema adherence when generating the output. + #[serde(skip_serializing_if = "Option::is_none")] + strict: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatCompletionTool { + /// The type of the tool. Currently, only 'function' is supported. + pub r#type: ChatCompletionToolType, + /// The name of the function to call. + pub function: ChatCompletionFunction, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "role", rename_all = "snake_case")] +pub enum ChatMessage { + Developer { + /// The contents of the developer message. + content: ChatMessageContent, + /// An optional name for the participant. Provides the model information to differentiate between participants of the same role. + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + }, + System { + /// The contents of the system message. + content: ChatMessageContent, + /// An optional name for the participant. Provides the model information to differentiate between participants of the same role. + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + }, + User { + /// The contents of the user message. + content: ChatMessageContent, + /// An optional name for the participant. Provides the model information to differentiate between participants of the same role. + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + }, + Assistant { + /// The contents of the assistant message. Required unless tool_calls is specified. + #[serde(skip_serializing_if = "Option::is_none")] + content: Option, + /// The reasoning content by the assistant. (DeepSeek API only) + #[serde(skip_serializing_if = "Option::is_none")] + reasoning_content: Option, + /// The refusal message by the assistant. + #[serde(skip_serializing_if = "Option::is_none")] + refusal: Option, + /// An optional name for the participant. Provides the model information to differentiate between participants of the same role. + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + /// Data about a previous audio response from the model. + #[serde(skip_serializing_if = "Option::is_none")] + audio: Option, + /// The tool calls generated by the model, such as function calls. + #[serde(skip_serializing_if = "Option::is_none")] + tool_calls: Option>, + }, + Tool { + /// The contents of the tool message. + content: ChatMessageContent, + /// Tool call that this message is responding to. + tool_call_id: String, + }, +} + +impl ChatMessage { + /// Get the ChatMessageContent data, if it exists. + pub fn message(&self) -> Option<&ChatMessageContent> { + match self { + ChatMessage::Developer { content, .. } + | ChatMessage::System { content, .. } + | ChatMessage::User { content, .. } + | ChatMessage::Assistant { + content: Some(content), + .. + } => Some(content), + ChatMessage::Assistant { content: None, .. } => None, + ChatMessage::Tool { .. } => None, + } + } + + /// Get the content of the message as text, if it is a simple text message. + pub fn text(&self) -> Option<&str> { + match self { + ChatMessage::Developer { content, .. } + | ChatMessage::System { content, .. } + | ChatMessage::User { content, .. } + | ChatMessage::Tool { content, .. } + | ChatMessage::Assistant { + content: Some(content), + .. + } => { + if let ChatMessageContent::Text(text) = content { + Some(text) + } else { + None + } + } + ChatMessage::Assistant { content: None, .. } => None, + } + } + + /// Get the name of the message sender, if it exists. + pub fn name(&self) -> Option<&str> { + match self { + ChatMessage::Developer { name, .. } + | ChatMessage::System { name, .. } + | ChatMessage::User { name, .. } + | ChatMessage::Assistant { name, .. } => name.as_deref(), + ChatMessage::Tool { .. } => None, + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(tag = "role", rename_all = "snake_case")] +pub enum DeltaChatMessage { + Developer { + /// The contents of the developer message. + content: ChatMessageContent, + /// An optional name for the participant. Provides the model information to differentiate between participants of the same role. + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + }, + System { + /// The contents of the system message. + content: ChatMessageContent, + /// An optional name for the participant. Provides the model information to differentiate between participants of the same role. + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + }, + User { + /// The contents of the user message. + content: ChatMessageContent, + /// An optional name for the participant. Provides the model information to differentiate between participants of the same role. + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + }, + Assistant { + /// The contents of the assistant message. Required unless tool_calls is specified. + #[serde(skip_serializing_if = "Option::is_none")] + content: Option, + /// The reasoning content by the assistant. (DeepSeek API only) + #[serde(skip_serializing_if = "Option::is_none")] + reasoning_content: Option, + /// The refusal message by the assistant. + #[serde(skip_serializing_if = "Option::is_none")] + refusal: Option, + /// An optional name for the participant. Provides the model information to differentiate between participants of the same role. + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + /// The tool calls generated by the model, such as function calls. + #[serde(skip_serializing_if = "Option::is_none")] + tool_calls: Option>, + }, + Tool { + /// The contents of the tool message. + content: String, + /// Tool call that this message is responding to. + tool_call_id: String, + }, + #[serde(untagged)] + Untagged { + #[serde(skip_serializing_if = "Option::is_none")] + content: Option, + #[serde(skip_serializing_if = "Option::is_none")] + reasoning_content: Option, + #[serde(skip_serializing_if = "Option::is_none")] + refusal: Option, + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + tool_calls: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + tool_call_id: Option, + }, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ToolCall { + /// The ID of the tool call. + pub id: String, + /// The type of the tool. Currently, only function is supported. + pub r#type: String, + /// The function that the model called. + pub function: Function, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct DeltaToolCall { + /// The index of the tool call in the list of tool calls. + #[serde(skip_serializing_if = "Option::is_none")] + pub index: Option, + /// /// The ID of the tool call. + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + /// The type of the tool. Currently, only 'function' is supported. + #[serde(skip_serializing_if = "Option::is_none")] + pub r#type: Option, + /// The function that the model called. + pub function: DeltaFunction, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct Function { + /// The name of the function to call. + pub name: String, + /// The arguments to call the function with, as generated by the model in JSON format. + pub arguments: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct DeltaFunction { + /// The name of the function to call. + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + /// The arguments to call the function with, as generated by the model in JSON format. + #[serde(skip_serializing_if = "Option::is_none")] + pub arguments: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatCompletionChoice { + /// The index of the choice in the list of choices. + pub index: u32, + /// A chat completion message generated by the model. + pub message: ChatMessage, + /// The reason the model stopped generating tokens. + #[serde(skip_serializing_if = "Option::is_none")] + pub finish_reason: Option, + /// Log probability information for the choice. + #[serde(skip_serializing_if = "Option::is_none")] + pub logprobs: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct AudioDataIdParameter { + /// Unique identifier for a previous audio response from the model. + pub id: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct AudioParameters { + /// The voice the model uses to respond. + pub voice: Voice, + /// Specifies the output audio format. + pub format: AudioFormat, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct LogProps { + /// A list of message content tokens with log probability information. + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option>, + /// A list of message refusal tokens with log probability information. + #[serde(skip_serializing_if = "Option::is_none")] + pub refusal: Option>, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct LogPropsContent { + /// Token information + #[serde(flatten)] + pub token_info: LogProbsContentInfo, + /// List of the most likely tokens and their log probability, at this token position. + pub top_logprobs: Vec, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct LogProbsContentInfo { + /// The token. + pub token: String, + /// The log probability of this token, if it is within the top 20 most likely tokens. + /// Otherwise, the value -9999.0 is used to signify that the token is very unlikely. + pub logprob: f32, + /// A list of integers representing the UTF-8 bytes representation of the token. + pub bytes: Option>, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatCompletionChunkChoice { + /// The index of the choice in the list of choices. + pub index: Option, + /// A chat completion delta generated by streamed model responses. + pub delta: DeltaChatMessage, + /// The reason the model stopped generating tokens. + #[serde(skip_serializing_if = "Option::is_none")] + pub finish_reason: Option, + /// Log probability information for the choice. + #[serde(skip_serializing_if = "Option::is_none")] + pub logprobs: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ImageUrlType { + /// Either a URL of the image or the base64 encoded image data. + pub url: String, + /// Specifies the detail level of the image. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct AudioUrlType { + /// audio URL or base64 + pub url: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct VideoUrlType { + /// video URL + pub url: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct PredictedOutput { + /// The type of the predicted content you want to provide. + pub r#type: PredictedOutputType, + /// The content that should be matched when generating a model response. + /// If generated tokens would match this content, the entire model response can be returned much more quickly. + pub content: PredictedOutputContent, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(untagged)] +pub enum PredictedOutputContent { + String(String), + Array(Vec), +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct PredictedOutputArrayPart { + /// The type of the content part. + pub r#type: String, + /// The text content. + pub text: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum PredictedOutputType { + Content, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum Modality { + Text, + Audio, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum ImageUrlDetail { + Auto, + High, + Low, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(untagged)] +pub enum ChatMessageContent { + Text(String), + ContentPart(Vec), + None, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(untagged)] +pub enum ChatMessageContentPart { + Text(ChatMessageTextContentPart), + Image(ChatMessageImageContentPart), + Audio(ChatMessageAudioContentPart), + Video(ChatMessageVideoContentPart), +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatMessageTextContentPart { + /// The type of the content part. + pub r#type: String, + /// The text content. + pub text: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatMessageImageContentPart { + /// The type of the content part. + pub r#type: String, + /// The text content. + pub image_url: ImageUrlType +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatMessageAudioContentPart { + /// The type of the content part. Always input_audio. + pub r#type: String, + /// The input audio data. + pub audio_url: AudioUrlType +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatMessageVideoContentPart { + /// The type of the content part. + pub r#type: String, + /// The text content. + pub video_url: VideoUrlType, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ChatMessageImageUrl { + /// Either a URL of the image or the base64 encoded image data. + pub url: String, + /// Specifies the detail level of the image. + pub detail: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct InputAudioData { + /// Base64 encoded audio data. + pub data: String, + /// The format of the encoded audio data. Currently supports "wav" and "mp3". + pub format: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct WebSearchOptions { + /// High level guidance for the amount of context window space to use for the search. + #[serde(skip_serializing_if = "Option::is_none")] + pub search_context_size: Option, + /// Approximate location parameters for the search. + #[serde(skip_serializing_if = "Option::is_none")] + pub user_location: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ApproximateUserLocation { + pub r#type: UserLocationType, + /// Approximate location parameters for the search. + pub approximate: WebSearchUserLocation, +} + +impl Display for ChatMessageContent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ChatMessageContent::Text(text) => write!(f, "{text}"), + ChatMessageContent::ContentPart(tcp) => { + for part in tcp { + write!(f, "{part:?}")?; + } + Ok(()) + } + ChatMessageContent::None => write!(f, ""), + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum ChatCompletionToolType { + Function, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum ChatCompletionToolChoice { + None, + Auto, + Required, + #[serde(untagged)] + ChatCompletionToolChoiceFunction(ChatCompletionToolChoiceFunction), +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct WebSearchUserLocation { + pub city: Option, + pub country: Option, + pub region: Option, + pub timezone: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum UserLocationType { + Approximate, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum Voice { + Alloy, + Ash, + Ballad, + Coral, + Echo, + Sage, + Shimmer, + Verse, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum AudioFormat { + Wav, + Mp3, + Flac, + Opus, + Pcm16, +} + +impl Default for ChatMessageContent { + fn default() -> Self { + ChatMessageContent::Text("".to_string()) + } +} + +impl DeltaFunction { + pub fn merge(&mut self, other: &Self) { + if self.name.is_none() && other.name.is_some() { + self.name.clone_from(&other.name); + } + + if let Some(arguments) = &other.arguments { + if let Some(self_arguments) = &mut self.arguments { + self_arguments.push_str(arguments); + } else { + self.arguments = Some(arguments.clone()); + } + } + } + + pub fn is_empty(&self) -> bool { + self.name.is_none() && self.arguments.is_none() + } +} diff --git a/src/params/mod.rs b/src/params/mod.rs new file mode 100644 index 0000000..4c7dfa7 --- /dev/null +++ b/src/params/mod.rs @@ -0,0 +1,2 @@ +pub mod chat; +pub mod shared; \ No newline at end of file diff --git a/src/params/shared.rs b/src/params/shared.rs new file mode 100644 index 0000000..3ff357c --- /dev/null +++ b/src/params/shared.rs @@ -0,0 +1,203 @@ + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct Usage { + /// Number of tokens in the prompt. + #[serde(skip_serializing_if = "Option::is_none")] + pub prompt_tokens: Option, + /// Number of tokens in the completion. + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_tokens: Option, + /// Number of tokens in the entire response. + pub total_tokens: u32, + /// Breakdown of tokens used in the prompt. + #[serde(skip_serializing_if = "Option::is_none")] + pub prompt_tokens_details: Option, + /// Breakdown of tokens used in a completion. + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_tokens_details: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct InputTokensDetails { + /// The number of tokens that were retrieved from the cache. + pub cached_tokens: u32, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct OutputTokensDetails { + /// The number of reasoning tokens. + pub reasoning_tokens: u32, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct PromptTokensDetails { + /// Audio input tokens present in the prompt. + #[serde(skip_serializing_if = "Option::is_none")] + pub audio_tokens: Option, + /// Cached tokens present in the prompt. + pub cached_tokens: u32, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct CompletionTokensDetails { + /// Tokens generated by the model for reasoning. + pub reasoning_tokens: u32, + /// Audio input tokens generated by the model. + #[serde(skip_serializing_if = "Option::is_none")] + pub audio_tokens: Option, + /// When using Predicted Outputs, the number of tokens in the prediction that appeared in the completion. + #[serde(skip_serializing_if = "Option::is_none")] + pub accepted_prediction_tokens: Option, + /// When using Predicted Outputs, the number of tokens in the prediction that did not appear in the completion. + #[serde(skip_serializing_if = "Option::is_none")] + pub rejected_prediction_tokens: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ResponseWrapper { + pub data: T, + pub headers: Headers, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct Headers { + /// The maximum number of requests that are permitted before exhausting the rate limit. + #[serde(rename = "x-ratelimit-limit-requests")] + pub x_ratelimit_limit_requests: Option, + /// The maximum number of tokens that are permitted before exhausting the rate limit. + #[serde(rename = "x-ratelimit-limit-tokens")] + pub x_ratelimit_limit_tokens: Option, + /// The remaining number of requests that are permitted before exhausting the rate limit. + #[serde(rename = "x-ratelimit-remaining-requests")] + pub x_ratelimit_remaining_requests: Option, + /// The remaining number of tokens that are permitted before exhausting the rate limit. + #[serde(rename = "x-ratelimit-remaining-tokens")] + pub x_ratelimit_remaining_tokens: Option, + /// The time until the rate limit (based on requests) resets to its initial state. + #[serde(rename = "x-ratelimit-reset-requests")] + pub x_ratelimit_reset_requests: Option, + /// The time until the rate limit (based on tokens) resets to its initial state. + #[serde(rename = "x-ratelimit-reset-tokens")] + pub x_ratelimit_reset_tokens: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct SimpleListParameters { + /// Identifier for the last object from the previous pagination request. + pub after: Option, + /// Number of objects to retrieve. + pub limit: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ListParameters { + /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, + /// Sort order by the created_at timestamp of the objects. asc for ascending order and desc for descending order. + #[serde(skip_serializing_if = "Option::is_none")] + pub order: Option, + /// A cursor for use in pagination. after is an object ID that defines your place in the list. + #[serde(skip_serializing_if = "Option::is_none")] + pub after: Option, + /// A cursor for use in pagination. before is an object ID that defines your place in the list. + #[serde(skip_serializing_if = "Option::is_none")] + pub before: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ListResponse { + // The object type, which is always "list". + pub object: String, + /// The list ob objects. + pub data: Vec, + /// The ID of the first objects in the list. + pub first_id: Option, + /// The ID of the last objects in the list. + pub last_id: Option, + /// Indicates whether there are more objects to retrieve. + pub has_more: bool, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct DeletedObject { + /// ID of the deleted object. + pub id: String, + /// The object type. + pub object: String, + /// Indicates whether the file was successfully deleted. + pub deleted: bool, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct LastError { + /// One of 'server_error' or 'rate_limit_exceeded'. + pub code: LastErrorCode, + /// A human-readable description of the error. + pub message: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum LastErrorCode { + ServerError, + RateLimitExceeded, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum FinishReason { + /// API returned complete message, or a message terminated by one of the stop sequences provided via the stop parameter. + #[serde(rename = "stop", alias = "STOP")] + StopSequenceReached, + /// Incomplete model output due to max_tokens parameter or token limit. + #[serde(rename = "length", alias = "MAX_TOKENS")] + TokenLimitReached, + /// Omitted content due to a flag from our content filters. + #[serde( + rename = "content_filter", + alias = "SAFETY", + alias = "SPII", + alias = "PROHIBITED_CONTENT", + alias = "BLOCKLIST", + alias = "RECITATION" + )] + ContentFilterFlagged, + /// The model decided to call one or more tools. + ToolCalls, + /// The model reached a natural stopping point. [Claude] + EndTurn, + /// The finish reason is unspecified. [Gemini] + #[serde(rename = "FINISH_REASON_UNSPECIFIED ")] + FinishReasonUnspecified, + #[serde(rename = "MALFORMED_FUNCTION_CALL")] + MalformedFunctionCall, + #[serde(rename = "OTHER")] + Other, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum ReasoningEffort { + High, + Medium, + Low, + Minimal, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum WebSearchContextSize { + Low, + Medium, + Large, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(untagged)] +pub enum StopToken { + String(String), + Array(Vec), +} diff --git a/src/utils/audio_utils.rs b/src/utils/audio_utils.rs index bc0680a..4ad37b0 100644 --- a/src/utils/audio_utils.rs +++ b/src/utils/audio_utils.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use std::thread; use std::{f64::consts::PI, io::Cursor}; -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionParameters, ChatCompletionResponse, ChatMessage, ChatMessageContent, ChatMessageContentPart, }; diff --git a/src/utils/img_utils.rs b/src/utils/img_utils.rs index 0e334d7..f824764 100644 --- a/src/utils/img_utils.rs +++ b/src/utils/img_utils.rs @@ -2,7 +2,7 @@ use std::io::Cursor; use std::thread; use std::{collections::HashSet, path::PathBuf}; -use aha_openai_dive::v1::resources::chat::{ +use crate::params::chat::{ ChatCompletionParameters, ChatMessage, ChatMessageContent, ChatMessageContentPart, }; use anyhow::{Result, anyhow}; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 9120cba..d3bd750 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -6,9 +6,10 @@ pub mod video_utils; use std::fs::File; use std::io::{Cursor, Read}; +use std::time::{SystemTime, UNIX_EPOCH}; use std::{collections::HashMap, fs, path::PathBuf, process::Command, time::Duration}; -use aha_openai_dive::v1::resources::{ +use crate::params::{ chat::{ AudioUrlType, ChatCompletionChoice, ChatCompletionChunkChoice, ChatCompletionChunkResponse, ChatCompletionParameters, ChatCompletionResponse, ChatMessage, ChatMessageAudioContentPart, @@ -377,6 +378,23 @@ pub fn read_pth_tensor_info_cycle>( Ok(dict_to_hashmap) } +// 获取秒级时间戳 +pub fn timestamp() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() +} + +// 获取毫秒级时间戳 +pub fn timestamp_millis() -> u128 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() +} + + pub fn round_by_factor(num: u32, factor: u32) -> u32 { let round = (num as f32 / factor as f32).round() as u32; round * factor @@ -400,7 +418,8 @@ pub fn build_img_completion_response( let mut response = ChatCompletionResponse { id: Some(id), choices: vec![], - created: chrono::Utc::now().timestamp() as u32, + // created: chrono::Utc::now().timestamp() as u32, + created: timestamp() as u32, model: model_name.to_string(), service_tier: None, system_fingerprint: None, @@ -444,7 +463,7 @@ pub fn build_audio_completion_response( let mut response = ChatCompletionResponse { id: Some(id), choices: vec![], - created: chrono::Utc::now().timestamp() as u32, + created: timestamp() as u32, model: model_name.to_string(), service_tier: None, system_fingerprint: None, @@ -498,7 +517,7 @@ pub fn build_completion_response( let mut response = ChatCompletionResponse { id: Some(id), choices: vec![], - created: chrono::Utc::now().timestamp() as u32, + created: timestamp() as u32, model: model_name.to_string(), service_tier: None, system_fingerprint: None, @@ -580,7 +599,7 @@ pub fn build_completion_chunk_response( let mut response = ChatCompletionChunkResponse { id: Some(id), choices: vec![], - created: chrono::Utc::now().timestamp() as u32, + created: timestamp() as u32, model: model_name.to_string(), system_fingerprint: None, object: "chat.completion.chunk".to_string(), diff --git a/tests/messy_test.rs b/tests/messy_test.rs index 9740826..b48b99a 100644 --- a/tests/messy_test.rs +++ b/tests/messy_test.rs @@ -5,8 +5,9 @@ // use std::io::{Read, Seek}; // use std::{io::Cursor, time::Instant}; +use aha::utils::{timestamp, timestamp_millis}; // use aha::utils::tensor_utils::repeat_interleave; -// use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +// use crate::params::chat::ChatCompletionParameters; use anyhow::Result; // use byteorder::{LittleEndian, ReadBytesExt}; // use candle_core::Tensor; @@ -35,6 +36,9 @@ async fn download_test() -> Result<()> { #[test] fn messy_test() -> Result<()> { // RUST_BACKTRACE=1 cargo test -F cuda --test messy_test messy_test -r -- --nocapture + println!("当前秒级时间戳: {}", timestamp()); + println!("当前毫秒级时间戳: {}", timestamp_millis()); + // let t1 = Tensor::randn(0.0, 1.0, (1, 2, 6), device)?; // println!(" t1: {}", t1); // let t2 = t1.pad_with_zeros(D::Minus1, -3, 0)?; diff --git a/tests/test_deepseek_ocr.rs b/tests/test_deepseek_ocr.rs index 8129eec..3acfa17 100644 --- a/tests/test_deepseek_ocr.rs +++ b/tests/test_deepseek_ocr.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; +use aha::params::chat::ChatCompletionParameters; use aha::models::{GenerateModel, deepseek_ocr::generate::DeepseekOCRGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; diff --git a/tests/test_fun_asr_nano.rs b/tests/test_fun_asr_nano.rs index d2f8cf8..80dd35b 100644 --- a/tests/test_fun_asr_nano.rs +++ b/tests/test_fun_asr_nano.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::models::{GenerateModel, fun_asr_nano::generate::FunAsrNanoGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; #[test] diff --git a/tests/test_gelab_zero.rs b/tests/test_gelab_zero.rs index 0b75033..131e227 100644 --- a/tests/test_gelab_zero.rs +++ b/tests/test_gelab_zero.rs @@ -1,7 +1,7 @@ use std::time::Instant; use aha::models::{GenerateModel, qwen3vl::generate::Qwen3VLGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; #[test] diff --git a/tests/test_gguf_qwen3_5.rs b/tests/test_gguf_qwen3_5.rs index 05326de..eb1f1be 100644 --- a/tests/test_gguf_qwen3_5.rs +++ b/tests/test_gguf_qwen3_5.rs @@ -1,7 +1,7 @@ use std::time::Instant; use aha::{ - chat::ChatCompletionParameters, + params::chat::ChatCompletionParameters, models::{GenerateModel, qwen3_5::generate::Qwen3_5GenerateModel}, }; use anyhow::Result; diff --git a/tests/test_glm_asr_nano.rs b/tests/test_glm_asr_nano.rs index 42d24f3..d0df313 100644 --- a/tests/test_glm_asr_nano.rs +++ b/tests/test_glm_asr_nano.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::models::{GenerateModel, glm_asr_nano::generate::GlmAsrNanoGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; diff --git a/tests/test_glm_ocr.rs b/tests/test_glm_ocr.rs index cb44df3..90ba247 100644 --- a/tests/test_glm_ocr.rs +++ b/tests/test_glm_ocr.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::models::{GenerateModel, glm_ocr::generate::GlmOcrGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; diff --git a/tests/test_hunyuan_ocr.rs b/tests/test_hunyuan_ocr.rs index b92a828..e642438 100644 --- a/tests/test_hunyuan_ocr.rs +++ b/tests/test_hunyuan_ocr.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::models::{GenerateModel, hunyuan_ocr::generate::HunyuanOCRGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; diff --git a/tests/test_lfm2.rs b/tests/test_lfm2.rs index 08cff28..7fb26b3 100644 --- a/tests/test_lfm2.rs +++ b/tests/test_lfm2.rs @@ -1,5 +1,5 @@ use aha::{ - chat::ChatCompletionParameters, + params::chat::ChatCompletionParameters, models::{GenerateModel, lfm2::generate::Lfm2GenerateModel}, }; use anyhow::Result; diff --git a/tests/test_lfm2vl.rs b/tests/test_lfm2vl.rs index 22bbbb1..8586863 100644 --- a/tests/test_lfm2vl.rs +++ b/tests/test_lfm2vl.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::{ - chat::ChatCompletionParameters, + params::chat::ChatCompletionParameters, models::{GenerateModel, lfm2vl::generate::Lfm2VLGenerateModel}, }; use anyhow::Result; @@ -12,8 +12,8 @@ fn lfm2vl_generate() -> Result<()> { let save_dir = aha::utils::get_default_save_dir().ok_or(anyhow::anyhow!("Failed to get save dir"))?; - // let model_path = format!("{}/LiquidAI/LFM2.5-VL-1.6B/", save_dir); - let model_path = format!("{}/LiquidAI/LFM2-VL-1.6B/", save_dir); + let model_path = format!("{}/LiquidAI/LFM2.5-VL-1.6B/", save_dir); + // let model_path = format!("{}/LiquidAI/LFM2-VL-1.6B/", save_dir); let message = r#" { "model": "lfm2vl", diff --git a/tests/test_minicpm4.rs b/tests/test_minicpm4.rs index 36fd65e..9e3753a 100644 --- a/tests/test_minicpm4.rs +++ b/tests/test_minicpm4.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::models::{GenerateModel, minicpm4::generate::MiniCPMGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; diff --git a/tests/test_paddleocr_vl.rs b/tests/test_paddleocr_vl.rs index d530d37..640ad5a 100644 --- a/tests/test_paddleocr_vl.rs +++ b/tests/test_paddleocr_vl.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::models::{GenerateModel, paddleocr_vl::generate::PaddleOCRVLGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; diff --git a/tests/test_qwen2_5vl.rs b/tests/test_qwen2_5vl.rs index cef4781..b4ae2f6 100644 --- a/tests/test_qwen2_5vl.rs +++ b/tests/test_qwen2_5vl.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::models::{GenerateModel, qwen2_5vl::generate::Qwen2_5VLGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; diff --git a/tests/test_qwen3.rs b/tests/test_qwen3.rs index 61bd73a..e06cc33 100644 --- a/tests/test_qwen3.rs +++ b/tests/test_qwen3.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::models::{GenerateModel, qwen3::generate::Qwen3GenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; diff --git a/tests/test_qwen3_5.rs b/tests/test_qwen3_5.rs index f515036..d901890 100644 --- a/tests/test_qwen3_5.rs +++ b/tests/test_qwen3_5.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::models::{GenerateModel, qwen3_5::generate::Qwen3_5GenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; diff --git a/tests/test_qwen3_asr.rs b/tests/test_qwen3_asr.rs index f9d5736..f477b64 100644 --- a/tests/test_qwen3_asr.rs +++ b/tests/test_qwen3_asr.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::models::{GenerateModel, qwen3_asr::generate::Qwen3AsrGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; #[test] diff --git a/tests/test_qwen3vl.rs b/tests/test_qwen3vl.rs index a431b87..039096a 100644 --- a/tests/test_qwen3vl.rs +++ b/tests/test_qwen3vl.rs @@ -1,7 +1,7 @@ use std::{pin::pin, time::Instant}; use aha::models::{GenerateModel, qwen3vl::generate::Qwen3VLGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; use rocket::futures::StreamExt; diff --git a/tests/test_rmbg2_0.rs b/tests/test_rmbg2_0.rs index 892b1ab..f5b541c 100644 --- a/tests/test_rmbg2_0.rs +++ b/tests/test_rmbg2_0.rs @@ -1,7 +1,7 @@ use std::time::Instant; use aha::models::rmbg2_0::generate::RMBG2_0Model; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; #[test] diff --git a/tests/test_robo_brain.rs b/tests/test_robo_brain.rs index 974cb6e..693e2d2 100644 --- a/tests/test_robo_brain.rs +++ b/tests/test_robo_brain.rs @@ -1,7 +1,7 @@ use std::time::Instant; use aha::models::{GenerateModel, qwen2_5vl::generate::Qwen2_5VLGenerateModel}; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; +use aha::params::chat::ChatCompletionParameters; use anyhow::Result; #[test] diff --git a/tests/test_voxcpm.rs b/tests/test_voxcpm.rs index bdbd458..3866a7e 100644 --- a/tests/test_voxcpm.rs +++ b/tests/test_voxcpm.rs @@ -1,5 +1,6 @@ use std::time::Instant; +use aha::params::chat::ChatCompletionParameters; use aha::{ models::{ GenerateModel, @@ -7,7 +8,6 @@ use aha::{ }, utils::audio_utils::{extract_and_save_audio_from_response, save_wav}, }; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; use anyhow::{Ok, Result}; #[test] diff --git a/tests/test_voxcpm1_5.rs b/tests/test_voxcpm1_5.rs index 397a2d1..c574514 100644 --- a/tests/test_voxcpm1_5.rs +++ b/tests/test_voxcpm1_5.rs @@ -1,5 +1,6 @@ use std::time::Instant; +use aha::params::chat::ChatCompletionParameters; use aha::{ models::{ GenerateModel, @@ -7,7 +8,6 @@ use aha::{ }, utils::audio_utils::{extract_and_save_audio_from_response, save_wav}, }; -use aha_openai_dive::v1::resources::chat::ChatCompletionParameters; use anyhow::{Ok, Result}; #[test]