Skip to main content

ai_profile/
lib.rs

1//! # ai-profile
2//!
3//! 桌面应用的 AI 模型服务配置层:provider 预置清单、`ai.profile` 互通协议、
4//! 端点拼接与连通性验证。
5//!
6//! ## 边界:什么进、什么不进
7//!
8//! | | 内容 | 归属 |
9//! |---|---|---|
10//! | ✅ | 预置清单、协议、端点拼接、模型清洗、验证与结构化错误、token 限额、历史裁剪 | 本 crate |
11//! | ❌ | **密钥存储与加密** | 留给应用(各家差异极大) |
12//! | ❌ | 数据库 / CRUD / 激活态管理 | 同上 |
13//!
14//! **本 crate 不持久化任何密钥明文**。验证/调用时接收调用方传入的 key,用完即弃。
15//!
16//! ## 三条数据铁律(都是踩出来的)
17//!
18//! 1. **`base_url` 原样使用,绝不推断版本段** —— 各家不统一(多数 `/v1`、智谱 `/v4`、
19//!    Gemini `/v1beta/openai`)。推断错的代价是隐性的:用户照文档填对了,
20//!    库悄悄加一段,他只看到 404。详见 [`endpoint`]。
21//! 2. **默认 model 选「够用档」而非「最强档」** —— 把旗舰塞进默认值,
22//!    等于替用户做了一个他没同意的花钱决定。
23//! 3. **模型清单清洗用排除法,不用白名单** —— 厂商上新远快于特征词更新,
24//!    白名单必然把新模型误藏,而"藏起来"对用户不可见。详见 [`model_filter`]。
25//!
26//! ## feature
27//!
28//! ```toml
29//! ai-profile = { version = "0.1", features = ["chat"] }              # 仅对话
30//! ai-profile = { version = "0.1", features = ["chat", "client"] }    # + 真实调用
31//! ```
32//!
33//! 不开 `client` 时零 HTTP 依赖,纯数据 + 纯函数,可编到 Android / iOS。
34
35#![forbid(unsafe_code)]
36#![warn(missing_docs)]
37
38pub mod endpoint;
39pub mod error;
40pub mod history;
41pub mod kind;
42pub mod limits;
43pub mod model_filter;
44pub mod preset;
45pub mod protocol;
46
47#[cfg(feature = "client")]
48pub mod client;
49
50/// 生图 / 视频 / 配音的真实调用。要同时开 `client` 与对应 kind 的 feature。
51#[cfg(all(
52    feature = "client",
53    any(feature = "image", feature = "video", feature = "tts")
54))]
55pub mod media;
56
57pub use error::VerifyError;
58pub use kind::{Kind, Protocol};
59pub use limits::{LimitSource, TokenLimits};
60pub use preset::{preset_by_key, presets, presets_for, vendors, ProviderPreset, Vendor};
61pub use protocol::{
62    parse_profile, parse_profiles, to_profile, ParseError, ParsedProfile, ParsedProfiles,
63};
64
65#[cfg(feature = "client")]
66pub use client::{verify, ServiceConfig, Verifier, VerifyOk};
67
68/// 重导出 `reqwest`,供 [`client::Verifier::from_builder`] 使用。
69///
70/// # 为什么要重导出
71///
72/// `from_builder` 收的是 `reqwest::ClientBuilder` —— 一个别人 crate 的类型。
73/// 下游若用自己依赖树里的 reqwest 建 builder,**版本对不上就编译不过**,
74/// 而且报错信息会是「expected ClientBuilder, found ClientBuilder」这种极难懂的形式。
75///
76/// 重导出之后下游写 `ai_profile::reqwest::Client::builder()`,版本必然匹配。
77///
78/// 🔴 代价要认:这让 reqwest 的大版本进入本 crate 的公开 API。
79/// 升到 reqwest 0.13 就是本 crate 的 **major** 变更,不是 patch。
80#[cfg(feature = "client")]
81pub use reqwest;
82
83// ⏸ 后续阶段(见 docs/tasks/archive/2026-09/ 的规划,已归档):
84// - client::dry_run —— 真实调用(产生费用),按 kind 分实现