Add miniflux webhook processing with KV store, change prompt.
Also updated README detailing the changes and setup required.
This commit is contained in:
parent
98e3c05ef7
commit
c57d15d69b
504
Cargo.lock
generated
504
Cargo.lock
generated
@ -28,6 +28,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.3.0"
|
||||
@ -51,15 +57,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.7"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
@ -67,6 +67,15 @@ version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
@ -131,6 +140,36 @@ version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.34"
|
||||
@ -281,6 +320,27 @@ dependencies = [
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.29.0"
|
||||
@ -289,16 +349,16 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.26"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
|
||||
checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
@ -319,14 +379,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -340,17 +404,6 @@ dependencies = [
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http 0.2.12",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "1.0.1"
|
||||
@ -358,7 +411,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http 1.1.0",
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body-util"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -367,47 +433,77 @@ version = "1.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.30"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9"
|
||||
checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.5.0"
|
||||
name = "hyper-rustls"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||
checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -469,6 +565,15 @@ version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "markdown"
|
||||
version = "1.0.0-alpha.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "911a8325e6fb87b89890cd4529a2ab34c2669c026279e61c26b7140a3d821ccb"
|
||||
dependencies = [
|
||||
"unicode-id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
@ -489,14 +594,18 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "miniflux-ai"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"console_error_panic_hook",
|
||||
"futures",
|
||||
"hex",
|
||||
"hmac",
|
||||
"markdown",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"worker",
|
||||
"worker-macros",
|
||||
]
|
||||
@ -569,7 +678,7 @@ version = "0.10.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
@ -671,9 +780,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.27"
|
||||
version = "0.12.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||
checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
@ -681,10 +790,13 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
@ -706,7 +818,22 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winreg",
|
||||
"windows-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -721,7 +848,7 @@ version = "0.38.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
@ -729,12 +856,43 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.4"
|
||||
name = "rustls"
|
||||
version = "0.23.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
|
||||
checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -758,7 +916,7 @@ version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@ -841,6 +999,17 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
@ -856,6 +1025,12 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.7"
|
||||
@ -866,6 +1041,18 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.75"
|
||||
@ -879,26 +1066,29 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.2"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.5.1"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
|
||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration-sys"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
|
||||
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@ -977,6 +1167,17 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.11"
|
||||
@ -990,6 +1191,27 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"pin-project",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.3"
|
||||
@ -1021,12 +1243,24 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-id"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1b6def86329695390197b82c1e244a54a131ceb66c996f2088a3876e2ae083f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
@ -1042,6 +1276,12 @@ dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.2"
|
||||
@ -1059,6 +1299,12 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
@ -1165,12 +1411,33 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
name = "windows-registry"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1179,7 +1446,7 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1188,22 +1455,7 @@ version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1212,46 +1464,28 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
@ -1264,64 +1498,30 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.50.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "worker"
|
||||
version = "0.3.4"
|
||||
@ -1333,8 +1533,8 @@ dependencies = [
|
||||
"chrono",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"js-sys",
|
||||
"matchit",
|
||||
"pin-project",
|
||||
@ -1395,3 +1595,9 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
|
18
Cargo.toml
18
Cargo.toml
@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "miniflux-ai"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
authors = [ "zhu327" ]
|
||||
authors = ["zhu327", "thallada"]
|
||||
|
||||
[package.metadata.release]
|
||||
release = false
|
||||
@ -20,11 +20,15 @@ codegen-units = 1
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.21"
|
||||
worker = { version="0.3.4" }
|
||||
worker-macros = { version="0.3.4" }
|
||||
base64 = "0.22"
|
||||
worker = { version = "0.3.4" }
|
||||
worker-macros = { version = "0.3.4" }
|
||||
console_error_panic_hook = { version = "0.1.7" }
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
hex = "0.4"
|
||||
hmac = "0.12"
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
sha2 = "0.10"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
futures = "0.3"
|
||||
futures = "0.3"
|
||||
markdown = "1.0.0-alpha.20"
|
||||
|
49
README.md
49
README.md
@ -22,31 +22,72 @@ This Cloudflare Workers tool automatically adds AI-generated summaries to articl
|
||||
### Installation
|
||||
|
||||
1. Clone the repository:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/zhu327/miniflux-ai.git
|
||||
cd miniflux-ai
|
||||
```
|
||||
|
||||
2. Deploy to Cloudflare Workers:
|
||||
2. Create the Cloudflare Worker KV namespace:
|
||||
|
||||
```bash
|
||||
npx wrangler kv:namespace create entries
|
||||
```
|
||||
|
||||
3. Update the `wrangler.toml` with the KV namespace ID from the previous command (under the `kv_namespaces` section).
|
||||
|
||||
4. Deploy to Cloudflare Workers:
|
||||
|
||||
```bash
|
||||
npx wrangler deploy
|
||||
```
|
||||
|
||||
5. Add the Miniflux Webhook integration. Copy the URL for your deployed cloudflare worker and paste it in the Miniflux Settings page under the Webhook integration. After saving the settings, there will be a text input containing the webhook secret key. Copy it and set it as the `MINIFLUX_WEBHOOK_SECRET` secret (see Configuration section below).
|
||||
|
||||
6. (Optional) To help differentiate the AI summary from the rest of the article text, add custom CSS styling for the `.ai-summary` block in your Miniflux settings (you may need to adjust the colors if you are not using a dark theme):
|
||||
|
||||
```css
|
||||
.ai-summary {
|
||||
background-color: #222;
|
||||
border: 1px solid #aaa;
|
||||
padding: 8px;
|
||||
padding-top: 0px;
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
The tool is configured using environment variables, which are set in the `wrangler.toml` file:
|
||||
The tool is configured using environment variables and [worker secrets](https://developers.cloudflare.com/workers/configuration/secrets/).
|
||||
|
||||
See [this docs page on how to acquire your Cloudflare account ID and Workers API token](https://developers.cloudflare.com/workers-ai/get-started/rest-api/).
|
||||
|
||||
You can set worker secrets with the command:
|
||||
|
||||
```
|
||||
|
||||
npx wrangler secret put SECRET_NAME
|
||||
|
||||
```
|
||||
|
||||
#### Secrets
|
||||
|
||||
- `MINIFLUX_URL`: Your Miniflux instance URL.
|
||||
- `MINIFLUX_USERNAME`: Your Miniflux username.
|
||||
- `MINIFLUX_PASSWORD`: Your Miniflux password.
|
||||
- `OPENAI_URL`: The endpoint for the OpenAI API.
|
||||
- `OPENAI_TOKEN`: Your OpenAI API token.
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
These environment variables can be set in the `wrangler.toml` file under the `[vars]` section:
|
||||
|
||||
- `OPENAI_MODEL`: The model ID to use for generating summaries. We recommend using the `@cf/qwen/qwen1.5-14b-chat-awq` model for best results.
|
||||
- `WHITELIST_URL`: A comma-separated list of website URLs that should be summarized.
|
||||
|
||||
### Usage
|
||||
|
||||
The tool runs as a scheduled Cloudflare Worker, querying for unread articles every 5 minutes. If an article is from a whitelisted site and does not contain code blocks, it generates a summary and updates the article.
|
||||
The worker listens for webhook requests from your Miniflux instance and when new entries are added it will store the entries in the Cloudflare KV store.
|
||||
|
||||
The worker also runs a scheduled cron job, querying the KV store for queued entries every 5 minutes. If the entry content is 500 characters or longer, it generates an AI summary and updates the article to include the summary at the top of the content.
|
||||
|
||||
### Contributing
|
||||
|
||||
|
249
src/lib.rs
249
src/lib.rs
@ -1,24 +1,24 @@
|
||||
extern crate console_error_panic_hook;
|
||||
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||
use futures::{stream, StreamExt};
|
||||
use hmac::{Hmac, Mac};
|
||||
use reqwest::header::{AUTHORIZATION, CONTENT_TYPE};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use worker::{event, Env, ScheduleContext, ScheduledEvent};
|
||||
use sha2::Sha256;
|
||||
use std::panic;
|
||||
use worker::*;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Feed {
|
||||
site_url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Entry {
|
||||
id: u64,
|
||||
title: String,
|
||||
url: String,
|
||||
content: String,
|
||||
feed: Feed,
|
||||
feed_id: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ApiResponse {
|
||||
struct NewEntriesRequest {
|
||||
entries: Vec<Entry>,
|
||||
}
|
||||
|
||||
@ -27,40 +27,13 @@ struct UpdateRequest {
|
||||
content: String,
|
||||
}
|
||||
|
||||
async fn get_entries(
|
||||
base_url: &str,
|
||||
username: &str,
|
||||
password: &str,
|
||||
) -> Result<ApiResponse, Box<dyn std::error::Error>> {
|
||||
// 创建 HTTP 客户端
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
// 使用 Basic Auth 进行身份验证
|
||||
let auth = format!(
|
||||
"Basic {}",
|
||||
STANDARD.encode(format!("{}:{}", username, password))
|
||||
);
|
||||
|
||||
// 发送 GET 请求
|
||||
let response = client
|
||||
.get(&format!("{}/v1/entries?status=unread&limit=100", base_url))
|
||||
.header(AUTHORIZATION, auth)
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.send()
|
||||
.await?
|
||||
.json::<ApiResponse>()
|
||||
.await?;
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
async fn update_entry(
|
||||
base_url: &str,
|
||||
username: &str,
|
||||
password: &str,
|
||||
id: u64,
|
||||
content: &str,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let auth = format!(
|
||||
@ -72,15 +45,17 @@ async fn update_entry(
|
||||
let update_request = UpdateRequest {
|
||||
content: content.to_string(),
|
||||
};
|
||||
console_log!("created update_request");
|
||||
|
||||
client
|
||||
.put(&url)
|
||||
.header(AUTHORIZATION, auth)
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.json(&update_request) // 将请求体序列化为 JSON
|
||||
.json(&update_request)
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?;
|
||||
console_log!("updated entry in miniflux");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -112,7 +87,8 @@ async fn request_openai_chat_completion(
|
||||
api_key: &str,
|
||||
model: &str,
|
||||
messages: Vec<Message>,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
) -> std::result::Result<String, Box<dyn std::error::Error>> {
|
||||
console_log!("request_openai_chat_completion");
|
||||
let client = reqwest::Client::new();
|
||||
let request_body = ChatCompletionRequest {
|
||||
model: model.to_string(),
|
||||
@ -120,7 +96,7 @@ async fn request_openai_chat_completion(
|
||||
};
|
||||
|
||||
let response = client
|
||||
.post(&format!("{}/v1/chat/completions", base_url))
|
||||
.post(format!("{}/v1/chat/completions", base_url))
|
||||
.header(AUTHORIZATION, format!("Bearer {}", api_key))
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.json(&request_body)
|
||||
@ -128,53 +104,56 @@ async fn request_openai_chat_completion(
|
||||
.await?;
|
||||
|
||||
if response.status().is_success() {
|
||||
console_log!("request_openai_chat_completion success");
|
||||
let completion_response: ChatCompletionResponse = response.json().await?;
|
||||
Ok(completion_response.choices[0].message.content.clone())
|
||||
} else {
|
||||
let error_message = response.text().await?;
|
||||
console_log!("request_openai_chat_completion error: {}", error_message);
|
||||
Err(format!("Error: {:?}", error_message).into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Miniflux {
|
||||
url: String,
|
||||
username: String,
|
||||
password: String,
|
||||
webhook_secret: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OpenAi {
|
||||
url: String,
|
||||
token: String,
|
||||
model: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Config {
|
||||
miniflux: Miniflux,
|
||||
openai: OpenAi,
|
||||
whitelist: HashSet<String>,
|
||||
}
|
||||
|
||||
async fn generate_and_update_entry(
|
||||
config: &Config,
|
||||
entry: Entry,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let content: &str = &entry.content;
|
||||
// Check if the content should be summarized and if the site is whitelisted
|
||||
if content.starts_with("<pre") || !config.whitelist.contains(&entry.feed.site_url) {
|
||||
) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
console_log!("entry id: {}", entry.id);
|
||||
console_log!("entry title: {}", entry.title);
|
||||
console_log!("entry url: {}", entry.url);
|
||||
if entry.content.trim().is_empty() || entry.content.len() < 500 {
|
||||
console_log!("skipping entry due to empty content or short content length");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let messages = vec![
|
||||
Message {
|
||||
role: "system".to_string(),
|
||||
content: "Please summarize the content of the article under 150 words in Chinese. Do not add any additional Character、markdown language to the result text. 请用不超过150个汉字概括文章内容。结果文本中不要添加任何额外的字符、Markdown语言。".to_string(),
|
||||
content: "You are an experienced and knowledgeable internet blogger that writes short and easy-to-read summaries for articles from various RSS feeds. Please summarize the content of the article in 250 words or less. Format your output in CommonMark compliant markdown. Do not give any extra comments, headers, or prefix. Only return the actual summary text. Similar to the blurbs on the back of books, highlight any aspects of the articles that may be of interest and grab the attention to any readers perusing.".to_string(),
|
||||
},
|
||||
Message {
|
||||
role: "user".to_string(),
|
||||
content: format!(
|
||||
"The following is the input content:\n---\n {}",
|
||||
content,
|
||||
),
|
||||
content: format!("The following is the article:\n---\nTitle: {}\nURL: {}\nContent: {}", &entry.title, &entry.url, &entry.content),
|
||||
},
|
||||
];
|
||||
|
||||
@ -188,9 +167,11 @@ async fn generate_and_update_entry(
|
||||
.await
|
||||
{
|
||||
if !summary.trim().is_empty() {
|
||||
console_log!("Summary: {}", summary);
|
||||
let updated_content = format!(
|
||||
"<pre style=\"white-space: pre-wrap;\"><code>\n💡AI 摘要:\n{}</code></pre><hr><br />{}",
|
||||
summary, content
|
||||
"<div class=\"ai-summary\"><h4>✨ AI Summary</h4>{}</div><hr><br />{}",
|
||||
markdown::to_html(&summary),
|
||||
&entry.content
|
||||
);
|
||||
|
||||
// Update the entry
|
||||
@ -205,50 +186,158 @@ async fn generate_and_update_entry(
|
||||
}
|
||||
}
|
||||
|
||||
console_log!("processed entry: {}", entry.id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_options() -> Result<Response> {
|
||||
let mut headers = Headers::new();
|
||||
headers.set("Access-Control-Allow-Origin", "*")?;
|
||||
headers.set("Access-Control-Allow-Methods", "POST, OPTIONS")?;
|
||||
headers.set(
|
||||
"Access-Control-Allow-Headers",
|
||||
"Content-Type, X-Miniflux-Signature",
|
||||
)?;
|
||||
Response::ok("").map(|resp| resp.with_headers(headers))
|
||||
}
|
||||
|
||||
#[event(scheduled)]
|
||||
async fn scheduled(_event: ScheduledEvent, env: Env, _ctx: ScheduleContext) {
|
||||
pub async fn scheduled(_event: ScheduledEvent, env: Env, _ctx: ScheduleContext) {
|
||||
console_log!("scheduled");
|
||||
let config = &Config {
|
||||
whitelist: env
|
||||
.var("WHITELIST_URL")
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.split(",")
|
||||
.map(|s| s.to_string())
|
||||
.collect(),
|
||||
openai: OpenAi {
|
||||
url: env.var("OPENAI_URL").unwrap().to_string(),
|
||||
token: env.var("OPENAI_TOKEN").unwrap().to_string(),
|
||||
url: env.secret("OPENAI_URL").unwrap().to_string(),
|
||||
token: env.secret("OPENAI_TOKEN").unwrap().to_string(),
|
||||
model: env.var("OPENAI_MODEL").unwrap().to_string(),
|
||||
},
|
||||
miniflux: Miniflux {
|
||||
url: env.var("MINIFLUX_URL").unwrap().to_string(),
|
||||
username: env.var("MINIFLUX_USERNAME").unwrap().to_string(),
|
||||
password: env.var("MINIFLUX_PASSWORD").unwrap().to_string(),
|
||||
url: env.secret("MINIFLUX_URL").unwrap().to_string(),
|
||||
username: env.secret("MINIFLUX_USERNAME").unwrap().to_string(),
|
||||
password: env.secret("MINIFLUX_PASSWORD").unwrap().to_string(),
|
||||
webhook_secret: env.secret("MINIFLUX_WEBHOOK_SECRET").unwrap().to_string(),
|
||||
},
|
||||
};
|
||||
console_log!("config");
|
||||
|
||||
// 查询未读文章
|
||||
let entries = get_entries(
|
||||
&config.miniflux.url,
|
||||
&config.miniflux.username,
|
||||
&config.miniflux.password,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let kv = env.kv("entries").unwrap();
|
||||
|
||||
// List all keys with the "entry:" prefix
|
||||
let keys = kv
|
||||
.list()
|
||||
.prefix("entry:".to_string())
|
||||
.execute()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// 生成摘要并更新的并发任务
|
||||
let max_concurrent_tasks = 5;
|
||||
|
||||
// Create a stream to process tasks with concurrency limit
|
||||
let _: Vec<_> = stream::iter(entries.entries)
|
||||
.map(|entry| {
|
||||
let _: Vec<_> = stream::iter(keys.keys)
|
||||
.map(|key| {
|
||||
let config = &config;
|
||||
async move { generate_and_update_entry(config, entry).await }
|
||||
let kv = kv.clone();
|
||||
async move {
|
||||
// Retrieve the entry
|
||||
if let Ok(Some(entry)) = kv.get(&key.name).json::<Entry>().await {
|
||||
console_log!("Processing entry: {}", key.name);
|
||||
|
||||
// Process the entry (call AI API, etc.)
|
||||
match generate_and_update_entry(config, entry).await {
|
||||
Ok(_) => {
|
||||
// If processing was successful, delete the entry from KV
|
||||
kv.delete(&key.name).await.unwrap();
|
||||
console_log!("Processed and removed entry: {}", key.name);
|
||||
}
|
||||
Err(e) => {
|
||||
console_error!("Error processing entry {}: {:?}", key.name, e);
|
||||
// Optionally, you could implement retry logic here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.buffer_unordered(max_concurrent_tasks)
|
||||
.collect()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[event(fetch)]
|
||||
async fn fetch(mut req: Request, env: Env, _ctx: Context) -> Result<Response> {
|
||||
panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||
console_log!("fetch");
|
||||
// Check if it's an OPTIONS request and handle it
|
||||
if req.method() == Method::Options {
|
||||
return handle_options();
|
||||
}
|
||||
console_log!("not options");
|
||||
|
||||
// Only proceed with POST requests
|
||||
if req.method() != Method::Post {
|
||||
return Response::error("Method not allowed", 405);
|
||||
}
|
||||
console_log!("is post");
|
||||
|
||||
let config = &Config {
|
||||
openai: OpenAi {
|
||||
url: env.secret("OPENAI_URL").unwrap().to_string(),
|
||||
token: env.secret("OPENAI_TOKEN").unwrap().to_string(),
|
||||
model: env.var("OPENAI_MODEL").unwrap().to_string(),
|
||||
},
|
||||
miniflux: Miniflux {
|
||||
url: env.secret("MINIFLUX_URL").unwrap().to_string(),
|
||||
username: env.secret("MINIFLUX_USERNAME").unwrap().to_string(),
|
||||
password: env.secret("MINIFLUX_PASSWORD").unwrap().to_string(),
|
||||
webhook_secret: env.secret("MINIFLUX_WEBHOOK_SECRET").unwrap().to_string(),
|
||||
},
|
||||
};
|
||||
console_log!("config");
|
||||
|
||||
let signature = req
|
||||
.headers()
|
||||
.get("x-miniflux-signature")
|
||||
.map_err(|_err| {
|
||||
Error::RustError("Missing signature header in webhook request".to_string())
|
||||
})?
|
||||
.ok_or_else(|| {
|
||||
Error::RustError("Missing signature header in webhook request".to_string())
|
||||
})?;
|
||||
console_log!("signature");
|
||||
let payload = match req.bytes().await {
|
||||
Ok(bytes) => bytes,
|
||||
Err(err) => return Response::error(format!("Failed to read payload: {}", err), 400),
|
||||
};
|
||||
console_log!("payload");
|
||||
|
||||
let mut mac = Hmac::<Sha256>::new_from_slice(config.miniflux.webhook_secret.as_bytes())
|
||||
.map_err(|_| Error::RustError("HMAC key error".to_string()))?;
|
||||
console_log!("mac");
|
||||
|
||||
mac.update(&payload);
|
||||
let hmac = hex::encode(mac.finalize().into_bytes());
|
||||
console_log!("hmac");
|
||||
|
||||
if hmac != signature {
|
||||
return Response::error("Incorrect webhook request signature", 403);
|
||||
}
|
||||
|
||||
// convert body to json
|
||||
let body: NewEntriesRequest = serde_json::from_slice::<NewEntriesRequest>(&payload)
|
||||
.map_err(|_err| Error::RustError("Failed to parse webhook json body".to_string()))?;
|
||||
console_log!("body");
|
||||
|
||||
let kv = env.kv("entries")?;
|
||||
|
||||
let max_concurrent_tasks = 5;
|
||||
|
||||
// Create a stream to process tasks with concurrency limit
|
||||
let _: Vec<_> = stream::iter(body.entries)
|
||||
.map(|entry| {
|
||||
let key = format!("entry:{}", entry.id);
|
||||
let kv = kv.clone();
|
||||
console_log!("putting KV key {}", key);
|
||||
async move { kv.put(&key, entry)?.execute().await }
|
||||
})
|
||||
.buffer_unordered(max_concurrent_tasks)
|
||||
.collect()
|
||||
.await;
|
||||
Response::ok("Webhook request processed")
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
name = "miniflux-ai"
|
||||
main = "build/worker/shim.mjs"
|
||||
compatibility_date = "2024-08-06"
|
||||
compatibility_date = "2024-09-06"
|
||||
|
||||
[[kv_namespaces]]
|
||||
binding = "entries"
|
||||
id = "<insert-your-namespace-id>"
|
||||
|
||||
[build]
|
||||
command = "cargo install -q worker-build && worker-build --release"
|
||||
@ -9,10 +13,4 @@ command = "cargo install -q worker-build && worker-build --release"
|
||||
crons = ["*/5 * * * *"]
|
||||
|
||||
[vars]
|
||||
MINIFLUX_URL = "your miniflux url"
|
||||
MINIFLUX_USERNAME = "your miniflux username"
|
||||
MINIFLUX_PASSWORD = "your miniflux password"
|
||||
OPENAI_URL = "https://api.cloudflare.com/client/v4/accounts/{your cloudflare account}/ai"
|
||||
OPENAI_TOKEN = "your cloudflare workers AI token"
|
||||
OPENAI_MODEL = "@cf/qwen/qwen1.5-14b-chat-awq"
|
||||
WHITELIST_URL = "https://www.zaobao.com/news/china,https://t.me/s/theinitium_rss,https://cn.nytimes.com,https://www.latepost.com/news/get-news-data,https://t.me/s/wsj_rss,http://www.zhihu.com,https://new.qq.com/omn/author/5157372,https://www.huxiu.com"
|
Loading…
Reference in New Issue
Block a user