summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsigoden <sigoden@gmail.com>2024-09-06 08:08:55 +0800
committerGitHub <noreply@github.com>2024-09-06 08:08:55 +0800
commit555f4f5d128d018912144b0e7f2b3a50223bf713 (patch)
tree46c72e49bb34817fcee1bece140831c11b1580e0
parent791b6150afd626baabc2d71acc1dc3dcb70ad4d0 (diff)
downloadaichat-555f4f5d128d018912144b0e7f2b3a50223bf713.tar.gz
feat: better html to markdown converter (#840)
-rw-r--r--Cargo.lock50
-rw-r--r--Cargo.toml2
-rw-r--r--src/utils/html_to_md.rs18
-rw-r--r--src/utils/mod.rs2
-rw-r--r--src/utils/request.rs16
5 files changed, 63 insertions, 25 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4702621..4ec3312 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -67,7 +67,7 @@ dependencies = [
"futures-util",
"hmac",
"hnsw_rs",
- "html2text",
+ "html_to_markdown",
"http",
"http-body-util",
"hyper",
@@ -1153,19 +1153,6 @@ dependencies = [
]
[[package]]
-name = "html2text"
-version = "0.12.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c66ee488a63a92237d5b48875b7e05bb293be8fb2894641c8118b60c08ab5ef"
-dependencies = [
- "html5ever",
- "markup5ever",
- "tendril",
- "thiserror",
- "unicode-width",
-]
-
-[[package]]
name = "html5ever"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1180,6 +1167,18 @@ dependencies = [
]
[[package]]
+name = "html_to_markdown"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e608e8dd0939bfb6b516d96a5919751b835297a02230aecb88d2fc84ebebaa8a"
+dependencies = [
+ "anyhow",
+ "html5ever",
+ "markup5ever_rcdom",
+ "regex",
+]
+
+[[package]]
name = "http"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1522,6 +1521,18 @@ dependencies = [
]
[[package]]
+name = "markup5ever_rcdom"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edaa21ab3701bfee5099ade5f7e1f84553fd19228cf332f13cd6e964bf59be18"
+dependencies = [
+ "html5ever",
+ "markup5ever",
+ "tendril",
+ "xml5ever",
+]
+
+[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3914,6 +3925,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d"
[[package]]
+name = "xml5ever"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bbb26405d8e919bc1547a5aa9abc95cbfa438f04844f5fdd9dc7596b748bf69"
+dependencies = [
+ "log",
+ "mac",
+ "markup5ever",
+]
+
+[[package]]
name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index d97e537..9ee6cb9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -59,9 +59,9 @@ path-absolutize = "3.1.1"
hnsw_rs = "0.3.0"
rayon = "1.10.0"
uuid = { version = "1.9.1", features = ["v4"] }
-html2text = "0.12.5"
scraper = { version = "0.20.0", default-features = false, features = ["deterministic"] }
sys-locale = "0.3.1"
+html_to_markdown = "0.1.0"
[dependencies.reqwest]
version = "0.12.0"
diff --git a/src/utils/html_to_md.rs b/src/utils/html_to_md.rs
new file mode 100644
index 0000000..2bc5e54
--- /dev/null
+++ b/src/utils/html_to_md.rs
@@ -0,0 +1,18 @@
+use std::{cell::RefCell, rc::Rc};
+
+use html_to_markdown::{markdown, TagHandler};
+
+pub fn html_to_md(html: &str) -> String {
+ let mut handlers: Vec<TagHandler> = vec![
+ Rc::new(RefCell::new(markdown::ParagraphHandler)),
+ Rc::new(RefCell::new(markdown::HeadingHandler)),
+ Rc::new(RefCell::new(markdown::ListHandler)),
+ Rc::new(RefCell::new(markdown::TableHandler::new())),
+ Rc::new(RefCell::new(markdown::StyledTextHandler)),
+ Rc::new(RefCell::new(markdown::CodeHandler)),
+ Rc::new(RefCell::new(markdown::WebpageChromeRemover)),
+ ];
+
+ html_to_markdown::convert_html_to_markdown(html.as_bytes(), &mut handlers)
+ .unwrap_or_else(|_| html.to_string())
+}
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index d9d6617..1090c4e 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -2,6 +2,7 @@ mod abort_signal;
mod clipboard;
mod command;
mod crypto;
+mod html_to_md;
mod path;
mod prompt_input;
mod render_prompt;
@@ -12,6 +13,7 @@ pub use self::abort_signal::*;
pub use self::clipboard::set_text;
pub use self::command::*;
pub use self::crypto::*;
+pub use self::html_to_md::*;
pub use self::path::*;
pub use self::prompt_input::*;
pub use self::render_prompt::render_prompt;
diff --git a/src/utils/request.rs b/src/utils/request.rs
index 73919d8..9f2804b 100644
--- a/src/utils/request.rs
+++ b/src/utils/request.rs
@@ -8,8 +8,11 @@ use reqwest::Url;
use scraper::{Html, Selector};
use serde::Deserialize;
use serde_json::Value;
-use std::{collections::HashMap, time::Duration};
-use std::{collections::HashSet, sync::Arc};
+use std::{
+ collections::{HashMap, HashSet},
+ sync::Arc,
+ time::Duration,
+};
use tokio::io::AsyncWriteExt;
use tokio::sync::Semaphore;
@@ -136,10 +139,7 @@ pub async fn fetch(
None => {
let contents = res.text().await?;
if extension == "html" {
- (
- html2text::from_read(contents.as_bytes(), usize::MAX),
- "md".into(),
- )
+ (html_to_md(&contents), "md".into())
} else {
(contents, extension)
}
@@ -387,10 +387,6 @@ async fn crawl_page(
Ok((path.to_string(), text, links.into_iter().collect()))
}
-fn html_to_md(html: &str) -> String {
- html2text::from_read(html.as_bytes(), usize::MAX)
-}
-
fn should_exclude_link(link: &str, exclude: &[String]) -> bool {
if link.contains("#") {
return true;