use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum Kind {
Chat,
#[cfg(feature = "image")]
Image,
#[cfg(feature = "video")]
Video,
#[cfg(feature = "tts")]
Tts,
}
impl Kind {
pub const fn label_key(self) -> &'static str {
match self {
Kind::Chat => "kind.chat",
#[cfg(feature = "image")]
Kind::Image => "kind.image",
#[cfg(feature = "video")]
Kind::Video => "kind.video",
#[cfg(feature = "tts")]
Kind::Tts => "kind.tts",
}
}
pub const fn label(self) -> &'static str {
match self {
Kind::Chat => "对话",
#[cfg(feature = "image")]
Kind::Image => "生图",
#[cfg(feature = "video")]
Kind::Video => "视频",
#[cfg(feature = "tts")]
Kind::Tts => "配音",
}
}
pub const fn supports_dry_run(self) -> bool {
match self {
Kind::Chat => true,
#[cfg(feature = "image")]
Kind::Image => true,
#[cfg(feature = "video")]
Kind::Video => false,
#[cfg(feature = "tts")]
Kind::Tts => true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Protocol {
#[serde(rename = "anthropic")]
Anthropic,
#[serde(rename = "openai_compatible")]
OpenAiCompatible,
}
impl Protocol {
pub const fn as_str(self) -> &'static str {
match self {
Protocol::Anthropic => "anthropic",
Protocol::OpenAiCompatible => "openai_compatible",
}
}
pub fn parse(s: &str) -> Option<Self> {
match s.trim() {
"anthropic" => Some(Protocol::Anthropic),
"openai_compatible" => Some(Protocol::OpenAiCompatible),
_ => None,
}
}
pub const fn default_base_url(self) -> &'static str {
match self {
Protocol::Anthropic => "https://api.anthropic.com/v1",
Protocol::OpenAiCompatible => "https://api.openai.com/v1",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn video_has_no_dry_run() {
assert!(Kind::Chat.supports_dry_run());
#[cfg(feature = "video")]
assert!(
!Kind::Video.supports_dry_run(),
"视频单次约 90 秒且费用高,不提供试运行"
);
}
#[test]
fn protocol_spellings_agree() {
for p in [Protocol::Anthropic, Protocol::OpenAiCompatible] {
let wire = serde_json::to_value(p).unwrap();
assert_eq!(wire, p.as_str(), "serde 线格式与 as_str 不一致");
assert_eq!(Protocol::parse(p.as_str()), Some(p));
let back: Protocol = serde_json::from_value(wire).unwrap();
assert_eq!(back, p);
}
assert_eq!(
Protocol::parse("open_ai_compatible"),
None,
"旧拼写不再接受"
);
}
#[test]
fn default_base_url_has_version_segment() {
for p in [Protocol::Anthropic, Protocol::OpenAiCompatible] {
assert!(
crate::endpoint::ends_with_version_segment(p.default_base_url()),
"{} 缺版本段",
p.default_base_url()
);
}
}
}