新增: AI 工具(download_file + http output_file + grep 窗口 + fetch_search 搜索 + get_app_config + generate_image)
download_file 跨平台 URL 到文件流式下载;http_request output_file 落盘 + 截断可配; grep context_chars 大单行窗口;fetch_search DuckDuckGo 免 key 搜索;get_app_config 只读返当前配置(治 AI 查配置绕 PowerShell);generate_image SenseNova 图像生成。
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
//! generate_image AI 工具声明式注册(调 provider 图像生成端点 + 下载落地)。
|
||||
//!
|
||||
//! 工具职责:调 provider 的 OpenAI 兼容 `/v1/images/generations` 端点生成图片,
|
||||
//! 自动下载到工作区 output_path。默认 model=sensenova-u1-fast(SenseNova U1 信息图生成),
|
||||
//! 也支持 DALL-E 等 OpenAI 兼容图像端点。
|
||||
//!
|
||||
//! 风险:High(付费 API 按张计费 + 写磁盘 + 外发网络)。
|
||||
//!
|
||||
//! 与 download_file 的分工:download_file 是「已知 URL → 落盘」,generate_image 是
|
||||
//! 「调 provider 生成 + 自动落盘」(封装 provider 凭证 + 端点拼接 + 响应解析 + 图片下载全链路)。
|
||||
//! 图像生成模型不是 chat 模型,走 /v1/images/generations 非 chat completions,
|
||||
//! 故不能经主对话链路调用,必须用本工具显式触发。
|
||||
//!
|
||||
//! handler 在 commands/ai/generate_image.rs::execute_generate_image,声明式注册收敛样板。
|
||||
//! 闭包捕获 db:Arc<Database>(选 provider + 解析凭证)+ allowed_dirs:Arc<RwLock<AllowedDirs>>
|
||||
//! (output_path 白名单校验 + 默认路径锚定)。
|
||||
//!
|
||||
//! ## 捕获变量说明(declare_tool! 单捕获限制)
|
||||
//!
|
||||
//! declare_tool! 宏只支持单捕获变量(见 crates/df-ai/src/ai_tools_decl.rs),本工具需 db +
|
||||
//! allowed_dirs 两个,故包进 tuple Arc `(Arc<Database>, Arc<RwLock<AllowedDirs>>)` 在闭包内解构。
|
||||
//! 这是宏单捕获限制的标准绕法(零架构改动:不改宏、不改 process_tool_calls 签名)。
|
||||
//!
|
||||
//! ## 注册位置说明
|
||||
//!
|
||||
//! generate_image 涉付费 API(网络)+ 写文件(落盘 output_path),与 download_file 同源
|
||||
//! (均持 allowed_dirs),归 register_http_tools 同层(register_generate_image_tool 子函数,
|
||||
//! 在 register_http_tools 之后调用)。
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use df_ai::ai_tools::{AiToolRegistry, RiskLevel};
|
||||
use df_ai::declare_tool;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::state::AllowedDirs;
|
||||
use df_storage::db::Database;
|
||||
|
||||
/// generate_image 捕获的 (db, allowed_dirs) tuple 类型(declare_tool! 单捕获绕法)。
|
||||
type GenerateImageCtx = (Arc<Database>, Arc<RwLock<AllowedDirs>>);
|
||||
|
||||
/// 注册 generate_image 工具到 `$registry`。
|
||||
///
|
||||
/// - name/desc/schema 面向 LLM 的工具说明
|
||||
/// - risk=High(付费 API + 写磁盘 + 外发网络)
|
||||
/// - handler 捕获 (db, allowed_dirs) tuple Arc,解构后转调 generate_image.rs::execute_generate_image
|
||||
/// (provider 选择 + 凭证解析 + 端点拼接 + SSRF 防护下载 + 原子写全在那)
|
||||
pub fn register(
|
||||
registry: &mut AiToolRegistry,
|
||||
db: &Arc<Database>,
|
||||
allowed_dirs: &Arc<RwLock<AllowedDirs>>,
|
||||
) {
|
||||
// 捕获 tuple:declare_tool! 单捕获限制的绕法。
|
||||
let ctx: GenerateImageCtx = (db.clone(), allowed_dirs.clone());
|
||||
|
||||
// schema:prompt(必填)+ model(默认 sensenova-u1-fast)+ size(可选)+ n(默认 1)
|
||||
// + provider_id(可选)+ output_path(可选)。
|
||||
let schema = {
|
||||
let mut props = serde_json::Map::new();
|
||||
props.insert("prompt".into(), serde_json::json!({ "type": "string", "description": "图片描述(中英文均可),越具体生成质量越高。例:'一只戴墨镜的橘猫坐在键盘上,赛博朋克风格,霓虹光'" }));
|
||||
props.insert("model".into(), serde_json::json!({ "type": "string", "description": "图像生成模型名。默认 sensenova-u1-fast(SenseNova U1 信息图生成,走 /v1/images/generations)。也支持 dall-e-3 等 OpenAI 兼容图像模型。不传用默认", "default": "sensenova-u1-fast" }));
|
||||
props.insert("size".into(), serde_json::json!({ "type": "string", "description": "可选图片尺寸字符串,不传则让 provider 用默认。SenseNova U1 常用 2752x1536 / 1536x2752(横/竖海报),DALL-E 常用 1024x1024" }));
|
||||
props.insert("n".into(), serde_json::json!({ "type": "integer", "description": "生成数量(默认 1,clamp [1,4])。多张时取首张 url/b64 落地", "minimum": 1, "maximum": 4, "default": 1 }));
|
||||
props.insert("provider_id".into(), serde_json::json!({ "type": "string", "description": "可选,指定 provider(多 provider 时);不传则按 model 名自动匹配厂商 host(sensenova→SenseNova,dall-e→OpenAI,google/imagen→Google),匹配不到取首个 openai_compat provider" }));
|
||||
props.insert("output_path".into(), serde_json::json!({ "type": "string", "description": "可选落盘路径(相对路径锚定到授权项目根,绝对路径须在授权目录内)。不传则默认 {首个持久授权目录}/generated_images/{model}-{时间戳}.png。父目录不存在自动创建,覆盖既有同名文件。注意:这是图像生成模型(非对话模型),通过本工具调用而非主对话链路" }));
|
||||
serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": props,
|
||||
"required": ["prompt"],
|
||||
})
|
||||
};
|
||||
declare_tool!(
|
||||
registry,
|
||||
ctx: GenerateImageCtx,
|
||||
"generate_image",
|
||||
"调用图像生成模型(默认 SenseNova U1 Fast 信息图生成,也支持 DALL-E 等 OpenAI 兼容图像端点)生成图片并下载到工作区。参数:prompt(图片描述,必填),model(默认 sensenova-u1-fast),size(可选,SenseNova U1 常用 2752x1536/1536x2752,DALL-E 常用 1024x1024),n(默认 1,clamp [1,4]),provider_id(可选,多 provider 时指定,否则按 model 名自动匹配厂商),output_path(可选,默认 generated_images/{model}-{时间戳}.png)。注意:本工具调用图像生成模型(非对话模型),走 /v1/images/generations 端点。返回 {path, url(或 null), model, provider_id, bytes_written, elapsed_ms}。风险:付费 API 按张计费 + 写磁盘",
|
||||
RiskLevel::High,
|
||||
schema: schema,
|
||||
args => {
|
||||
// 解构 tuple 捕获:db 选 provider + 解析凭证,allowed_dirs 解析 output_path 白名单
|
||||
let (db, allowed_dirs) = ctx;
|
||||
crate::commands::ai::generate_image::execute_generate_image(args, &db, &allowed_dirs).await
|
||||
}
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user