删除冗余,修改描述

This commit is contained in:
2026-06-17 13:48:25 +08:00
parent 57c030a62a
commit 08aadef8cf
3 changed files with 1 additions and 155 deletions
+1 -2
View File
@@ -2,7 +2,7 @@
name = "iAs" name = "iAs"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
description = "微信 AI 智能助手 — 通过 DeepSeek LLM 实现 AI 自动回复" description = "AI 智能助手"
[dependencies] [dependencies]
# ── 异步运行时 ── # ── 异步运行时 ──
@@ -51,4 +51,3 @@ scraper = "0.27.0" # HTML 解析(f
[[bin]] [[bin]]
name = "ias" name = "ias"
path = "src/main.rs" path = "src/main.rs"
-10
View File
@@ -1,10 +0,0 @@
[package]
name = "ias-fetch"
version = "0.1.0"
edition = "2024"
[dependencies]
chromiumoxide = { version = "0.7", default-features = false, features = ["tokio-runtime", "bytes"] }
futures = "0.3"
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }
-143
View File
@@ -1,143 +0,0 @@
//! ias-fetch — 通过 headless Chrome 提取网页正文
//!
//! 启动无头 Chrome 渲染页面 JS,取渲染后的纯文本输出到 stdout。
//! 专供 JSON 工具 `${cmd:ias-fetch {{url}}}` 调用。
//!
//! 用法:
//! ias-fetch <url> # 默认:取 body.innerText
//! ias-fetch --raw <url> # 返回完整 HTML
//! ias-fetch --timeout 15 <url> # 自定义超时(默认 15s)
use futures::StreamExt;
use std::time::Duration;
use chromiumoxide::{Browser, BrowserConfig, Page};
const DEFAULT_TIMEOUT: u64 = 15;
const MAX_OUTPUT_CHARS: usize = 10_000;
#[tokio::main]
async fn main() {
let args: Vec<String> = std::env::args().collect();
let mut raw_mode = false;
let mut timeout_secs = DEFAULT_TIMEOUT;
let mut url: Option<String> = None;
let mut i = 1;
while i < args.len() {
match args[i].as_str() {
"--raw" => raw_mode = true,
"--timeout" => {
i += 1;
timeout_secs = args.get(i).and_then(|s| s.parse().ok()).unwrap_or(DEFAULT_TIMEOUT);
}
s if s.starts_with("http://") || s.starts_with("https://") => {
url = Some(s.to_string());
}
s if !s.starts_with('-') => url = Some(s.to_string()),
_ => {}
}
i += 1;
}
let url = match url {
Some(u) => {
if u.starts_with("http://") || u.starts_with("https://") {
u
} else {
format!("https://{}", u)
}
}
None => {
eprintln!("用法: ias-fetch [--raw] [--timeout N] <url>");
std::process::exit(1);
}
};
let timeout = Duration::from_secs(timeout_secs);
match tokio::time::timeout(timeout, fetch_page(&url, raw_mode)).await {
Ok(Ok(output)) => {
if output.is_empty() {
eprintln!("页面无内容");
std::process::exit(1);
}
println!("{}", output);
}
Ok(Err(e)) => {
eprintln!("{}", e);
std::process::exit(1);
}
Err(_) => {
eprintln!("超时 ({}s): {}", timeout_secs, url);
std::process::exit(1);
}
}
}
async fn fetch_page(url: &str, raw_mode: bool) -> Result<String, String> {
let (mut browser, mut handler) = Browser::launch(
BrowserConfig::builder()
.build()
.map_err(|e| format!("Chrome 配置失败: {}", e))?,
)
.await
.map_err(|e| format!("启动 Chrome 失败: {}\n请确保已安装 chromium 或 google-chrome", e))?;
let handle = tokio::spawn(async move {
while let Some(_event) = handler.next().await {
// 持续消费 handler 事件
}
});
// new_page 接受 URL,自动导航并等待加载
let page = browser
.new_page(url)
.await
.map_err(|e| format!("导航到 {} 失败: {}", url, e))?;
// 额外等待 JS 渲染
tokio::time::sleep(Duration::from_secs(2)).await;
// 提取内容
let content = if raw_mode {
page.content().await.map_err(|e| format!("获取 HTML 失败: {}", e))?
} else {
get_inner_text(&page).await?
};
// 清理
browser.close().await.ok();
handle.await.ok();
// 截断
if content.chars().count() > MAX_OUTPUT_CHARS {
Ok(format!(
"{}…(已截断,完整内容 {} 字符)",
content.chars().take(MAX_OUTPUT_CHARS).collect::<String>(),
content.chars().count()
))
} else {
Ok(content)
}
}
/// 通过 evaluate JS 获取 body.innerText
async fn get_inner_text(page: &Page) -> Result<String, String> {
let result = page
.evaluate("document.body?.innerText || document.documentElement?.innerText || ''")
.await
.map_err(|e| format!("提取正文失败: {}", e))?;
let value: serde_json::Value = result
.into_value()
.map_err(|e| format!("解析 evaluate 结果失败: {}", e))?;
match value {
serde_json::Value::String(s) => {
let cleaned: Vec<&str> = s.lines().map(|l| l.trim()).filter(|l| !l.is_empty()).collect();
Ok(cleaned.join("\n"))
}
_ => Ok(String::new()),
}
}