commit 968d9bc2452481a85ea4568181d68e7b005923dc
parent a7012754602a44e5a8da5b25f816afd7f55b379c
Author: William Casarin <jb55@jb55.com>
Date: Sun, 23 Mar 2025 18:43:31 -0700
dave is alive
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
9 files changed, 1585 insertions(+), 30 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -312,6 +312,43 @@ dependencies = [
]
[[package]]
+name = "async-openai"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14d76e2f5af19477d6254415acc95ba97c6cc6f3b1e3cb4676b7f0fab8194298"
+dependencies = [
+ "async-openai-macros",
+ "backoff",
+ "base64 0.22.1",
+ "bytes",
+ "derive_builder",
+ "eventsource-stream",
+ "futures",
+ "rand 0.8.5",
+ "reqwest",
+ "reqwest-eventsource",
+ "secrecy",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.12",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "async-openai-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0289cba6d5143bfe8251d57b4a8cac036adf158525a76533a7082ba65ec76398"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "async-process"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -449,6 +486,20 @@ dependencies = [
]
[[package]]
+name = "backoff"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1"
+dependencies = [
+ "futures-core",
+ "getrandom 0.2.15",
+ "instant",
+ "pin-project-lite",
+ "rand 0.8.5",
+ "tokio",
+]
+
+[[package]]
name = "backtrace"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -529,7 +580,7 @@ dependencies = [
"proc-macro2",
"quote",
"regex",
- "rustc-hash",
+ "rustc-hash 1.1.0",
"shlex",
"syn",
"which",
@@ -980,7 +1031,7 @@ dependencies = [
"bitflags 1.3.2",
"core-foundation 0.9.4",
"core-graphics-types",
- "foreign-types",
+ "foreign-types 0.5.0",
"libc",
]
@@ -1071,6 +1122,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
[[package]]
+name = "darling"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "data-encoding"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1092,6 +1178,37 @@ dependencies = [
]
[[package]]
+name = "derive_builder"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
+dependencies = [
+ "derive_builder_macro",
+]
+
+[[package]]
+name = "derive_builder_core"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "derive_builder_macro"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
+dependencies = [
+ "derive_builder_core",
+ "syn",
+]
+
+[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1379,6 +1496,15 @@ dependencies = [
]
[[package]]
+name = "encoding_rs"
+version = "0.8.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
name = "endi"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1524,6 +1650,17 @@ dependencies = [
]
[[package]]
+name = "eventsource-stream"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab"
+dependencies = [
+ "futures-core",
+ "nom",
+ "pin-project-lite",
+]
+
+[[package]]
name = "ewebsock"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1608,12 +1745,21 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared 0.1.1",
+]
+
+[[package]]
+name = "foreign-types"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
dependencies = [
"foreign-types-macros",
- "foreign-types-shared",
+ "foreign-types-shared 0.3.1",
]
[[package]]
@@ -1629,6 +1775,12 @@ dependencies = [
[[package]]
name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "foreign-types-shared"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
@@ -1727,6 +1879,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
+name = "futures-timer"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
+
+[[package]]
name = "futures-util"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1784,9 +1942,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
"r-efi",
"wasi 0.14.2+wasi-0.2.4",
+ "wasm-bindgen",
]
[[package]]
@@ -1952,6 +2112,25 @@ dependencies = [
]
[[package]]
+name = "h2"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
name = "half"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2047,6 +2226,29 @@ dependencies = [
]
[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
name = "httparse"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2059,6 +2261,80 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c3b1f728c459d27b12448862017b96ad4767b1ec2ec5e6434e99f1577f085b8"
[[package]]
+name = "hyper"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
+dependencies = [
+ "futures-util",
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "rustls-native-certs",
+ "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.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "libc",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
name = "icu_collections"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2177,6 +2453,12 @@ dependencies = [
]
[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
name = "idna"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2287,6 +2569,12 @@ dependencies = [
]
[[package]]
+name = "ipnet"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
+
+[[package]]
name = "is-docker"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2593,7 +2881,7 @@ dependencies = [
"bitflags 2.9.0",
"block",
"core-graphics-types",
- "foreign-types",
+ "foreign-types 0.5.0",
"log",
"objc",
"paste",
@@ -2667,7 +2955,7 @@ dependencies = [
"hexf-parse",
"indexmap",
"log",
- "rustc-hash",
+ "rustc-hash 1.1.0",
"spirv",
"strum",
"termcolor",
@@ -2676,6 +2964,23 @@ dependencies = [
]
[[package]]
+name = "native-tls"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
+dependencies = [
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework 2.11.1",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
name = "natord"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2922,6 +3227,7 @@ dependencies = [
"egui_extras",
"notedeck",
"notedeck_columns",
+ "notedeck_dave",
"profiling",
"puffin",
"puffin_egui",
@@ -2967,7 +3273,7 @@ dependencies = [
"puffin_egui",
"rfd",
"rmpv",
- "security-framework",
+ "security-framework 2.11.1",
"serde",
"serde_derive",
"serde_json",
@@ -2987,6 +3293,22 @@ dependencies = [
]
[[package]]
+name = "notedeck_dave"
+version = "0.3.1"
+dependencies = [
+ "async-openai",
+ "bytemuck",
+ "eframe",
+ "egui",
+ "egui-wgpu",
+ "futures",
+ "notedeck",
+ "reqwest",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3371,6 +3693,50 @@ dependencies = [
]
[[package]]
+name = "openssl"
+version = "0.10.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
+dependencies = [
+ "bitflags 2.9.0",
+ "cfg-if",
+ "foreign-types 0.3.2",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.107"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3729,17 +4095,71 @@ dependencies = [
]
[[package]]
-name = "quote"
-version = "1.0.40"
+name = "quinn"
+version = "0.11.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012"
dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "r-efi"
-version = "5.2.0"
+ "bytes",
+ "cfg_aliases",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash 2.1.1",
+ "rustls",
+ "socket2",
+ "thiserror 2.0.12",
+ "tokio",
+ "tracing",
+ "web-time 1.1.0",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc"
+dependencies = [
+ "bytes",
+ "getrandom 0.3.2",
+ "rand 0.9.0",
+ "ring",
+ "rustc-hash 2.1.1",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "thiserror 2.0.12",
+ "tinyvec",
+ "tracing",
+ "web-time 1.1.0",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2",
+ "tracing",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
@@ -3965,6 +4385,74 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
[[package]]
+name = "reqwest"
+version = "0.12.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
+dependencies = [
+ "base64 0.22.1",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-tls",
+ "hyper-util",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "mime_guess",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-pemfile",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "system-configuration",
+ "tokio",
+ "tokio-native-tls",
+ "tokio-rustls",
+ "tokio-util",
+ "tower",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-streams",
+ "web-sys",
+ "windows-registry",
+]
+
+[[package]]
+name = "reqwest-eventsource"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "632c55746dbb44275691640e7b40c907c16a2dc1a5842aa98aaec90da6ec6bde"
+dependencies = [
+ "eventsource-stream",
+ "futures-core",
+ "futures-timer",
+ "mime",
+ "nom",
+ "pin-project-lite",
+ "reqwest",
+ "thiserror 1.0.69",
+]
+
+[[package]]
name = "resvg"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4065,6 +4553,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
+name = "rustc-hash"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+
+[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4115,10 +4609,34 @@ dependencies = [
]
[[package]]
+name = "rustls-native-certs"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3"
+dependencies = [
+ "openssl-probe",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework 3.2.0",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
name = "rustls-pki-types"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
+dependencies = [
+ "web-time 1.1.0",
+]
[[package]]
name = "rustls-webpki"
@@ -4162,6 +4680,15 @@ dependencies = [
]
[[package]]
+name = "schannel"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4231,6 +4758,16 @@ dependencies = [
]
[[package]]
+name = "secrecy"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a"
+dependencies = [
+ "serde",
+ "zeroize",
+]
+
+[[package]]
name = "security-framework"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4244,6 +4781,19 @@ dependencies = [
]
[[package]]
+name = "security-framework"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316"
+dependencies = [
+ "bitflags 2.9.0",
+ "core-foundation 0.10.0",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
name = "security-framework-sys"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4313,6 +4863,18 @@ dependencies = [
]
[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4459,9 +5021,9 @@ dependencies = [
[[package]]
name = "socket2"
-version = "0.5.8"
+version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
+checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
dependencies = [
"libc",
"windows-sys 0.52.0",
@@ -4498,6 +5060,12 @@ dependencies = [
]
[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
name = "strum"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4547,6 +5115,15 @@ dependencies = [
]
[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
name = "synstructure"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4558,6 +5135,27 @@ dependencies = [
]
[[package]]
+name = "system-configuration"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
+dependencies = [
+ "bitflags 2.9.0",
+ "core-foundation 0.9.4",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
name = "system-deps"
version = "6.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4776,6 +5374,16 @@ dependencies = [
]
[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
name = "tokio-rustls"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4798,6 +5406,17 @@ dependencies = [
]
[[package]]
+name = "tokio-stream"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
name = "tokio-tungstenite"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4814,6 +5433,19 @@ dependencies = [
]
[[package]]
+name = "tokio-util"
+version = "0.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
name = "toml"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4848,6 +5480,33 @@ dependencies = [
]
[[package]]
+name = "tower"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "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"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[package]]
name = "tracing"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4933,6 +5592,12 @@ dependencies = [
]
[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
name = "ttf-parser"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4984,7 +5649,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f"
dependencies = [
- "rustc-hash",
+ "rustc-hash 1.1.0",
]
[[package]]
@@ -5182,6 +5847,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
name = "vec1"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5210,6 +5881,15 @@ dependencies = [
]
[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5296,6 +5976,19 @@ dependencies = [
]
[[package]]
+name = "wasm-streams"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
+dependencies = [
+ "futures-util",
+ "js-sys",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
name = "wayland-backend"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5510,7 +6203,7 @@ dependencies = [
"parking_lot",
"profiling",
"raw-window-handle",
- "rustc-hash",
+ "rustc-hash 1.1.0",
"smallvec",
"thiserror 2.0.12",
"wgpu-hal",
@@ -5550,7 +6243,7 @@ dependencies = [
"profiling",
"raw-window-handle",
"renderdoc-sys",
- "rustc-hash",
+ "rustc-hash 1.1.0",
"smallvec",
"thiserror 2.0.12",
"wasm-bindgen",
@@ -5632,8 +6325,8 @@ checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
dependencies = [
"windows-implement",
"windows-interface",
- "windows-result",
- "windows-strings",
+ "windows-result 0.2.0",
+ "windows-strings 0.1.0",
"windows-targets 0.52.6",
]
@@ -5660,6 +6353,23 @@ dependencies = [
]
[[package]]
+name = "windows-link"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+
+[[package]]
+name = "windows-registry"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
+dependencies = [
+ "windows-result 0.3.2",
+ "windows-strings 0.3.1",
+ "windows-targets 0.53.0",
+]
+
+[[package]]
name = "windows-result"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5669,16 +6379,34 @@ dependencies = [
]
[[package]]
+name = "windows-result"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
name = "windows-strings"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [
- "windows-result",
+ "windows-result 0.2.0",
"windows-targets 0.52.6",
]
[[package]]
+name = "windows-strings"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5753,7 +6481,7 @@ dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
- "windows_i686_gnullvm",
+ "windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
@@ -5761,6 +6489,22 @@ dependencies = [
]
[[package]]
+name = "windows-targets"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
+dependencies = [
+ "windows_aarch64_gnullvm 0.53.0",
+ "windows_aarch64_msvc 0.53.0",
+ "windows_i686_gnu 0.53.0",
+ "windows_i686_gnullvm 0.53.0",
+ "windows_i686_msvc 0.53.0",
+ "windows_x86_64_gnu 0.53.0",
+ "windows_x86_64_gnullvm 0.53.0",
+ "windows_x86_64_msvc 0.53.0",
+]
+
+[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5779,6 +6523,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+
+[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5797,6 +6547,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+
+[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5815,12 +6571,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
+name = "windows_i686_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+
+[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
+name = "windows_i686_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+
+[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5839,6 +6607,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
+name = "windows_i686_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+
+[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5857,6 +6631,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+
+[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5875,6 +6655,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+
+[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5893,6 +6679,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+
+[[package]]
name = "winit"
version = "0.30.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
@@ -5,8 +5,9 @@ members = [
"crates/notedeck",
"crates/notedeck_chrome",
"crates/notedeck_columns",
+ "crates/notedeck_dave",
- "crates/enostr", "crates/tokenator",
+ "crates/enostr", "crates/tokenator", "crates/notedeck_dave",
]
[workspace.dependencies]
@@ -18,6 +19,7 @@ bitflags = "2.5.0"
dirs = "5.0.1"
eframe = { version = "0.31.1", default-features = false, features = [ "wgpu", "wayland", "x11", "android-game-activity" ] }
egui = { version = "0.31.1", features = ["serde"] }
+egui-wgpu = "0.31.1"
egui_extras = { version = "0.31.1", features = ["all_loaders"] }
egui-winit = { version = "0.31.1", features = ["android-game-activity", "clipboard"] }
egui_nav = { git = "https://github.com/damus-io/egui-nav", rev = "5e816ac95e20f31dbb243a0d76179eab329a8ac0" }
@@ -39,6 +41,7 @@ nostrdb = { git = "https://github.com/damus-io/nostrdb-rs", rev = "7a6af440c12e7
notedeck = { path = "crates/notedeck" }
notedeck_chrome = { path = "crates/notedeck_chrome" }
notedeck_columns = { path = "crates/notedeck_columns" }
+notedeck_dave = { path = "crates/notedeck_dave" }
tokenator = { path = "crates/tokenator" }
open = "5.3.0"
poll-promise = { version = "0.3.0", features = ["tokio"] }
@@ -67,6 +70,7 @@ profiling = "1.0"
lightning-invoice = "0.33.1"
secp256k1 = "0.30.0"
hashbrown = "0.15.2"
+openai-api-rs = "6.0.3"
[profile.small]
inherits = 'release'
@@ -87,6 +91,7 @@ strip = true # Strip symbols from binary*
egui = { git = "https://github.com/damus-io/egui", rev = "93cd1cedc1e8eed2b055e317226838e37a845aad" }
eframe = { git = "https://github.com/damus-io/egui", rev = "93cd1cedc1e8eed2b055e317226838e37a845aad" }
egui-winit = { git = "https://github.com/damus-io/egui", rev = "93cd1cedc1e8eed2b055e317226838e37a845aad" }
+egui-wgpu = { git = "https://github.com/damus-io/egui", rev = "93cd1cedc1e8eed2b055e317226838e37a845aad" }
egui_extras = { git = "https://github.com/damus-io/egui", rev = "93cd1cedc1e8eed2b055e317226838e37a845aad" }
epaint = { git = "https://github.com/damus-io/egui", rev = "93cd1cedc1e8eed2b055e317226838e37a845aad" }
puffin = { git = "https://github.com/jb55/puffin", package = "puffin", rev = "c6a6242adaf90b6292c0f462d2acd34d96d224d2" }
diff --git a/crates/notedeck_chrome/Cargo.toml b/crates/notedeck_chrome/Cargo.toml
@@ -13,6 +13,7 @@ eframe = { workspace = true }
egui_extras = { workspace = true }
egui = { workspace = true }
notedeck_columns = { workspace = true }
+notedeck_dave = { workspace = true }
notedeck = { workspace = true }
puffin = { workspace = true, optional = true }
puffin_egui = { workspace = true, optional = true }
diff --git a/crates/notedeck_chrome/src/notedeck.rs b/crates/notedeck_chrome/src/notedeck.rs
@@ -4,6 +4,7 @@ use notedeck_chrome::setup::{generate_native_options, setup_chrome};
use notedeck::{DataPath, DataPathType, Notedeck};
use notedeck_columns::Damus;
+use notedeck_dave::Dave;
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::EnvFilter;
@@ -11,6 +12,38 @@ use tracing_subscriber::EnvFilter;
//#[cfg(target_arch = "wasm32")]
//use wasm_bindgen::prelude::*;
+struct Chrome {
+ active: i32,
+ apps: Vec<Box<dyn notedeck::App>>,
+}
+
+impl Chrome {
+ pub fn new() -> Self {
+ Chrome {
+ active: 0,
+ apps: vec![],
+ }
+ }
+
+ pub fn add_app(&mut self, app: impl notedeck::App + 'static) {
+ self.apps.push(Box::new(app));
+ }
+
+ pub fn set_active(&mut self, app: i32) {
+ self.active = app;
+ }
+}
+
+impl notedeck::App for Chrome {
+ fn update(&mut self, ctx: &mut notedeck::AppContext, ui: &mut egui::Ui) {
+ let active = self.active;
+ self.apps[active as usize].update(ctx, ui);
+ //for i in 0..self.apps.len() {
+ // self.apps[i].update(ctx, ui);
+ //}
+ }
+}
+
fn setup_logging(path: &DataPath) -> Option<WorkerGuard> {
#[allow(unused_variables)] // need guard to live for lifetime of program
let (maybe_non_blocking, maybe_guard) = {
@@ -78,15 +111,19 @@ async fn main() {
Box::new(|cc| {
let args: Vec<String> = std::env::args().collect();
let ctx = &cc.egui_ctx;
+
let mut notedeck = Notedeck::new(ctx, base_path, &args);
- setup_chrome(ctx, notedeck.args(), notedeck.theme());
- let damus = Damus::new(&mut notedeck.app_context(), &args);
+ let mut chrome = Chrome::new();
+ let columns = Damus::new(&mut notedeck.app_context(), &args);
+ let dave = Dave::new(cc.wgpu_render_state.as_ref());
+
+ setup_chrome(ctx, notedeck.args(), notedeck.theme());
// ensure we recognized all the arguments
let completely_unrecognized: Vec<String> = notedeck
.unrecognized_args()
- .intersection(damus.unrecognized_args())
+ .intersection(columns.unrecognized_args())
.cloned()
.collect();
assert!(
@@ -95,8 +132,13 @@ async fn main() {
completely_unrecognized
);
- // TODO: move "chrome" frame over Damus app somehow
- notedeck.set_app(damus);
+ chrome.add_app(columns);
+ chrome.add_app(dave);
+
+ // test dav
+ chrome.set_active(1);
+
+ notedeck.set_app(chrome);
Ok(Box::new(notedeck))
}),
diff --git a/crates/notedeck_chrome/src/setup.rs b/crates/notedeck_chrome/src/setup.rs
@@ -65,6 +65,8 @@ pub fn generate_native_options(paths: DataPath) -> NativeOptions {
});
eframe::NativeOptions {
+ // for 3d widgets
+ depth_buffer: 24,
window_builder: Some(window_builder),
viewport: egui::ViewportBuilder::default().with_icon(std::sync::Arc::new(
eframe::icon_data::from_png_bytes(app_icon()).expect("icon"),
@@ -80,6 +82,8 @@ fn generate_native_options_with_builder_modifiers(
Box::new(move |builder: egui::ViewportBuilder| apply_builder_modifiers(builder));
eframe::NativeOptions {
+ // for 3d widgets
+ depth_buffer: 24,
window_builder: Some(window_builder),
..Default::default()
}
diff --git a/crates/notedeck_dave/Cargo.toml b/crates/notedeck_dave/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "notedeck_dave"
+edition = "2021"
+version.workspace = true
+
+[dependencies]
+async-openai = "0.28.0"
+egui = { workspace = true }
+notedeck = { workspace = true }
+eframe = { workspace = true }
+tokio = { workspace = true }
+tracing = { workspace = true }
+egui-wgpu = { workspace = true }
+bytemuck = "1.22.0"
+futures = "0.3.31"
+reqwest = "0.12.15"
diff --git a/crates/notedeck_dave/shader.wgsl b/crates/notedeck_dave/shader.wgsl
@@ -0,0 +1,68 @@
+struct VertexOut {
+ @location(0) color: vec4<f32>,
+ @builtin(position) position: vec4<f32>,
+};
+
+struct Uniforms {
+ @size(16) angle: f32, // pad to 16 bytes
+};
+
+@group(0) @binding(0)
+var<uniform> uniforms: Uniforms;
+
+@vertex
+fn vs_main(@builtin(vertex_index) v_idx: u32) -> VertexOut {
+ // Cube vertices hardcoded in the shader
+ var positions = array<vec3<f32>, 8>(
+ vec3<f32>(-0.5, -0.5, 0.5), // front bottom left
+ vec3<f32>(0.5, -0.5, 0.5), // front bottom right
+ vec3<f32>(0.5, 0.5, 0.5), // front top right
+ vec3<f32>(-0.5, 0.5, 0.5), // front top left
+ vec3<f32>(-0.5, -0.5, -0.5), // back bottom left
+ vec3<f32>(0.5, -0.5, -0.5), // back bottom right
+ vec3<f32>(0.5, 0.5, -0.5), // back top right
+ vec3<f32>(-0.5, 0.5, -0.5) // back top left
+ );
+
+ // Cube indices hardcoded in the shader
+ var indices = array<u32, 36>(
+ // front face
+ 0, 1, 2, 2, 3, 0,
+ // back face
+ 4, 5, 6, 6, 7, 4,
+ // right face
+ 1, 5, 6, 6, 2, 1,
+ // left face
+ 0, 4, 7, 7, 3, 0,
+ // top face
+ 3, 2, 6, 6, 7, 3,
+ // bottom face
+ 0, 1, 5, 5, 4, 0
+ );
+
+ var out: VertexOut;
+ var idx = indices[v_idx];
+ var pos = positions[idx];
+
+ // simple rotation around Y axis
+ var cosA = cos(uniforms.angle);
+ var sinA = sin(uniforms.angle);
+ var rotated_x = pos.x * cosA + pos.z * sinA;
+ var rotated_z = -pos.x * sinA + pos.z * cosA;
+
+ // With proper perspective transformation:
+ var z_pos = rotated_z - 2.0; // Move cube away from camera
+ var w = -z_pos; // Set w to -z for perspective division
+ out.position = vec4<f32>(rotated_x, pos.y, rotated_z, w);
+
+ // simple white shading based on position
+ var shade = 0.5 + 0.5 * (rotated_z + pos.y);
+ out.color = vec4<f32>(shade, shade, shade, 1.0);
+
+ return out;
+}
+
+@fragment
+fn fs_main(in: VertexOut) -> @location(0) vec4<f32> {
+ return in.color;
+}
diff --git a/crates/notedeck_dave/src/avatar.rs b/crates/notedeck_dave/src/avatar.rs
@@ -0,0 +1,416 @@
+use std::num::NonZeroU64;
+
+use eframe::egui_wgpu::{self, wgpu};
+use egui::{Rect, Response};
+
+pub struct DaveAvatar {
+ rotation: Quaternion,
+}
+
+// A simple quaternion implementation
+struct Quaternion {
+ x: f32,
+ y: f32,
+ z: f32,
+ w: f32,
+}
+
+impl Quaternion {
+ // Create identity quaternion
+ fn identity() -> Self {
+ Self {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ w: 1.0,
+ }
+ }
+
+ // Create from axis-angle representation
+ fn from_axis_angle(axis: [f32; 3], angle: f32) -> Self {
+ let half_angle = angle * 0.5;
+ let s = half_angle.sin();
+ Self {
+ x: axis[0] * s,
+ y: axis[1] * s,
+ z: axis[2] * s,
+ w: half_angle.cos(),
+ }
+ }
+
+ // Multiply two quaternions (combines rotations)
+ fn multiply(&self, other: &Self) -> Self {
+ Self {
+ x: self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y,
+ y: self.w * other.y - self.x * other.z + self.y * other.w + self.z * other.x,
+ z: self.w * other.z + self.x * other.y - self.y * other.x + self.z * other.w,
+ w: self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z,
+ }
+ }
+
+ // Convert quaternion to 4x4 matrix (for 3D transformation with homogeneous coordinates)
+ fn to_matrix4(&self) -> [f32; 16] {
+ // Normalize quaternion
+ let magnitude =
+ (self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w).sqrt();
+ let x = self.x / magnitude;
+ let y = self.y / magnitude;
+ let z = self.z / magnitude;
+ let w = self.w / magnitude;
+
+ let x2 = x * x;
+ let y2 = y * y;
+ let z2 = z * z;
+ let xy = x * y;
+ let xz = x * z;
+ let yz = y * z;
+ let wx = w * x;
+ let wy = w * y;
+ let wz = w * z;
+
+ // Row-major 3x3 rotation matrix components
+ let m00 = 1.0 - 2.0 * (y2 + z2);
+ let m01 = 2.0 * (xy - wz);
+ let m02 = 2.0 * (xz + wy);
+
+ let m10 = 2.0 * (xy + wz);
+ let m11 = 1.0 - 2.0 * (x2 + z2);
+ let m12 = 2.0 * (yz - wx);
+
+ let m20 = 2.0 * (xz - wy);
+ let m21 = 2.0 * (yz + wx);
+ let m22 = 1.0 - 2.0 * (x2 + y2);
+
+ // Convert 3x3 rotation matrix to 4x4 transformation matrix
+ // Note: This is column-major for WGPU
+ [
+ m00, m10, m20, 0.0, m01, m11, m21, 0.0, m02, m12, m22, 0.0, 0.0, 0.0, 0.0, 1.0,
+ ]
+ }
+}
+
+// Matrix utilities for perspective projection
+fn perspective_matrix(fovy_radians: f32, aspect: f32, near: f32, far: f32) -> [f32; 16] {
+ let f = 1.0 / (fovy_radians / 2.0).tan();
+ let nf = 1.0 / (near - far);
+
+ // Column-major for WGPU
+ [
+ f / aspect,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ f,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ (far + near) * nf,
+ -1.0,
+ 0.0,
+ 0.0,
+ 2.0 * far * near * nf,
+ 0.0,
+ ]
+}
+
+// Combine two 4x4 matrices (column-major)
+fn matrix_multiply(a: &[f32; 16], b: &[f32; 16]) -> [f32; 16] {
+ let mut result = [0.0; 16];
+
+ for row in 0..4 {
+ for col in 0..4 {
+ let mut sum = 0.0;
+ for i in 0..4 {
+ sum += a[row + i * 4] * b[i + col * 4];
+ }
+ result[row + col * 4] = sum;
+ }
+ }
+
+ result
+}
+
+impl DaveAvatar {
+ pub fn new(wgpu_render_state: &egui_wgpu::RenderState) -> Self {
+ let device = &wgpu_render_state.device;
+
+ // Create shader module with improved shader code
+ let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
+ label: Some("cube_shader"),
+ source: wgpu::ShaderSource::Wgsl(
+ r#"
+struct Uniforms {
+ model_view_proj: mat4x4<f32>,
+};
+
+@group(0) @binding(0)
+var<uniform> uniforms: Uniforms;
+
+struct VertexOutput {
+ @builtin(position) position: vec4<f32>,
+ @location(0) color: vec4<f32>,
+};
+
+@vertex
+fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
+ // Define cube vertices (-0.5 to 0.5 in each dimension)
+ var positions = array<vec3<f32>, 8>(
+ vec3<f32>(-0.5, -0.5, -0.5), // 0: left bottom back
+ vec3<f32>(0.5, -0.5, -0.5), // 1: right bottom back
+ vec3<f32>(-0.5, 0.5, -0.5), // 2: left top back
+ vec3<f32>(0.5, 0.5, -0.5), // 3: right top back
+ vec3<f32>(-0.5, -0.5, 0.5), // 4: left bottom front
+ vec3<f32>(0.5, -0.5, 0.5), // 5: right bottom front
+ vec3<f32>(-0.5, 0.5, 0.5), // 6: left top front
+ vec3<f32>(0.5, 0.5, 0.5) // 7: right top front
+ );
+
+ // Define indices for the 12 triangles (6 faces * 2 triangles)
+ var indices = array<u32, 36>(
+ // back face (Z-)
+ 0, 2, 1, 1, 2, 3,
+ // front face (Z+)
+ 4, 5, 6, 5, 7, 6,
+ // left face (X-)
+ 0, 4, 2, 2, 4, 6,
+ // right face (X+)
+ 1, 3, 5, 3, 7, 5,
+ // bottom face (Y-)
+ 0, 1, 4, 1, 5, 4,
+ // top face (Y+)
+ 2, 6, 3, 3, 6, 7
+ );
+
+ // Define colors for each face
+ var face_colors = array<vec4<f32>, 6>(
+ vec4<f32>(1.0, 0.0, 0.0, 1.0), // back: red
+ vec4<f32>(0.0, 1.0, 0.0, 1.0), // front: green
+ vec4<f32>(0.0, 0.0, 1.0, 1.0), // left: blue
+ vec4<f32>(1.0, 1.0, 0.0, 1.0), // right: yellow
+ vec4<f32>(1.0, 0.0, 1.0, 1.0), // bottom: magenta
+ vec4<f32>(0.0, 1.0, 1.0, 1.0) // top: cyan
+ );
+
+ var output: VertexOutput;
+
+ // Get vertex from indices
+ let index = indices[vertex_index];
+ let position = positions[index];
+
+ // Determine which face this vertex belongs to
+ let face_index = vertex_index / 6u;
+
+ // Apply model-view-projection matrix
+ output.position = uniforms.model_view_proj * vec4<f32>(position, 1.0);
+
+ // Set color based on face
+ output.color = face_colors[face_index];
+
+ return output;
+}
+
+@fragment
+fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
+ return in.color;
+}
+"#
+ .into(),
+ ),
+ });
+
+ // Create uniform buffer for MVP matrix
+ let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
+ label: Some("cube_uniform_buffer"),
+ size: 64, // 4x4 matrix of f32 (16 * 4 bytes)
+ usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
+ mapped_at_creation: false,
+ });
+
+ // Create bind group layout
+ let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
+ label: Some("cube_bind_group_layout"),
+ entries: &[wgpu::BindGroupLayoutEntry {
+ binding: 0,
+ visibility: wgpu::ShaderStages::VERTEX,
+ ty: wgpu::BindingType::Buffer {
+ ty: wgpu::BufferBindingType::Uniform,
+ has_dynamic_offset: false,
+ min_binding_size: NonZeroU64::new(64),
+ },
+ count: None,
+ }],
+ });
+
+ // Create bind group
+ let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
+ label: Some("cube_bind_group"),
+ layout: &bind_group_layout,
+ entries: &[wgpu::BindGroupEntry {
+ binding: 0,
+ resource: uniform_buffer.as_entire_binding(),
+ }],
+ });
+
+ // Create pipeline layout
+ let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
+ label: Some("cube_pipeline_layout"),
+ bind_group_layouts: &[&bind_group_layout],
+ push_constant_ranges: &[],
+ });
+
+ // Create render pipeline
+ let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
+ label: Some("cube_pipeline"),
+ layout: Some(&pipeline_layout),
+ vertex: wgpu::VertexState {
+ module: &shader,
+ entry_point: Some("vs_main"),
+ buffers: &[], // No vertex buffer - vertices are in the shader
+ compilation_options: wgpu::PipelineCompilationOptions::default(),
+ },
+ fragment: Some(wgpu::FragmentState {
+ module: &shader,
+ entry_point: Some("fs_main"),
+ targets: &[Some(wgpu::ColorTargetState {
+ format: wgpu_render_state.target_format,
+ blend: Some(wgpu::BlendState::ALPHA_BLENDING),
+ write_mask: wgpu::ColorWrites::ALL,
+ })],
+ compilation_options: wgpu::PipelineCompilationOptions::default(),
+ }),
+ primitive: wgpu::PrimitiveState {
+ topology: wgpu::PrimitiveTopology::TriangleList,
+ strip_index_format: None,
+ front_face: wgpu::FrontFace::Ccw,
+ cull_mode: Some(wgpu::Face::Back),
+ polygon_mode: wgpu::PolygonMode::Fill,
+ unclipped_depth: false,
+ conservative: false,
+ },
+ depth_stencil: Some(wgpu::DepthStencilState {
+ format: wgpu::TextureFormat::Depth24Plus,
+ depth_write_enabled: true,
+ depth_compare: wgpu::CompareFunction::Less,
+ stencil: wgpu::StencilState::default(),
+ bias: wgpu::DepthBiasState::default(),
+ }),
+ multisample: wgpu::MultisampleState::default(),
+ multiview: None,
+ cache: None,
+ });
+
+ // Store resources in renderer
+ wgpu_render_state
+ .renderer
+ .write()
+ .callback_resources
+ .insert(CubeRenderResources {
+ pipeline,
+ bind_group,
+ uniform_buffer,
+ });
+
+ Self {
+ rotation: Quaternion::identity(),
+ }
+ }
+}
+
+impl DaveAvatar {
+ pub fn render(&mut self, rect: Rect, ui: &mut egui::Ui) -> Response {
+ let response = ui.allocate_rect(rect, egui::Sense::drag());
+
+ // Update rotation based on drag or animation
+ if response.dragged() {
+ // Create rotation quaternions based on drag
+ let x_rotation =
+ Quaternion::from_axis_angle([1.0, 0.0, 0.0], response.drag_delta().y * 0.01);
+ let y_rotation =
+ Quaternion::from_axis_angle([0.0, 1.0, 0.0], response.drag_delta().x * 0.01);
+
+ // Apply rotations (order matters)
+ self.rotation = y_rotation.multiply(&x_rotation).multiply(&self.rotation);
+ } else {
+ // Continuous rotation - reduced speed and simplified axis
+ let continuous_rotation = Quaternion::from_axis_angle([0.0, 1.0, 0.0], 0.005);
+ self.rotation = continuous_rotation.multiply(&self.rotation);
+ }
+
+ // Create model matrix from rotation quaternion
+ let model_matrix = self.rotation.to_matrix4();
+
+ // Create projection matrix with proper depth range
+ // Adjust aspect ratio based on rect dimensions
+ let aspect = rect.width() / rect.height();
+ let projection = perspective_matrix(std::f32::consts::PI / 4.0, aspect, 0.1, 100.0);
+
+ // Create view matrix (move camera back a bit)
+ let view_matrix = [
+ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -3.0, 1.0,
+ ];
+
+ // Combine matrices: projection * view * model
+ let mv_matrix = matrix_multiply(&view_matrix, &model_matrix);
+ let mvp_matrix = matrix_multiply(&projection, &mv_matrix);
+
+ // Request continuous rendering
+ ui.ctx().request_repaint();
+
+ // Add paint callback
+ ui.painter().add(egui_wgpu::Callback::new_paint_callback(
+ rect,
+ CubeCallback { mvp_matrix },
+ ));
+
+ response
+ }
+}
+
+// Callback implementation
+struct CubeCallback {
+ mvp_matrix: [f32; 16], // Model-View-Projection matrix
+}
+
+impl egui_wgpu::CallbackTrait for CubeCallback {
+ fn prepare(
+ &self,
+ _device: &wgpu::Device,
+ queue: &wgpu::Queue,
+ _screen_descriptor: &egui_wgpu::ScreenDescriptor,
+ _egui_encoder: &mut wgpu::CommandEncoder,
+ resources: &mut egui_wgpu::CallbackResources,
+ ) -> Vec<wgpu::CommandBuffer> {
+ let resources: &CubeRenderResources = resources.get().unwrap();
+
+ // Update uniform buffer with MVP matrix
+ queue.write_buffer(
+ &resources.uniform_buffer,
+ 0,
+ bytemuck::cast_slice(&self.mvp_matrix),
+ );
+
+ Vec::new()
+ }
+
+ fn paint(
+ &self,
+ _info: egui::PaintCallbackInfo,
+ render_pass: &mut wgpu::RenderPass,
+ resources: &egui_wgpu::CallbackResources,
+ ) {
+ let resources: &CubeRenderResources = resources.get().unwrap();
+
+ render_pass.set_pipeline(&resources.pipeline);
+ render_pass.set_bind_group(0, &resources.bind_group, &[]);
+ render_pass.draw(0..36, 0..1); // 36 vertices for a cube (6 faces * 2 triangles * 3 vertices)
+ }
+}
+
+// Simple resources struct
+struct CubeRenderResources {
+ pipeline: wgpu::RenderPipeline,
+ bind_group: wgpu::BindGroup,
+ uniform_buffer: wgpu::Buffer,
+}
diff --git a/crates/notedeck_dave/src/lib.rs b/crates/notedeck_dave/src/lib.rs
@@ -0,0 +1,211 @@
+use async_openai::{
+ config::OpenAIConfig,
+ types::{
+ ChatCompletionRequestAssistantMessage, ChatCompletionRequestAssistantMessageContent,
+ ChatCompletionRequestMessage, ChatCompletionRequestUserMessage,
+ ChatCompletionRequestUserMessageContent, CreateChatCompletionRequest,
+ },
+ Client,
+};
+use futures::StreamExt;
+use notedeck::AppContext;
+use std::sync::mpsc::{self, Receiver};
+
+use avatar::DaveAvatar;
+use egui::{Rect, Vec2};
+use egui_wgpu::RenderState;
+
+mod avatar;
+
+#[derive(Debug, Clone)]
+pub enum Message {
+ User(String),
+ Assistant(String),
+}
+
+impl Message {
+ pub fn to_api_msg(&self) -> ChatCompletionRequestMessage {
+ match self {
+ Message::User(msg) => {
+ ChatCompletionRequestMessage::User(ChatCompletionRequestUserMessage {
+ name: None,
+ content: ChatCompletionRequestUserMessageContent::Text(msg.clone()),
+ })
+ }
+
+ Message::Assistant(msg) => {
+ ChatCompletionRequestMessage::Assistant(ChatCompletionRequestAssistantMessage {
+ content: Some(ChatCompletionRequestAssistantMessageContent::Text(
+ msg.clone(),
+ )),
+ ..Default::default()
+ })
+ }
+ }
+ }
+}
+
+pub struct Dave {
+ chat: Vec<Message>,
+ /// A 3d representation of dave.
+ avatar: Option<DaveAvatar>,
+ input: String,
+ pubkey: String,
+ client: async_openai::Client<OpenAIConfig>,
+ incoming_tokens: Option<Receiver<String>>,
+}
+
+impl Dave {
+ pub fn new(render_state: Option<&RenderState>) -> Self {
+ let mut config = OpenAIConfig::new();
+ if let Ok(api_key) = std::env::var("OPENAI_API_KEY") {
+ config = config.with_api_key(api_key);
+ }
+ let client = Client::with_config(config);
+
+ let input = "".to_string();
+ let pubkey = "test_pubkey".to_string();
+ let avatar = render_state.map(DaveAvatar::new);
+
+ Dave {
+ client,
+ pubkey,
+ avatar,
+ incoming_tokens: None,
+ input,
+ chat: vec![
+ Message::User("how do I computer".to_string()),
+ Message::Assistant("Seriously?".to_string()),
+ Message::User("ye".to_string()),
+ ],
+ }
+ }
+
+ fn render(&mut self, ui: &mut egui::Ui) {
+ if let Some(recvr) = &self.incoming_tokens {
+ if let Ok(token) = recvr.try_recv() {
+ match self.chat.last_mut() {
+ Some(Message::Assistant(msg)) => *msg = msg.clone() + " " + &token,
+ Some(_) => self.chat.push(Message::Assistant(token)),
+ None => {}
+ }
+ }
+ }
+
+ // Scroll area for chat messages
+ egui::Frame::new().inner_margin(10.0).show(ui, |ui| {
+ egui::ScrollArea::vertical()
+ .stick_to_bottom(true)
+ .auto_shrink([false; 2])
+ .show(ui, |ui| {
+ ui.vertical(|ui| {
+ self.render_chat(ui);
+
+ self.inputbox(ui);
+ })
+ });
+ });
+
+ if let Some(avatar) = &mut self.avatar {
+ let avatar_size = Vec2::splat(400.0);
+ let pos = Vec2::splat(100.0).to_pos2();
+ let pos = Rect::from_min_max(pos, pos + avatar_size);
+ avatar.render(pos, ui);
+ }
+ }
+
+ fn render_chat(&self, ui: &mut egui::Ui) {
+ for message in &self.chat {
+ match message {
+ Message::User(msg) => self.user_chat(msg, ui),
+ Message::Assistant(msg) => self.system_chat(msg, ui),
+ }
+ }
+ }
+
+ fn inputbox(&mut self, ui: &mut egui::Ui) {
+ ui.horizontal(|ui| {
+ ui.add(egui::TextEdit::multiline(&mut self.input));
+ if ui.button("Sned").clicked() {
+ self.send_user_message(ui.ctx());
+ self.input.clear();
+ }
+ });
+ }
+
+ fn user_chat(&self, msg: &str, ui: &mut egui::Ui) {
+ ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
+ ui.label(msg);
+ });
+ }
+
+ fn system_chat(&self, msg: &str, ui: &mut egui::Ui) {
+ ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {
+ ui.label(msg);
+ });
+ }
+
+ fn send_user_message(&mut self, ctx: &egui::Context) {
+ let messages = self.chat.iter().map(|c| c.to_api_msg()).collect();
+ let pubkey = self.pubkey.clone();
+ let (tx, rx) = mpsc::channel();
+ self.incoming_tokens = Some(rx);
+ let ctx = ctx.clone();
+ let client = self.client.clone();
+ tokio::spawn(async move {
+ let mut token_stream = match client
+ .chat()
+ .create_stream(CreateChatCompletionRequest {
+ model: "gpt-4o".to_string(),
+ stream: Some(true),
+ messages,
+ user: Some(pubkey),
+ ..Default::default()
+ })
+ .await
+ {
+ Err(err) => {
+ tracing::error!("openai chat error: {err}");
+ return;
+ }
+
+ Ok(stream) => stream,
+ };
+
+ tracing::info!("got stream!");
+
+ while let Some(token) = token_stream.next().await {
+ let token = match token {
+ Ok(token) => token,
+ Err(err) => {
+ tracing::error!("failed to get token: {err}");
+ return;
+ }
+ };
+ let Some(choice) = token.choices.first() else {
+ return;
+ };
+ let Some(content) = &choice.delta.content else {
+ return;
+ };
+ tracing::debug!("got token: {content}");
+
+ tx.send(content.to_owned()).unwrap();
+ ctx.request_repaint();
+ }
+ });
+ }
+}
+
+impl notedeck::App for Dave {
+ fn update(&mut self, _ctx: &mut AppContext<'_>, ui: &mut egui::Ui) {
+ /*
+ self.app
+ .frame_history
+ .on_new_frame(ctx.input(|i| i.time), frame.info().cpu_usage);
+ */
+
+ //update_dave(self, ctx, ui.ctx());
+ self.render(ui);
+ }
+}