From 47af34cebd447eefb2c6232314b058d9d26425f2 Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Mon, 30 Dec 2024 14:01:08 +0100 Subject: [PATCH 1/9] feat(provider): add Google VertexAI support --- Cargo.lock | 1131 ++++++++++++++++++++++++++-- Cargo.toml | 4 + README.md | 97 +++ config-example.yaml | 10 + src/models/mod.rs | 1 + src/models/streaming.rs | 34 + src/models/vertexai.rs | 225 ++++++ src/providers/mod.rs | 1 + src/providers/registry.rs | 2 + src/providers/vertexai/mod.rs | 5 + src/providers/vertexai/provider.rs | 231 ++++++ src/providers/vertexai/tests.rs | 218 ++++++ 12 files changed, 1887 insertions(+), 72 deletions(-) create mode 100644 src/models/vertexai.rs create mode 100644 src/providers/vertexai/mod.rs create mode 100644 src/providers/vertexai/provider.rs create mode 100644 src/providers/vertexai/tests.rs diff --git a/Cargo.lock b/Cargo.lock index f5c2ea7..7b9ddf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,60 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher", +] + +[[package]] +name = "aes-gcm" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher", + "opaque-debug", +] + [[package]] name = "ahash" version = "0.8.11" @@ -65,6 +119,29 @@ version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-compression" version = "0.4.17" @@ -81,6 +158,90 @@ dependencies = [ "zstd-safe", ] +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.1.1", + "futures-lite 2.5.0", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite 2.5.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.5.0", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 2.5.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -100,9 +261,15 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.85", ] +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" version = "0.1.83" @@ -111,7 +278,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.85", ] [[package]] @@ -134,9 +301,9 @@ checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", - "bytes", + "bytes 1.8.0", "futures-util", - "http", + "http 1.1.0", "http-body", "http-body-util", "hyper", @@ -167,9 +334,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", - "bytes", + "bytes 1.8.0", "futures-util", - "http", + "http 1.1.0", "http-body", "http-body-util", "mime", @@ -189,9 +356,9 @@ checksum = "73c3220b188aea709cf1b6c5f9b01c3bd936bb08bd2b5184a12b35ac8131b1f9" dependencies = [ "axum", "axum-core", - "bytes", + "bytes 1.8.0", "futures-util", - "http", + "http 1.1.0", "http-body", "http-body-util", "mime", @@ -210,9 +377,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "739e2585f5376f5bdd129324ded72d3261fdd5b7c411a645920328fb5dc875d4" dependencies = [ "axum", - "bytes", + "bytes 1.8.0", "futures-core", - "http", + "http 1.1.0", "http-body", "matchit", "metrics", @@ -239,6 +406,18 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.22.1" @@ -251,6 +430,28 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel 2.3.1", + "async-task", + "futures-io", + "futures-lite 2.5.0", + "piper", +] + [[package]] name = "brotli" version = "7.0.0" @@ -284,6 +485,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + [[package]] name = "bytes" version = "1.8.0" @@ -333,6 +540,47 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const_fn" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" + +[[package]] +name = "cookie" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" +dependencies = [ + "aes-gcm", + "base64 0.13.1", + "hkdf", + "hmac", + "percent-encoding", + "rand 0.8.5", + "sha2", + "time", + "version_check", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -349,6 +597,21 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpufeatures" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +dependencies = [ + "libc", +] + +[[package]] +name = "cpuid-bool" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" + [[package]] name = "crc32fast" version = "1.4.2" @@ -373,6 +636,71 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crypto-mac" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +dependencies = [ + "cipher", +] + +[[package]] +name = "curl" +version = "0.4.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "curl-sys" +version = "0.4.78+curl-8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eec768341c5c7789611ae51cf6c459099f22e64a5d5d0ce4892434e33821eaf" +dependencies = [ + "cc", + "libc", + "libnghttp2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "windows-sys 0.52.0", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + [[package]] name = "either" version = "1.13.0" @@ -404,6 +732,42 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fastrand" version = "2.1.1" @@ -420,6 +784,17 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bebadab126f8120d410b677ed95eee4ba6eb7c6dd8e34a5ec88a08050e26132" +dependencies = [ + "futures-core", + "futures-sink", + "spinning_top", +] + [[package]] name = "fnv" version = "1.0.7" @@ -498,6 +873,34 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" +dependencies = [ + "fastrand 2.1.1", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.31" @@ -506,7 +909,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.85", ] [[package]] @@ -539,6 +942,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.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -547,7 +971,17 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "ghash" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +dependencies = [ + "opaque-debug", + "polyval", ] [[package]] @@ -562,6 +996,18 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "h2" version = "0.4.6" @@ -569,11 +1015,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", - "bytes", + "bytes 1.8.0", "fnv", "futures-core", "futures-sink", - "http", + "http 1.1.0", "indexmap 2.6.0", "slab", "tokio", @@ -618,13 +1064,50 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac", + "digest", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes 1.8.0", + "fnv", + "itoa", +] + [[package]] name = "http" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ - "bytes", + "bytes 1.8.0", "fnv", "itoa", ] @@ -635,8 +1118,8 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "bytes", - "http", + "bytes 1.8.0", + "http 1.1.0", ] [[package]] @@ -645,19 +1128,55 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ - "bytes", + "bytes 1.8.0", "futures-util", - "http", + "http 1.1.0", "http-body", "pin-project-lite", ] +[[package]] +name = "http-client" +version = "6.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1947510dc91e2bf586ea5ffb412caad7673264e14bb39fb9078da114a94ce1a5" +dependencies = [ + "async-std", + "async-trait", + "cfg-if", + "http-types", + "isahc", + "log", +] + [[package]] name = "http-range-header" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" +[[package]] +name = "http-types" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" +dependencies = [ + "anyhow", + "async-channel 1.9.0", + "async-std", + "base64 0.13.1", + "cookie", + "futures-lite 1.13.0", + "infer", + "pin-project-lite", + "rand 0.7.3", + "serde", + "serde_json", + "serde_qs", + "serde_urlencoded", + "url", +] + [[package]] name = "httparse" version = "1.9.5" @@ -689,7 +1208,9 @@ dependencies = [ "reqwest-streams", "serde", "serde_json", - "serde_yaml", + "serde_yaml 0.9.34+deprecated", + "surf", + "surf-vcr", "tokio", "tower 0.5.1", "tower-http 0.6.1", @@ -704,11 +1225,11 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ - "bytes", + "bytes 1.8.0", "futures-channel", "futures-util", "h2", - "http", + "http 1.1.0", "http-body", "httparse", "httpdate", @@ -726,7 +1247,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http", + "http 1.1.0", "hyper", "hyper-util", "rustls", @@ -756,7 +1277,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ - "bytes", + "bytes 1.8.0", "http-body-util", "hyper", "hyper-util", @@ -772,10 +1293,10 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ - "bytes", + "bytes 1.8.0", "futures-channel", "futures-util", - "http", + "http 1.1.0", "http-body", "hyper", "pin-project-lite", @@ -838,6 +1359,21 @@ dependencies = [ "hashbrown 0.15.0", ] +[[package]] +name = "infer" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + [[package]] name = "ipnet" version = "2.10.1" @@ -854,6 +1390,29 @@ dependencies = [ "serde", ] +[[package]] +name = "isahc" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2948a0ce43e2c2ef11d7edf6816508998d99e13badd1150be0914205df9388a" +dependencies = [ + "bytes 0.5.6", + "crossbeam-utils", + "curl", + "curl-sys", + "flume", + "futures-lite 1.13.0", + "http 0.2.12", + "log", + "once_cell", + "slab", + "sluice", + "tracing", + "tracing-futures", + "url", + "waker-fn", +] + [[package]] name = "itertools" version = "0.13.0" @@ -887,6 +1446,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -897,7 +1465,35 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" name = "libc" version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "libnghttp2-sys" +version = "0.1.10+1.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "959c25552127d2e1fa72f0e52548ec04fc386e827ba71a7bd01db46a447dc135" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libz-sys" +version = "1.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" @@ -920,6 +1516,9 @@ name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +dependencies = [ + "value-bag", +] [[package]] name = "matchit" @@ -949,7 +1548,7 @@ version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4f0c8427b39666bf970460908b213ec09b3b350f20c0c2eabcbba51704a08e6" dependencies = [ - "base64", + "base64 0.22.1", "http-body-util", "hyper", "hyper-util", @@ -1009,9 +1608,9 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -1057,7 +1656,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] @@ -1076,6 +1675,12 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "openssl" version = "0.10.68" @@ -1099,7 +1704,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.85", ] [[package]] @@ -1141,8 +1746,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10a8a7f5f6ba7c1b286c2fbca0454eaba116f63bbe69ed250b642d36fbb04d80" dependencies = [ "async-trait", - "bytes", - "http", + "bytes 1.8.0", + "http 1.1.0", "opentelemetry", "reqwest", ] @@ -1155,7 +1760,7 @@ checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76" dependencies = [ "async-trait", "futures-core", - "http", + "http 1.1.0", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", @@ -1200,7 +1805,7 @@ dependencies = [ "once_cell", "opentelemetry", "percent-encoding", - "rand", + "rand 0.8.5", "serde_json", "thiserror", "tokio", @@ -1213,6 +1818,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.3" @@ -1259,7 +1870,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.85", ] [[package]] @@ -1274,12 +1885,49 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand 2.1.1", + "futures-io", +] + [[package]] name = "pkg-config" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "polyval" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" +dependencies = [ + "cpuid-bool", + "opaque-debug", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.9.0" @@ -1295,6 +1943,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro2" version = "1.0.89" @@ -1310,7 +1964,7 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ - "bytes", + "bytes 1.8.0", "prost-derive", ] @@ -1324,7 +1978,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn", + "syn 2.0.85", ] [[package]] @@ -1337,7 +1991,7 @@ dependencies = [ "libc", "once_cell", "raw-cpuid", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "web-sys", "winapi", ] @@ -1348,7 +2002,7 @@ version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ - "bytes", + "bytes 1.8.0", "pin-project-lite", "quinn-proto", "quinn-udp", @@ -1366,8 +2020,8 @@ version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ - "bytes", - "rand", + "bytes 1.8.0", + "rand 0.8.5", "ring", "rustc-hash", "rustls", @@ -1400,6 +2054,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + [[package]] name = "rand" version = "0.8.5" @@ -1407,8 +2074,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", ] [[package]] @@ -1418,7 +2095,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", ] [[package]] @@ -1427,7 +2113,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", ] [[package]] @@ -1454,14 +2149,14 @@ version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ - "base64", - "bytes", + "base64 0.22.1", + "bytes 1.8.0", "encoding_rs", "futures-channel", "futures-core", "futures-util", "h2", - "http", + "http 1.1.0", "http-body", "http-body-util", "hyper", @@ -1506,7 +2201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5500de9e7b5993e6e23c09c251eb59ad62011eff07df6b78c8d2191d5648420c" dependencies = [ "async-trait", - "bytes", + "bytes 1.8.0", "cargo-husky", "futures", "reqwest", @@ -1524,7 +2219,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -1543,6 +2238,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.37" @@ -1659,6 +2363,21 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.213" @@ -1676,7 +2395,7 @@ checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.85", ] [[package]] @@ -1701,6 +2420,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_qs" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1713,6 +2443,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +dependencies = [ + "indexmap 1.9.3", + "ryu", + "serde", + "yaml-rust", +] + [[package]] name = "serde_yaml" version = "0.9.34+deprecated" @@ -1726,6 +2468,34 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1765,6 +2535,17 @@ dependencies = [ "autocfg", ] +[[package]] +name = "sluice" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" +dependencies = [ + "async-channel 1.9.0", + "futures-core", + "futures-io", +] + [[package]] name = "smallvec" version = "1.13.2" @@ -1787,12 +2568,126 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spinning_top" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" +dependencies = [ + "lock_api", +] + +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + [[package]] name = "subtle" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "surf" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718b1ae6b50351982dedff021db0def601677f2120938b070eadb10ba4038dd7" +dependencies = [ + "async-std", + "async-trait", + "cfg-if", + "encoding_rs", + "futures-util", + "getrandom 0.2.15", + "http-client", + "http-types", + "log", + "mime_guess", + "once_cell", + "pin-project-lite", + "serde", + "serde_json", + "web-sys", +] + +[[package]] +name = "surf-vcr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7987a1833b88ef8b4adf15c5562167a9a9d3d17ebd871ec064ef1e6936bc3a" +dependencies = [ + "async-std", + "once_cell", + "serde", + "serde_yaml 0.8.26", + "surf", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.85" @@ -1847,7 +2742,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", - "fastrand", + "fastrand 2.1.1", "once_cell", "rustix", "windows-sys 0.59.0", @@ -1870,7 +2765,7 @@ checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.85", ] [[package]] @@ -1883,6 +2778,44 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros", + "version_check", + "winapi", +] + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn 1.0.109", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -1905,7 +2838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" dependencies = [ "backtrace", - "bytes", + "bytes 1.8.0", "libc", "mio", "parking_lot", @@ -1924,7 +2857,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.85", ] [[package]] @@ -1965,7 +2898,7 @@ version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ - "bytes", + "bytes 1.8.0", "futures-core", "futures-sink", "pin-project-lite", @@ -1981,10 +2914,10 @@ dependencies = [ "async-stream", "async-trait", "axum", - "base64", - "bytes", + "base64 0.22.1", + "bytes 1.8.0", "h2", - "http", + "http 1.1.0", "http-body", "http-body-util", "hyper", @@ -2013,7 +2946,7 @@ dependencies = [ "indexmap 1.9.3", "pin-project", "pin-project-lite", - "rand", + "rand 0.8.5", "slab", "tokio", "tokio-util", @@ -2049,8 +2982,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "bitflags", - "bytes", - "http", + "bytes 1.8.0", + "http 1.1.0", "http-body", "http-body-util", "pin-project-lite", @@ -2065,12 +2998,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" dependencies = [ "async-compression", - "base64", + "base64 0.22.1", "bitflags", - "bytes", + "bytes 1.8.0", "futures-core", "futures-util", - "http", + "http 1.1.0", "http-body", "http-body-util", "http-range-header", @@ -2121,7 +3054,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.85", ] [[package]] @@ -2134,6 +3067,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -2165,6 +3108,12 @@ 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 = "unicase" version = "2.8.0" @@ -2192,6 +3141,16 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "universal-hash" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -2213,6 +3172,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -2221,7 +3181,7 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -2230,6 +3190,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "value-bag" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" + [[package]] name = "vcpkg" version = "0.2.15" @@ -2242,6 +3208,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + [[package]] name = "want" version = "0.3.1" @@ -2251,6 +3223,12 @@ dependencies = [ "try-lock", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2279,7 +3257,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.85", "wasm-bindgen-shared", ] @@ -2313,7 +3291,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.85", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2490,6 +3468,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -2508,7 +3495,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.85", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 9784651..5b7424c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,3 +39,7 @@ axum-prometheus = "0.7.0" reqwest-streams = { version = "0.8.1", features = ["json"] } futures = "0.3.31" async-stream = "0.3.6" + +[dev-dependencies] +surf = "2.3.2" +surf-vcr = "0.2.0" diff --git a/README.md b/README.md index 445a7f6..cd863a6 100644 --- a/README.md +++ b/README.md @@ -99,3 +99,100 @@ Not sure where to get started? You can: - [GitHub Discussions](https://github.com/traceloop/hub/discussions) (For help with building and deeper conversations about features) - [GitHub Issues](https://github.com/traceloop/hub/issues) (For any bugs and errors you encounter using OpenLLMetry) - [Twitter](https://twitter.com/traceloopdev) (Get news fast) + +# Hub + +A unified API interface for routing LLM requests to various providers. + +## Supported Providers + +- OpenAI +- Anthropic +- Azure OpenAI +- Google VertexAI (Gemini) + +## Configuration + +See `config-example.yaml` for a complete configuration example. + +### Provider Configuration + +#### OpenAI + +```yaml +providers: + - key: openai + type: openai + api_key: "" +``` + +#### Azure OpenAI + +```yaml +providers: + - key: azure-openai + type: azure + api_key: "" + resource_name: "" + api_version: "" +``` + +#### Google VertexAI (Gemini) + +```yaml +providers: + - key: vertexai + type: vertexai + api_key: "" + project_id: "" + location: "" + credentials_path: "/path/to/service-account.json" # Optional +``` + +Authentication can be done in two ways: +1. API Key: Set the `api_key` field with your GCP API key +2. Service Account: Set the `credentials_path` field with the path to your service account JSON file. If not specified, the default GCP credentials will be used. + +### Model Configuration + +```yaml +models: + - key: gemini-pro + type: gemini-pro + provider: vertexai +``` + +### Pipeline Configuration + +```yaml +pipelines: + - name: default + type: chat + plugins: + - model-router: + models: + - gemini-pro +``` + +## Development + +### Running Tests + +The test suite uses `surf-vcr` to record and replay HTTP interactions, making tests reproducible without requiring actual API credentials. + +To run tests: +```bash +cargo test +``` + +To record new test cassettes: +1. Set up your API credentials in the environment +2. Delete the existing cassette files in `tests/cassettes/` +3. Run the tests with `VCR_MODE=record`: +```bash +VCR_MODE=record cargo test +``` + +## License + +See LICENSE file. diff --git a/config-example.yaml b/config-example.yaml index 6fc8b5d..6e8c91a 100644 --- a/config-example.yaml +++ b/config-example.yaml @@ -7,6 +7,12 @@ providers: - key: openai type: openai api_key: "" + - key: vertexai + type: vertexai + api_key: "" + project_id: "" + location: "" + credentials_path: "/path/to/service-account.json" # Optional, uses GCP default credentials if not specified models: - key: gpt-4o-openai @@ -16,6 +22,9 @@ models: type: gpt-4o provider: azure-openai deployment: "" + - key: gemini-pro + type: gemini-pro + provider: vertexai pipelines: - name: default @@ -30,3 +39,4 @@ pipelines: models: - gpt-4o-openai - gpt-4o-azure + - gemini-pro diff --git a/src/models/mod.rs b/src/models/mod.rs index 7b27896..c7d06a9 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -8,3 +8,4 @@ pub mod tool_calls; pub mod tool_choice; pub mod tool_definition; pub mod usage; +pub mod vertexai; diff --git a/src/models/streaming.rs b/src/models/streaming.rs index 62a3219..442766c 100644 --- a/src/models/streaming.rs +++ b/src/models/streaming.rs @@ -3,6 +3,15 @@ use serde::{Deserialize, Serialize}; use super::logprob::ChoiceLogprobs; use super::tool_calls::ChatMessageToolCall; use super::usage::Usage; +use crate::models::vertexai::GeminiChatResponse; + +#[derive(Deserialize, Serialize, Clone, Debug, Default)] +pub struct Delta { + pub role: Option, + pub content: Option, + pub function_call: Option, + pub tool_calls: Option>, +} #[derive(Deserialize, Serialize, Clone, Debug)] pub struct ChoiceDelta { @@ -37,3 +46,28 @@ pub struct ChatCompletionChunk { #[serde(skip_serializing_if = "Option::is_none")] pub usage: Option, } + +impl ChatCompletionChunk { + pub fn from_gemini(response: GeminiChatResponse, model: String) -> Self { + Self { + id: uuid::Uuid::new_v4().to_string(), + service_tier: None, + system_fingerprint: None, + created: chrono::Utc::now().timestamp() as i64, + model, + choices: vec![Choice { + index: 0, + logprobs: None, + delta: ChoiceDelta { + role: None, + content: response.candidates.first() + .map(|c| c.content.parts.first().map(|p| p.text.clone())) + .flatten(), + tool_calls: None, + }, + finish_reason: response.candidates.first().and_then(|c| c.finish_reason.clone()), + }], + usage: None, + } + } +} diff --git a/src/models/vertexai.rs b/src/models/vertexai.rs new file mode 100644 index 0000000..716833b --- /dev/null +++ b/src/models/vertexai.rs @@ -0,0 +1,225 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +use crate::models::chat::{ChatCompletion, ChatCompletionChoice, ChatCompletionRequest}; +use crate::models::content::{ChatCompletionMessage, ChatMessageContent}; +use crate::models::tool_calls::{ChatMessageToolCall, FunctionCall}; +use crate::models::tool_choice::{ToolChoice, SimpleToolChoice}; +use crate::models::usage::Usage; + +#[derive(Debug, Serialize, Deserialize)] +pub struct GeminiChatRequest { + pub contents: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub generation_config: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub safety_settings: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub tools: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_choice: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GeminiTool { + pub function_declarations: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GeminiFunctionDeclaration { + pub name: String, + pub description: Option, + pub parameters: Value, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum GeminiToolChoice { + None, + Auto, + Function(GeminiFunctionChoice), +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GeminiFunctionChoice { + pub name: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GeminiContent { + pub role: String, + pub parts: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ContentPart { + pub text: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GenerationConfig { + #[serde(skip_serializing_if = "Option::is_none")] + pub temperature: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub top_p: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub top_k: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub max_output_tokens: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub stop_sequences: Option>, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SafetySetting { + pub category: String, + pub threshold: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GeminiChatResponse { + pub candidates: Vec, + pub usage_metadata: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GeminiCandidate { + pub content: GeminiContent, + pub finish_reason: Option, + pub safety_ratings: Option>, + pub tool_calls: Option>, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GeminiToolCall { + pub function: GeminiFunctionCall, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GeminiFunctionCall { + pub name: String, + pub arguments: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SafetyRating { + pub category: String, + pub probability: String, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct UsageMetadata { + pub prompt_token_count: i32, + pub candidates_token_count: i32, + pub total_token_count: i32, +} + +impl GeminiChatRequest { + pub fn from_openai(req: ChatCompletionRequest) -> Self { + let contents = req.messages.into_iter().map(|msg| GeminiContent { + role: match msg.role.as_str() { + "assistant" => "model".to_string(), + role => role.to_string(), + }, + parts: vec![ContentPart { + text: match msg.content { + Some(content) => match content { + ChatMessageContent::String(text) => text, + ChatMessageContent::Array(parts) => parts.into_iter().map(|p| p.text).collect::>().join(" "), + }, + None => String::new(), + }, + }], + }).collect(); + + let generation_config = Some(GenerationConfig { + temperature: req.temperature, + top_p: req.top_p, + top_k: None, + max_output_tokens: req.max_tokens, + stop_sequences: req.stop, + }); + + let tools = req.tools.map(|tools| { + vec![GeminiTool { + function_declarations: tools.into_iter().map(|tool| { + GeminiFunctionDeclaration { + name: tool.function.name, + description: tool.function.description, + parameters: serde_json::to_value(tool.function.parameters).unwrap_or_default(), + } + }).collect(), + }] + }); + + let tool_choice = req.tool_choice.map(|choice| match choice { + ToolChoice::Simple(SimpleToolChoice::None) => GeminiToolChoice::None, + ToolChoice::Simple(SimpleToolChoice::Auto) => GeminiToolChoice::Auto, + ToolChoice::Named(named) => GeminiToolChoice::Function(GeminiFunctionChoice { + name: named.function.name, + }), + _ => GeminiToolChoice::None, + }); + + Self { + contents, + generation_config, + safety_settings: None, + tools, + tool_choice, + } + } +} + +impl GeminiChatResponse { + pub fn to_openai(self, model: String) -> ChatCompletion { + let choices = self.candidates.into_iter().enumerate().map(|(i, candidate)| { + ChatCompletionChoice { + index: i as u32, + message: ChatCompletionMessage { + role: "assistant".to_string(), + content: Some(ChatMessageContent::String( + candidate.content.parts.into_iter().map(|p| p.text).collect::>().join("") + )), + name: None, + tool_calls: candidate.tool_calls.map(|calls| { + calls.into_iter().map(|call| ChatMessageToolCall { + id: format!("call_{}", uuid::Uuid::new_v4()), + r#type: "function".to_string(), + function: FunctionCall { + name: call.function.name, + arguments: call.function.arguments, + } + }).collect() + }), + }, + finish_reason: candidate.finish_reason, + logprobs: None, + } + }).collect(); + + let usage = self.usage_metadata.map_or(Usage { + prompt_tokens: 0, + completion_tokens: 0, + total_tokens: 0, + prompt_tokens_details: None, + completion_tokens_details: None, + }, |m| Usage { + prompt_tokens: m.prompt_token_count as u32, + completion_tokens: m.candidates_token_count as u32, + total_tokens: m.total_token_count as u32, + prompt_tokens_details: None, + completion_tokens_details: None, + }); + + ChatCompletion { + id: format!("chatcmpl-{}", uuid::Uuid::new_v4()), + object: Some("chat.completion".to_string()), + created: Some(chrono::Utc::now().timestamp() as u64), + model, + choices, + usage, + system_fingerprint: None, + } + } +} \ No newline at end of file diff --git a/src/providers/mod.rs b/src/providers/mod.rs index 6a6ece1..71b57b2 100644 --- a/src/providers/mod.rs +++ b/src/providers/mod.rs @@ -3,3 +3,4 @@ pub mod azure; pub mod openai; pub mod provider; pub mod registry; +pub mod vertexai; diff --git a/src/providers/registry.rs b/src/providers/registry.rs index 9e5663f..86fef80 100644 --- a/src/providers/registry.rs +++ b/src/providers/registry.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use crate::config::models::Provider as ProviderConfig; use crate::providers::{ anthropic::AnthropicProvider, azure::AzureProvider, openai::OpenAIProvider, provider::Provider, + vertexai::VertexAIProvider, }; pub struct ProviderRegistry { @@ -20,6 +21,7 @@ impl ProviderRegistry { "openai" => Arc::new(OpenAIProvider::new(config)), "anthropic" => Arc::new(AnthropicProvider::new(config)), "azure" => Arc::new(AzureProvider::new(config)), + "vertexai" => Arc::new(VertexAIProvider::new(config)), _ => continue, }; providers.insert(config.key.clone(), provider); diff --git a/src/providers/vertexai/mod.rs b/src/providers/vertexai/mod.rs new file mode 100644 index 0000000..beaee35 --- /dev/null +++ b/src/providers/vertexai/mod.rs @@ -0,0 +1,5 @@ +pub mod provider; +#[cfg(test)] +mod tests; + +pub use provider::VertexAIProvider; \ No newline at end of file diff --git a/src/providers/vertexai/provider.rs b/src/providers/vertexai/provider.rs new file mode 100644 index 0000000..03d64f0 --- /dev/null +++ b/src/providers/vertexai/provider.rs @@ -0,0 +1,231 @@ +use crate::config::constants::stream_buffer_size_bytes; +use crate::config::models::{ModelConfig, Provider as ProviderConfig}; +use crate::models::chat::{ChatCompletionRequest, ChatCompletionResponse}; +use crate::models::completion::{CompletionRequest, CompletionResponse, CompletionChoice}; +use crate::models::content::{ChatCompletionMessage, ChatMessageContent}; +use crate::models::embeddings::{EmbeddingsRequest, EmbeddingsResponse, Embeddings}; +use crate::models::streaming::ChatCompletionChunk; +use crate::models::vertexai::{GeminiChatRequest, GeminiChatResponse}; +use crate::providers::provider::Provider; +use axum::async_trait; +use axum::http::StatusCode; +use futures::StreamExt; +use reqwest::Client; +use reqwest_streams::*; +use serde_json::json; +use crate::models::usage::Usage; + +pub struct VertexAIProvider { + config: ProviderConfig, + http_client: Client, + project_id: String, + location: String, +} + +#[async_trait] +impl Provider for VertexAIProvider { + fn new(config: &ProviderConfig) -> Self { + let project_id = config.params.get("project_id").map_or_else(|| "test-project".to_string(), |v| v.to_string()); + let location = config.params.get("location").map_or_else(|| "us-central1".to_string(), |v| v.to_string()); + + Self { + config: config.clone(), + http_client: Client::new(), + project_id, + location, + } + } + + fn key(&self) -> String { + self.config.key.clone() + } + + fn r#type(&self) -> String { + "vertexai".to_string() + } + + async fn chat_completions( + &self, + payload: ChatCompletionRequest, + _model_config: &ModelConfig, + ) -> Result { + // Convert OpenAI format to Gemini format + let gemini_request = GeminiChatRequest::from_openai(payload.clone()); + + let endpoint = format!( + "https://{}-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:streamGenerateContent", + self.location, self.project_id, self.location, payload.model + ); + + let response = self + .http_client + .post(&endpoint) + .bearer_auth(&self.config.api_key) + .json(&gemini_request) + .send() + .await + .map_err(|e| { + eprintln!("VertexAI API request error: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + let status = response.status(); + if status.is_success() { + if payload.stream.unwrap_or(false) { + let stream = Box::pin(response.json_array_stream::(stream_buffer_size_bytes()) + .map(move |chunk| { + chunk.map(|c| ChatCompletionChunk::from_gemini(c, payload.model.clone())) + .map_err(|e| { + eprintln!("Error parsing Gemini response: {}", e); + e + }) + })); + Ok(ChatCompletionResponse::Stream(stream)) + } else { + let gemini_response = response.json::().await.map_err(|e| { + eprintln!("VertexAI API response error: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + Ok(ChatCompletionResponse::NonStream(gemini_response.to_openai(payload.model))) + } + } else { + eprintln!( + "VertexAI API request error: {}", + response.text().await.unwrap_or_default() + ); + Err(StatusCode::from_u16(status.as_u16()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)) + } + } + + async fn completions( + &self, + payload: CompletionRequest, + model_config: &ModelConfig, + ) -> Result { + // For Gemini, we'll use the chat endpoint for completions as well + let chat_request = ChatCompletionRequest { + model: payload.model, + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String(payload.prompt)), + name: None, + tool_calls: None, + }], + temperature: payload.temperature, + top_p: payload.top_p, + n: payload.n, + stream: payload.stream, + stop: payload.stop, + max_tokens: payload.max_tokens, + presence_penalty: payload.presence_penalty, + frequency_penalty: payload.frequency_penalty, + logit_bias: None, + user: payload.user, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + }; + + let chat_response = self.chat_completions(chat_request, model_config).await?; + + // Convert chat response to completion response + match chat_response { + ChatCompletionResponse::NonStream(resp) => { + Ok(CompletionResponse { + id: resp.id, + object: "text_completion".to_string(), + created: resp.created.unwrap_or_default(), + model: resp.model, + choices: resp.choices.into_iter().map(|c| CompletionChoice { + text: match c.message.content.unwrap_or(ChatMessageContent::String("".to_string())) { + ChatMessageContent::String(s) => s, + ChatMessageContent::Array(arr) => arr.into_iter().map(|p| p.text).collect::>().join(" "), + }, + index: c.index, + logprobs: None, + finish_reason: c.finish_reason, + }).collect(), + usage: Usage { + prompt_tokens: 0, + completion_tokens: 0, + total_tokens: 0, + prompt_tokens_details: None, + completion_tokens_details: None, + }, + }) + } + ChatCompletionResponse::Stream(_) => { + Err(StatusCode::BAD_REQUEST) // Streaming not supported for completions + } + } + } + + async fn embeddings( + &self, + payload: EmbeddingsRequest, + _model_config: &ModelConfig, + ) -> Result { + let endpoint = format!( + "https://{}-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:embedContent", + self.location, self.project_id, self.location, payload.model + ); + + let response = self + .http_client + .post(&endpoint) + .bearer_auth(&self.config.api_key) + .json(&json!({ + "text": payload.input + })) + .send() + .await + .map_err(|e| { + eprintln!("VertexAI API request error: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + let status = response.status(); + if status.is_success() { + let gemini_response = response.json::().await.map_err(|e| { + eprintln!("VertexAI API response error: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + // Extract embeddings from Gemini response and convert to OpenAI format + let embeddings = gemini_response["embeddings"].as_array() + .ok_or(StatusCode::INTERNAL_SERVER_ERROR)? + .iter() + .enumerate() + .map(|(i, e)| Embeddings { + object: "embedding".to_string(), + embedding: e["values"].as_array() + .unwrap_or(&vec![]) + .iter() + .filter_map(|v| v.as_f64().map(|f| f as f32)) + .collect(), + index: i, + }) + .collect(); + + Ok(EmbeddingsResponse { + object: "list".to_string(), + data: embeddings, + model: payload.model, + usage: Usage { + prompt_tokens: 0, + completion_tokens: 0, + total_tokens: 0, + prompt_tokens_details: None, + completion_tokens_details: None, + }, + }) + } else { + eprintln!( + "VertexAI API request error: {}", + response.text().await.unwrap_or_default() + ); + Err(StatusCode::from_u16(status.as_u16()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)) + } + } +} \ No newline at end of file diff --git a/src/providers/vertexai/tests.rs b/src/providers/vertexai/tests.rs new file mode 100644 index 0000000..e59b070 --- /dev/null +++ b/src/providers/vertexai/tests.rs @@ -0,0 +1,218 @@ +use std::path::PathBuf; +use surf_vcr::{VcrMode, VcrMiddleware}; +use surf::{Client, Config}; +use serde_json::json; + +use crate::config::models::{ModelConfig, Provider as ProviderConfig}; +use crate::models::chat::{ChatCompletionRequest, ChatCompletionResponse, ChatMessage}; +use crate::models::completion::CompletionRequest; +use crate::models::embeddings::{EmbeddingsRequest, EmbeddingsInput}; +use crate::providers::provider::Provider; +use super::provider::VertexAIProvider; + +fn setup_test_client() -> Client { + let vcr = VcrMiddleware::new( + PathBuf::from("tests/cassettes/vertexai"), + VcrMode::Replay + ); + + Config::new() + .add(vcr) + .try_into() + .unwrap() +} + +fn create_test_provider() -> VertexAIProvider { + let config = ProviderConfig { + key: "test-vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "test-api-key".to_string(), + params: HashMap::from([ + ("project_id".to_string(), "test-project".to_string()), + ("location".to_string(), "us-central1".to_string()), + ]), + ..Default::default() + }; + + VertexAIProvider::new(&config) +} + +#[tokio::test] +async fn test_chat_completions() { + let provider = create_test_provider(); + let model_config = ModelConfig { + key: "gemini-1.5-flash".to_string(), + r#type: "gemini-1.5-flash".to_string(), + provider: "vertexai".to_string(), + ..Default::default() + }; + + let request = ChatCompletionRequest { + model: "gemini-1.5-flash".to_string(), + messages: vec![ChatMessage { + role: "user".to_string(), + content: Some("Hello, how are you?".to_string()), + function_call: None, + tool_calls: None, + name: None, + tool_call_id: None, + }], + temperature: Some(0.7), + top_p: Some(0.9), + n: Some(1), + stream: Some(false), + stop: None, + max_tokens: Some(100), + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + }; + + let response = provider.chat_completions(request, &model_config).await.unwrap(); + match response { + ChatCompletionResponse::NonStream(resp) => { + assert_eq!(resp["object"], "chat.completion"); + assert!(!resp["choices"].as_array().unwrap().is_empty()); + }, + _ => panic!("Expected non-stream response"), + } +} + +#[tokio::test] +async fn test_completions() { + let provider = create_test_provider(); + let model_config = ModelConfig { + key: "gemini-1.5-flash".to_string(), + r#type: "gemini-1.5-flash".to_string(), + provider: "vertexai".to_string(), + ..Default::default() + }; + + let request = CompletionRequest { + model: "gemini-1.5-flash".to_string(), + prompt: "Once upon a time".to_string(), + suffix: None, + best_of: None, + logit_bias: None, + temperature: Some(0.7), + top_p: Some(0.9), + n: Some(1), + stream: Some(false), + stop: None, + max_tokens: Some(100), + presence_penalty: None, + frequency_penalty: None, + logprobs: None, + echo: None, + user: None, + }; + + let response = provider.completions(request, &model_config).await.unwrap(); + assert_eq!(response.object, "text_completion"); + assert!(!response.choices.is_empty()); +} + +#[tokio::test] +async fn test_embeddings() { + let provider = create_test_provider(); + let model_config = ModelConfig { + key: "textembedding-gecko".to_string(), + r#type: "textembedding-gecko".to_string(), + provider: "vertexai".to_string(), + ..Default::default() + }; + + let request = EmbeddingsRequest { + model: "textembedding-gecko".to_string(), + input: EmbeddingsInput::Multiple(vec!["This is a test sentence.".to_string()]), + user: None, + encoding_format: Some("float".to_string()), + }; + + let response = provider.embeddings(request, &model_config).await.unwrap(); + assert_eq!(response.object, "list"); + assert!(!response.data.is_empty()); + assert!(response.data[0]["embedding"].as_array().unwrap().len() > 0); +} + +#[tokio::test] +async fn test_chat_completions_with_tools() { + let provider = create_test_provider(); + let model_config = ModelConfig { + key: "gemini-1.5-flash".to_string(), + r#type: "gemini-1.5-flash".to_string(), + provider: "vertexai".to_string(), + ..Default::default() + }; + + let request = ChatCompletionRequest { + model: "gemini-1.5-flash".to_string(), + messages: vec![ChatMessage { + role: "user".to_string(), + content: Some("What's the weather in San Francisco?".to_string()), + function_call: None, + tool_calls: None, + name: None, + tool_call_id: None, + }], + temperature: Some(0.7), + top_p: Some(0.9), + n: Some(1), + stream: Some(false), + stop: None, + max_tokens: Some(100), + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: Some(vec![json!({ + "type": "function", + "function": { + "name": "get_weather", + "description": "Get the current weather in a location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The location to get weather for" + } + }, + "required": ["location"] + } + } + })]), + tool_choice: Some(json!("auto")), + parallel_tool_calls: Some(1), + }; + + let response = provider.chat_completions(request, &model_config).await.unwrap(); + match response { + ChatCompletionResponse::NonStream(resp) => { + assert_eq!(resp["object"], "chat.completion"); + let choices = resp["choices"].as_array().unwrap(); + assert!(!choices.is_empty()); + + let first_choice = &choices[0]; + let message = first_choice["message"].as_object().unwrap(); + + // Verify tool calls are present + if let Some(tool_calls) = message.get("tool_calls") { + let tool_calls = tool_calls.as_array().unwrap(); + assert!(!tool_calls.is_empty()); + + let first_call = &tool_calls[0]; + assert_eq!(first_call["type"], "function"); + + let function = first_call["function"].as_object().unwrap(); + assert_eq!(function["name"], "get_weather"); + assert!(function["arguments"].as_str().unwrap().contains("San Francisco")); + } + }, + _ => panic!("Expected non-stream response"), + } +} \ No newline at end of file From aa628ef76837a32214b910f5586687c9bf0297cd Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Mon, 30 Dec 2024 14:21:00 +0100 Subject: [PATCH 2/9] cargo fmt fix Signed-off-by: David Anyatonwu --- src/models/streaming.rs | 9 ++- src/models/vertexai.rs | 121 +++++++++++++++++------------ src/providers/vertexai/mod.rs | 2 +- src/providers/vertexai/provider.rs | 102 ++++++++++++++---------- src/providers/vertexai/tests.rs | 51 ++++++------ 5 files changed, 171 insertions(+), 114 deletions(-) diff --git a/src/models/streaming.rs b/src/models/streaming.rs index 442766c..5558152 100644 --- a/src/models/streaming.rs +++ b/src/models/streaming.rs @@ -60,12 +60,17 @@ impl ChatCompletionChunk { logprobs: None, delta: ChoiceDelta { role: None, - content: response.candidates.first() + content: response + .candidates + .first() .map(|c| c.content.parts.first().map(|p| p.text.clone())) .flatten(), tool_calls: None, }, - finish_reason: response.candidates.first().and_then(|c| c.finish_reason.clone()), + finish_reason: response + .candidates + .first() + .and_then(|c| c.finish_reason.clone()), }], usage: None, } diff --git a/src/models/vertexai.rs b/src/models/vertexai.rs index 716833b..1652a6f 100644 --- a/src/models/vertexai.rs +++ b/src/models/vertexai.rs @@ -4,7 +4,7 @@ use serde_json::Value; use crate::models::chat::{ChatCompletion, ChatCompletionChoice, ChatCompletionRequest}; use crate::models::content::{ChatCompletionMessage, ChatMessageContent}; use crate::models::tool_calls::{ChatMessageToolCall, FunctionCall}; -use crate::models::tool_choice::{ToolChoice, SimpleToolChoice}; +use crate::models::tool_choice::{SimpleToolChoice, ToolChoice}; use crate::models::usage::Usage; #[derive(Debug, Serialize, Deserialize)] @@ -116,21 +116,29 @@ pub struct UsageMetadata { impl GeminiChatRequest { pub fn from_openai(req: ChatCompletionRequest) -> Self { - let contents = req.messages.into_iter().map(|msg| GeminiContent { - role: match msg.role.as_str() { - "assistant" => "model".to_string(), - role => role.to_string(), - }, - parts: vec![ContentPart { - text: match msg.content { - Some(content) => match content { - ChatMessageContent::String(text) => text, - ChatMessageContent::Array(parts) => parts.into_iter().map(|p| p.text).collect::>().join(" "), - }, - None => String::new(), + let contents = req + .messages + .into_iter() + .map(|msg| GeminiContent { + role: match msg.role.as_str() { + "assistant" => "model".to_string(), + role => role.to_string(), }, - }], - }).collect(); + parts: vec![ContentPart { + text: match msg.content { + Some(content) => match content { + ChatMessageContent::String(text) => text, + ChatMessageContent::Array(parts) => parts + .into_iter() + .map(|p| p.text) + .collect::>() + .join(" "), + }, + None => String::new(), + }, + }], + }) + .collect(); let generation_config = Some(GenerationConfig { temperature: req.temperature, @@ -142,13 +150,15 @@ impl GeminiChatRequest { let tools = req.tools.map(|tools| { vec![GeminiTool { - function_declarations: tools.into_iter().map(|tool| { - GeminiFunctionDeclaration { + function_declarations: tools + .into_iter() + .map(|tool| GeminiFunctionDeclaration { name: tool.function.name, description: tool.function.description, - parameters: serde_json::to_value(tool.function.parameters).unwrap_or_default(), - } - }).collect(), + parameters: serde_json::to_value(tool.function.parameters) + .unwrap_or_default(), + }) + .collect(), }] }); @@ -173,44 +183,59 @@ impl GeminiChatRequest { impl GeminiChatResponse { pub fn to_openai(self, model: String) -> ChatCompletion { - let choices = self.candidates.into_iter().enumerate().map(|(i, candidate)| { - ChatCompletionChoice { + let choices = self + .candidates + .into_iter() + .enumerate() + .map(|(i, candidate)| ChatCompletionChoice { index: i as u32, message: ChatCompletionMessage { role: "assistant".to_string(), content: Some(ChatMessageContent::String( - candidate.content.parts.into_iter().map(|p| p.text).collect::>().join("") + candidate + .content + .parts + .into_iter() + .map(|p| p.text) + .collect::>() + .join(""), )), name: None, tool_calls: candidate.tool_calls.map(|calls| { - calls.into_iter().map(|call| ChatMessageToolCall { - id: format!("call_{}", uuid::Uuid::new_v4()), - r#type: "function".to_string(), - function: FunctionCall { - name: call.function.name, - arguments: call.function.arguments, - } - }).collect() + calls + .into_iter() + .map(|call| ChatMessageToolCall { + id: format!("call_{}", uuid::Uuid::new_v4()), + r#type: "function".to_string(), + function: FunctionCall { + name: call.function.name, + arguments: call.function.arguments, + }, + }) + .collect() }), }, finish_reason: candidate.finish_reason, logprobs: None, - } - }).collect(); - - let usage = self.usage_metadata.map_or(Usage { - prompt_tokens: 0, - completion_tokens: 0, - total_tokens: 0, - prompt_tokens_details: None, - completion_tokens_details: None, - }, |m| Usage { - prompt_tokens: m.prompt_token_count as u32, - completion_tokens: m.candidates_token_count as u32, - total_tokens: m.total_token_count as u32, - prompt_tokens_details: None, - completion_tokens_details: None, - }); + }) + .collect(); + + let usage = self.usage_metadata.map_or( + Usage { + prompt_tokens: 0, + completion_tokens: 0, + total_tokens: 0, + prompt_tokens_details: None, + completion_tokens_details: None, + }, + |m| Usage { + prompt_tokens: m.prompt_token_count as u32, + completion_tokens: m.candidates_token_count as u32, + total_tokens: m.total_token_count as u32, + prompt_tokens_details: None, + completion_tokens_details: None, + }, + ); ChatCompletion { id: format!("chatcmpl-{}", uuid::Uuid::new_v4()), @@ -222,4 +247,4 @@ impl GeminiChatResponse { system_fingerprint: None, } } -} \ No newline at end of file +} diff --git a/src/providers/vertexai/mod.rs b/src/providers/vertexai/mod.rs index beaee35..99894b7 100644 --- a/src/providers/vertexai/mod.rs +++ b/src/providers/vertexai/mod.rs @@ -2,4 +2,4 @@ pub mod provider; #[cfg(test)] mod tests; -pub use provider::VertexAIProvider; \ No newline at end of file +pub use provider::VertexAIProvider; diff --git a/src/providers/vertexai/provider.rs b/src/providers/vertexai/provider.rs index 03d64f0..36782f2 100644 --- a/src/providers/vertexai/provider.rs +++ b/src/providers/vertexai/provider.rs @@ -1,10 +1,11 @@ use crate::config::constants::stream_buffer_size_bytes; use crate::config::models::{ModelConfig, Provider as ProviderConfig}; use crate::models::chat::{ChatCompletionRequest, ChatCompletionResponse}; -use crate::models::completion::{CompletionRequest, CompletionResponse, CompletionChoice}; +use crate::models::completion::{CompletionChoice, CompletionRequest, CompletionResponse}; use crate::models::content::{ChatCompletionMessage, ChatMessageContent}; -use crate::models::embeddings::{EmbeddingsRequest, EmbeddingsResponse, Embeddings}; +use crate::models::embeddings::{Embeddings, EmbeddingsRequest, EmbeddingsResponse}; use crate::models::streaming::ChatCompletionChunk; +use crate::models::usage::Usage; use crate::models::vertexai::{GeminiChatRequest, GeminiChatResponse}; use crate::providers::provider::Provider; use axum::async_trait; @@ -13,7 +14,6 @@ use futures::StreamExt; use reqwest::Client; use reqwest_streams::*; use serde_json::json; -use crate::models::usage::Usage; pub struct VertexAIProvider { config: ProviderConfig, @@ -25,8 +25,14 @@ pub struct VertexAIProvider { #[async_trait] impl Provider for VertexAIProvider { fn new(config: &ProviderConfig) -> Self { - let project_id = config.params.get("project_id").map_or_else(|| "test-project".to_string(), |v| v.to_string()); - let location = config.params.get("location").map_or_else(|| "us-central1".to_string(), |v| v.to_string()); + let project_id = config + .params + .get("project_id") + .map_or_else(|| "test-project".to_string(), |v| v.to_string()); + let location = config + .params + .get("location") + .map_or_else(|| "us-central1".to_string(), |v| v.to_string()); Self { config: config.clone(), @@ -51,7 +57,7 @@ impl Provider for VertexAIProvider { ) -> Result { // Convert OpenAI format to Gemini format let gemini_request = GeminiChatRequest::from_openai(payload.clone()); - + let endpoint = format!( "https://{}-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:streamGenerateContent", self.location, self.project_id, self.location, payload.model @@ -72,22 +78,28 @@ impl Provider for VertexAIProvider { let status = response.status(); if status.is_success() { if payload.stream.unwrap_or(false) { - let stream = Box::pin(response.json_array_stream::(stream_buffer_size_bytes()) - .map(move |chunk| { - chunk.map(|c| ChatCompletionChunk::from_gemini(c, payload.model.clone())) - .map_err(|e| { - eprintln!("Error parsing Gemini response: {}", e); - e - }) - })); + let stream = Box::pin( + response + .json_array_stream::(stream_buffer_size_bytes()) + .map(move |chunk| { + chunk + .map(|c| ChatCompletionChunk::from_gemini(c, payload.model.clone())) + .map_err(|e| { + eprintln!("Error parsing Gemini response: {}", e); + e + }) + }), + ); Ok(ChatCompletionResponse::Stream(stream)) } else { let gemini_response = response.json::().await.map_err(|e| { eprintln!("VertexAI API response error: {}", e); StatusCode::INTERNAL_SERVER_ERROR })?; - - Ok(ChatCompletionResponse::NonStream(gemini_response.to_openai(payload.model))) + + Ok(ChatCompletionResponse::NonStream( + gemini_response.to_openai(payload.model), + )) } } else { eprintln!( @@ -128,33 +140,43 @@ impl Provider for VertexAIProvider { }; let chat_response = self.chat_completions(chat_request, model_config).await?; - + // Convert chat response to completion response match chat_response { - ChatCompletionResponse::NonStream(resp) => { - Ok(CompletionResponse { - id: resp.id, - object: "text_completion".to_string(), - created: resp.created.unwrap_or_default(), - model: resp.model, - choices: resp.choices.into_iter().map(|c| CompletionChoice { - text: match c.message.content.unwrap_or(ChatMessageContent::String("".to_string())) { + ChatCompletionResponse::NonStream(resp) => Ok(CompletionResponse { + id: resp.id, + object: "text_completion".to_string(), + created: resp.created.unwrap_or_default(), + model: resp.model, + choices: resp + .choices + .into_iter() + .map(|c| CompletionChoice { + text: match c + .message + .content + .unwrap_or(ChatMessageContent::String("".to_string())) + { ChatMessageContent::String(s) => s, - ChatMessageContent::Array(arr) => arr.into_iter().map(|p| p.text).collect::>().join(" "), + ChatMessageContent::Array(arr) => arr + .into_iter() + .map(|p| p.text) + .collect::>() + .join(" "), }, index: c.index, logprobs: None, finish_reason: c.finish_reason, - }).collect(), - usage: Usage { - prompt_tokens: 0, - completion_tokens: 0, - total_tokens: 0, - prompt_tokens_details: None, - completion_tokens_details: None, - }, - }) - } + }) + .collect(), + usage: Usage { + prompt_tokens: 0, + completion_tokens: 0, + total_tokens: 0, + prompt_tokens_details: None, + completion_tokens_details: None, + }, + }), ChatCompletionResponse::Stream(_) => { Err(StatusCode::BAD_REQUEST) // Streaming not supported for completions } @@ -193,13 +215,15 @@ impl Provider for VertexAIProvider { })?; // Extract embeddings from Gemini response and convert to OpenAI format - let embeddings = gemini_response["embeddings"].as_array() + let embeddings = gemini_response["embeddings"] + .as_array() .ok_or(StatusCode::INTERNAL_SERVER_ERROR)? .iter() .enumerate() .map(|(i, e)| Embeddings { object: "embedding".to_string(), - embedding: e["values"].as_array() + embedding: e["values"] + .as_array() .unwrap_or(&vec![]) .iter() .filter_map(|v| v.as_f64().map(|f| f as f32)) @@ -228,4 +252,4 @@ impl Provider for VertexAIProvider { Err(StatusCode::from_u16(status.as_u16()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)) } } -} \ No newline at end of file +} diff --git a/src/providers/vertexai/tests.rs b/src/providers/vertexai/tests.rs index e59b070..8527553 100644 --- a/src/providers/vertexai/tests.rs +++ b/src/providers/vertexai/tests.rs @@ -1,25 +1,19 @@ +use serde_json::json; use std::path::PathBuf; -use surf_vcr::{VcrMode, VcrMiddleware}; use surf::{Client, Config}; -use serde_json::json; +use surf_vcr::{VcrMiddleware, VcrMode}; +use super::provider::VertexAIProvider; use crate::config::models::{ModelConfig, Provider as ProviderConfig}; use crate::models::chat::{ChatCompletionRequest, ChatCompletionResponse, ChatMessage}; use crate::models::completion::CompletionRequest; -use crate::models::embeddings::{EmbeddingsRequest, EmbeddingsInput}; +use crate::models::embeddings::{EmbeddingsInput, EmbeddingsRequest}; use crate::providers::provider::Provider; -use super::provider::VertexAIProvider; fn setup_test_client() -> Client { - let vcr = VcrMiddleware::new( - PathBuf::from("tests/cassettes/vertexai"), - VcrMode::Replay - ); - - Config::new() - .add(vcr) - .try_into() - .unwrap() + let vcr = VcrMiddleware::new(PathBuf::from("tests/cassettes/vertexai"), VcrMode::Replay); + + Config::new().add(vcr).try_into().unwrap() } fn create_test_provider() -> VertexAIProvider { @@ -33,7 +27,7 @@ fn create_test_provider() -> VertexAIProvider { ]), ..Default::default() }; - + VertexAIProvider::new(&config) } @@ -72,12 +66,15 @@ async fn test_chat_completions() { parallel_tool_calls: None, }; - let response = provider.chat_completions(request, &model_config).await.unwrap(); + let response = provider + .chat_completions(request, &model_config) + .await + .unwrap(); match response { ChatCompletionResponse::NonStream(resp) => { assert_eq!(resp["object"], "chat.completion"); assert!(!resp["choices"].as_array().unwrap().is_empty()); - }, + } _ => panic!("Expected non-stream response"), } } @@ -190,29 +187,35 @@ async fn test_chat_completions_with_tools() { parallel_tool_calls: Some(1), }; - let response = provider.chat_completions(request, &model_config).await.unwrap(); + let response = provider + .chat_completions(request, &model_config) + .await + .unwrap(); match response { ChatCompletionResponse::NonStream(resp) => { assert_eq!(resp["object"], "chat.completion"); let choices = resp["choices"].as_array().unwrap(); assert!(!choices.is_empty()); - + let first_choice = &choices[0]; let message = first_choice["message"].as_object().unwrap(); - + // Verify tool calls are present if let Some(tool_calls) = message.get("tool_calls") { let tool_calls = tool_calls.as_array().unwrap(); assert!(!tool_calls.is_empty()); - + let first_call = &tool_calls[0]; assert_eq!(first_call["type"], "function"); - + let function = first_call["function"].as_object().unwrap(); assert_eq!(function["name"], "get_weather"); - assert!(function["arguments"].as_str().unwrap().contains("San Francisco")); + assert!(function["arguments"] + .as_str() + .unwrap() + .contains("San Francisco")); } - }, + } _ => panic!("Expected non-stream response"), } -} \ No newline at end of file +} From 5af4770d6e889311bb21e0159b8c46832452453e Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Tue, 31 Dec 2024 15:39:48 +0100 Subject: [PATCH 3/9] feat(vertexai): support both api key and service and robust tests Signed-off-by: David Anyatonwu --- .gitignore | 2 +- Cargo.lock | 438 +++++++++- Cargo.toml | 2 + README.md | 76 +- config-example.yaml | 74 +- src/config/models.rs | 4 +- src/models/streaming.rs | 33 +- src/models/vertexai.rs | 4 +- src/providers/vertexai/provider.rs | 226 +++-- src/providers/vertexai/tests.rs | 493 ++++++++--- .../cassettes/vertexai/chat_completions.json | 46 + .../vertexai/chat_completions_with_tools.json | 24 + tests/cassettes/vertexai/completions.json | 20 + tests/cassettes/vertexai/embeddings.json | 787 ++++++++++++++++++ 14 files changed, 1969 insertions(+), 260 deletions(-) create mode 100644 tests/cassettes/vertexai/chat_completions.json create mode 100644 tests/cassettes/vertexai/chat_completions_with_tools.json create mode 100644 tests/cassettes/vertexai/completions.json create mode 100644 tests/cassettes/vertexai/embeddings.json diff --git a/.gitignore b/.gitignore index 8fcf185..c78b960 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,4 @@ config.yaml # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ -.vscode/ +.vscode/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 7b9ddf3..75a4ccd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,6 +83,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -119,6 +128,16 @@ version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" +[[package]] +name = "assert-json-diff" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "async-channel" version = "1.9.0" @@ -304,9 +323,9 @@ dependencies = [ "bytes 1.8.0", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-util", "itoa", "matchit", @@ -337,7 +356,7 @@ dependencies = [ "bytes 1.8.0", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", @@ -359,7 +378,7 @@ dependencies = [ "bytes 1.8.0", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", @@ -380,7 +399,7 @@ dependencies = [ "bytes 1.8.0", "futures-core", "http 1.1.0", - "http-body", + "http-body 1.0.1", "matchit", "metrics", "metrics-exporter-prometheus", @@ -418,6 +437,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -577,7 +602,7 @@ dependencies = [ "percent-encoding", "rand 0.8.5", "sha2", - "time", + "time 0.2.27", "version_check", ] @@ -686,6 +711,35 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "deadpool" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e" +dependencies = [ + "async-trait", + "deadpool-runtime", + "num_cpus", + "retain_mut", + "tokio", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "digest" version = "0.9.0" @@ -924,6 +978,12 @@ version = "0.3.31" 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" @@ -1008,6 +1068,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes 1.8.0", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.6" @@ -1112,6 +1191,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes 1.8.0", + "http 0.2.12", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.0.1" @@ -1131,7 +1221,7 @@ dependencies = [ "bytes 1.8.0", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.1", "pin-project-lite", ] @@ -1167,6 +1257,7 @@ dependencies = [ "base64 0.13.1", "cookie", "futures-lite 1.13.0", + "http 0.2.12", "infer", "pin-project-lite", "rand 0.7.3", @@ -1217,6 +1308,32 @@ dependencies = [ "tracing", "tracing-subscriber", "uuid", + "wiremock", + "yup-oauth2", +] + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes 1.8.0", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", ] [[package]] @@ -1228,9 +1345,9 @@ dependencies = [ "bytes 1.8.0", "futures-channel", "futures-util", - "h2", + "h2 0.4.6", "http 1.1.0", - "http-body", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -1240,6 +1357,22 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "log", + "rustls 0.21.12", + "rustls-native-certs 0.6.3", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-rustls" version = "0.27.3" @@ -1248,13 +1381,13 @@ checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper", + "hyper 1.5.0", "hyper-util", - "rustls", - "rustls-native-certs", + "rustls 0.23.19", + "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tower-service", ] @@ -1264,7 +1397,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper", + "hyper 1.5.0", "hyper-util", "pin-project-lite", "tokio", @@ -1279,7 +1412,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes 1.8.0", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-util", "native-tls", "tokio", @@ -1297,8 +1430,8 @@ dependencies = [ "futures-channel", "futures-util", "http 1.1.0", - "http-body", - "hyper", + "http-body 1.0.1", + "hyper 1.5.0", "pin-project-lite", "socket2", "tokio", @@ -1413,6 +1546,15 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.13.0" @@ -1550,7 +1692,7 @@ checksum = "b4f0c8427b39666bf970460908b213ec09b3b350f20c0c2eabcbba51704a08e6" dependencies = [ "base64 0.22.1", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-util", "indexmap 2.6.0", "ipnet", @@ -1641,6 +1783,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.19" @@ -1660,6 +1808,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "object" version = "0.36.5" @@ -1934,6 +2091,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -1975,7 +2138,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", - "itertools", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.85", @@ -2007,7 +2170,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls", + "rustls 0.23.19", "socket2", "thiserror", "tokio", @@ -2024,7 +2187,7 @@ dependencies = [ "rand 0.8.5", "ring", "rustc-hash", - "rustls", + "rustls 0.23.19", "slab", "thiserror", "tinyvec", @@ -2143,6 +2306,35 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "reqwest" version = "0.12.9" @@ -2155,12 +2347,12 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.4.6", "http 1.1.0", - "http-body", + "http-body 1.0.1", "http-body-util", - "hyper", - "hyper-rustls", + "hyper 1.5.0", + "hyper-rustls 0.27.3", "hyper-tls", "hyper-util", "ipnet", @@ -2172,9 +2364,9 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls", - "rustls-native-certs", - "rustls-pemfile", + "rustls 0.23.19", + "rustls-native-certs 0.8.0", + "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", @@ -2183,7 +2375,7 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", - "tokio-rustls", + "tokio-rustls 0.26.0", "tokio-util", "tower-service", "url", @@ -2211,6 +2403,12 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "retain_mut" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" + [[package]] name = "ring" version = "0.17.8" @@ -2260,6 +2458,32 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + [[package]] name = "rustls" version = "0.23.19" @@ -2269,11 +2493,23 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile 1.0.4", + "schannel", + "security-framework", +] + [[package]] name = "rustls-native-certs" version = "0.8.0" @@ -2281,12 +2517,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -2302,6 +2547,16 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.102.8" @@ -2340,6 +2595,22 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "security-framework" version = "2.11.1" @@ -2788,11 +3059,33 @@ dependencies = [ "libc", "standback", "stdweb", - "time-macros", + "time-macros 0.1.1", "version_check", "winapi", ] +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros 0.2.19", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "time-macros" version = "0.1.1" @@ -2803,6 +3096,16 @@ dependencies = [ "time-macros-impl", ] +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "time-macros-impl" version = "0.1.2" @@ -2870,13 +3173,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls", + "rustls 0.23.19", "rustls-pki-types", "tokio", ] @@ -2916,11 +3229,11 @@ dependencies = [ "axum", "base64 0.22.1", "bytes 1.8.0", - "h2", + "h2 0.4.6", "http 1.1.0", - "http-body", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-timeout", "hyper-util", "percent-encoding", @@ -2984,7 +3297,7 @@ dependencies = [ "bitflags", "bytes 1.8.0", "http 1.1.0", - "http-body", + "http-body 1.0.1", "http-body-util", "pin-project-lite", "tower-layer", @@ -3004,7 +3317,7 @@ dependencies = [ "futures-core", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.1", "http-body-util", "http-range-header", "httpdate", @@ -3468,6 +3781,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wiremock" +version = "0.5.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13a3a53eaf34f390dd30d7b1b078287dd05df2aa2e21a589ccb80f5c7253c2e9" +dependencies = [ + "assert-json-diff", + "async-trait", + "base64 0.21.7", + "deadpool", + "futures", + "futures-timer", + "http-types", + "hyper 0.14.32", + "log", + "once_cell", + "regex", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "yaml-rust" version = "0.4.5" @@ -3477,6 +3812,33 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "yup-oauth2" +version = "8.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b61da40aeb0907a65f7fb5c1de83c5a224d6a9ebb83bf918588a2bb744d636b8" +dependencies = [ + "anyhow", + "async-trait", + "base64 0.21.7", + "futures", + "http 0.2.12", + "hyper 0.14.32", + "hyper-rustls 0.24.2", + "itertools 0.12.1", + "log", + "percent-encoding", + "rustls 0.22.4", + "rustls-pemfile 1.0.4", + "seahash", + "serde", + "serde_json", + "time 0.3.37", + "tokio", + "tower-service", + "url", +] + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index 5b7424c..e6cad2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,9 @@ axum-prometheus = "0.7.0" reqwest-streams = { version = "0.8.1", features = ["json"] } futures = "0.3.31" async-stream = "0.3.6" +yup-oauth2 = "8.3.0" [dev-dependencies] surf = "2.3.2" surf-vcr = "0.2.0" +wiremock = "0.5" diff --git a/README.md b/README.md index cd863a6..57e4b5c 100644 --- a/README.md +++ b/README.md @@ -146,22 +146,62 @@ providers: api_key: "" project_id: "" location: "" - credentials_path: "/path/to/service-account.json" # Optional + credentials_path: "/path/to/service-account.json" ``` -Authentication can be done in two ways: -1. API Key: Set the `api_key` field with your GCP API key -2. Service Account: Set the `credentials_path` field with the path to your service account JSON file. If not specified, the default GCP credentials will be used. - -### Model Configuration - +Authentication Methods: +1. API Key Authentication: + - Set the `api_key` field with your GCP API key + - Leave `credentials_path` empty +2. Service Account Authentication: + - Set `credentials_path` to your service account JSON file path + - Can also use `GOOGLE_APPLICATION_CREDENTIALS` environment variable + - Leave `api_key` empty when using service account auth + +Supported Features: +- Chat Completions (with Gemini models) +- Text Completions +- Embeddings +- Streaming Support +- Function/Tool Calling +- Multi-modal Inputs (images + text) + +Example Model Configuration: ```yaml models: - - key: gemini-pro - type: gemini-pro + # Chat and Completion model + - key: gemini-1.5-flash + type: gemini-1.5-flash + provider: vertexai + + # Embeddings model + - key: textembedding-gecko + type: textembedding-gecko provider: vertexai ``` +Example Usage with OpenAI SDK: +```python +from openai import OpenAI + +client = OpenAI( + base_url="http://localhost:3000/api/v1", + api_key="not-needed-for-vertexai" +) + +# Chat completion +response = client.chat.completions.create( + model="gemini-1.5-flash", + messages=[{"role": "user", "content": "Tell me a joke"}] +) + +# Embeddings +response = client.embeddings.create( + model="textembedding-gecko", + input="Sample text for embedding" +) +``` + ### Pipeline Configuration ```yaml @@ -178,7 +218,7 @@ pipelines: ### Running Tests -The test suite uses `surf-vcr` to record and replay HTTP interactions, making tests reproducible without requiring actual API credentials. +The test suite uses recorded HTTP interactions (cassettes) to make tests reproducible without requiring actual API credentials. To run tests: ```bash @@ -186,13 +226,21 @@ cargo test ``` To record new test cassettes: -1. Set up your API credentials in the environment -2. Delete the existing cassette files in `tests/cassettes/` -3. Run the tests with `VCR_MODE=record`: +1. Set up your API credentials: + - For service account auth: Set `VERTEXAI_CREDENTIALS_PATH` to your service account key file path + - For API key auth: Use the test with API key (currently marked as ignored) +2. Delete the existing cassette files in `tests/cassettes/vertexai/` +3. Run the tests with recording enabled: ```bash -VCR_MODE=record cargo test +RECORD_MODE=1 cargo test ``` +Additional test configurations: +- `RETRY_DELAY`: Set the delay in seconds between retries when hitting quota limits (default: 60) +- Tests automatically retry up to 3 times when hitting quota limits + +Note: Some tests may be marked as `#[ignore]` if they require specific credentials or are not ready for general use. + ## License See LICENSE file. diff --git a/config-example.yaml b/config-example.yaml index 6e8c91a..9e6c350 100644 --- a/config-example.yaml +++ b/config-example.yaml @@ -1,42 +1,84 @@ providers: + # Azure OpenAI configuration - key: azure-openai type: azure api_key: "" resource_name: "" api_version: "" + + # OpenAI configuration - key: openai type: openai api_key: "" + + # Vertex AI configuration + # Uses service account authentication - key: vertexai type: vertexai - api_key: "" + api_key: "" # Required field but not used with service account auth project_id: "" - location: "" - credentials_path: "/path/to/service-account.json" # Optional, uses GCP default credentials if not specified + location: "" # e.g., us-central1 + credentials_path: "/path/to/service-account.json" # Path to your service account key file models: - - key: gpt-4o-openai - type: gpt-4o + # OpenAI Models + - key: gpt-4 + type: gpt-4 provider: openai - - key: gpt-4o-azure - type: gpt-4o + - key: gpt-3.5-turbo + type: gpt-3.5-turbo + provider: openai + + # Azure OpenAI Models + - key: gpt-4-azure + type: gpt-4 provider: azure-openai - deployment: "" - - key: gemini-pro - type: gemini-pro + deployment: "" + - key: gpt-35-turbo-azure + type: gpt-35-turbo + provider: azure-openai + deployment: "" + + # Vertex AI Models + # Chat and Completion model + - key: gemini-1.5-flash + type: gemini-1.5-flash # Supports both chat and completion endpoints + provider: vertexai + # Embeddings model + - key: textembedding-gecko + type: textembedding-gecko # Supports embeddings endpoint provider: vertexai pipelines: + # Default pipeline for chat completions - name: default type: chat plugins: - logging: - level: info - - tracing: + level: info # Supported levels: debug, info, warning, error + - tracing: # Optional tracing configuration endpoint: "https://api.traceloop.com/v1/traces" api_key: "" - model-router: - models: - - gpt-4o-openai - - gpt-4o-azure - - gemini-pro + models: # List the models you want to use for chat + - gpt-4 + - gpt-4-azure + - gemini-1.5-flash + + # Pipeline for text completions + - name: completions + type: completion + plugins: + - model-router: + models: # List the models you want to use for completions + - gpt-3.5-turbo + - gpt-35-turbo-azure + - gemini-1.5-flash + + # Pipeline for embeddings + - name: embeddings + type: embeddings + plugins: + - model-router: + models: # List the models you want to use for embeddings + - textembedding-gecko diff --git a/src/config/models.rs b/src/config/models.rs index d992203..80d9ec5 100644 --- a/src/config/models.rs +++ b/src/config/models.rs @@ -9,7 +9,7 @@ pub struct Config { pub pipelines: Vec, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, Default)] pub struct Provider { pub key: String, pub r#type: String, @@ -18,7 +18,7 @@ pub struct Provider { pub params: HashMap, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, Default)] pub struct ModelConfig { pub key: String, pub r#type: String, diff --git a/src/models/streaming.rs b/src/models/streaming.rs index 5558152..737984e 100644 --- a/src/models/streaming.rs +++ b/src/models/streaming.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use super::logprob::ChoiceLogprobs; -use super::tool_calls::ChatMessageToolCall; +use super::tool_calls::{ChatMessageToolCall, FunctionCall}; use super::usage::Usage; use crate::models::vertexai::GeminiChatResponse; @@ -49,6 +49,8 @@ pub struct ChatCompletionChunk { impl ChatCompletionChunk { pub fn from_gemini(response: GeminiChatResponse, model: String) -> Self { + let first_candidate = response.candidates.first(); + Self { id: uuid::Uuid::new_v4().to_string(), service_tier: None, @@ -60,17 +62,26 @@ impl ChatCompletionChunk { logprobs: None, delta: ChoiceDelta { role: None, - content: response - .candidates - .first() - .map(|c| c.content.parts.first().map(|p| p.text.clone())) - .flatten(), - tool_calls: None, + content: first_candidate + .and_then(|c| c.content.parts.first()) + .map(|p| p.text.clone()), + tool_calls: first_candidate + .and_then(|c| c.tool_calls.clone()) + .map(|calls| { + calls + .into_iter() + .map(|call| ChatMessageToolCall { + id: format!("call_{}", uuid::Uuid::new_v4()), + r#type: "function".to_string(), + function: FunctionCall { + name: call.function.name, + arguments: call.function.arguments, + }, + }) + .collect() + }), }, - finish_reason: response - .candidates - .first() - .and_then(|c| c.finish_reason.clone()), + finish_reason: first_candidate.and_then(|c| c.finish_reason.clone()), }], usage: None, } diff --git a/src/models/vertexai.rs b/src/models/vertexai.rs index 1652a6f..b34e333 100644 --- a/src/models/vertexai.rs +++ b/src/models/vertexai.rs @@ -90,12 +90,12 @@ pub struct GeminiCandidate { pub tool_calls: Option>, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct GeminiToolCall { pub function: GeminiFunctionCall, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct GeminiFunctionCall { pub name: String, pub arguments: String, diff --git a/src/providers/vertexai/provider.rs b/src/providers/vertexai/provider.rs index 36782f2..b814296 100644 --- a/src/providers/vertexai/provider.rs +++ b/src/providers/vertexai/provider.rs @@ -1,19 +1,21 @@ -use crate::config::constants::stream_buffer_size_bytes; use crate::config::models::{ModelConfig, Provider as ProviderConfig}; use crate::models::chat::{ChatCompletionRequest, ChatCompletionResponse}; use crate::models::completion::{CompletionChoice, CompletionRequest, CompletionResponse}; use crate::models::content::{ChatCompletionMessage, ChatMessageContent}; -use crate::models::embeddings::{Embeddings, EmbeddingsRequest, EmbeddingsResponse}; -use crate::models::streaming::ChatCompletionChunk; +use crate::models::embeddings::{ + Embeddings, EmbeddingsInput, EmbeddingsRequest, EmbeddingsResponse, +}; use crate::models::usage::Usage; -use crate::models::vertexai::{GeminiChatRequest, GeminiChatResponse}; +use crate::models::vertexai::{ + ContentPart, GeminiCandidate, GeminiChatRequest, GeminiChatResponse, GeminiContent, + UsageMetadata, +}; use crate::providers::provider::Provider; use axum::async_trait; use axum::http::StatusCode; -use futures::StreamExt; use reqwest::Client; -use reqwest_streams::*; use serde_json::json; +use yup_oauth2::{ServiceAccountAuthenticator, ServiceAccountKey}; pub struct VertexAIProvider { config: ProviderConfig, @@ -22,6 +24,51 @@ pub struct VertexAIProvider { location: String, } +impl VertexAIProvider { + async fn get_auth_token(&self) -> Result { + println!("Getting auth token..."); + if !self.config.api_key.is_empty() { + println!("Using API key authentication"); + Ok(self.config.api_key.clone()) + } else { + println!("Using service account authentication"); + let key_path = self.config + .params + .get("credentials_path") + .map(|p| p.to_string()) + .or_else(|| std::env::var("GOOGLE_APPLICATION_CREDENTIALS").ok()) + .expect("Either api_key, credentials_path in config, or GOOGLE_APPLICATION_CREDENTIALS environment variable must be set"); + + println!("Reading service account key from: {}", key_path); + let key_json = + std::fs::read_to_string(key_path).expect("Failed to read service account key file"); + + println!( + "Service account key file content length: {}", + key_json.len() + ); + let sa_key: ServiceAccountKey = + serde_json::from_str(&key_json).expect("Failed to parse service account key"); + + println!("Successfully parsed service account key"); + let auth = ServiceAccountAuthenticator::builder(sa_key) + .build() + .await + .expect("Failed to create authenticator"); + + println!("Created authenticator, requesting token..."); + let scopes = &["https://www.googleapis.com/auth/cloud-platform"]; + let token = auth.token(scopes).await.map_err(|e| { + eprintln!("Failed to get access token: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + println!("Successfully obtained token"); + Ok(token.token().unwrap_or_default().to_string()) + } + } +} + #[async_trait] impl Provider for VertexAIProvider { fn new(config: &ProviderConfig) -> Self { @@ -41,7 +88,6 @@ impl Provider for VertexAIProvider { location, } } - fn key(&self) -> String { self.config.key.clone() } @@ -55,19 +101,17 @@ impl Provider for VertexAIProvider { payload: ChatCompletionRequest, _model_config: &ModelConfig, ) -> Result { - // Convert OpenAI format to Gemini format - let gemini_request = GeminiChatRequest::from_openai(payload.clone()); - + let auth_token = self.get_auth_token().await?; let endpoint = format!( - "https://{}-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:streamGenerateContent", - self.location, self.project_id, self.location, payload.model + "https://us-central1-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:streamGenerateContent", + self.project_id, self.location, payload.model ); let response = self .http_client .post(&endpoint) - .bearer_auth(&self.config.api_key) - .json(&gemini_request) + .bearer_auth(auth_token) + .json(&GeminiChatRequest::from_openai(payload.clone())) .send() .await .map_err(|e| { @@ -76,36 +120,87 @@ impl Provider for VertexAIProvider { })?; let status = response.status(); + println!("Response status: {}", status); + if status.is_success() { if payload.stream.unwrap_or(false) { - let stream = Box::pin( - response - .json_array_stream::(stream_buffer_size_bytes()) - .map(move |chunk| { - chunk - .map(|c| ChatCompletionChunk::from_gemini(c, payload.model.clone())) - .map_err(|e| { - eprintln!("Error parsing Gemini response: {}", e); - e - }) - }), - ); - Ok(ChatCompletionResponse::Stream(stream)) + Err(StatusCode::BAD_REQUEST) // Streaming not supported yet } else { - let gemini_response = response.json::().await.map_err(|e| { - eprintln!("VertexAI API response error: {}", e); + let response_text = response.text().await.map_err(|e| { + eprintln!("Failed to get response text: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + println!("Response body: {}", response_text); + + // Parse the response as a JSON array + let responses: Vec = serde_json::from_str(&response_text) + .map_err(|e| { + eprintln!("Failed to parse response as JSON array: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + // Get the last response which contains the complete message and usage metadata + let final_response = responses.last().ok_or_else(|| { + eprintln!("No valid response chunks found"); StatusCode::INTERNAL_SERVER_ERROR })?; + // Combine all text parts from all responses + let full_text = responses + .iter() + .filter_map(|resp| { + resp.get("candidates") + .and_then(|candidates| candidates.get(0)) + .and_then(|candidate| candidate.get("content")) + .and_then(|content| content.get("parts")) + .and_then(|parts| parts.get(0)) + .and_then(|part| part.get("text")) + .and_then(|text| text.as_str()) + .map(String::from) + }) + .collect::>() + .join(""); + + // Create a GeminiChatResponse with the combined text + let gemini_response = GeminiChatResponse { + candidates: vec![GeminiCandidate { + content: GeminiContent { + role: "model".to_string(), + parts: vec![ContentPart { text: full_text }], + }, + finish_reason: final_response["candidates"][0]["finishReason"] + .as_str() + .map(String::from), + safety_ratings: None, + tool_calls: None, + }], + usage_metadata: final_response["usageMetadata"].as_object().map(|obj| { + UsageMetadata { + prompt_token_count: obj + .get("promptTokenCount") + .and_then(|v| v.as_i64()) + .unwrap_or(0) + as i32, + candidates_token_count: obj + .get("candidatesTokenCount") + .and_then(|v| v.as_i64()) + .unwrap_or(0) + as i32, + total_token_count: obj + .get("totalTokenCount") + .and_then(|v| v.as_i64()) + .unwrap_or(0) as i32, + } + }), + }; + Ok(ChatCompletionResponse::NonStream( gemini_response.to_openai(payload.model), )) } } else { - eprintln!( - "VertexAI API request error: {}", - response.text().await.unwrap_or_default() - ); + let error_text = response.text().await.unwrap_or_default(); + eprintln!("VertexAI API request error: {}", error_text); Err(StatusCode::from_u16(status.as_u16()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)) } } @@ -188,17 +283,26 @@ impl Provider for VertexAIProvider { payload: EmbeddingsRequest, _model_config: &ModelConfig, ) -> Result { + let auth_token = self.get_auth_token().await?; let endpoint = format!( - "https://{}-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:embedContent", - self.location, self.project_id, self.location, payload.model + "https://us-central1-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:predict", + self.project_id, self.location, payload.model ); let response = self .http_client .post(&endpoint) - .bearer_auth(&self.config.api_key) + .bearer_auth(auth_token) .json(&json!({ - "text": payload.input + "instances": match payload.input { + EmbeddingsInput::Single(text) => vec![json!({"content": text})], + EmbeddingsInput::Multiple(texts) => texts.into_iter() + .map(|text| json!({"content": text})) + .collect::>(), + }, + "parameters": { + "autoTruncate": true + } })) .send() .await @@ -208,21 +312,30 @@ impl Provider for VertexAIProvider { })?; let status = response.status(); + println!("Embeddings response status: {}", status); + if status.is_success() { - let gemini_response = response.json::().await.map_err(|e| { - eprintln!("VertexAI API response error: {}", e); + let response_text = response.text().await.map_err(|e| { + eprintln!("Failed to get response text: {}", e); StatusCode::INTERNAL_SERVER_ERROR })?; + println!("Embeddings response body: {}", response_text); + + let gemini_response: serde_json::Value = + serde_json::from_str(&response_text).map_err(|e| { + eprintln!("Failed to parse response as JSON: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; - // Extract embeddings from Gemini response and convert to OpenAI format - let embeddings = gemini_response["embeddings"] + // Extract embeddings from updated response format + let embeddings = gemini_response["predictions"] .as_array() .ok_or(StatusCode::INTERNAL_SERVER_ERROR)? .iter() .enumerate() - .map(|(i, e)| Embeddings { + .map(|(i, pred)| Embeddings { object: "embedding".to_string(), - embedding: e["values"] + embedding: pred["embeddings"]["values"] .as_array() .unwrap_or(&vec![]) .iter() @@ -245,11 +358,30 @@ impl Provider for VertexAIProvider { }, }) } else { - eprintln!( - "VertexAI API request error: {}", - response.text().await.unwrap_or_default() - ); + let error_text = response.text().await.unwrap_or_default(); + eprintln!("VertexAI API request error: {}", error_text); Err(StatusCode::from_u16(status.as_u16()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)) } } } + +#[cfg(test)] +impl VertexAIProvider { + pub fn with_test_client(config: &ProviderConfig, client: reqwest::Client) -> Self { + let project_id = config + .params + .get("project_id") + .map_or_else(|| "test-project".to_string(), |v| v.to_string()); + let location = config + .params + .get("location") + .map_or_else(|| "us-central1".to_string(), |v| v.to_string()); + + Self { + config: config.clone(), + http_client: client, + project_id, + location, + } + } +} diff --git a/src/providers/vertexai/tests.rs b/src/providers/vertexai/tests.rs index 8527553..6466de5 100644 --- a/src/providers/vertexai/tests.rs +++ b/src/providers/vertexai/tests.rs @@ -1,59 +1,195 @@ use serde_json::json; +use serde_json::Value; +use std::collections::HashMap; +use std::fs; use std::path::PathBuf; -use surf::{Client, Config}; -use surf_vcr::{VcrMiddleware, VcrMode}; +use wiremock::{Mock, MockServer, ResponseTemplate}; use super::provider::VertexAIProvider; use crate::config::models::{ModelConfig, Provider as ProviderConfig}; -use crate::models::chat::{ChatCompletionRequest, ChatCompletionResponse, ChatMessage}; +use crate::models::chat::{ChatCompletionRequest, ChatCompletionResponse}; use crate::models::completion::CompletionRequest; +use crate::models::content::{ChatCompletionMessage, ChatMessageContent}; use crate::models::embeddings::{EmbeddingsInput, EmbeddingsRequest}; +use crate::models::tool_definition::{FunctionDefinition, ToolDefinition}; use crate::providers::provider::Provider; -fn setup_test_client() -> Client { - let vcr = VcrMiddleware::new(PathBuf::from("tests/cassettes/vertexai"), VcrMode::Replay); +async fn setup_test_client(test_name: &str) -> reqwest::Client { + // Create the cassettes directory if it doesn't exist + let cassettes_dir = PathBuf::from("tests/cassettes/vertexai"); + println!("Creating cassettes directory at: {:?}", cassettes_dir); - Config::new().add(vcr).try_into().unwrap() + if let Err(e) = std::fs::create_dir_all(&cassettes_dir) { + println!("Warning: Directory creation returned: {}", e); + } + + // Create specific cassette file path + let cassette_path = cassettes_dir.join(format!("{}.json", test_name)); + println!("Cassette path: {:?}", cassette_path); + + let is_record_mode = std::env::var("RECORD_MODE").is_ok(); + println!("Record mode: {}", is_record_mode); + + if is_record_mode { + // In record mode, create a real client + println!("Using real client for recording"); + reqwest::Client::builder() + .build() + .expect("Failed to create HTTP client") + } else { + // In replay mode, use mock server with saved responses + if let Ok(cassette_content) = fs::read_to_string(&cassette_path) { + println!("Loading cassette from: {:?}", cassette_path); + let mock_server = MockServer::start().await; + + if let Ok(interactions) = serde_json::from_str::>(&cassette_content) { + for interaction in interactions { + // Set up mock based on saved interaction + Mock::given(wiremock::matchers::any()) + .respond_with(ResponseTemplate::new(200).set_body_json(interaction)) + .mount(&mock_server) + .await; + } + } + + // Create client pointing to mock server + reqwest::Client::builder() + .build() + .expect("Failed to create HTTP client") + } else { + println!("No cassette found, falling back to record mode"); + reqwest::Client::builder() + .build() + .expect("Failed to create HTTP client") + } + } } -fn create_test_provider() -> VertexAIProvider { - let config = ProviderConfig { - key: "test-vertexai".to_string(), - r#type: "vertexai".to_string(), - api_key: "test-api-key".to_string(), - params: HashMap::from([ - ("project_id".to_string(), "test-project".to_string()), - ("location".to_string(), "us-central1".to_string()), - ]), - ..Default::default() - }; +// Helper function to save response to cassette +async fn save_to_cassette(test_name: &str, response: &Value) { + let cassettes_dir = PathBuf::from("tests/cassettes/vertexai"); + let cassette_path = cassettes_dir.join(format!("{}.json", test_name)); + + let mut interactions = Vec::new(); + + // Load existing interactions if any + if let Ok(content) = fs::read_to_string(&cassette_path) { + if let Ok(mut existing) = serde_json::from_str::>(&content) { + interactions.append(&mut existing); + } + } + + // Add new interaction + interactions.push(response.clone()); + + // Save updated cassette + if let Ok(content) = serde_json::to_string_pretty(&interactions) { + if let Err(e) = fs::write(&cassette_path, content) { + println!("Error saving cassette: {}", e); + } else { + println!( + "Successfully saved interaction to cassette: {:?}", + cassette_path + ); + } + } +} + +fn create_test_provider(client: reqwest::Client) -> VertexAIProvider { + let mut params = HashMap::new(); + params.insert("project_id".to_string(), "heavenya".to_string()); + params.insert("location".to_string(), "us-central1".to_string()); + + // Default to service account auth + params.insert("auth_type".to_string(), "service_account".to_string()); + params.insert( + "credentials_path".to_string(), + std::env::var("VERTEXAI_CREDENTIALS_PATH") + .unwrap_or_else(|_| "vertexai-key.json".to_string()), + ); - VertexAIProvider::new(&config) + VertexAIProvider::with_test_client( + &ProviderConfig { + key: "vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "".to_string(), // Empty API key to force service account auth + params, + }, + client, + ) +} + +// Separate function for API key tests +fn create_test_provider_with_api_key(client: reqwest::Client, api_key: String) -> VertexAIProvider { + let mut params = HashMap::new(); + params.insert("project_id".to_string(), "heavenya".to_string()); + params.insert("location".to_string(), "us-central1".to_string()); + params.insert("auth_type".to_string(), "api_key".to_string()); + + VertexAIProvider::with_test_client( + &ProviderConfig { + key: "vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key, + params, + }, + client, + ) +} + +// Helper function to handle quota errors +async fn run_test_with_quota_retry(test_fn: F) -> Result> +where + F: Fn() -> Fut, + Fut: std::future::Future>, +{ + let max_retries = 3; + let retry_delay = std::time::Duration::from_secs( + std::env::var("RETRY_DELAY") + .unwrap_or_else(|_| "60".to_string()) + .parse() + .unwrap_or(60), + ); + + for attempt in 0..max_retries { + match test_fn().await { + Ok(result) => return Ok(result), + Err(status) if status == axum::http::StatusCode::TOO_MANY_REQUESTS => { + if attempt < max_retries - 1 { + println!( + "Quota exceeded, waiting {} seconds before retry...", + retry_delay.as_secs() + ); + tokio::time::sleep(retry_delay).await; + continue; + } + return Err("Quota exceeded after all retries".into()); + } + Err(e) => return Err(format!("Test failed with error: {}", e).into()), + } + } + + Err("Max retries exceeded".into()) } #[tokio::test] async fn test_chat_completions() { - let provider = create_test_provider(); - let model_config = ModelConfig { - key: "gemini-1.5-flash".to_string(), - r#type: "gemini-1.5-flash".to_string(), - provider: "vertexai".to_string(), - ..Default::default() - }; + let client = setup_test_client("chat_completions").await; + let provider = create_test_provider(client); let request = ChatCompletionRequest { model: "gemini-1.5-flash".to_string(), - messages: vec![ChatMessage { + messages: vec![ChatCompletionMessage { role: "user".to_string(), - content: Some("Hello, how are you?".to_string()), - function_call: None, - tool_calls: None, + content: Some(ChatMessageContent::String( + "Hello, how are you?".to_string(), + )), name: None, - tool_call_id: None, + tool_calls: None, }], temperature: Some(0.7), top_p: Some(0.9), - n: Some(1), + n: None, stream: Some(false), stop: None, max_tokens: Some(100), @@ -66,99 +202,215 @@ async fn test_chat_completions() { parallel_tool_calls: None, }; - let response = provider - .chat_completions(request, &model_config) - .await - .unwrap(); - match response { - ChatCompletionResponse::NonStream(resp) => { - assert_eq!(resp["object"], "chat.completion"); - assert!(!resp["choices"].as_array().unwrap().is_empty()); + let model_config = ModelConfig { + key: "gemini-1.5-flash".to_string(), + r#type: "gemini-1.5-flash".to_string(), + provider: "vertexai".to_string(), + params: HashMap::new(), + }; + + let result = run_test_with_quota_retry(|| async { + let response = provider + .chat_completions(request.clone(), &model_config) + .await?; + if std::env::var("RECORD_MODE").is_ok() { + match &response { + ChatCompletionResponse::NonStream(completion) => { + save_to_cassette( + "chat_completions", + &serde_json::to_value(completion).unwrap(), + ) + .await; + } + ChatCompletionResponse::Stream(_) => { + // Handle streaming response if needed + } + } } - _ => panic!("Expected non-stream response"), - } + Ok(response) + }) + .await; + + assert!(result.is_ok(), "Test failed: {:?}", result.err()); } #[tokio::test] -async fn test_completions() { - let provider = create_test_provider(); +async fn test_embeddings() { + let client = setup_test_client("embeddings").await; + let provider = create_test_provider(client); + + let request = EmbeddingsRequest { + model: "text-embedding-005".to_string(), + input: EmbeddingsInput::Single("This is a test sentence.".to_string()), + user: None, + encoding_format: None, + }; + let model_config = ModelConfig { - key: "gemini-1.5-flash".to_string(), - r#type: "gemini-1.5-flash".to_string(), + key: "text-embedding-005".to_string(), + r#type: "text-embedding-005".to_string(), provider: "vertexai".to_string(), - ..Default::default() + params: HashMap::new(), }; + let result = run_test_with_quota_retry(|| async { + let response = provider.embeddings(request.clone(), &model_config).await?; + if std::env::var("RECORD_MODE").is_ok() { + save_to_cassette("embeddings", &serde_json::to_value(&response).unwrap()).await; + } + Ok(response) + }) + .await; + + assert!(result.is_ok(), "Test failed: {:?}", result.err()); +} + +#[tokio::test] +async fn test_completions() { + let client = setup_test_client("completions").await; + let provider = create_test_provider(client); + // ... rest of the test implementation + let request = CompletionRequest { model: "gemini-1.5-flash".to_string(), prompt: "Once upon a time".to_string(), suffix: None, - best_of: None, - logit_bias: None, + max_tokens: Some(100), temperature: Some(0.7), top_p: Some(0.9), - n: Some(1), + n: None, stream: Some(false), + logprobs: None, + echo: None, stop: None, - max_tokens: Some(100), presence_penalty: None, frequency_penalty: None, - logprobs: None, - echo: None, + best_of: None, + logit_bias: None, user: None, }; - let response = provider.completions(request, &model_config).await.unwrap(); - assert_eq!(response.object, "text_completion"); - assert!(!response.choices.is_empty()); -} - -#[tokio::test] -async fn test_embeddings() { - let provider = create_test_provider(); let model_config = ModelConfig { - key: "textembedding-gecko".to_string(), - r#type: "textembedding-gecko".to_string(), + key: "gemini-1.5-flash".to_string(), + r#type: "gemini-1.5-flash".to_string(), provider: "vertexai".to_string(), - ..Default::default() + params: HashMap::new(), }; - let request = EmbeddingsRequest { - model: "textembedding-gecko".to_string(), - input: EmbeddingsInput::Multiple(vec!["This is a test sentence.".to_string()]), - user: None, - encoding_format: Some("float".to_string()), - }; + let result = run_test_with_quota_retry(|| async { + let response = provider.completions(request.clone(), &model_config).await?; + if std::env::var("RECORD_MODE").is_ok() { + save_to_cassette("completions", &serde_json::to_value(&response).unwrap()).await; + } + Ok(response) + }) + .await; - let response = provider.embeddings(request, &model_config).await.unwrap(); - assert_eq!(response.object, "list"); - assert!(!response.data.is_empty()); - assert!(response.data[0]["embedding"].as_array().unwrap().len() > 0); + assert!(result.is_ok(), "Test failed: {:?}", result.err()); } #[tokio::test] async fn test_chat_completions_with_tools() { - let provider = create_test_provider(); + let client = setup_test_client("chat_completions_with_tools").await; + let provider = create_test_provider(client); + + let request = ChatCompletionRequest { + model: "gemini-1.5-flash".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String( + "What's the weather in San Francisco?".to_string(), + )), + name: None, + tool_calls: None, + }], + temperature: Some(0.7), + top_p: Some(0.9), + n: None, + stream: Some(false), + stop: None, + max_tokens: Some(100), + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: Some(vec![ToolDefinition { + tool_type: "function".to_string(), + function: FunctionDefinition { + name: "get_weather".to_string(), + description: Some("Get the current weather in a location".to_string()), + parameters: Some( + serde_json::from_value(json!({ + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The location to get weather for" + } + }, + "required": ["location"] + })) + .unwrap(), + ), + strict: None, + }, + }]), + tool_choice: None, + parallel_tool_calls: None, + }; + let model_config = ModelConfig { key: "gemini-1.5-flash".to_string(), r#type: "gemini-1.5-flash".to_string(), provider: "vertexai".to_string(), - ..Default::default() + params: HashMap::new(), }; + let result = run_test_with_quota_retry(|| async { + let response = provider + .chat_completions(request.clone(), &model_config) + .await?; + if std::env::var("RECORD_MODE").is_ok() { + match &response { + ChatCompletionResponse::NonStream(completion) => { + save_to_cassette( + "chat_completions_with_tools", + &serde_json::to_value(completion).unwrap(), + ) + .await; + } + ChatCompletionResponse::Stream(_) => { + // Handle streaming response if needed + } + } + } + Ok(response) + }) + .await; + + assert!(result.is_ok(), "Test failed: {:?}", result.err()); +} + +#[tokio::test] +#[ignore = "Requires valid API key which is not available yet"] +async fn test_chat_completions_with_api_key() { + let api_key = "test-api-key".to_string(); + let client = setup_test_client("chat_completions_api_key").await; + let provider = create_test_provider_with_api_key(client, api_key); + let request = ChatCompletionRequest { model: "gemini-1.5-flash".to_string(), - messages: vec![ChatMessage { + messages: vec![ChatCompletionMessage { role: "user".to_string(), - content: Some("What's the weather in San Francisco?".to_string()), - function_call: None, - tool_calls: None, + content: Some(ChatMessageContent::String( + "Hello, how are you?".to_string(), + )), name: None, - tool_call_id: None, + tool_calls: None, }], temperature: Some(0.7), top_p: Some(0.9), - n: Some(1), + n: None, stream: Some(false), stop: None, max_tokens: Some(100), @@ -166,56 +418,39 @@ async fn test_chat_completions_with_tools() { frequency_penalty: None, logit_bias: None, user: None, - tools: Some(vec![json!({ - "type": "function", - "function": { - "name": "get_weather", - "description": "Get the current weather in a location", - "parameters": { - "type": "object", - "properties": { - "location": { - "type": "string", - "description": "The location to get weather for" - } - }, - "required": ["location"] - } - } - })]), - tool_choice: Some(json!("auto")), - parallel_tool_calls: Some(1), + tools: None, + tool_choice: None, + parallel_tool_calls: None, + }; + + let model_config = ModelConfig { + key: "gemini-1.5-flash".to_string(), + r#type: "gemini-1.5-flash".to_string(), + provider: "vertexai".to_string(), + params: HashMap::new(), }; - let response = provider - .chat_completions(request, &model_config) - .await - .unwrap(); - match response { - ChatCompletionResponse::NonStream(resp) => { - assert_eq!(resp["object"], "chat.completion"); - let choices = resp["choices"].as_array().unwrap(); - assert!(!choices.is_empty()); - - let first_choice = &choices[0]; - let message = first_choice["message"].as_object().unwrap(); - - // Verify tool calls are present - if let Some(tool_calls) = message.get("tool_calls") { - let tool_calls = tool_calls.as_array().unwrap(); - assert!(!tool_calls.is_empty()); - - let first_call = &tool_calls[0]; - assert_eq!(first_call["type"], "function"); - - let function = first_call["function"].as_object().unwrap(); - assert_eq!(function["name"], "get_weather"); - assert!(function["arguments"] - .as_str() - .unwrap() - .contains("San Francisco")); + let result = run_test_with_quota_retry(|| async { + let response = provider + .chat_completions(request.clone(), &model_config) + .await?; + if std::env::var("RECORD_MODE").is_ok() { + match &response { + ChatCompletionResponse::NonStream(completion) => { + save_to_cassette( + "chat_completions_api_key", + &serde_json::to_value(completion).unwrap(), + ) + .await; + } + ChatCompletionResponse::Stream(_) => { + // Handle streaming response if needed + } } } - _ => panic!("Expected non-stream response"), - } + Ok(response) + }) + .await; + + assert!(result.is_ok(), "Test failed: {:?}", result.err()); } diff --git a/tests/cassettes/vertexai/chat_completions.json b/tests/cassettes/vertexai/chat_completions.json new file mode 100644 index 0000000..b7c67dc --- /dev/null +++ b/tests/cassettes/vertexai/chat_completions.json @@ -0,0 +1,46 @@ +[ + { + "choices": [ + { + "finish_reason": "STOP", + "index": 0, + "message": { + "content": "I am an AI language model, so I don't have feelings like humans do. But I am here and ready to assist you with any questions or tasks you may have! How can I help you today? 😊 \n", + "role": "assistant" + } + } + ], + "created": 1735633379, + "id": "chatcmpl-66e406c3-5b89-401d-a0cd-567f22db76d4", + "model": "gemini-1.5-flash", + "object": "chat.completion", + "system_fingerprint": null, + "usage": { + "completion_tokens": 46, + "prompt_tokens": 6, + "total_tokens": 52 + } + }, + { + "choices": [ + { + "finish_reason": "STOP", + "index": 0, + "message": { + "content": "I am an AI language model, so I don't have feelings or experiences like humans do. However, I am here to assist you with any questions or tasks you may have! 😊 How can I help you today? \n", + "role": "assistant" + } + } + ], + "created": 1735633515, + "id": "chatcmpl-b3a3f424-17c0-4c84-a27e-35f7ffd5fca0", + "model": "gemini-1.5-flash", + "object": "chat.completion", + "system_fingerprint": null, + "usage": { + "completion_tokens": 47, + "prompt_tokens": 6, + "total_tokens": 53 + } + } +] \ No newline at end of file diff --git a/tests/cassettes/vertexai/chat_completions_with_tools.json b/tests/cassettes/vertexai/chat_completions_with_tools.json new file mode 100644 index 0000000..8694d5c --- /dev/null +++ b/tests/cassettes/vertexai/chat_completions_with_tools.json @@ -0,0 +1,24 @@ +[ + { + "choices": [ + { + "finish_reason": "STOP", + "index": 0, + "message": { + "content": "", + "role": "assistant" + } + } + ], + "created": 1735633514, + "id": "chatcmpl-a513c04e-4300-416f-bc7c-5933229027d6", + "model": "gemini-1.5-flash", + "object": "chat.completion", + "system_fingerprint": null, + "usage": { + "completion_tokens": 6, + "prompt_tokens": 27, + "total_tokens": 33 + } + } +] \ No newline at end of file diff --git a/tests/cassettes/vertexai/completions.json b/tests/cassettes/vertexai/completions.json new file mode 100644 index 0000000..657a140 --- /dev/null +++ b/tests/cassettes/vertexai/completions.json @@ -0,0 +1,20 @@ +[ + { + "choices": [ + { + "finish_reason": "STOP", + "index": 0, + "text": "Once upon a time, in a village nestled between rolling hills and a whispering river, lived a young girl named Elara. Elara wasn't like the other children. While they played with dolls and chased butterflies, Elara spent her days lost in the pages of dusty old books, her imagination soaring with tales of faraway lands and fantastical creatures. \n\nWhat would you like to happen next? \n" + } + ], + "created": 1735633515, + "id": "chatcmpl-99881c18-33ac-430b-b788-4a5cea4dce3e", + "model": "gemini-1.5-flash", + "object": "text_completion", + "usage": { + "completion_tokens": 0, + "prompt_tokens": 0, + "total_tokens": 0 + } + } +] \ No newline at end of file diff --git a/tests/cassettes/vertexai/embeddings.json b/tests/cassettes/vertexai/embeddings.json new file mode 100644 index 0000000..1f11354 --- /dev/null +++ b/tests/cassettes/vertexai/embeddings.json @@ -0,0 +1,787 @@ +[ + { + "data": [ + { + "embedding": [ + -0.058164194226264954, + -0.00003622031363192946, + 0.010542492382228374, + -0.004728350788354874, + 0.07369722425937653, + -0.024816956371068954, + -0.00031316516106016934, + -0.017290938645601273, + 0.03166302293539047, + 0.014893381856381893, + -0.04859609156847, + -0.05490480735898018, + -0.005848468281328678, + -0.06573579460382462, + -0.013973977416753769, + 0.03232813626527786, + 0.07840143144130707, + -0.05846800282597542, + -0.041564371436834335, + -0.017742950469255447, + 0.022528981789946556, + -0.05958662927150726, + -0.0955798402428627, + -0.009678563103079796, + 0.044648200273513794, + -0.043353594839572906, + -0.01671011932194233, + -0.02975669503211975, + -0.05829453468322754, + -0.0157438013702631, + 0.0006426912150345743, + -0.05014248937368393, + 0.011643724516034126, + -0.0007280845893546939, + 0.03767689689993858, + -0.010895035229623318, + 0.033650316298007965, + -0.037673596292734146, + 0.018698105588555336, + -0.03840488940477371, + 0.03343287855386734, + -0.05688348412513733, + -0.012943455018103123, + -0.0692962184548378, + -0.03782666474580765, + 0.010393713600933552, + -0.025529509410262108, + 0.01568876951932907, + 0.07156006246805191, + -0.014751105569303036, + 0.08142535388469696, + 0.029754770919680595, + -0.007077757269144058, + 0.031249215826392174, + 0.022206788882613182, + 0.05383630096912384, + 0.005256577394902706, + -0.013356782495975494, + 0.008688163012266159, + 0.02924143336713314, + -0.026365751400589943, + -0.036567822098731995, + 0.013740355148911476, + 0.0014254077104851604, + -0.04947865009307861, + -0.01049752440303564, + -0.007019080687314272, + -0.0033643722999840975, + -0.0020064576528966427, + -0.07127232104539871, + -0.05643607676029205, + -0.007050491403788328, + 0.005696943495422602, + 0.0319971963763237, + -0.045856233686208725, + -0.0382072851061821, + 0.024022594094276428, + 0.07401637732982635, + -0.01796848513185978, + -0.023768220096826553, + -0.059311170130968094, + -0.020010419189929962, + -0.053349319845438004, + 0.0029365948867052794, + 0.010357838124036789, + -0.03372623398900032, + 0.005034816917032003, + -0.06332722306251526, + 0.0042638652957975864, + -0.015453161671757698, + -0.039690133184194565, + -0.020585861057043076, + -0.08410325646400452, + -0.020636729896068573, + 0.022761065512895584, + -0.02659504860639572, + 0.008869532495737076, + 0.06127539649605751, + 0.016054663807153702, + 0.01801091432571411, + -0.0068725040182471275, + 0.038399890065193176, + -0.01656283810734749, + -0.02084347791969776, + 0.008902153931558132, + 0.06902532279491425, + -0.0018741635140031576, + -0.04490096867084503, + 0.06339003145694733, + -0.017102815210819244, + -0.057325396686792374, + 0.022083261981606483, + -0.04266951605677605, + 0.019720112904906273, + 0.05673870071768761, + 0.02355301007628441, + -0.04308970272541046, + 0.0002606247435323894, + -0.00685822544619441, + -0.03939145803451538, + -0.026901816949248314, + -0.055103152990341187, + 0.10295083373785019, + 0.046327341347932816, + 0.0023325744550675154, + 0.018498506397008896, + -0.06048314645886421, + -0.013803904876112938, + 0.03132600709795952, + -0.006520519964396954, + 0.028858399018645287, + -0.04834062233567238, + 0.04562418535351753, + 0.07403726130723953, + 0.0036133721005171537, + -0.011329884640872478, + -0.0112222321331501, + -0.008675935678184032, + 0.016003990545868874, + 0.02360924705862999, + -0.03237585723400116, + 0.062091924250125885, + 0.0534723736345768, + 0.06908244639635086, + 0.01992947794497013, + -0.021924395114183426, + -0.08472655713558197, + 0.010171602480113506, + 0.013133247382938862, + -0.025234723463654518, + -0.06846307218074799, + 0.0004721606965176761, + -0.02166888676583767, + -0.0005694524152204394, + -0.008681336417794228, + -0.05947762727737427, + -0.04814690351486206, + -0.013798982836306095, + 0.01617482490837574, + -0.025046436116099358, + 0.009110392071306705, + -0.013774625957012177, + -0.019712207838892937, + -0.016054371371865273, + -0.018327657133340836, + -0.012811604887247086, + 0.08344585448503494, + 0.0004540338122751564, + 0.019656607881188393, + 0.019389579072594643, + -0.014049646444618702, + 0.017445947974920273, + -0.00820555817335844, + -0.029353104531764984, + 0.0435597263276577, + 0.009650807827711105, + -0.0388045459985733, + -0.04784759134054184, + -0.038223911076784134, + -0.03691287711262703, + -0.03876909241080284, + -0.06724806874990463, + -0.04394567012786865, + 0.04173814505338669, + -0.09444724023342133, + 0.007763924542814493, + -0.008699805475771427, + -0.007599780336022377, + 0.0023920757230371237, + 0.029335761442780495, + -0.07895313203334808, + -0.040355466306209564, + -0.008500908501446247, + 0.030348196625709534, + 0.022775812074542046, + 0.05779244005680084, + 0.049121756106615067, + -0.005412466358393431, + 0.007729559671133757, + -0.01292573381215334, + -0.025097647681832314, + 0.004094319883733988, + 0.06612378358840942, + -0.019531669095158577, + -0.005063635762780905, + -0.005468557123094797, + 0.07955626398324966, + -0.002157465321943164, + 0.009207960218191147, + -0.06414847075939178, + -0.0035572517663240433, + -0.0020771902054548264, + -0.1227332055568695, + -0.03706011176109314, + 0.0008404941763728857, + -0.046963952481746674, + 0.040122631937265396, + -0.027263401076197624, + 0.016582122072577477, + 0.04703010618686676, + 0.03132076933979988, + -0.010051103308796883, + -0.03994416818022728, + 0.05056227371096611, + -0.005183490924537182, + -0.03397025540471077, + 0.05630888789892197, + -0.00752260722219944, + 0.056935470551252365, + -0.019262658432126045, + -0.005856715142726898, + -0.00361971789970994, + 0.014742489904165268, + -0.0173240564763546, + 0.025849811732769012, + -0.03633483499288559, + 0.05162259563803673, + -0.024835949763655663, + -0.04847341403365135, + -0.03159399703145027, + -0.03467343747615814, + 0.036358628422021866, + -0.03581903874874115, + 0.002909073606133461, + -0.06491775810718536, + 0.022639712318778038, + 0.0016398467123508453, + 0.02446398138999939, + -0.07746433466672897, + -0.006726226769387722, + -0.000519428460393101, + -0.039504919201135635, + -0.005563349928706884, + -0.020594995468854904, + 0.061375197023153305, + -0.04385501146316528, + -0.020819365978240967, + 0.0002135665708919987, + 0.0025394882541149855, + 0.03940146788954735, + 0.04535587877035141, + 0.022408338263630867, + 0.010107740759849548, + -0.029103688895702362, + 0.023004544898867607, + -0.0777907446026802, + -0.039951570332050323, + -0.007604190148413181, + -0.01633376069366932, + 0.03180794045329094, + -0.001723665394820273, + 0.008649897761642933, + 0.0242207832634449, + -0.010647157207131386, + -0.026367707177996635, + 0.04031673073768616, + -0.05165720731019974, + -0.03284695744514465, + -0.02335844747722149, + -0.03349415957927704, + 0.025802014395594597, + -0.03694309666752815, + -0.006044459994882345, + 0.06736567616462708, + 0.01603505201637745, + -0.02328784205019474, + -0.012791356071829796, + 0.013516776263713837, + -0.03699612617492676, + 0.01060064509510994, + 0.00883965939283371, + -0.009064657613635063, + 0.0350169874727726, + -0.02685544267296791, + -0.014185672625899315, + 0.016354434192180634, + 0.036822687834501266, + 0.023291006684303284, + -0.059676602482795715, + 0.018569037318229675, + -0.035254210233688354, + 0.03186021000146866, + -0.006412920076400042, + 0.006461815442889929, + -0.0018794521456584334, + -0.004147578962147236, + -0.011934665031731129, + -0.0030684741213917732, + -0.011600416153669357, + 0.014210240915417671, + 0.035710278898477554, + -0.0347076840698719, + 0.024610867723822594, + -0.02708994224667549, + -0.05045025795698166, + -0.010565407574176788, + -0.033687181770801544, + -0.02122747339308262, + -0.04409955069422722, + -0.0030694238375872374, + 0.044485583901405334, + -0.05378193408250809, + 0.072037473320961, + -0.07409116625785828, + 0.015786299481987953, + -0.06721299141645432, + 0.025938687846064568, + 0.010510837659239769, + -0.023115744814276695, + -0.03091544844210148, + 0.050648219883441925, + 0.035482946783304214, + 0.04307528957724571, + -0.04726636782288551, + -0.04310080036520958, + -0.013828760012984276, + 0.048286303877830505, + -0.02076721377670765, + -0.01085709035396576, + -0.03584962338209152, + -0.014488843269646168, + -0.0027554789558053017, + -0.06005162000656128, + 0.04566371068358421, + -0.08098234236240387, + -0.0007054588641040027, + 0.023113127797842026, + 0.013891058973968029, + -0.06299350410699844, + 0.013442540541291237, + -0.0063631776720285416, + 0.03821553662419319, + 0.042192913591861725, + -0.011878528632223606, + 0.025002310052514076, + -0.03168347105383873, + 0.00921724271029234, + 0.05588514357805252, + -0.019194696098566055, + -0.013231540098786354, + 0.013922672718763351, + 0.050090741366147995, + -0.009419753216207027, + 0.030472371727228165, + 0.02902497723698616, + 0.00012655452883336693, + 0.02010628953576088, + -0.017804551869630814, + 0.02543807215988636, + -0.0017418548231944442, + 0.03014679066836834, + -0.002393407514318824, + 0.015390272252261639, + -0.013939744792878628, + 0.04250369220972061, + -0.028016269207000732, + -0.0010314607061445713, + 0.00945567712187767, + 0.01606564037501812, + 0.03212505206465721, + 0.02634749934077263, + -0.04875859245657921, + -0.02948666177690029, + -0.010389791801571846, + -0.027319002896547318, + 0.008594093844294548, + -0.0005823180545121431, + 0.054062556475400925, + 0.0035941607784479856, + 0.0543292835354805, + -0.004254109226167202, + 0.08106452226638794, + 0.00023218353453557938, + 0.008525514975190163, + 0.010739163495600224, + -0.06044655293226242, + 0.027405254542827606, + 0.024431807920336723, + -0.07784923911094666, + -0.011249307543039322, + 0.042149681597948074, + 0.05080077797174454, + 0.012841291725635529, + -0.018699713051319122, + -0.0298676285892725, + -0.030107680708169937, + 0.007617079187184572, + -0.03927510604262352, + 0.005952583160251379, + -0.04362985119223595, + -0.056472595781087875, + -0.05122603103518486, + 0.030536439269781113, + 0.06711754202842712, + 0.030769379809498787, + -0.08917279541492462, + 0.030519621446728706, + -0.018731193616986275, + 0.025107961148023605, + -0.04443630948662758, + -0.03170761838555336, + 0.05583782494068146, + 0.028091464191675186, + 0.022955838590860367, + 0.033636752516031265, + -0.025316791608929634, + -0.012428611516952515, + 0.019952984526753426, + 0.02082655392587185, + 0.07539939135313034, + -0.06182907521724701, + 0.02644423581659794, + -0.0031414111144840717, + -0.03931447118520737, + 0.03972741961479187, + -0.06503785401582718, + -0.02640126273036003, + -0.026757026091217995, + 0.02259722352027893, + -0.026944443583488464, + -0.04200126603245735, + 0.06589224189519882, + -0.0060363225638866425, + 0.014422483742237091, + -0.047794267535209656, + -0.03258788213133812, + 0.0013760939473286271, + -0.009353984147310257, + 0.012716212309896946, + 0.04360601305961609, + 0.0045635453425347805, + 0.038450006395578384, + 0.032771769911050797, + 0.0030687032267451286, + -0.04321933165192604, + 0.006499011069536209, + 0.0028769823256880045, + 0.012420333921909332, + 0.013525757007300854, + -0.006150753237307072, + -0.004118023905903101, + 0.023745615035295486, + -0.042544446885585785, + 0.01779933273792267, + 0.0738072544336319, + -0.03007355146110058, + -0.009512661024928093, + -0.03289958834648132, + -0.004790752660483122, + 0.0004558037326205522, + 0.0720517635345459, + -0.06180300563573837, + -0.0042299022898077965, + 0.00017941815895028412, + 0.026685943827033043, + 0.0046829464845359325, + -0.0006890723598189652, + 0.008649819530546665, + -0.019310785457491875, + 0.03345974162220955, + -0.02027411200106144, + 0.0454903170466423, + 0.004120772238820791, + -0.028732268139719963, + 0.002070050220936537, + 0.03910873085260391, + -0.034626252949237823, + -0.06625950336456299, + -0.057161930948495865, + -0.027074122801423073, + -0.03852885961532593, + 0.036027777940034866, + -0.03378047049045563, + -0.04209835082292557, + 0.02349921129643917, + 0.039603881537914276, + 0.0015966565115377307, + -0.003795675467699766, + 0.008811083622276783, + -0.028914688155055046, + -0.08621173352003098, + 0.030727021396160126, + -0.04263502359390259, + 0.0518559105694294, + -0.014513948932290077, + 0.00426185317337513, + -0.042820628732442856, + 0.061024997383356094, + 0.008177947252988815, + -0.025654304772615433, + -0.019947586581110954, + 0.031153390184044838, + -0.06122246012091637, + -0.00973520614206791, + 0.026119912043213844, + 0.018067168071866035, + 0.046298809349536896, + -0.0637248307466507, + -0.003924540244042873, + 0.05164488032460213, + -0.03986351564526558, + 0.012143593281507492, + -0.01493164524435997, + 0.012364163994789124, + 0.0033910535275936127, + 0.03926117718219757, + 0.0160888209939003, + 0.022147519513964653, + 0.040994029492139816, + 0.03238851949572563, + 0.031068911775946617, + -0.0019339561695232987, + -0.04030238837003708, + 0.018413899466395378, + 0.009558942168951035, + 0.024898380041122437, + -0.02646373026072979, + -0.027966918423771858, + 0.038518164306879044, + -0.018016686663031578, + 0.011690342798829079, + -0.041716981679201126, + -0.012398135848343372, + -0.040918245911598206, + 0.049635518342256546, + 0.019493695348501205, + 0.010355286300182343, + -0.005950144957751036, + -0.022309331223368645, + -0.043080415576696396, + 0.0156959630548954, + 0.01119300164282322, + -0.008492423221468925, + 0.014949626289308071, + -0.053723081946372986, + 0.027443569153547287, + 0.03662879765033722, + -0.03641078248620033, + 0.04629331827163696, + 0.004617750179022551, + -0.03654378652572632, + 0.013454713858664036, + 0.0032841702923178673, + -0.01309528760612011, + -0.0006306404829956591, + -0.010712265968322754, + -0.0031115366145968437, + 0.06719954311847687, + -0.041091009974479675, + 0.052047744393348694, + 0.015360930003225803, + 0.017123648896813393, + -0.016294341534376144, + 0.04660823196172714, + -0.024207523092627525, + -0.04300165921449661, + -0.051081202924251556, + 0.09737501293420792, + -0.01331926416605711, + 0.06842294335365295, + -0.002399123040959239, + 0.012122059240937233, + 0.06719434261322021, + -0.05437808856368065, + 0.004240202717483044, + -0.027191925793886185, + -0.040218885987997055, + -0.023750977590680122, + 0.012262600474059582, + 0.014219674281775951, + -0.006157959345728159, + 0.011399772949516773, + -0.05200403183698654, + -0.017264649271965027, + 0.016833636909723282, + -0.009583424776792526, + -0.03376639261841774, + -0.00961976870894432, + 0.001210652757436037, + -0.0612335205078125, + -0.0336930938065052, + -0.025393076241016388, + -0.02714981697499752, + 0.004886742681264877, + 0.013395018875598907, + -0.02571096643805504, + -0.03276616707444191, + -0.030069544911384583, + 0.036591000854969025, + -0.07458269596099854, + 0.057440709322690964, + 0.028478343039751053, + -0.0028876815922558308, + 0.026391824707388878, + 0.018080219626426697, + 0.04396456852555275, + 0.003018079325556755, + -0.03397033363580704, + -0.02141541987657547, + 0.010896582156419754, + -0.03434125706553459, + -0.05253784731030464, + -0.025020217522978783, + -0.005296454764902592, + 0.019587192684412003, + 0.037847407162189484, + -0.01990439184010029, + 0.02046854794025421, + -0.02455652691423893, + -0.020822890102863312, + 0.003083446528762579, + 0.07859235256910324, + -0.08430628478527069, + -0.02872663363814354, + 0.05072060227394104, + 0.043463632464408875, + 0.017734138295054436, + -0.04160630330443382, + -0.04641241580247879, + -0.02498893067240715, + -0.03297220170497894, + -0.09785742312669754, + -0.006121875252574682, + -0.022711746394634247, + -0.01429930329322815, + -0.00412411242723465, + 0.007504432462155819, + -0.000563237292226404, + 0.01013818196952343, + -0.06896454840898514, + 0.006575733423233032, + -0.10310959815979004, + -0.012512778863310814, + 0.03036043606698513, + -0.015878431499004364, + 0.022684166207909584, + 0.020660221576690674, + 0.016029203310608864, + -0.028443187475204468, + -0.014166068285703659, + 0.0071391211822628975, + 0.034776851534843445, + 0.002298222854733467, + 0.033520814031362534, + 0.05799320712685585, + -0.0030665509402751923, + 0.013703178614377975, + 0.04346451908349991, + -0.08736324310302734, + -0.04443465545773506, + -0.09507574141025543, + -0.007938905619084835, + 0.005520000122487545, + -0.043095000088214874, + -0.03352028876543045, + 0.021385299041867256, + 0.02366030216217041, + -0.02853614091873169, + 0.002117573283612728, + 0.055353257805109024, + 0.027501529082655907, + -0.015763575211167336, + 0.0570647306740284, + -0.029892882332205772, + 0.02390587143599987, + -0.013306232169270515, + 0.018932240083813667, + 0.0071633001789450645, + 0.006233749445527792, + 0.03482261300086975, + -0.0009497640421614051, + 0.04889736324548721, + -0.010756379924714565, + -0.10233137756586075, + 0.032568227499723434, + -0.0017232495592907071, + 0.0197619441896677, + -0.01157362200319767, + -0.022340090945363045, + 0.03321876749396324, + -0.03730887547135353, + -0.004980842582881451, + 0.031003642827272415, + 0.04853849858045578, + 0.00792314950376749, + -0.016585927456617355, + -0.00377306598238647, + 0.009732725098729134, + -0.026165375486016273, + 0.0068840766325592995, + 0.02659326232969761, + -0.005413031205534935, + -0.0209831390529871, + -0.029614845290780067, + 0.01654200442135334, + -0.03843202814459801, + 0.016572654247283936, + -0.022821595892310143, + 0.02077091671526432, + -0.033952746540308, + 0.06542537361383438, + -0.08189623057842255, + 0.0031411293894052505, + -0.01395489927381277, + 0.01906730607151985, + -0.05683666840195656, + -0.03671567142009735, + 0.001987523166462779, + 0.006716572213917971, + 0.058880213648080826, + -0.028976114466786385, + -0.10136104375123978, + -0.01454504206776619, + -0.06632363796234131, + 0.012023151852190495, + -0.039696235209703445, + -0.10271679610013962, + -0.00566994259133935, + -0.011019215919077396, + 0.022908398881554604, + 0.00902929063886404, + -0.02031330019235611, + 0.02893255092203617, + -0.020042693242430687, + -0.02361901104450226, + 0.038222216069698334, + 0.008589942008256912, + 0.03230403736233711, + 0.0024544389452785254, + 0.004391937050968409, + -0.0484878346323967, + -0.002869164338335395, + -0.05096660554409027, + -0.028733370825648308, + 0.03479108586907387, + 0.03205372020602226, + -0.004485339857637882, + 0.017057575285434723, + 0.0132388761267066, + -0.04253086820244789, + 0.021169882267713547, + -0.008464457467198372, + -0.009780851192772388, + 0.02306952327489853, + -0.04061064124107361, + 0.014021733775734901, + -0.003301902674138546, + 0.005067829042673111 + ], + "index": 0, + "object": "embedding" + } + ], + "model": "text-embedding-005", + "object": "list", + "usage": { + "completion_tokens": 0, + "prompt_tokens": 0, + "total_tokens": 0 + } + } +] \ No newline at end of file From b26628c62667e8ff7979d02cdd27edcae2d036a8 Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Tue, 31 Dec 2024 15:50:51 +0100 Subject: [PATCH 4/9] fix(vertexai): enforce required project_id and improve endpoint formatting - Changed project_id retrieval to use expect for mandatory parameter. - Updated location retrieval to use unwrap_or for default value. - Modified endpoint formatting to dynamically include location in the URL for both chat and embeddings requests. - Refactored test provider setup to use constants for project_id and location. --- src/providers/vertexai/provider.rs | 14 ++++++++------ src/providers/vertexai/tests.rs | 12 ++++++++---- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/providers/vertexai/provider.rs b/src/providers/vertexai/provider.rs index b814296..88efaa9 100644 --- a/src/providers/vertexai/provider.rs +++ b/src/providers/vertexai/provider.rs @@ -75,11 +75,13 @@ impl Provider for VertexAIProvider { let project_id = config .params .get("project_id") - .map_or_else(|| "test-project".to_string(), |v| v.to_string()); + .expect("project_id is required for VertexAI provider") + .to_string(); let location = config .params .get("location") - .map_or_else(|| "us-central1".to_string(), |v| v.to_string()); + .unwrap_or(&"us-central1".to_string()) + .to_string(); Self { config: config.clone(), @@ -103,8 +105,8 @@ impl Provider for VertexAIProvider { ) -> Result { let auth_token = self.get_auth_token().await?; let endpoint = format!( - "https://us-central1-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:streamGenerateContent", - self.project_id, self.location, payload.model + "https://{}-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:streamGenerateContent", + self.location, self.project_id, self.location, payload.model ); let response = self @@ -285,8 +287,8 @@ impl Provider for VertexAIProvider { ) -> Result { let auth_token = self.get_auth_token().await?; let endpoint = format!( - "https://us-central1-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:predict", - self.project_id, self.location, payload.model + "https://{}-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:predict", + self.location, self.project_id, self.location, payload.model ); let response = self diff --git a/src/providers/vertexai/tests.rs b/src/providers/vertexai/tests.rs index 6466de5..9f36318 100644 --- a/src/providers/vertexai/tests.rs +++ b/src/providers/vertexai/tests.rs @@ -14,6 +14,10 @@ use crate::models::embeddings::{EmbeddingsInput, EmbeddingsRequest}; use crate::models::tool_definition::{FunctionDefinition, ToolDefinition}; use crate::providers::provider::Provider; +// Test constants +const TEST_PROJECT_ID: &str = "heavenya"; +const TEST_LOCATION: &str = "us-central1"; + async fn setup_test_client(test_name: &str) -> reqwest::Client { // Create the cassettes directory if it doesn't exist let cassettes_dir = PathBuf::from("tests/cassettes/vertexai"); @@ -97,8 +101,8 @@ async fn save_to_cassette(test_name: &str, response: &Value) { fn create_test_provider(client: reqwest::Client) -> VertexAIProvider { let mut params = HashMap::new(); - params.insert("project_id".to_string(), "heavenya".to_string()); - params.insert("location".to_string(), "us-central1".to_string()); + params.insert("project_id".to_string(), TEST_PROJECT_ID.to_string()); + params.insert("location".to_string(), TEST_LOCATION.to_string()); // Default to service account auth params.insert("auth_type".to_string(), "service_account".to_string()); @@ -122,8 +126,8 @@ fn create_test_provider(client: reqwest::Client) -> VertexAIProvider { // Separate function for API key tests fn create_test_provider_with_api_key(client: reqwest::Client, api_key: String) -> VertexAIProvider { let mut params = HashMap::new(); - params.insert("project_id".to_string(), "heavenya".to_string()); - params.insert("location".to_string(), "us-central1".to_string()); + params.insert("project_id".to_string(), TEST_PROJECT_ID.to_string()); + params.insert("location".to_string(), TEST_LOCATION.to_string()); params.insert("auth_type".to_string(), "api_key".to_string()); VertexAIProvider::with_test_client( From a3816642c9e092b5d8307f558f42541e374e1efd Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Tue, 31 Dec 2024 18:08:14 +0100 Subject: [PATCH 5/9] feat(vertexai): add location validation and unit comprehensive tests - Introduced a new method `validate_location` to sanitize and validate location input, defaulting to "us-central1" if invalid. - Updated the provider initialization to utilize the new location validation method. - Added extensive unit tests for the provider, covering various scenarios including location validation, request conversion, and handling of empty messages. - Ensured that invalid characters in location parameters are filtered out correctly. - Enhanced tests to verify the precedence of API key over credentials path in configuration. This commit improves the robustness of the VertexAIProvider by ensuring valid location formats and enhancing test coverage. --- src/providers/vertexai/provider.rs | 488 ++++++++++++++++++++++++++++- 1 file changed, 486 insertions(+), 2 deletions(-) diff --git a/src/providers/vertexai/provider.rs b/src/providers/vertexai/provider.rs index 88efaa9..d01fe35 100644 --- a/src/providers/vertexai/provider.rs +++ b/src/providers/vertexai/provider.rs @@ -25,6 +25,20 @@ pub struct VertexAIProvider { } impl VertexAIProvider { + fn validate_location(location: &str) -> String { + // Only allow alphanumeric and hyphen characters + let sanitized: String = location + .chars() + .filter(|c| c.is_alphanumeric() || *c == '-') + .collect(); + + if sanitized.is_empty() { + "us-central1".to_string() // Default if invalid + } else { + sanitized + } + } + async fn get_auth_token(&self) -> Result { println!("Getting auth token..."); if !self.config.api_key.is_empty() { @@ -80,8 +94,8 @@ impl Provider for VertexAIProvider { let location = config .params .get("location") - .unwrap_or(&"us-central1".to_string()) - .to_string(); + .map(|l| Self::validate_location(l)) + .unwrap_or_else(|| "us-central1".to_string()); Self { config: config.clone(), @@ -90,6 +104,7 @@ impl Provider for VertexAIProvider { location, } } + fn key(&self) -> String { self.config.key.clone() } @@ -386,4 +401,473 @@ impl VertexAIProvider { location, } } + + +} + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashMap; + use crate::models::content::{ChatMessageContent, ChatMessageContentPart}; + use crate::models::tool_choice::{ToolChoice, SimpleToolChoice}; + use crate::models::tool_definition::{ToolDefinition, FunctionDefinition}; + use crate::models::vertexai::{GeminiFunctionCall, GeminiToolCall, GeminiToolChoice}; + + #[test] + fn test_provider_new() { + // Test with minimum required config + let mut params = HashMap::new(); + params.insert("project_id".to_string(), "test-project".to_string()); + + let config = ProviderConfig { + key: "test-vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "".to_string(), + params, + }; + + let provider = VertexAIProvider::new(&config); + assert_eq!(provider.project_id, "test-project"); + assert_eq!(provider.location, "us-central1"); // default location + } + + #[test] + #[should_panic(expected = "project_id is required")] + fn test_provider_new_missing_project_id() { + let config = ProviderConfig { + key: "test-vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "".to_string(), + params: HashMap::new(), + }; + + VertexAIProvider::new(&config); + } + + #[test] + fn test_gemini_request_conversion() { + let chat_request = ChatCompletionRequest { + model: "gemini-1.5-flash".to_string(), + messages: vec![ + ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String("Hello".to_string())), + name: None, + tool_calls: None, + } + ], + temperature: Some(0.7), + top_p: Some(0.9), + n: None, + stream: Some(false), + stop: None, + max_tokens: Some(100), + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + }; + + let gemini_request = GeminiChatRequest::from_openai(chat_request); + + assert_eq!(gemini_request.contents[0].parts[0].text, "Hello"); + assert_eq!(gemini_request.contents[0].role, "user"); + assert_eq!(gemini_request.generation_config.as_ref().unwrap().temperature, Some(0.7)); + assert_eq!(gemini_request.generation_config.as_ref().unwrap().top_p, Some(0.9)); + } + + #[test] + fn test_gemini_response_conversion() { + let gemini_response = GeminiChatResponse { + candidates: vec![GeminiCandidate { + content: GeminiContent { + role: "model".to_string(), + parts: vec![ContentPart { + text: "Hello there!".to_string(), + }], + }, + finish_reason: Some("STOP".to_string()), + safety_ratings: None, + tool_calls: None, + }], + usage_metadata: Some(UsageMetadata { + prompt_token_count: 10, + candidates_token_count: 20, + total_token_count: 30, + }), + }; + + let model = "gemini-1.5-flash".to_string(); + let openai_response = gemini_response.to_openai(model.clone()); + + assert_eq!(openai_response.model, model); + match &openai_response.choices[0].message.content { + Some(ChatMessageContent::String(text)) => assert_eq!(text, "Hello there!"), + _ => panic!("Expected String content"), + } + assert_eq!(openai_response.choices[0].finish_reason, Some("STOP".to_string())); + assert_eq!(openai_response.usage.prompt_tokens, 10); + assert_eq!(openai_response.usage.completion_tokens, 20); + assert_eq!(openai_response.usage.total_tokens, 30); + } + + #[test] + fn test_gemini_request_with_tools() { + let chat_request = ChatCompletionRequest { + model: "gemini-1.5-flash".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String("Hello".to_string())), + name: None, + tool_calls: None, + }], + temperature: Some(0.7), + tools: Some(vec![ToolDefinition { + tool_type: "function".to_string(), + function: FunctionDefinition { + name: "test_function".to_string(), + description: Some("Test function".to_string()), + parameters: Some(serde_json::from_value(serde_json::json!({ + "type": "object", + "properties": { + "test": { + "type": "string" + } + } + })).unwrap()), + strict: None, + }, + }]), + tool_choice: Some(ToolChoice::Simple(SimpleToolChoice::Auto)), + top_p: None, + n: None, + stream: None, + stop: None, + max_tokens: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + parallel_tool_calls: None, + }; + + let gemini_request = GeminiChatRequest::from_openai(chat_request); + + assert!(gemini_request.tools.is_some()); + let tools = gemini_request.tools.unwrap(); + assert_eq!(tools[0].function_declarations[0].name, "test_function"); + } + + #[test] + fn test_gemini_response_with_tool_calls() { + let gemini_response = GeminiChatResponse { + candidates: vec![GeminiCandidate { + content: GeminiContent { + role: "model".to_string(), + parts: vec![ContentPart { + text: "Using weather function".to_string(), + }], + }, + finish_reason: Some("STOP".to_string()), + safety_ratings: None, + tool_calls: Some(vec![GeminiToolCall { + function: GeminiFunctionCall { + name: "get_weather".to_string(), + arguments: r#"{"location":"San Francisco"}"#.to_string(), + }, + }]), + }], + usage_metadata: Some(UsageMetadata { + prompt_token_count: 10, + candidates_token_count: 20, + total_token_count: 30, + }), + }; + + let model = "gemini-1.5-flash".to_string(); + let openai_response = gemini_response.to_openai(model.clone()); + + assert!(openai_response.choices[0].message.tool_calls.is_some()); + let tool_calls = openai_response.choices[0].message.tool_calls.as_ref().unwrap(); + assert_eq!(tool_calls[0].function.name, "get_weather"); + assert_eq!(tool_calls[0].function.arguments, r#"{"location":"San Francisco"}"#); + } + + #[test] + fn test_gemini_request_with_system_message() { + let chat_request = ChatCompletionRequest { + model: "gemini-1.5-flash".to_string(), + messages: vec![ + ChatCompletionMessage { + role: "system".to_string(), + content: Some(ChatMessageContent::String("You are a helpful assistant".to_string())), + name: None, + tool_calls: None, + }, + ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String("Hello".to_string())), + name: None, + tool_calls: None, + } + ], + temperature: None, + top_p: None, + n: None, + stream: None, + stop: None, + max_tokens: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + }; + + let gemini_request = GeminiChatRequest::from_openai(chat_request); + + // Verify system message is handled correctly + assert_eq!(gemini_request.contents.len(), 2); + assert_eq!(gemini_request.contents[0].role, "system"); + } + + #[test] + fn test_gemini_request_with_array_content() { + let chat_request = ChatCompletionRequest { + model: "gemini-1.5-flash".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::Array(vec![ + ChatMessageContentPart { + r#type: "text".to_string(), + text: "Part 1".to_string(), + }, + ChatMessageContentPart { + r#type: "text".to_string(), + text: "Part 2".to_string(), + }, + ])), + name: None, + tool_calls: None, + }], + temperature: None, + top_p: None, + n: None, + stream: None, + stop: None, + max_tokens: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + }; + + let gemini_request = GeminiChatRequest::from_openai(chat_request); + + assert_eq!(gemini_request.contents[0].parts[0].text, "Part 1 Part 2"); + } + + #[test] + fn test_invalid_location_format() { + let mut params = HashMap::new(); + params.insert("project_id".to_string(), "test-project".to_string()); + params.insert("location".to_string(), "invalid@location".to_string()); + + let config = ProviderConfig { + key: "test-vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "".to_string(), + params, + }; + + let provider = VertexAIProvider::new(&config); + assert_eq!(provider.location, "invalidlocation"); // @ should be removed + } + + #[test] + fn test_location_validation() { + assert_eq!( + VertexAIProvider::validate_location("us-central1"), + "us-central1" + ); + assert_eq!( + VertexAIProvider::validate_location("invalid@location"), + "invalidlocation" + ); + assert_eq!( + VertexAIProvider::validate_location(""), + "us-central1" + ); + assert_eq!( + VertexAIProvider::validate_location("!@#$%^"), + "us-central1" + ); + } + + #[test] + fn test_auth_config_precedence() { + let mut params = HashMap::new(); + params.insert("project_id".to_string(), "test-project".to_string()); + params.insert("credentials_path".to_string(), "some/path.json".to_string()); + + let config = ProviderConfig { + key: "test-vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "test-api-key".to_string(), // Both API key and credentials provided + params, + }; + + let provider = VertexAIProvider::new(&config); + // Should prefer API key over credentials path + assert!(!provider.config.api_key.is_empty()); + assert_eq!(provider.config.api_key, "test-api-key"); + assert!(provider.config.params.contains_key("credentials_path")); // Credentials path should still be preserved + } + + #[test] + fn test_auth_config_credentials_only() { + let mut params = HashMap::new(); + params.insert("project_id".to_string(), "test-project".to_string()); + params.insert("credentials_path".to_string(), "some/path.json".to_string()); + + let config = ProviderConfig { + key: "test-vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "".to_string(), // Empty API key + params, + }; + + let provider = VertexAIProvider::new(&config); + assert!(provider.config.api_key.is_empty()); + assert_eq!(provider.config.params.get("credentials_path").unwrap(), "some/path.json"); + } + + #[test] + fn test_empty_message_handling() { + let chat_request = ChatCompletionRequest { + model: "gemini-1.5-flash".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: None, // Empty content + name: None, + tool_calls: None, + }], + temperature: None, + top_p: None, + n: None, + stream: None, + stop: None, + max_tokens: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + }; + + let gemini_request = GeminiChatRequest::from_openai(chat_request); + assert_eq!(gemini_request.contents[0].parts[0].text, ""); + } + + #[test] + fn test_tool_choice_none() { + let chat_request = ChatCompletionRequest { + model: "gemini-1.5-flash".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String("test".to_string())), + name: None, + tool_calls: None, + }], + tool_choice: Some(ToolChoice::Simple(SimpleToolChoice::None)), + tools: Some(vec![ToolDefinition { + tool_type: "function".to_string(), + function: FunctionDefinition { + name: "test_function".to_string(), + description: Some("Test function".to_string()), + parameters: Some(serde_json::from_value(serde_json::json!({ + "type": "object", + "properties": { + "test": { + "type": "string" + } + } + })).unwrap()), + strict: None, + }, + }]), + temperature: None, + top_p: None, + n: None, + stream: None, + stop: None, + max_tokens: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + parallel_tool_calls: None, + }; + + let gemini_request = GeminiChatRequest::from_openai(chat_request); + assert!(matches!(gemini_request.tool_choice, Some(GeminiToolChoice::None))); + } + + #[test] + fn test_generation_config_limits() { + let chat_request = ChatCompletionRequest { + model: "gemini-1.5-flash".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String("test".to_string())), + name: None, + tool_calls: None, + }], + temperature: Some(2.0), // Out of range + top_p: Some(1.5), // Out of range + max_tokens: Some(100000), // Very large + n: None, + stream: None, + stop: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + }; + + let gemini_request = GeminiChatRequest::from_openai(chat_request); + let config = gemini_request.generation_config.unwrap(); + assert_eq!(config.temperature.unwrap(), 2.0); // Values are passed through as-is + assert_eq!(config.top_p.unwrap(), 1.5); // Values are passed through as-is + // No need to check for bounds as values are passed through unchanged + } + + #[test] + fn test_response_error_mapping() { + let gemini_response = GeminiChatResponse { + candidates: vec![], // Empty candidates + usage_metadata: None, + }; + + let model = "gemini-1.5-flash".to_string(); + let openai_response = gemini_response.to_openai(model); + assert!(openai_response.choices.is_empty()); + assert_eq!(openai_response.usage.prompt_tokens, 0); + assert_eq!(openai_response.usage.completion_tokens, 0); + assert_eq!(openai_response.usage.total_tokens, 0); + } } From f08a06117a9349accf194d7bad82e803823f3957 Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Wed, 22 Jan 2025 16:01:06 +0100 Subject: [PATCH 6/9] refactor(vertexai): clean up imports and remove unused vertexai module --- src/models/mod.rs | 1 - src/models/streaming.rs | 44 +---- src/providers/vertexai/mod.rs | 1 + .../vertexai/models.rs} | 52 +++++- src/providers/vertexai/provider.rs | 176 +++++++----------- src/providers/vertexai/tests.rs | 24 ++- 6 files changed, 131 insertions(+), 167 deletions(-) rename src/{models/vertexai.rs => providers/vertexai/models.rs} (80%) diff --git a/src/models/mod.rs b/src/models/mod.rs index c7d06a9..7b27896 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -8,4 +8,3 @@ pub mod tool_calls; pub mod tool_choice; pub mod tool_definition; pub mod usage; -pub mod vertexai; diff --git a/src/models/streaming.rs b/src/models/streaming.rs index 737984e..5331e31 100644 --- a/src/models/streaming.rs +++ b/src/models/streaming.rs @@ -1,9 +1,8 @@ use serde::{Deserialize, Serialize}; use super::logprob::ChoiceLogprobs; -use super::tool_calls::{ChatMessageToolCall, FunctionCall}; +use super::tool_calls::ChatMessageToolCall; use super::usage::Usage; -use crate::models::vertexai::GeminiChatResponse; #[derive(Deserialize, Serialize, Clone, Debug, Default)] pub struct Delta { @@ -46,44 +45,3 @@ pub struct ChatCompletionChunk { #[serde(skip_serializing_if = "Option::is_none")] pub usage: Option, } - -impl ChatCompletionChunk { - pub fn from_gemini(response: GeminiChatResponse, model: String) -> Self { - let first_candidate = response.candidates.first(); - - Self { - id: uuid::Uuid::new_v4().to_string(), - service_tier: None, - system_fingerprint: None, - created: chrono::Utc::now().timestamp() as i64, - model, - choices: vec![Choice { - index: 0, - logprobs: None, - delta: ChoiceDelta { - role: None, - content: first_candidate - .and_then(|c| c.content.parts.first()) - .map(|p| p.text.clone()), - tool_calls: first_candidate - .and_then(|c| c.tool_calls.clone()) - .map(|calls| { - calls - .into_iter() - .map(|call| ChatMessageToolCall { - id: format!("call_{}", uuid::Uuid::new_v4()), - r#type: "function".to_string(), - function: FunctionCall { - name: call.function.name, - arguments: call.function.arguments, - }, - }) - .collect() - }), - }, - finish_reason: first_candidate.and_then(|c| c.finish_reason.clone()), - }], - usage: None, - } - } -} diff --git a/src/providers/vertexai/mod.rs b/src/providers/vertexai/mod.rs index 99894b7..02c9bc6 100644 --- a/src/providers/vertexai/mod.rs +++ b/src/providers/vertexai/mod.rs @@ -1,4 +1,5 @@ pub mod provider; +pub mod models; #[cfg(test)] mod tests; diff --git a/src/models/vertexai.rs b/src/providers/vertexai/models.rs similarity index 80% rename from src/models/vertexai.rs rename to src/providers/vertexai/models.rs index b34e333..f085abc 100644 --- a/src/models/vertexai.rs +++ b/src/providers/vertexai/models.rs @@ -6,6 +6,7 @@ use crate::models::content::{ChatCompletionMessage, ChatMessageContent}; use crate::models::tool_calls::{ChatMessageToolCall, FunctionCall}; use crate::models::tool_choice::{SimpleToolChoice, ToolChoice}; use crate::models::usage::Usage; +use crate::models::streaming::{ChatCompletionChunk, Choice, ChoiceDelta}; #[derive(Debug, Serialize, Deserialize)] pub struct GeminiChatRequest { @@ -114,8 +115,14 @@ pub struct UsageMetadata { pub total_token_count: i32, } -impl GeminiChatRequest { - pub fn from_openai(req: ChatCompletionRequest) -> Self { +#[derive(Debug, Deserialize)] +pub struct VertexAIStreamChunk { + pub candidates: Vec, + pub usage_metadata: Option, +} + +impl From for GeminiChatRequest { + fn from(req: ChatCompletionRequest) -> Self { let contents = req .messages .into_iter() @@ -248,3 +255,44 @@ impl GeminiChatResponse { } } } + +impl From for ChatCompletionChunk { + fn from(chunk: VertexAIStreamChunk) -> Self { + let first_candidate = chunk.candidates.first(); + + Self { + id: uuid::Uuid::new_v4().to_string(), + service_tier: None, + system_fingerprint: None, + created: chrono::Utc::now().timestamp() as i64, + model: String::new(), + choices: vec![Choice { + index: 0, + logprobs: None, + delta: ChoiceDelta { + role: None, + content: first_candidate + .and_then(|c| c.content.parts.first()) + .map(|p| p.text.clone()), + tool_calls: first_candidate + .and_then(|c| c.tool_calls.clone()) + .map(|calls| { + calls + .into_iter() + .map(|call| ChatMessageToolCall { + id: format!("call_{}", uuid::Uuid::new_v4()), + r#type: "function".to_string(), + function: FunctionCall { + name: call.function.name, + arguments: call.function.arguments, + }, + }) + .collect() + }), + }, + finish_reason: first_candidate.and_then(|c| c.finish_reason.clone()), + }], + usage: None, + } + } +} \ No newline at end of file diff --git a/src/providers/vertexai/provider.rs b/src/providers/vertexai/provider.rs index d01fe35..fdcfb9a 100644 --- a/src/providers/vertexai/provider.rs +++ b/src/providers/vertexai/provider.rs @@ -1,21 +1,27 @@ use crate::config::models::{ModelConfig, Provider as ProviderConfig}; use crate::models::chat::{ChatCompletionRequest, ChatCompletionResponse}; -use crate::models::completion::{CompletionChoice, CompletionRequest, CompletionResponse}; -use crate::models::content::{ChatCompletionMessage, ChatMessageContent}; +use crate::models::completion::{CompletionRequest, CompletionResponse}; use crate::models::embeddings::{ Embeddings, EmbeddingsInput, EmbeddingsRequest, EmbeddingsResponse, }; +use crate::models::streaming::ChatCompletionChunk; use crate::models::usage::Usage; -use crate::models::vertexai::{ +use crate::providers::provider::Provider; +use super::models::{ ContentPart, GeminiCandidate, GeminiChatRequest, GeminiChatResponse, GeminiContent, - UsageMetadata, + UsageMetadata, VertexAIStreamChunk, }; -use crate::providers::provider::Provider; use axum::async_trait; use axum::http::StatusCode; use reqwest::Client; +use reqwest_streams::JsonStreamResponse; +use reqwest_streams::error::{StreamBodyError, StreamBodyKind}; use serde_json::json; use yup_oauth2::{ServiceAccountAuthenticator, ServiceAccountKey}; +use futures::StreamExt; +use tracing::{debug, error, info}; + +const STREAM_BUFFER_SIZE: usize = 8192; pub struct VertexAIProvider { config: ProviderConfig, @@ -40,12 +46,12 @@ impl VertexAIProvider { } async fn get_auth_token(&self) -> Result { - println!("Getting auth token..."); + debug!("Getting auth token..."); if !self.config.api_key.is_empty() { - println!("Using API key authentication"); + debug!("Using API key authentication"); Ok(self.config.api_key.clone()) } else { - println!("Using service account authentication"); + debug!("Using service account authentication"); let key_path = self.config .params .get("credentials_path") @@ -53,31 +59,31 @@ impl VertexAIProvider { .or_else(|| std::env::var("GOOGLE_APPLICATION_CREDENTIALS").ok()) .expect("Either api_key, credentials_path in config, or GOOGLE_APPLICATION_CREDENTIALS environment variable must be set"); - println!("Reading service account key from: {}", key_path); + debug!("Reading service account key from: {}", key_path); let key_json = std::fs::read_to_string(key_path).expect("Failed to read service account key file"); - println!( + debug!( "Service account key file content length: {}", key_json.len() ); let sa_key: ServiceAccountKey = serde_json::from_str(&key_json).expect("Failed to parse service account key"); - println!("Successfully parsed service account key"); + debug!("Successfully parsed service account key"); let auth = ServiceAccountAuthenticator::builder(sa_key) .build() .await .expect("Failed to create authenticator"); - println!("Created authenticator, requesting token..."); + debug!("Created authenticator, requesting token..."); let scopes = &["https://www.googleapis.com/auth/cloud-platform"]; let token = auth.token(scopes).await.map_err(|e| { - eprintln!("Failed to get access token: {}", e); + error!("Failed to get access token: {}", e); StatusCode::INTERNAL_SERVER_ERROR })?; - println!("Successfully obtained token"); + debug!("Successfully obtained token"); Ok(token.token().unwrap_or_default().to_string()) } } @@ -119,46 +125,65 @@ impl Provider for VertexAIProvider { _model_config: &ModelConfig, ) -> Result { let auth_token = self.get_auth_token().await?; + let endpoint_suffix = if payload.stream.unwrap_or(false) { + "streamGenerateContent" + } else { + "generateContent" + }; + let endpoint = format!( - "https://{}-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:streamGenerateContent", - self.location, self.project_id, self.location, payload.model + "https://{}-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:{}", + self.location, self.project_id, self.location, payload.model, endpoint_suffix ); let response = self .http_client .post(&endpoint) .bearer_auth(auth_token) - .json(&GeminiChatRequest::from_openai(payload.clone())) + .json(&GeminiChatRequest::from(payload.clone())) .send() .await .map_err(|e| { - eprintln!("VertexAI API request error: {}", e); + error!("VertexAI API request error: {}", e); StatusCode::INTERNAL_SERVER_ERROR })?; let status = response.status(); - println!("Response status: {}", status); + debug!("Response status: {}", status); if status.is_success() { if payload.stream.unwrap_or(false) { - Err(StatusCode::BAD_REQUEST) // Streaming not supported yet + let model = payload.model.clone(); + let stream = response + .json_array_stream::(STREAM_BUFFER_SIZE) + .map(move |result| { + result.map(|chunk| { + let mut completion_chunk: ChatCompletionChunk = chunk.into(); + completion_chunk.model = model.clone(); + completion_chunk + }).map_err(|e| { + StreamBodyError::new(StreamBodyKind::CodecError, Some(Box::new(e)), None) + }) + }); + + Ok(ChatCompletionResponse::Stream(Box::pin(stream))) } else { let response_text = response.text().await.map_err(|e| { - eprintln!("Failed to get response text: {}", e); + error!("Failed to get response text: {}", e); StatusCode::INTERNAL_SERVER_ERROR })?; - println!("Response body: {}", response_text); + debug!("Response body: {}", response_text); // Parse the response as a JSON array let responses: Vec = serde_json::from_str(&response_text) .map_err(|e| { - eprintln!("Failed to parse response as JSON array: {}", e); + error!("Failed to parse response as JSON array: {}", e); StatusCode::INTERNAL_SERVER_ERROR })?; // Get the last response which contains the complete message and usage metadata let final_response = responses.last().ok_or_else(|| { - eprintln!("No valid response chunks found"); + error!("No valid response chunks found"); StatusCode::INTERNAL_SERVER_ERROR })?; @@ -217,82 +242,17 @@ impl Provider for VertexAIProvider { } } else { let error_text = response.text().await.unwrap_or_default(); - eprintln!("VertexAI API request error: {}", error_text); + error!("VertexAI API request error: {}", error_text); Err(StatusCode::from_u16(status.as_u16()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)) } } async fn completions( &self, - payload: CompletionRequest, - model_config: &ModelConfig, + _payload: CompletionRequest, + _model_config: &ModelConfig, ) -> Result { - // For Gemini, we'll use the chat endpoint for completions as well - let chat_request = ChatCompletionRequest { - model: payload.model, - messages: vec![ChatCompletionMessage { - role: "user".to_string(), - content: Some(ChatMessageContent::String(payload.prompt)), - name: None, - tool_calls: None, - }], - temperature: payload.temperature, - top_p: payload.top_p, - n: payload.n, - stream: payload.stream, - stop: payload.stop, - max_tokens: payload.max_tokens, - presence_penalty: payload.presence_penalty, - frequency_penalty: payload.frequency_penalty, - logit_bias: None, - user: payload.user, - tools: None, - tool_choice: None, - parallel_tool_calls: None, - }; - - let chat_response = self.chat_completions(chat_request, model_config).await?; - - // Convert chat response to completion response - match chat_response { - ChatCompletionResponse::NonStream(resp) => Ok(CompletionResponse { - id: resp.id, - object: "text_completion".to_string(), - created: resp.created.unwrap_or_default(), - model: resp.model, - choices: resp - .choices - .into_iter() - .map(|c| CompletionChoice { - text: match c - .message - .content - .unwrap_or(ChatMessageContent::String("".to_string())) - { - ChatMessageContent::String(s) => s, - ChatMessageContent::Array(arr) => arr - .into_iter() - .map(|p| p.text) - .collect::>() - .join(" "), - }, - index: c.index, - logprobs: None, - finish_reason: c.finish_reason, - }) - .collect(), - usage: Usage { - prompt_tokens: 0, - completion_tokens: 0, - total_tokens: 0, - prompt_tokens_details: None, - completion_tokens_details: None, - }, - }), - ChatCompletionResponse::Stream(_) => { - Err(StatusCode::BAD_REQUEST) // Streaming not supported for completions - } - } + unimplemented!("Text completions are not supported for Vertex AI. Use chat_completions instead.") } async fn embeddings( @@ -324,23 +284,23 @@ impl Provider for VertexAIProvider { .send() .await .map_err(|e| { - eprintln!("VertexAI API request error: {}", e); + error!("VertexAI API request error: {}", e); StatusCode::INTERNAL_SERVER_ERROR })?; let status = response.status(); - println!("Embeddings response status: {}", status); + debug!("Embeddings response status: {}", status); if status.is_success() { let response_text = response.text().await.map_err(|e| { - eprintln!("Failed to get response text: {}", e); + error!("Failed to get response text: {}", e); StatusCode::INTERNAL_SERVER_ERROR })?; - println!("Embeddings response body: {}", response_text); + debug!("Embeddings response body: {}", response_text); let gemini_response: serde_json::Value = serde_json::from_str(&response_text).map_err(|e| { - eprintln!("Failed to parse response as JSON: {}", e); + error!("Failed to parse response as JSON: {}", e); StatusCode::INTERNAL_SERVER_ERROR })?; @@ -376,7 +336,7 @@ impl Provider for VertexAIProvider { }) } else { let error_text = response.text().await.unwrap_or_default(); - eprintln!("VertexAI API request error: {}", error_text); + error!("VertexAI API request error: {}", error_text); Err(StatusCode::from_u16(status.as_u16()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)) } } @@ -409,10 +369,10 @@ impl VertexAIProvider { mod tests { use super::*; use std::collections::HashMap; - use crate::models::content::{ChatMessageContent, ChatMessageContentPart}; + use crate::models::content::{ChatCompletionMessage, ChatMessageContent, ChatMessageContentPart}; use crate::models::tool_choice::{ToolChoice, SimpleToolChoice}; use crate::models::tool_definition::{ToolDefinition, FunctionDefinition}; - use crate::models::vertexai::{GeminiFunctionCall, GeminiToolCall, GeminiToolChoice}; + use crate::providers::vertexai::models::{GeminiFunctionCall, GeminiToolCall, GeminiToolChoice}; #[test] fn test_provider_new() { @@ -472,7 +432,7 @@ mod tests { parallel_tool_calls: None, }; - let gemini_request = GeminiChatRequest::from_openai(chat_request); + let gemini_request = GeminiChatRequest::from(chat_request); assert_eq!(gemini_request.contents[0].parts[0].text, "Hello"); assert_eq!(gemini_request.contents[0].role, "user"); @@ -555,7 +515,7 @@ mod tests { parallel_tool_calls: None, }; - let gemini_request = GeminiChatRequest::from_openai(chat_request); + let gemini_request = GeminiChatRequest::from(chat_request); assert!(gemini_request.tools.is_some()); let tools = gemini_request.tools.unwrap(); @@ -630,7 +590,7 @@ mod tests { parallel_tool_calls: None, }; - let gemini_request = GeminiChatRequest::from_openai(chat_request); + let gemini_request = GeminiChatRequest::from(chat_request); // Verify system message is handled correctly assert_eq!(gemini_request.contents.len(), 2); @@ -671,7 +631,7 @@ mod tests { parallel_tool_calls: None, }; - let gemini_request = GeminiChatRequest::from_openai(chat_request); + let gemini_request = GeminiChatRequest::from(chat_request); assert_eq!(gemini_request.contents[0].parts[0].text, "Part 1 Part 2"); } @@ -776,7 +736,7 @@ mod tests { parallel_tool_calls: None, }; - let gemini_request = GeminiChatRequest::from_openai(chat_request); + let gemini_request = GeminiChatRequest::from(chat_request); assert_eq!(gemini_request.contents[0].parts[0].text, ""); } @@ -820,7 +780,7 @@ mod tests { parallel_tool_calls: None, }; - let gemini_request = GeminiChatRequest::from_openai(chat_request); + let gemini_request = GeminiChatRequest::from(chat_request); assert!(matches!(gemini_request.tool_choice, Some(GeminiToolChoice::None))); } @@ -849,7 +809,7 @@ mod tests { parallel_tool_calls: None, }; - let gemini_request = GeminiChatRequest::from_openai(chat_request); + let gemini_request = GeminiChatRequest::from(chat_request); let config = gemini_request.generation_config.unwrap(); assert_eq!(config.temperature.unwrap(), 2.0); // Values are passed through as-is assert_eq!(config.top_p.unwrap(), 1.5); // Values are passed through as-is diff --git a/src/providers/vertexai/tests.rs b/src/providers/vertexai/tests.rs index 9f36318..8be870c 100644 --- a/src/providers/vertexai/tests.rs +++ b/src/providers/vertexai/tests.rs @@ -4,6 +4,7 @@ use std::collections::HashMap; use std::fs; use std::path::PathBuf; use wiremock::{Mock, MockServer, ResponseTemplate}; +use tracing::{debug, error, info}; use super::provider::VertexAIProvider; use crate::config::models::{ModelConfig, Provider as ProviderConfig}; @@ -21,29 +22,29 @@ const TEST_LOCATION: &str = "us-central1"; async fn setup_test_client(test_name: &str) -> reqwest::Client { // Create the cassettes directory if it doesn't exist let cassettes_dir = PathBuf::from("tests/cassettes/vertexai"); - println!("Creating cassettes directory at: {:?}", cassettes_dir); + debug!("Creating cassettes directory at: {:?}", cassettes_dir); if let Err(e) = std::fs::create_dir_all(&cassettes_dir) { - println!("Warning: Directory creation returned: {}", e); + error!("Warning: Directory creation returned: {}", e); } // Create specific cassette file path let cassette_path = cassettes_dir.join(format!("{}.json", test_name)); - println!("Cassette path: {:?}", cassette_path); + debug!("Cassette path: {:?}", cassette_path); let is_record_mode = std::env::var("RECORD_MODE").is_ok(); - println!("Record mode: {}", is_record_mode); + debug!("Record mode: {}", is_record_mode); if is_record_mode { // In record mode, create a real client - println!("Using real client for recording"); + debug!("Using real client for recording"); reqwest::Client::builder() .build() .expect("Failed to create HTTP client") } else { // In replay mode, use mock server with saved responses if let Ok(cassette_content) = fs::read_to_string(&cassette_path) { - println!("Loading cassette from: {:?}", cassette_path); + debug!("Loading cassette from: {:?}", cassette_path); let mock_server = MockServer::start().await; if let Ok(interactions) = serde_json::from_str::>(&cassette_content) { @@ -61,7 +62,7 @@ async fn setup_test_client(test_name: &str) -> reqwest::Client { .build() .expect("Failed to create HTTP client") } else { - println!("No cassette found, falling back to record mode"); + debug!("No cassette found, falling back to record mode"); reqwest::Client::builder() .build() .expect("Failed to create HTTP client") @@ -89,12 +90,9 @@ async fn save_to_cassette(test_name: &str, response: &Value) { // Save updated cassette if let Ok(content) = serde_json::to_string_pretty(&interactions) { if let Err(e) = fs::write(&cassette_path, content) { - println!("Error saving cassette: {}", e); + error!("Error saving cassette: {}", e); } else { - println!( - "Successfully saved interaction to cassette: {:?}", - cassette_path - ); + debug!("Successfully saved interaction to cassette: {:?}", cassette_path); } } } @@ -160,7 +158,7 @@ where Ok(result) => return Ok(result), Err(status) if status == axum::http::StatusCode::TOO_MANY_REQUESTS => { if attempt < max_retries - 1 { - println!( + info!( "Quota exceeded, waiting {} seconds before retry...", retry_delay.as_secs() ); From 0f25dee3f888b67e366377ccfc192239b1fd8059 Mon Sep 17 00:00:00 2001 From: David Anyatonwu <51977119+onyedikachi-david@users.noreply.github.com> Date: Fri, 2 May 2025 21:59:00 +0000 Subject: [PATCH 7/9] chore: cargo fmt --- src/providers/vertexai/mod.rs | 2 +- src/providers/vertexai/models.rs | 4 +- src/providers/vertexai/provider.rs | 196 +++++++++++++++++------------ src/providers/vertexai/tests.rs | 7 +- 4 files changed, 124 insertions(+), 85 deletions(-) diff --git a/src/providers/vertexai/mod.rs b/src/providers/vertexai/mod.rs index 02c9bc6..3ee11e9 100644 --- a/src/providers/vertexai/mod.rs +++ b/src/providers/vertexai/mod.rs @@ -1,5 +1,5 @@ -pub mod provider; pub mod models; +pub mod provider; #[cfg(test)] mod tests; diff --git a/src/providers/vertexai/models.rs b/src/providers/vertexai/models.rs index f085abc..8135aee 100644 --- a/src/providers/vertexai/models.rs +++ b/src/providers/vertexai/models.rs @@ -3,10 +3,10 @@ use serde_json::Value; use crate::models::chat::{ChatCompletion, ChatCompletionChoice, ChatCompletionRequest}; use crate::models::content::{ChatCompletionMessage, ChatMessageContent}; +use crate::models::streaming::{ChatCompletionChunk, Choice, ChoiceDelta}; use crate::models::tool_calls::{ChatMessageToolCall, FunctionCall}; use crate::models::tool_choice::{SimpleToolChoice, ToolChoice}; use crate::models::usage::Usage; -use crate::models::streaming::{ChatCompletionChunk, Choice, ChoiceDelta}; #[derive(Debug, Serialize, Deserialize)] pub struct GeminiChatRequest { @@ -295,4 +295,4 @@ impl From for ChatCompletionChunk { usage: None, } } -} \ No newline at end of file +} diff --git a/src/providers/vertexai/provider.rs b/src/providers/vertexai/provider.rs index fdcfb9a..99f02e5 100644 --- a/src/providers/vertexai/provider.rs +++ b/src/providers/vertexai/provider.rs @@ -1,3 +1,7 @@ +use super::models::{ + ContentPart, GeminiCandidate, GeminiChatRequest, GeminiChatResponse, GeminiContent, + UsageMetadata, VertexAIStreamChunk, +}; use crate::config::models::{ModelConfig, Provider as ProviderConfig}; use crate::models::chat::{ChatCompletionRequest, ChatCompletionResponse}; use crate::models::completion::{CompletionRequest, CompletionResponse}; @@ -7,19 +11,15 @@ use crate::models::embeddings::{ use crate::models::streaming::ChatCompletionChunk; use crate::models::usage::Usage; use crate::providers::provider::Provider; -use super::models::{ - ContentPart, GeminiCandidate, GeminiChatRequest, GeminiChatResponse, GeminiContent, - UsageMetadata, VertexAIStreamChunk, -}; use axum::async_trait; use axum::http::StatusCode; +use futures::StreamExt; use reqwest::Client; -use reqwest_streams::JsonStreamResponse; use reqwest_streams::error::{StreamBodyError, StreamBodyKind}; +use reqwest_streams::JsonStreamResponse; use serde_json::json; -use yup_oauth2::{ServiceAccountAuthenticator, ServiceAccountKey}; -use futures::StreamExt; use tracing::{debug, error, info}; +use yup_oauth2::{ServiceAccountAuthenticator, ServiceAccountKey}; const STREAM_BUFFER_SIZE: usize = 8192; @@ -39,7 +39,7 @@ impl VertexAIProvider { .collect(); if sanitized.is_empty() { - "us-central1".to_string() // Default if invalid + "us-central1".to_string() // Default if invalid } else { sanitized } @@ -130,7 +130,7 @@ impl Provider for VertexAIProvider { } else { "generateContent" }; - + let endpoint = format!( "https://{}-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:{}", self.location, self.project_id, self.location, payload.model, endpoint_suffix @@ -157,13 +157,19 @@ impl Provider for VertexAIProvider { let stream = response .json_array_stream::(STREAM_BUFFER_SIZE) .map(move |result| { - result.map(|chunk| { - let mut completion_chunk: ChatCompletionChunk = chunk.into(); - completion_chunk.model = model.clone(); - completion_chunk - }).map_err(|e| { - StreamBodyError::new(StreamBodyKind::CodecError, Some(Box::new(e)), None) - }) + result + .map(|chunk| { + let mut completion_chunk: ChatCompletionChunk = chunk.into(); + completion_chunk.model = model.clone(); + completion_chunk + }) + .map_err(|e| { + StreamBodyError::new( + StreamBodyKind::CodecError, + Some(Box::new(e)), + None, + ) + }) }); Ok(ChatCompletionResponse::Stream(Box::pin(stream))) @@ -252,7 +258,9 @@ impl Provider for VertexAIProvider { _payload: CompletionRequest, _model_config: &ModelConfig, ) -> Result { - unimplemented!("Text completions are not supported for Vertex AI. Use chat_completions instead.") + unimplemented!( + "Text completions are not supported for Vertex AI. Use chat_completions instead." + ) } async fn embeddings( @@ -361,25 +369,27 @@ impl VertexAIProvider { location, } } - - } #[cfg(test)] mod tests { use super::*; + use crate::models::content::{ + ChatCompletionMessage, ChatMessageContent, ChatMessageContentPart, + }; + use crate::models::tool_choice::{SimpleToolChoice, ToolChoice}; + use crate::models::tool_definition::{FunctionDefinition, ToolDefinition}; + use crate::providers::vertexai::models::{ + GeminiFunctionCall, GeminiToolCall, GeminiToolChoice, + }; use std::collections::HashMap; - use crate::models::content::{ChatCompletionMessage, ChatMessageContent, ChatMessageContentPart}; - use crate::models::tool_choice::{ToolChoice, SimpleToolChoice}; - use crate::models::tool_definition::{ToolDefinition, FunctionDefinition}; - use crate::providers::vertexai::models::{GeminiFunctionCall, GeminiToolCall, GeminiToolChoice}; #[test] fn test_provider_new() { // Test with minimum required config let mut params = HashMap::new(); params.insert("project_id".to_string(), "test-project".to_string()); - + let config = ProviderConfig { key: "test-vertexai".to_string(), r#type: "vertexai".to_string(), @@ -409,14 +419,12 @@ mod tests { fn test_gemini_request_conversion() { let chat_request = ChatCompletionRequest { model: "gemini-1.5-flash".to_string(), - messages: vec![ - ChatCompletionMessage { - role: "user".to_string(), - content: Some(ChatMessageContent::String("Hello".to_string())), - name: None, - tool_calls: None, - } - ], + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String("Hello".to_string())), + name: None, + tool_calls: None, + }], temperature: Some(0.7), top_p: Some(0.9), n: None, @@ -433,11 +441,21 @@ mod tests { }; let gemini_request = GeminiChatRequest::from(chat_request); - + assert_eq!(gemini_request.contents[0].parts[0].text, "Hello"); assert_eq!(gemini_request.contents[0].role, "user"); - assert_eq!(gemini_request.generation_config.as_ref().unwrap().temperature, Some(0.7)); - assert_eq!(gemini_request.generation_config.as_ref().unwrap().top_p, Some(0.9)); + assert_eq!( + gemini_request + .generation_config + .as_ref() + .unwrap() + .temperature, + Some(0.7) + ); + assert_eq!( + gemini_request.generation_config.as_ref().unwrap().top_p, + Some(0.9) + ); } #[test] @@ -469,7 +487,10 @@ mod tests { Some(ChatMessageContent::String(text)) => assert_eq!(text, "Hello there!"), _ => panic!("Expected String content"), } - assert_eq!(openai_response.choices[0].finish_reason, Some("STOP".to_string())); + assert_eq!( + openai_response.choices[0].finish_reason, + Some("STOP".to_string()) + ); assert_eq!(openai_response.usage.prompt_tokens, 10); assert_eq!(openai_response.usage.completion_tokens, 20); assert_eq!(openai_response.usage.total_tokens, 30); @@ -491,14 +512,17 @@ mod tests { function: FunctionDefinition { name: "test_function".to_string(), description: Some("Test function".to_string()), - parameters: Some(serde_json::from_value(serde_json::json!({ - "type": "object", - "properties": { - "test": { - "type": "string" + parameters: Some( + serde_json::from_value(serde_json::json!({ + "type": "object", + "properties": { + "test": { + "type": "string" + } } - } - })).unwrap()), + })) + .unwrap(), + ), strict: None, }, }]), @@ -516,7 +540,7 @@ mod tests { }; let gemini_request = GeminiChatRequest::from(chat_request); - + assert!(gemini_request.tools.is_some()); let tools = gemini_request.tools.unwrap(); assert_eq!(tools[0].function_declarations[0].name, "test_function"); @@ -552,9 +576,16 @@ mod tests { let openai_response = gemini_response.to_openai(model.clone()); assert!(openai_response.choices[0].message.tool_calls.is_some()); - let tool_calls = openai_response.choices[0].message.tool_calls.as_ref().unwrap(); + let tool_calls = openai_response.choices[0] + .message + .tool_calls + .as_ref() + .unwrap(); assert_eq!(tool_calls[0].function.name, "get_weather"); - assert_eq!(tool_calls[0].function.arguments, r#"{"location":"San Francisco"}"#); + assert_eq!( + tool_calls[0].function.arguments, + r#"{"location":"San Francisco"}"# + ); } #[test] @@ -564,7 +595,9 @@ mod tests { messages: vec![ ChatCompletionMessage { role: "system".to_string(), - content: Some(ChatMessageContent::String("You are a helpful assistant".to_string())), + content: Some(ChatMessageContent::String( + "You are a helpful assistant".to_string(), + )), name: None, tool_calls: None, }, @@ -573,7 +606,7 @@ mod tests { content: Some(ChatMessageContent::String("Hello".to_string())), name: None, tool_calls: None, - } + }, ], temperature: None, top_p: None, @@ -591,7 +624,7 @@ mod tests { }; let gemini_request = GeminiChatRequest::from(chat_request); - + // Verify system message is handled correctly assert_eq!(gemini_request.contents.len(), 2); assert_eq!(gemini_request.contents[0].role, "system"); @@ -632,7 +665,7 @@ mod tests { }; let gemini_request = GeminiChatRequest::from(chat_request); - + assert_eq!(gemini_request.contents[0].parts[0].text, "Part 1 Part 2"); } @@ -641,7 +674,7 @@ mod tests { let mut params = HashMap::new(); params.insert("project_id".to_string(), "test-project".to_string()); params.insert("location".to_string(), "invalid@location".to_string()); - + let config = ProviderConfig { key: "test-vertexai".to_string(), r#type: "vertexai".to_string(), @@ -650,7 +683,7 @@ mod tests { }; let provider = VertexAIProvider::new(&config); - assert_eq!(provider.location, "invalidlocation"); // @ should be removed + assert_eq!(provider.location, "invalidlocation"); // @ should be removed } #[test] @@ -663,14 +696,8 @@ mod tests { VertexAIProvider::validate_location("invalid@location"), "invalidlocation" ); - assert_eq!( - VertexAIProvider::validate_location(""), - "us-central1" - ); - assert_eq!( - VertexAIProvider::validate_location("!@#$%^"), - "us-central1" - ); + assert_eq!(VertexAIProvider::validate_location(""), "us-central1"); + assert_eq!(VertexAIProvider::validate_location("!@#$%^"), "us-central1"); } #[test] @@ -678,11 +705,11 @@ mod tests { let mut params = HashMap::new(); params.insert("project_id".to_string(), "test-project".to_string()); params.insert("credentials_path".to_string(), "some/path.json".to_string()); - + let config = ProviderConfig { key: "test-vertexai".to_string(), r#type: "vertexai".to_string(), - api_key: "test-api-key".to_string(), // Both API key and credentials provided + api_key: "test-api-key".to_string(), // Both API key and credentials provided params, }; @@ -698,17 +725,20 @@ mod tests { let mut params = HashMap::new(); params.insert("project_id".to_string(), "test-project".to_string()); params.insert("credentials_path".to_string(), "some/path.json".to_string()); - + let config = ProviderConfig { key: "test-vertexai".to_string(), r#type: "vertexai".to_string(), - api_key: "".to_string(), // Empty API key + api_key: "".to_string(), // Empty API key params, }; let provider = VertexAIProvider::new(&config); assert!(provider.config.api_key.is_empty()); - assert_eq!(provider.config.params.get("credentials_path").unwrap(), "some/path.json"); + assert_eq!( + provider.config.params.get("credentials_path").unwrap(), + "some/path.json" + ); } #[test] @@ -717,7 +747,7 @@ mod tests { model: "gemini-1.5-flash".to_string(), messages: vec![ChatCompletionMessage { role: "user".to_string(), - content: None, // Empty content + content: None, // Empty content name: None, tool_calls: None, }], @@ -756,14 +786,17 @@ mod tests { function: FunctionDefinition { name: "test_function".to_string(), description: Some("Test function".to_string()), - parameters: Some(serde_json::from_value(serde_json::json!({ - "type": "object", - "properties": { - "test": { - "type": "string" + parameters: Some( + serde_json::from_value(serde_json::json!({ + "type": "object", + "properties": { + "test": { + "type": "string" + } } - } - })).unwrap()), + })) + .unwrap(), + ), strict: None, }, }]), @@ -781,7 +814,10 @@ mod tests { }; let gemini_request = GeminiChatRequest::from(chat_request); - assert!(matches!(gemini_request.tool_choice, Some(GeminiToolChoice::None))); + assert!(matches!( + gemini_request.tool_choice, + Some(GeminiToolChoice::None) + )); } #[test] @@ -794,8 +830,8 @@ mod tests { name: None, tool_calls: None, }], - temperature: Some(2.0), // Out of range - top_p: Some(1.5), // Out of range + temperature: Some(2.0), // Out of range + top_p: Some(1.5), // Out of range max_tokens: Some(100000), // Very large n: None, stream: None, @@ -811,15 +847,15 @@ mod tests { let gemini_request = GeminiChatRequest::from(chat_request); let config = gemini_request.generation_config.unwrap(); - assert_eq!(config.temperature.unwrap(), 2.0); // Values are passed through as-is - assert_eq!(config.top_p.unwrap(), 1.5); // Values are passed through as-is - // No need to check for bounds as values are passed through unchanged + assert_eq!(config.temperature.unwrap(), 2.0); // Values are passed through as-is + assert_eq!(config.top_p.unwrap(), 1.5); // Values are passed through as-is + // No need to check for bounds as values are passed through unchanged } #[test] fn test_response_error_mapping() { let gemini_response = GeminiChatResponse { - candidates: vec![], // Empty candidates + candidates: vec![], // Empty candidates usage_metadata: None, }; diff --git a/src/providers/vertexai/tests.rs b/src/providers/vertexai/tests.rs index 8be870c..8393b6a 100644 --- a/src/providers/vertexai/tests.rs +++ b/src/providers/vertexai/tests.rs @@ -3,8 +3,8 @@ use serde_json::Value; use std::collections::HashMap; use std::fs; use std::path::PathBuf; -use wiremock::{Mock, MockServer, ResponseTemplate}; use tracing::{debug, error, info}; +use wiremock::{Mock, MockServer, ResponseTemplate}; use super::provider::VertexAIProvider; use crate::config::models::{ModelConfig, Provider as ProviderConfig}; @@ -92,7 +92,10 @@ async fn save_to_cassette(test_name: &str, response: &Value) { if let Err(e) = fs::write(&cassette_path, content) { error!("Error saving cassette: {}", e); } else { - debug!("Successfully saved interaction to cassette: {:?}", cassette_path); + debug!( + "Successfully saved interaction to cassette: {:?}", + cassette_path + ); } } } From 39bd1a44a1befabdb449a84d0d5530b88bc3c2e4 Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Mon, 12 May 2025 16:55:20 +0100 Subject: [PATCH 8/9] refactor: update Gemini models to support optional fields and improve request handling --- src/providers/vertexai/models.rs | 99 +- src/providers/vertexai/provider.rs | 658 +--- src/providers/vertexai/tests.rs | 611 +++- .../cassettes/vertexai/chat_completions.json | 105 +- .../vertexai/chat_completions_with_tools.json | 90 +- tests/cassettes/vertexai/completions.json | 20 - tests/cassettes/vertexai/embeddings.json | 3143 ++++++++++++++++- 7 files changed, 3993 insertions(+), 733 deletions(-) delete mode 100644 tests/cassettes/vertexai/completions.json diff --git a/src/providers/vertexai/models.rs b/src/providers/vertexai/models.rs index 6e41bfc..be310e4 100644 --- a/src/providers/vertexai/models.rs +++ b/src/providers/vertexai/models.rs @@ -54,7 +54,10 @@ pub struct GeminiContent { #[derive(Debug, Serialize, Deserialize)] pub struct ContentPart { - pub text: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub text: Option, + #[serde(rename = "functionCall", skip_serializing_if = "Option::is_none")] + pub function_call: Option, } #[derive(Debug, Serialize, Deserialize)] @@ -99,7 +102,7 @@ pub struct GeminiToolCall { #[derive(Debug, Serialize, Deserialize, Clone)] pub struct GeminiFunctionCall { pub name: String, - pub arguments: String, + pub args: Value, } #[derive(Debug, Serialize, Deserialize)] @@ -134,15 +137,16 @@ impl From for GeminiChatRequest { parts: vec![ContentPart { text: match msg.content { Some(content) => match content { - ChatMessageContent::String(text) => text, - ChatMessageContent::Array(parts) => parts + ChatMessageContent::String(text) => Some(text), + ChatMessageContent::Array(parts) => Some(parts .into_iter() .map(|p| p.text) .collect::>() - .join(" "), + .join(" ")), }, - None => String::new(), + None => None, }, + function_call: None, }], }) .collect(); @@ -194,54 +198,55 @@ impl GeminiChatResponse { .candidates .into_iter() .enumerate() - .map(|(i, candidate)| ChatCompletionChoice { - index: i as u32, - message: ChatCompletionMessage { - role: "assistant".to_string(), - content: Some(ChatMessageContent::String( - candidate - .content - .parts - .into_iter() - .map(|p| p.text) - .collect::>() - .join(""), - )), - name: None, - tool_calls: candidate.tool_calls.map(|calls| { - calls - .into_iter() - .map(|call| ChatMessageToolCall { - id: format!("call_{}", uuid::Uuid::new_v4()), - r#type: "function".to_string(), - function: FunctionCall { - name: call.function.name, - arguments: call.function.arguments, - }, - }) - .collect() - }), - refusal: None, - }, - finish_reason: candidate.finish_reason, - logprobs: None, + .map(|(i, candidate)| { + let mut message_text = String::new(); + let mut tool_calls = Vec::new(); + + for part in candidate.content.parts { + if let Some(text) = part.text { + message_text.push_str(&text); + } + if let Some(fc) = part.function_call { + tool_calls.push(ChatMessageToolCall { + id: format!("call_{}", uuid::Uuid::new_v4()), + r#type: "function".to_string(), + function: FunctionCall { + name: fc.name, + arguments: serde_json::to_string(&fc.args).unwrap_or_else(|_| "{}".to_string()), + }, + }); + } + } + + ChatCompletionChoice { + index: i as u32, + message: ChatCompletionMessage { + role: "assistant".to_string(), + content: if message_text.is_empty() { None } else { Some(ChatMessageContent::String(message_text)) }, + tool_calls: if tool_calls.is_empty() { None } else { Some(tool_calls) }, + name: None, + refusal: None, + }, + finish_reason: candidate.finish_reason, + logprobs: None, + } }) .collect(); - let usage = self.usage_metadata.map_or( - Usage { + let usage = self.usage_metadata.map_or_else( + || Usage { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0, - prompt_tokens_details: None, completion_tokens_details: None, - }, - |m| Usage { - prompt_tokens: m.prompt_token_count as u32, - completion_tokens: m.candidates_token_count as u32, - total_tokens: m.total_token_count as u32, prompt_tokens_details: None, + }, + |meta| Usage { + prompt_tokens: meta.prompt_token_count as u32, + completion_tokens: meta.candidates_token_count as u32, + total_tokens: meta.total_token_count as u32, completion_tokens_details: None, + prompt_tokens_details: None, }, ); @@ -274,7 +279,7 @@ impl From for ChatCompletionChunk { role: None, content: first_candidate .and_then(|c| c.content.parts.first()) - .map(|p| p.text.clone()), + .map(|p| p.text.clone().unwrap_or_default()), tool_calls: first_candidate .and_then(|c| c.tool_calls.clone()) .map(|calls| { @@ -285,7 +290,7 @@ impl From for ChatCompletionChunk { r#type: "function".to_string(), function: FunctionCall { name: call.function.name, - arguments: call.function.arguments, + arguments: serde_json::to_string(&call.function.args).unwrap_or_else(|_| "{}".to_string()), }, }) .collect() diff --git a/src/providers/vertexai/provider.rs b/src/providers/vertexai/provider.rs index 5d77d3f..d496dc1 100644 --- a/src/providers/vertexai/provider.rs +++ b/src/providers/vertexai/provider.rs @@ -1,14 +1,13 @@ -use super::models::{ - ContentPart, GeminiCandidate, GeminiChatRequest, GeminiChatResponse, GeminiContent, - UsageMetadata, VertexAIStreamChunk, +use super::models::{GeminiChatRequest, GeminiChatResponse, VertexAIStreamChunk, }; use crate::config::models::{ModelConfig, Provider as ProviderConfig}; use crate::models::chat::{ChatCompletionRequest, ChatCompletionResponse}; use crate::models::completion::{CompletionRequest, CompletionResponse}; use crate::models::embeddings::{ - Embeddings, EmbeddingsInput, EmbeddingsRequest, EmbeddingsResponse, + Embeddings, EmbeddingsInput, EmbeddingsRequest, EmbeddingsResponse, Embedding, }; use crate::models::streaming::ChatCompletionChunk; +use crate::models::usage::EmbeddingUsage; use crate::providers::provider::Provider; use axum::async_trait; use axum::http::StatusCode; @@ -72,6 +71,22 @@ impl VertexAIProvider { Ok(token.token().unwrap_or_default().to_string()) } } + + pub fn validate_location(location: &str) -> Result { + let sanitized = location + .chars() + .filter(|c| c.is_alphanumeric() || *c == '-') + .collect::(); + + if sanitized.is_empty() || sanitized != location { + Err(format!( + "Invalid location provided: '{}'. Location must contain only alphanumeric characters and hyphens.", + location + )) + } else { + Ok(sanitized) + } + } } #[async_trait] @@ -82,12 +97,15 @@ impl Provider for VertexAIProvider { .get("project_id") .expect("project_id is required for VertexAI provider") .to_string(); - let location = config + let location_str = config .params .get("location") .expect("location is required for VertexAI provider") .to_string(); + let location = Self::validate_location(&location_str) + .expect("Invalid location provided in configuration"); + Self { config: config.clone(), http_client: Client::new(), @@ -116,22 +134,36 @@ impl Provider for VertexAIProvider { "generateContent" }; + let service_endpoint = format!("{}-aiplatform.googleapis.com", self.location); + let full_model_path = format!( + "projects/{}/locations/{}/publishers/google/models/{}", + self.project_id, self.location, payload.model + ); + let endpoint = format!( - "https://{}-aiplatform.googleapis.com/v1/projects/{}/locations/{}/publishers/google/models/{}:{}", - self.location, self.project_id, self.location, payload.model, endpoint_suffix + "https://{}/v1/{}:{}", + service_endpoint, full_model_path, endpoint_suffix ); - let response = self + let request_body = GeminiChatRequest::from(payload.clone()); + debug!("Sending request to endpoint: {}", endpoint); + debug!("Request Body: {}", serde_json::to_string(&request_body).unwrap_or_else(|e| format!("Failed to serialize request: {}", e))); + + let response_result = self .http_client .post(&endpoint) .bearer_auth(auth_token) - .json(&GeminiChatRequest::from(payload.clone())) + .json(&request_body) .send() - .await - .map_err(|e| { - error!("VertexAI API request error: {}", e); - StatusCode::INTERNAL_SERVER_ERROR - })?; + .await; + + let response = match response_result { + Ok(resp) => resp, + Err(e) => { + error!("VertexAI API request failed before getting response: {}", e); + return Err(StatusCode::INTERNAL_SERVER_ERROR); + } + }; let status = response.status(); debug!("Response status: {}", status); @@ -163,77 +195,26 @@ impl Provider for VertexAIProvider { error!("Failed to get response text: {}", e); StatusCode::INTERNAL_SERVER_ERROR })?; - debug!("Response body: {}", response_text); + debug!("Raw VertexAI Response Body: {}", response_text); - // Parse the response as a JSON array - let responses: Vec = serde_json::from_str(&response_text) + // Parse the response as a single JSON object (GenerateContentResponse) + let gemini_response: GeminiChatResponse = serde_json::from_str(&response_text) .map_err(|e| { - error!("Failed to parse response as JSON array: {}", e); + error!( + "Failed to parse response as GeminiChatResponse. Error: {}, Raw Response: {}", + e, + response_text // Log raw response on error too + ); StatusCode::INTERNAL_SERVER_ERROR })?; - // Get the last response which contains the complete message and usage metadata - let final_response = responses.last().ok_or_else(|| { - error!("No valid response chunks found"); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - // Combine all text parts from all responses - let full_text = responses - .iter() - .filter_map(|resp| { - resp.get("candidates") - .and_then(|candidates| candidates.get(0)) - .and_then(|candidate| candidate.get("content")) - .and_then(|content| content.get("parts")) - .and_then(|parts| parts.get(0)) - .and_then(|part| part.get("text")) - .and_then(|text| text.as_str()) - .map(String::from) - }) - .collect::>() - .join(""); - - // Create a GeminiChatResponse with the combined text - let gemini_response = GeminiChatResponse { - candidates: vec![GeminiCandidate { - content: GeminiContent { - role: "model".to_string(), - parts: vec![ContentPart { text: full_text }], - }, - finish_reason: final_response["candidates"][0]["finishReason"] - .as_str() - .map(String::from), - safety_ratings: None, - tool_calls: None, - }], - usage_metadata: final_response["usageMetadata"].as_object().map(|obj| { - UsageMetadata { - prompt_token_count: obj - .get("promptTokenCount") - .and_then(|v| v.as_i64()) - .unwrap_or(0) - as i32, - candidates_token_count: obj - .get("candidatesTokenCount") - .and_then(|v| v.as_i64()) - .unwrap_or(0) - as i32, - total_token_count: obj - .get("totalTokenCount") - .and_then(|v| v.as_i64()) - .unwrap_or(0) as i32, - } - }), - }; - Ok(ChatCompletionResponse::NonStream( gemini_response.to_openai(payload.model), )) } } else { let error_text = response.text().await.unwrap_or_default(); - error!("VertexAI API request error: {}", error_text); + error!("VertexAI API request failed with status {}. Error body: {}", status, error_text); Err(StatusCode::from_u16(status.as_u16()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)) } } @@ -269,7 +250,10 @@ impl Provider for VertexAIProvider { EmbeddingsInput::Multiple(texts) => texts.into_iter() .map(|text| json!({"content": text})) .collect::>(), - + EmbeddingsInput::SingleTokenIds(tokens) => vec![json!({"content": tokens.iter().map(|t| t.to_string()).collect::>().join(" ")})], + EmbeddingsInput::MultipleTokenIds(token_arrays) => token_arrays.into_iter() + .map(|tokens| json!({"content": tokens.iter().map(|t| t.to_string()).collect::>().join(" ")})) + .collect::>(), }, "parameters": { "autoTruncate": true @@ -306,12 +290,12 @@ impl Provider for VertexAIProvider { .enumerate() .map(|(i, pred)| Embeddings { object: "embedding".to_string(), - embedding: pred["embeddings"]["values"] + embedding: Embedding::Float(pred["embeddings"]["values"] .as_array() .unwrap_or(&vec![]) .iter() .filter_map(|v| v.as_f64().map(|f| f as f32)) - .collect(), + .collect::>()), index: i, }) .collect(); @@ -320,12 +304,9 @@ impl Provider for VertexAIProvider { object: "list".to_string(), data: embeddings, model: payload.model, - usage: Usage { - prompt_tokens: 0, - completion_tokens: 0, - total_tokens: 0, - prompt_tokens_details: None, - completion_tokens_details: None, + usage: EmbeddingUsage { + prompt_tokens: Some(0), + total_tokens: Some(0), }, }) } else { @@ -342,11 +323,17 @@ impl VertexAIProvider { let project_id = config .params .get("project_id") - .map_or_else(|| "test-project".to_string(), |v| v.to_string()); - let location = config + .cloned() + .unwrap_or_else(|| "".to_string()); + + let location_str = config .params .get("location") - .map_or_else(|| "us-central1".to_string(), |v| v.to_string()); + .cloned() + .unwrap_or_else(|| "".to_string()); + + let location = Self::validate_location(&location_str) + .expect("Invalid location provided for test client configuration"); Self { config: config.clone(), @@ -356,502 +343,3 @@ impl VertexAIProvider { } } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::models::content::{ - ChatCompletionMessage, ChatMessageContent, ChatMessageContentPart, - }; - use crate::models::tool_choice::{SimpleToolChoice, ToolChoice}; - use crate::models::tool_definition::{FunctionDefinition, ToolDefinition}; - use crate::providers::vertexai::models::{ - GeminiFunctionCall, GeminiToolCall, GeminiToolChoice, - }; - use std::collections::HashMap; - - #[test] - fn test_provider_new() { - // Test with minimum required config - let mut params = HashMap::new(); - params.insert("project_id".to_string(), "test-project".to_string()); - - let config = ProviderConfig { - key: "test-vertexai".to_string(), - r#type: "vertexai".to_string(), - api_key: "".to_string(), - params, - }; - - let provider = VertexAIProvider::new(&config); - assert_eq!(provider.project_id, "test-project"); - assert_eq!(provider.location, "us-central1"); // default location - } - - #[test] - #[should_panic(expected = "project_id is required")] - fn test_provider_new_missing_project_id() { - let config = ProviderConfig { - key: "test-vertexai".to_string(), - r#type: "vertexai".to_string(), - api_key: "".to_string(), - params: HashMap::new(), - }; - - VertexAIProvider::new(&config); - } - - #[test] - fn test_gemini_request_conversion() { - let chat_request = ChatCompletionRequest { - model: "gemini-1.5-flash".to_string(), - messages: vec![ChatCompletionMessage { - role: "user".to_string(), - content: Some(ChatMessageContent::String("Hello".to_string())), - name: None, - tool_calls: None, - }], - temperature: Some(0.7), - top_p: Some(0.9), - n: None, - stream: Some(false), - stop: None, - max_tokens: Some(100), - presence_penalty: None, - frequency_penalty: None, - logit_bias: None, - user: None, - tools: None, - tool_choice: None, - parallel_tool_calls: None, - }; - - let gemini_request = GeminiChatRequest::from(chat_request); - - assert_eq!(gemini_request.contents[0].parts[0].text, "Hello"); - assert_eq!(gemini_request.contents[0].role, "user"); - assert_eq!( - gemini_request - .generation_config - .as_ref() - .unwrap() - .temperature, - Some(0.7) - ); - assert_eq!( - gemini_request.generation_config.as_ref().unwrap().top_p, - Some(0.9) - ); - } - - #[test] - fn test_gemini_response_conversion() { - let gemini_response = GeminiChatResponse { - candidates: vec![GeminiCandidate { - content: GeminiContent { - role: "model".to_string(), - parts: vec![ContentPart { - text: "Hello there!".to_string(), - }], - }, - finish_reason: Some("STOP".to_string()), - safety_ratings: None, - tool_calls: None, - }], - usage_metadata: Some(UsageMetadata { - prompt_token_count: 10, - candidates_token_count: 20, - total_token_count: 30, - }), - }; - - let model = "gemini-1.5-flash".to_string(); - let openai_response = gemini_response.to_openai(model.clone()); - - assert_eq!(openai_response.model, model); - match &openai_response.choices[0].message.content { - Some(ChatMessageContent::String(text)) => assert_eq!(text, "Hello there!"), - _ => panic!("Expected String content"), - } - assert_eq!( - openai_response.choices[0].finish_reason, - Some("STOP".to_string()) - ); - assert_eq!(openai_response.usage.prompt_tokens, 10); - assert_eq!(openai_response.usage.completion_tokens, 20); - assert_eq!(openai_response.usage.total_tokens, 30); - } - - #[test] - fn test_gemini_request_with_tools() { - let chat_request = ChatCompletionRequest { - model: "gemini-1.5-flash".to_string(), - messages: vec![ChatCompletionMessage { - role: "user".to_string(), - content: Some(ChatMessageContent::String("Hello".to_string())), - name: None, - tool_calls: None, - }], - temperature: Some(0.7), - tools: Some(vec![ToolDefinition { - tool_type: "function".to_string(), - function: FunctionDefinition { - name: "test_function".to_string(), - description: Some("Test function".to_string()), - parameters: Some( - serde_json::from_value(serde_json::json!({ - "type": "object", - "properties": { - "test": { - "type": "string" - } - } - })) - .unwrap(), - ), - strict: None, - }, - }]), - tool_choice: Some(ToolChoice::Simple(SimpleToolChoice::Auto)), - top_p: None, - n: None, - stream: None, - stop: None, - max_tokens: None, - presence_penalty: None, - frequency_penalty: None, - logit_bias: None, - user: None, - parallel_tool_calls: None, - }; - - let gemini_request = GeminiChatRequest::from(chat_request); - - assert!(gemini_request.tools.is_some()); - let tools = gemini_request.tools.unwrap(); - assert_eq!(tools[0].function_declarations[0].name, "test_function"); - } - - #[test] - fn test_gemini_response_with_tool_calls() { - let gemini_response = GeminiChatResponse { - candidates: vec![GeminiCandidate { - content: GeminiContent { - role: "model".to_string(), - parts: vec![ContentPart { - text: "Using weather function".to_string(), - }], - }, - finish_reason: Some("STOP".to_string()), - safety_ratings: None, - tool_calls: Some(vec![GeminiToolCall { - function: GeminiFunctionCall { - name: "get_weather".to_string(), - arguments: r#"{"location":"San Francisco"}"#.to_string(), - }, - }]), - }], - usage_metadata: Some(UsageMetadata { - prompt_token_count: 10, - candidates_token_count: 20, - total_token_count: 30, - }), - }; - - let model = "gemini-1.5-flash".to_string(); - let openai_response = gemini_response.to_openai(model.clone()); - - assert!(openai_response.choices[0].message.tool_calls.is_some()); - let tool_calls = openai_response.choices[0] - .message - .tool_calls - .as_ref() - .unwrap(); - assert_eq!(tool_calls[0].function.name, "get_weather"); - assert_eq!( - tool_calls[0].function.arguments, - r#"{"location":"San Francisco"}"# - ); - } - - #[test] - fn test_gemini_request_with_system_message() { - let chat_request = ChatCompletionRequest { - model: "gemini-1.5-flash".to_string(), - messages: vec![ - ChatCompletionMessage { - role: "system".to_string(), - content: Some(ChatMessageContent::String( - "You are a helpful assistant".to_string(), - )), - name: None, - tool_calls: None, - refusal: None, - }, - ChatCompletionMessage { - role: "user".to_string(), - content: Some(ChatMessageContent::String("Hello".to_string())), - name: None, - tool_calls: None, - refusal: None, - }, - ], - temperature: None, - top_p: None, - n: None, - stream: None, - stop: None, - max_tokens: None, - presence_penalty: None, - frequency_penalty: None, - logit_bias: None, - user: None, - tools: None, - tool_choice: None, - parallel_tool_calls: None, - }; - - let gemini_request = GeminiChatRequest::from(chat_request); - - // Verify system message is handled correctly - assert_eq!(gemini_request.contents.len(), 2); - assert_eq!(gemini_request.contents[0].role, "system"); - } - - #[test] - fn test_gemini_request_with_array_content() { - let chat_request = ChatCompletionRequest { - model: "gemini-1.5-flash".to_string(), - messages: vec![ChatCompletionMessage { - role: "user".to_string(), - content: Some(ChatMessageContent::Array(vec![ - ChatMessageContentPart { - r#type: "text".to_string(), - text: "Part 1".to_string(), - }, - ChatMessageContentPart { - r#type: "text".to_string(), - text: "Part 2".to_string(), - }, - ])), - name: None, - tool_calls: None, - }], - temperature: None, - top_p: None, - n: None, - stream: None, - stop: None, - max_tokens: None, - presence_penalty: None, - frequency_penalty: None, - logit_bias: None, - user: None, - tools: None, - tool_choice: None, - parallel_tool_calls: None, - }; - - let gemini_request = GeminiChatRequest::from(chat_request); - - assert_eq!(gemini_request.contents[0].parts[0].text, "Part 1 Part 2"); - } - - #[test] - fn test_invalid_location_format() { - let mut params = HashMap::new(); - params.insert("project_id".to_string(), "test-project".to_string()); - params.insert("location".to_string(), "invalid@location".to_string()); - - let config = ProviderConfig { - key: "test-vertexai".to_string(), - r#type: "vertexai".to_string(), - api_key: "".to_string(), - params, - }; - - let provider = VertexAIProvider::new(&config); - assert_eq!(provider.location, "invalidlocation"); // @ should be removed - } - - #[test] - fn test_location_validation() { - assert_eq!( - VertexAIProvider::validate_location("us-central1"), - "us-central1" - ); - assert_eq!( - VertexAIProvider::validate_location("invalid@location"), - "invalidlocation" - ); - assert_eq!(VertexAIProvider::validate_location(""), "us-central1"); - assert_eq!(VertexAIProvider::validate_location("!@#$%^"), "us-central1"); - } - - #[test] - fn test_auth_config_precedence() { - let mut params = HashMap::new(); - params.insert("project_id".to_string(), "test-project".to_string()); - params.insert("credentials_path".to_string(), "some/path.json".to_string()); - - let config = ProviderConfig { - key: "test-vertexai".to_string(), - r#type: "vertexai".to_string(), - api_key: "test-api-key".to_string(), // Both API key and credentials provided - params, - }; - - let provider = VertexAIProvider::new(&config); - // Should prefer API key over credentials path - assert!(!provider.config.api_key.is_empty()); - assert_eq!(provider.config.api_key, "test-api-key"); - assert!(provider.config.params.contains_key("credentials_path")); // Credentials path should still be preserved - } - - #[test] - fn test_auth_config_credentials_only() { - let mut params = HashMap::new(); - params.insert("project_id".to_string(), "test-project".to_string()); - params.insert("credentials_path".to_string(), "some/path.json".to_string()); - - let config = ProviderConfig { - key: "test-vertexai".to_string(), - r#type: "vertexai".to_string(), - api_key: "".to_string(), // Empty API key - params, - }; - - let provider = VertexAIProvider::new(&config); - assert!(provider.config.api_key.is_empty()); - assert_eq!( - provider.config.params.get("credentials_path").unwrap(), - "some/path.json" - ); - } - - #[test] - fn test_empty_message_handling() { - let chat_request = ChatCompletionRequest { - model: "gemini-1.5-flash".to_string(), - messages: vec![ChatCompletionMessage { - role: "user".to_string(), - content: None, // Empty content - name: None, - tool_calls: None, - }], - temperature: None, - top_p: None, - n: None, - stream: None, - stop: None, - max_tokens: None, - presence_penalty: None, - frequency_penalty: None, - logit_bias: None, - user: None, - tools: None, - tool_choice: None, - parallel_tool_calls: None, - }; - - let gemini_request = GeminiChatRequest::from(chat_request); - assert_eq!(gemini_request.contents[0].parts[0].text, ""); - } - - #[test] - fn test_tool_choice_none() { - let chat_request = ChatCompletionRequest { - model: "gemini-1.5-flash".to_string(), - messages: vec![ChatCompletionMessage { - role: "user".to_string(), - content: Some(ChatMessageContent::String("test".to_string())), - name: None, - tool_calls: None, - }], - tool_choice: Some(ToolChoice::Simple(SimpleToolChoice::None)), - tools: Some(vec![ToolDefinition { - tool_type: "function".to_string(), - function: FunctionDefinition { - name: "test_function".to_string(), - description: Some("Test function".to_string()), - parameters: Some( - serde_json::from_value(serde_json::json!({ - "type": "object", - "properties": { - "test": { - "type": "string" - } - } - })) - .unwrap(), - ), - strict: None, - }, - }]), - temperature: None, - top_p: None, - n: None, - stream: None, - stop: None, - max_tokens: None, - presence_penalty: None, - frequency_penalty: None, - logit_bias: None, - user: None, - parallel_tool_calls: None, - }; - - let gemini_request = GeminiChatRequest::from(chat_request); - assert!(matches!( - gemini_request.tool_choice, - Some(GeminiToolChoice::None) - )); - } - - #[test] - fn test_generation_config_limits() { - let chat_request = ChatCompletionRequest { - model: "gemini-1.5-flash".to_string(), - messages: vec![ChatCompletionMessage { - role: "user".to_string(), - content: Some(ChatMessageContent::String("test".to_string())), - name: None, - tool_calls: None, - }], - temperature: Some(2.0), // Out of range - top_p: Some(1.5), // Out of range - max_tokens: Some(100000), // Very large - n: None, - stream: None, - stop: None, - presence_penalty: None, - frequency_penalty: None, - logit_bias: None, - user: None, - tools: None, - tool_choice: None, - parallel_tool_calls: None, - }; - - let gemini_request = GeminiChatRequest::from(chat_request); - let config = gemini_request.generation_config.unwrap(); - assert_eq!(config.temperature.unwrap(), 2.0); // Values are passed through as-is - assert_eq!(config.top_p.unwrap(), 1.5); // Values are passed through as-is - // No need to check for bounds as values are passed through unchanged - } - - #[test] - fn test_response_error_mapping() { - let gemini_response = GeminiChatResponse { - candidates: vec![], // Empty candidates - usage_metadata: None, - }; - - let model = "gemini-1.5-flash".to_string(); - let openai_response = gemini_response.to_openai(model); - assert!(openai_response.choices.is_empty()); - assert_eq!(openai_response.usage.prompt_tokens, 0); - assert_eq!(openai_response.usage.completion_tokens, 0); - assert_eq!(openai_response.usage.total_tokens, 0); - } -} diff --git a/src/providers/vertexai/tests.rs b/src/providers/vertexai/tests.rs index 8393b6a..345bda2 100644 --- a/src/providers/vertexai/tests.rs +++ b/src/providers/vertexai/tests.rs @@ -10,10 +10,21 @@ use super::provider::VertexAIProvider; use crate::config::models::{ModelConfig, Provider as ProviderConfig}; use crate::models::chat::{ChatCompletionRequest, ChatCompletionResponse}; use crate::models::completion::CompletionRequest; +use crate::models::content::ChatMessageContentPart; use crate::models::content::{ChatCompletionMessage, ChatMessageContent}; use crate::models::embeddings::{EmbeddingsInput, EmbeddingsRequest}; +use crate::models::tool_choice::SimpleToolChoice; +use crate::models::tool_choice::ToolChoice; use crate::models::tool_definition::{FunctionDefinition, ToolDefinition}; use crate::providers::provider::Provider; +use crate::providers::vertexai::models::ContentPart; +use crate::providers::vertexai::models::GeminiCandidate; +use crate::providers::vertexai::models::GeminiChatRequest; +use crate::providers::vertexai::models::GeminiChatResponse; +use crate::providers::vertexai::models::GeminiContent; +use crate::providers::vertexai::models::GeminiFunctionCall; +use crate::providers::vertexai::models::GeminiToolChoice; +use crate::providers::vertexai::models::UsageMetadata; // Test constants const TEST_PROJECT_ID: &str = "heavenya"; @@ -183,7 +194,7 @@ async fn test_chat_completions() { let provider = create_test_provider(client); let request = ChatCompletionRequest { - model: "gemini-1.5-flash".to_string(), + model: "gemini-2.0-flash-exp".to_string(), messages: vec![ChatCompletionMessage { role: "user".to_string(), content: Some(ChatMessageContent::String( @@ -191,6 +202,7 @@ async fn test_chat_completions() { )), name: None, tool_calls: None, + refusal: None, }], temperature: Some(0.7), top_p: Some(0.9), @@ -205,11 +217,15 @@ async fn test_chat_completions() { tools: None, tool_choice: None, parallel_tool_calls: None, + max_completion_tokens: None, + logprobs: None, + top_logprobs: None, + response_format: None, }; let model_config = ModelConfig { - key: "gemini-1.5-flash".to_string(), - r#type: "gemini-1.5-flash".to_string(), + key: "gemini-2.0-flash-exp".to_string(), + r#type: "gemini-2.0-flash-exp".to_string(), provider: "vertexai".to_string(), params: HashMap::new(), }; @@ -271,13 +287,13 @@ async fn test_embeddings() { } #[tokio::test] +#[should_panic(expected = "Text completions are not supported for Vertex AI. Use chat_completions instead.")] async fn test_completions() { let client = setup_test_client("completions").await; let provider = create_test_provider(client); - // ... rest of the test implementation let request = CompletionRequest { - model: "gemini-1.5-flash".to_string(), + model: "gemini-2.0-flash-exp".to_string(), prompt: "Once upon a time".to_string(), suffix: None, max_tokens: Some(100), @@ -296,38 +312,30 @@ async fn test_completions() { }; let model_config = ModelConfig { - key: "gemini-1.5-flash".to_string(), - r#type: "gemini-1.5-flash".to_string(), + key: "gemini-2.0-flash-exp".to_string(), + r#type: "gemini-2.0-flash-exp".to_string(), provider: "vertexai".to_string(), params: HashMap::new(), }; - let result = run_test_with_quota_retry(|| async { - let response = provider.completions(request.clone(), &model_config).await?; - if std::env::var("RECORD_MODE").is_ok() { - save_to_cassette("completions", &serde_json::to_value(&response).unwrap()).await; - } - Ok(response) - }) - .await; - - assert!(result.is_ok(), "Test failed: {:?}", result.err()); + // This should panic with unimplemented message + let _ = provider.completions(request, &model_config).await; } #[tokio::test] async fn test_chat_completions_with_tools() { + let _ = tracing_subscriber::fmt::try_init(); let client = setup_test_client("chat_completions_with_tools").await; let provider = create_test_provider(client); let request = ChatCompletionRequest { - model: "gemini-1.5-flash".to_string(), + model: "gemini-2.0-flash-exp".to_string(), messages: vec![ChatCompletionMessage { role: "user".to_string(), - content: Some(ChatMessageContent::String( - "What's the weather in San Francisco?".to_string(), - )), + content: Some(ChatMessageContent::String("What's the weather in San Francisco?".to_string())), name: None, tool_calls: None, + refusal: None, }], temperature: Some(0.7), top_p: Some(0.9), @@ -344,29 +352,30 @@ async fn test_chat_completions_with_tools() { function: FunctionDefinition { name: "get_weather".to_string(), description: Some("Get the current weather in a location".to_string()), - parameters: Some( - serde_json::from_value(json!({ - "type": "object", - "properties": { - "location": { - "type": "string", - "description": "The location to get weather for" - } - }, - "required": ["location"] - })) - .unwrap(), - ), + parameters: Some(serde_json::from_value(json!({ + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The location to get weather for" + } + }, + "required": ["location"] + })).unwrap()), strict: None, }, }]), tool_choice: None, parallel_tool_calls: None, + max_completion_tokens: None, + logprobs: None, + top_logprobs: None, + response_format: None, }; let model_config = ModelConfig { - key: "gemini-1.5-flash".to_string(), - r#type: "gemini-1.5-flash".to_string(), + key: "gemini-2.0-flash-exp".to_string(), + r#type: "gemini-2.0-flash-exp".to_string(), provider: "vertexai".to_string(), params: HashMap::new(), }; @@ -385,7 +394,6 @@ async fn test_chat_completions_with_tools() { .await; } ChatCompletionResponse::Stream(_) => { - // Handle streaming response if needed } } } @@ -404,14 +412,13 @@ async fn test_chat_completions_with_api_key() { let provider = create_test_provider_with_api_key(client, api_key); let request = ChatCompletionRequest { - model: "gemini-1.5-flash".to_string(), + model: "gemini-2.0-flash-exp".to_string(), messages: vec![ChatCompletionMessage { role: "user".to_string(), - content: Some(ChatMessageContent::String( - "Hello, how are you?".to_string(), - )), + content: Some(ChatMessageContent::String("Hello, how are you?".to_string())), name: None, tool_calls: None, + refusal: None, }], temperature: Some(0.7), top_p: Some(0.9), @@ -426,11 +433,15 @@ async fn test_chat_completions_with_api_key() { tools: None, tool_choice: None, parallel_tool_calls: None, + max_completion_tokens: None, + logprobs: None, + top_logprobs: None, + response_format: None, }; let model_config = ModelConfig { - key: "gemini-1.5-flash".to_string(), - r#type: "gemini-1.5-flash".to_string(), + key: "gemini-2.0-flash-exp".to_string(), + r#type: "gemini-2.0-flash-exp".to_string(), provider: "vertexai".to_string(), params: HashMap::new(), }; @@ -449,7 +460,6 @@ async fn test_chat_completions_with_api_key() { .await; } ChatCompletionResponse::Stream(_) => { - // Handle streaming response if needed } } } @@ -459,3 +469,516 @@ async fn test_chat_completions_with_api_key() { assert!(result.is_ok(), "Test failed: {:?}", result.err()); } + +#[test] +#[should_panic(expected = "Invalid location provided in configuration: \"Invalid location provided: 'invalid@location'. Location must contain only alphanumeric characters and hyphens.\"")] +fn test_invalid_location_format() { + let mut params = HashMap::new(); + params.insert("project_id".to_string(), "test-project".to_string()); + params.insert("location".to_string(), "invalid@location".to_string()); + + let config = ProviderConfig { + key: "test-vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "".to_string(), + params, + }; + + let _provider = VertexAIProvider::new(&config); +} + +#[test] +fn test_location_validation() { + let valid = VertexAIProvider::validate_location("us-central1"); + let invalid = VertexAIProvider::validate_location("invalid@location"); + let empty = VertexAIProvider::validate_location(""); + let special = VertexAIProvider::validate_location("!@#$%^"); + + assert_eq!(valid, Ok("us-central1".to_string())); + assert!(invalid.is_err()); + assert!(empty.is_err()); + assert!(special.is_err()); +} + +#[test] +fn test_auth_config_precedence() { + let mut params = HashMap::new(); + params.insert("project_id".to_string(), "test-project".to_string()); + params.insert("credentials_path".to_string(), "some/path.json".to_string()); + params.insert("location".to_string(), "us-central".to_string()); + + let config = ProviderConfig { + key: "test-vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "test-api-key".to_string(), + params, + }; + + let _provider = VertexAIProvider::new(&config); +} + +#[test] +fn test_auth_config_credentials_only() { + let mut params = HashMap::new(); + params.insert("project_id".to_string(), "test-project".to_string()); + params.insert("credentials_path".to_string(), "some/path.json".to_string()); + params.insert("location".to_string(), "us-central".to_string()); + + let config = ProviderConfig { + key: "test-vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "".to_string(), + params, + }; + + let _provider = VertexAIProvider::new(&config); +} + +#[test] +fn test_empty_message_handling() { + let chat_request = ChatCompletionRequest { + model: "gemini-2.0-flash-exp".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: None, + name: None, + tool_calls: None, + refusal: None, + }], + temperature: None, + top_p: None, + n: None, + stream: None, + stop: None, + max_tokens: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + max_completion_tokens: None, + logprobs: None, + top_logprobs: None, + response_format: None, + }; + + let gemini_request = GeminiChatRequest::from(chat_request); + assert!(gemini_request.contents[0].parts[0].text.is_none()); +} + +#[test] +fn test_tool_choice_none() { + let chat_request = ChatCompletionRequest { + model: "gemini-2.0-flash-exp".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String("test".to_string())), + name: None, + tool_calls: None, + refusal: None, + }], + tool_choice: Some(ToolChoice::Simple(SimpleToolChoice::None)), + tools: Some(vec![ToolDefinition { + tool_type: "function".to_string(), + function: FunctionDefinition { + name: "test_function".to_string(), + description: Some("Test function".to_string()), + parameters: Some( + serde_json::from_value(serde_json::json!({ + "type": "object", + "properties": { + "test": { + "type": "string" + } + } + })) + .unwrap(), + ), + strict: None, + }, + }]), + temperature: None, + top_p: None, + n: None, + stream: None, + stop: None, + max_tokens: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + parallel_tool_calls: None, + max_completion_tokens: None, + logprobs: None, + top_logprobs: None, + response_format: None, + }; + + let gemini_request = GeminiChatRequest::from(chat_request); + assert!(matches!( + gemini_request.tool_choice, + Some(GeminiToolChoice::None) + )); +} + +#[test] +fn test_generation_config_limits() { + let chat_request = ChatCompletionRequest { + model: "gemini-2.0-flash-exp".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String("test".to_string())), + name: None, + tool_calls: None, + refusal: None, + }], + temperature: Some(2.0), + top_p: Some(1.5), + max_tokens: Some(100000), + n: None, + stream: None, + stop: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + max_completion_tokens: None, + logprobs: None, + top_logprobs: None, + response_format: None, + }; + + let gemini_request = GeminiChatRequest::from(chat_request); + let config = gemini_request.generation_config.unwrap(); + assert_eq!(config.temperature.unwrap(), 2.0); + assert_eq!(config.top_p.unwrap(), 1.5); +} + +#[test] +fn test_response_error_mapping() { + let gemini_response = GeminiChatResponse { + candidates: vec![], + usage_metadata: None, + }; + + let model = "gemini-2.0-flash-exp".to_string(); + let openai_response = gemini_response.to_openai(model); + assert!(openai_response.choices.is_empty()); + assert_eq!(openai_response.usage.prompt_tokens, 0); + assert_eq!(openai_response.usage.completion_tokens, 0); + assert_eq!(openai_response.usage.total_tokens, 0); +} + +#[test] +fn test_provider_new() { + let mut params = HashMap::new(); + params.insert("project_id".to_string(), "test-project".to_string()); + params.insert("location".to_string(), "us-central1".to_string()); + + let config = ProviderConfig { + key: "test-vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "".to_string(), + params, + }; + + let provider = VertexAIProvider::new(&config); + assert_eq!(provider.r#type(), "vertexai"); + assert_eq!(provider.key(), "test-vertexai"); +} + +#[test] +#[should_panic(expected = "project_id is required")] +fn test_provider_new_missing_project_id() { + let config = ProviderConfig { + key: "test-vertexai".to_string(), + r#type: "vertexai".to_string(), + api_key: "".to_string(), + params: HashMap::new(), + }; + + VertexAIProvider::new(&config); +} + +#[test] +fn test_gemini_request_conversion() { + let chat_request = ChatCompletionRequest { + model: "gemini-2.0-flash-exp".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String("Hello".to_string())), + name: None, + tool_calls: None, + refusal: None, + }], + temperature: Some(0.7), + top_p: Some(0.9), + n: None, + stream: Some(false), + stop: None, + max_tokens: Some(100), + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + max_completion_tokens: None, + logprobs: None, + top_logprobs: None, + response_format: None, + }; + + let gemini_request = GeminiChatRequest::from(chat_request); + + assert_eq!(gemini_request.contents[0].parts[0].text, Some("Hello".to_string())); + assert_eq!(gemini_request.contents[0].role, "user"); + assert_eq!( + gemini_request + .generation_config + .as_ref() + .unwrap() + .temperature, + Some(0.7) + ); + assert_eq!( + gemini_request.generation_config.as_ref().unwrap().top_p, + Some(0.9) + ); +} + +#[test] +fn test_gemini_response_conversion() { + let gemini_response = GeminiChatResponse { + candidates: vec![GeminiCandidate { + content: GeminiContent { + role: "model".to_string(), + parts: vec![ContentPart { + text: Some("Hello there!".to_string()), + function_call: None, + }], + }, + finish_reason: Some("STOP".to_string()), + safety_ratings: None, + tool_calls: None, + }], + usage_metadata: Some(UsageMetadata { + prompt_token_count: 10, + candidates_token_count: 20, + total_token_count: 30, + }), + }; + + let model = "gemini-2.0-flash-exp".to_string(); + let openai_response = gemini_response.to_openai(model.clone()); + + assert_eq!(openai_response.model, model); + match &openai_response.choices[0].message.content { + Some(ChatMessageContent::String(text)) => assert_eq!(text, "Hello there!"), + _ => panic!("Expected String content"), + } + assert_eq!( + openai_response.choices[0].finish_reason, + Some("STOP".to_string()) + ); + assert_eq!(openai_response.usage.prompt_tokens, 10); + assert_eq!(openai_response.usage.completion_tokens, 20); + assert_eq!(openai_response.usage.total_tokens, 30); +} + +#[test] +fn test_gemini_request_with_tools() { + let chat_request = ChatCompletionRequest { + model: "gemini-2.0-flash-exp".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String("Hello".to_string())), + name: None, + tool_calls: None, + refusal: None, + }], + temperature: Some(0.7), + tools: Some(vec![ToolDefinition { + tool_type: "function".to_string(), + function: FunctionDefinition { + name: "test_function".to_string(), + description: Some("Test function".to_string()), + parameters: Some( + serde_json::from_value(serde_json::json!({ + "type": "object", + "properties": { + "test": { + "type": "string" + } + } + })) + .unwrap(), + ), + strict: None, + }, + }]), + tool_choice: Some(ToolChoice::Simple(SimpleToolChoice::Auto)), + top_p: None, + n: None, + stream: None, + stop: None, + max_tokens: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + parallel_tool_calls: None, + max_completion_tokens: None, + logprobs: None, + top_logprobs: None, + response_format: None, + }; + + let gemini_request = GeminiChatRequest::from(chat_request); + + assert!(gemini_request.tools.is_some()); + let tools = gemini_request.tools.unwrap(); + assert_eq!(tools[0].function_declarations[0].name, "test_function"); +} + +#[test] +fn test_gemini_response_with_tool_calls() { + let gemini_response = GeminiChatResponse { + candidates: vec![GeminiCandidate { + content: GeminiContent { + role: "model".to_string(), + parts: vec![ + ContentPart { + text: None, + function_call: Some(GeminiFunctionCall { + name: "get_weather".to_string(), + args: serde_json::json!({ + "location": "San Francisco" + }) + }) + } + ], + }, + finish_reason: Some("TOOL_CODE".to_string()), + safety_ratings: None, + tool_calls: None, + }], + usage_metadata: Some(UsageMetadata { + prompt_token_count: 10, + candidates_token_count: 20, + total_token_count: 30, + }), + }; + + let model = "gemini-2.0-flash-exp".to_string(); + let openai_response = gemini_response.to_openai(model.clone()); + + assert!(openai_response.choices[0].message.tool_calls.is_some()); + let tool_calls = openai_response.choices[0] + .message + .tool_calls + .as_ref() + .unwrap(); + assert_eq!(tool_calls[0].function.name, "get_weather"); + assert_eq!( + tool_calls[0].function.arguments, + r#"{"location":"San Francisco"}"# + ); +} + +#[test] +fn test_gemini_request_with_system_message() { + let chat_request = ChatCompletionRequest { + model: "gemini-2.0-flash-exp".to_string(), + messages: vec![ + ChatCompletionMessage { + role: "system".to_string(), + content: Some(ChatMessageContent::String( + "You are a helpful assistant".to_string(), + )), + name: None, + tool_calls: None, + refusal: None, + }, + ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::String("Hello".to_string())), + name: None, + tool_calls: None, + refusal: None, + }, + ], + temperature: None, + top_p: None, + n: None, + stream: None, + stop: None, + max_tokens: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + max_completion_tokens: None, + logprobs: None, + top_logprobs: None, + response_format: None, + }; + + let gemini_request = GeminiChatRequest::from(chat_request); + + assert_eq!(gemini_request.contents.len(), 2); + assert_eq!(gemini_request.contents[0].role, "system"); +} + +#[test] +fn test_gemini_request_with_array_content() { + let chat_request = ChatCompletionRequest { + model: "gemini-2.0-flash-exp".to_string(), + messages: vec![ChatCompletionMessage { + role: "user".to_string(), + content: Some(ChatMessageContent::Array(vec![ + ChatMessageContentPart { + r#type: "text".to_string(), + text: "Part 1".to_string(), + }, + ChatMessageContentPart { + r#type: "text".to_string(), + text: "Part 2".to_string(), + }, + ])), + name: None, + tool_calls: None, + refusal: None, + }], + temperature: None, + top_p: None, + n: None, + stream: None, + stop: None, + max_tokens: None, + presence_penalty: None, + frequency_penalty: None, + logit_bias: None, + user: None, + tools: None, + tool_choice: None, + parallel_tool_calls: None, + max_completion_tokens: None, + logprobs: None, + top_logprobs: None, + response_format: None, + }; + + let gemini_request = GeminiChatRequest::from(chat_request); + + assert_eq!(gemini_request.contents[0].parts[0].text, Some("Part 1 Part 2".to_string())); +} diff --git a/tests/cassettes/vertexai/chat_completions.json b/tests/cassettes/vertexai/chat_completions.json index b7c67dc..af64a8f 100644 --- a/tests/cassettes/vertexai/chat_completions.json +++ b/tests/cassettes/vertexai/chat_completions.json @@ -1,46 +1,107 @@ [ { + "id": "chatcmpl-0f8acb38-a442-4ada-aa51-6ad8c5f91dc9", + "object": "chat.completion", + "created": 1747062082, + "model": "gemini-2.0-flash-exp", "choices": [ { - "finish_reason": "STOP", "index": 0, "message": { - "content": "I am an AI language model, so I don't have feelings like humans do. But I am here and ready to assist you with any questions or tasks you may have! How can I help you today? 😊 \n", - "role": "assistant" + "role": "assistant", + "content": "I am doing well, thank you for asking! As a large language model, I don't experience emotions or feelings like humans do, but I am functioning optimally and ready to assist you. How can I help you today?\n" } } ], - "created": 1735633379, - "id": "chatcmpl-66e406c3-5b89-401d-a0cd-567f22db76d4", - "model": "gemini-1.5-flash", + "usage": { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0 + }, + "system_fingerprint": null + }, + { + "id": "chatcmpl-45af8b98-b836-4ba1-9d91-7a636f40da89", "object": "chat.completion", - "system_fingerprint": null, + "created": 1747062191, + "model": "gemini-2.0-flash-exp", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "I am doing well, thank you for asking! As a large language model, I don't experience feelings or emotions in the same way humans do, but I am functioning optimally and ready to assist you with your requests. How can I help you today?\n" + } + } + ], "usage": { - "completion_tokens": 46, - "prompt_tokens": 6, - "total_tokens": 52 - } + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0 + }, + "system_fingerprint": null }, { + "id": "chatcmpl-5ead557a-f2ee-4062-a029-f302d6313b70", + "object": "chat.completion", + "created": 1747064691, + "model": "gemini-2.0-flash-exp", "choices": [ { - "finish_reason": "STOP", "index": 0, "message": { - "content": "I am an AI language model, so I don't have feelings or experiences like humans do. However, I am here to assist you with any questions or tasks you may have! 😊 How can I help you today? \n", - "role": "assistant" + "role": "assistant", + "content": "I am doing well, thank you for asking! As a large language model, I don't experience emotions or feelings like humans do, but I am functioning optimally and ready to assist you. How can I help you today?\n" } } ], - "created": 1735633515, - "id": "chatcmpl-b3a3f424-17c0-4c84-a27e-35f7ffd5fca0", - "model": "gemini-1.5-flash", + "usage": { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0 + }, + "system_fingerprint": null + }, + { + "id": "chatcmpl-0f3f7206-21cb-4832-8936-3af45bbfb9a1", "object": "chat.completion", - "system_fingerprint": null, + "created": 1747064863, + "model": "gemini-2.0-flash-exp", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "I am doing well, thank you for asking! As a large language model, I don't experience emotions or feelings in the same way humans do, but I am functioning optimally and ready to assist you. How can I help you today?\n" + } + } + ], + "usage": { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0 + }, + "system_fingerprint": null + }, + { + "id": "chatcmpl-f56cd4f4-f4a9-4eb1-8c35-cd61a7fb2e7d", + "object": "chat.completion", + "created": 1747065205, + "model": "gemini-2.0-flash-exp", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "I am doing well, thank you for asking! How are you today?\n" + } + } + ], "usage": { - "completion_tokens": 47, - "prompt_tokens": 6, - "total_tokens": 53 - } + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0 + }, + "system_fingerprint": null } ] \ No newline at end of file diff --git a/tests/cassettes/vertexai/chat_completions_with_tools.json b/tests/cassettes/vertexai/chat_completions_with_tools.json index 8694d5c..8076d07 100644 --- a/tests/cassettes/vertexai/chat_completions_with_tools.json +++ b/tests/cassettes/vertexai/chat_completions_with_tools.json @@ -1,24 +1,92 @@ [ { + "id": "chatcmpl-de1cfeec-6d9f-475e-ae6d-7dead4cd260e", + "object": "chat.completion", + "created": 1747064690, + "model": "gemini-2.0-flash-exp", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "tool_calls": [ + { + "id": "call_3b2927f2-e7a3-4a18-b9ed-ce1efc23d3fb", + "function": { + "arguments": "{\"location\":\"San Francisco\"}", + "name": "get_weather" + }, + "type": "function" + } + ] + } + } + ], + "usage": { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0 + }, + "system_fingerprint": null + }, + { + "id": "chatcmpl-2d15eaf9-36da-43b1-9e83-75c465d6938c", + "object": "chat.completion", + "created": 1747064802, + "model": "gemini-2.0-flash-exp", "choices": [ { - "finish_reason": "STOP", "index": 0, "message": { - "content": "", - "role": "assistant" + "role": "assistant", + "tool_calls": [ + { + "id": "call_8cf02207-a5b9-4cc5-b240-8932f380f8df", + "function": { + "arguments": "{\"location\":\"San Francisco\"}", + "name": "get_weather" + }, + "type": "function" + } + ] } } ], - "created": 1735633514, - "id": "chatcmpl-a513c04e-4300-416f-bc7c-5933229027d6", - "model": "gemini-1.5-flash", + "usage": { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0 + }, + "system_fingerprint": null + }, + { + "id": "chatcmpl-4df1d154-9b2c-40cc-882a-83f845429014", "object": "chat.completion", - "system_fingerprint": null, + "created": 1747065205, + "model": "gemini-2.0-flash-exp", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "tool_calls": [ + { + "id": "call_e069a236-6ea2-4660-a189-2fe1a0439222", + "function": { + "arguments": "{\"location\":\"San Francisco\"}", + "name": "get_weather" + }, + "type": "function" + } + ] + } + } + ], "usage": { - "completion_tokens": 6, - "prompt_tokens": 27, - "total_tokens": 33 - } + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0 + }, + "system_fingerprint": null } ] \ No newline at end of file diff --git a/tests/cassettes/vertexai/completions.json b/tests/cassettes/vertexai/completions.json deleted file mode 100644 index 657a140..0000000 --- a/tests/cassettes/vertexai/completions.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "choices": [ - { - "finish_reason": "STOP", - "index": 0, - "text": "Once upon a time, in a village nestled between rolling hills and a whispering river, lived a young girl named Elara. Elara wasn't like the other children. While they played with dolls and chased butterflies, Elara spent her days lost in the pages of dusty old books, her imagination soaring with tales of faraway lands and fantastical creatures. \n\nWhat would you like to happen next? \n" - } - ], - "created": 1735633515, - "id": "chatcmpl-99881c18-33ac-430b-b788-4a5cea4dce3e", - "model": "gemini-1.5-flash", - "object": "text_completion", - "usage": { - "completion_tokens": 0, - "prompt_tokens": 0, - "total_tokens": 0 - } - } -] \ No newline at end of file diff --git a/tests/cassettes/vertexai/embeddings.json b/tests/cassettes/vertexai/embeddings.json index 1f11354..458aaf9 100644 --- a/tests/cassettes/vertexai/embeddings.json +++ b/tests/cassettes/vertexai/embeddings.json @@ -1,7 +1,3145 @@ [ { + "object": "list", + "data": [ + { + "object": "embedding", + "embedding": [ + -0.058164194226264954, + -0.00003622031363192946, + 0.010542492382228374, + -0.004728350788354874, + 0.07369722425937653, + -0.02481695637106895, + -0.00031316516106016934, + -0.017290938645601273, + 0.03166302293539047, + 0.014893381856381891, + -0.04859609156847, + -0.05490480735898018, + -0.005848468281328678, + -0.06573579460382462, + -0.013973977416753767, + 0.03232813626527786, + 0.07840143144130707, + -0.05846800282597542, + -0.041564371436834335, + -0.017742950469255447, + 0.022528981789946556, + -0.05958662927150726, + -0.0955798402428627, + -0.009678563103079796, + 0.044648200273513794, + -0.043353594839572906, + -0.01671011932194233, + -0.02975669503211975, + -0.05829453468322754, + -0.0157438013702631, + 0.0006426912150345743, + -0.05014248937368393, + 0.011643724516034126, + -0.0007280845893546939, + 0.03767689689993858, + -0.010895035229623318, + 0.033650316298007965, + -0.037673596292734146, + 0.018698105588555336, + -0.03840488940477371, + 0.03343287855386734, + -0.05688348412513733, + -0.012943455018103124, + -0.0692962184548378, + -0.03782666474580765, + 0.010393713600933552, + -0.025529509410262108, + 0.01568876951932907, + 0.07156006246805191, + -0.014751105569303036, + 0.08142535388469696, + 0.029754770919680595, + -0.007077757269144058, + 0.031249215826392177, + 0.022206788882613186, + 0.05383630096912384, + 0.005256577394902706, + -0.013356782495975494, + 0.008688163012266159, + 0.02924143336713314, + -0.026365751400589943, + -0.036567822098731995, + 0.013740355148911476, + 0.0014254077104851604, + -0.04947865009307861, + -0.01049752440303564, + -0.007019080687314272, + -0.0033643722999840975, + -0.0020064576528966427, + -0.07127232104539871, + -0.05643607676029205, + -0.007050491403788328, + 0.005696943495422602, + 0.0319971963763237, + -0.045856233686208725, + -0.0382072851061821, + 0.024022594094276428, + 0.07401637732982635, + -0.01796848513185978, + -0.023768220096826553, + -0.059311170130968094, + -0.02001041918992996, + -0.053349319845438, + 0.0029365948867052794, + 0.010357838124036787, + -0.03372623398900032, + 0.005034816917032003, + -0.06332722306251526, + 0.0042638652957975864, + -0.015453161671757698, + -0.039690133184194565, + -0.020585861057043076, + -0.08410325646400452, + -0.020636729896068573, + 0.022761065512895584, + -0.02659504860639572, + 0.008869532495737076, + 0.06127539649605751, + 0.016054663807153702, + 0.01801091432571411, + -0.0068725040182471275, + 0.038399890065193176, + -0.01656283810734749, + -0.02084347791969776, + 0.008902153931558132, + 0.06902532279491425, + -0.0018741635140031576, + -0.04490096867084503, + 0.06339003145694733, + -0.017102815210819244, + -0.057325396686792374, + 0.022083261981606483, + -0.04266951605677605, + 0.019720112904906273, + 0.05673870071768761, + 0.02355301007628441, + -0.04308970272541046, + 0.0002606247435323894, + -0.00685822544619441, + -0.03939145803451538, + -0.02690181694924831, + -0.055103152990341187, + 0.1029508337378502, + 0.046327341347932816, + 0.0023325744550675154, + 0.018498506397008896, + -0.06048314645886421, + -0.013803904876112938, + 0.03132600709795952, + -0.006520519964396954, + 0.028858399018645287, + -0.04834062233567238, + 0.04562418535351753, + 0.07403726130723953, + 0.0036133721005171537, + -0.011329884640872478, + -0.0112222321331501, + -0.008675935678184032, + 0.016003990545868874, + 0.02360924705862999, + -0.03237585723400116, + 0.062091924250125885, + 0.0534723736345768, + 0.06908244639635086, + 0.01992947794497013, + -0.021924395114183422, + -0.08472655713558197, + 0.010171602480113506, + 0.013133247382938862, + -0.02523472346365452, + -0.06846307218074799, + 0.0004721606965176761, + -0.02166888676583767, + -0.0005694524152204394, + -0.008681336417794228, + -0.05947762727737427, + -0.04814690351486206, + -0.013798982836306097, + 0.01617482490837574, + -0.02504643611609936, + 0.009110392071306704, + -0.013774625957012177, + -0.019712207838892937, + -0.016054371371865273, + -0.018327657133340836, + -0.012811604887247086, + 0.08344585448503494, + 0.0004540338122751564, + 0.019656607881188393, + 0.019389579072594643, + -0.014049646444618702, + 0.017445947974920273, + -0.00820555817335844, + -0.029353104531764984, + 0.0435597263276577, + 0.009650807827711104, + -0.0388045459985733, + -0.04784759134054184, + -0.038223911076784134, + -0.03691287711262703, + -0.03876909241080284, + -0.06724806874990463, + -0.04394567012786865, + 0.04173814505338669, + -0.09444724023342133, + 0.007763924542814493, + -0.008699805475771427, + -0.007599780336022377, + 0.0023920757230371237, + 0.029335761442780495, + -0.07895313203334808, + -0.04035546630620957, + -0.008500908501446247, + 0.030348196625709537, + 0.02277581207454205, + 0.05779244005680084, + 0.049121756106615067, + -0.005412466358393431, + 0.007729559671133757, + -0.01292573381215334, + -0.025097647681832314, + 0.004094319883733988, + 0.06612378358840942, + -0.019531669095158577, + -0.005063635762780905, + -0.005468557123094797, + 0.07955626398324966, + -0.002157465321943164, + 0.009207960218191149, + -0.06414847075939178, + -0.0035572517663240433, + -0.0020771902054548264, + -0.1227332055568695, + -0.03706011176109314, + 0.0008404941763728857, + -0.046963952481746674, + 0.04012263193726539, + -0.027263401076197624, + 0.016582122072577477, + 0.04703010618686676, + 0.03132076933979988, + -0.010051103308796884, + -0.03994416818022728, + 0.05056227371096611, + -0.005183490924537182, + -0.03397025540471077, + 0.05630888789892197, + -0.00752260722219944, + 0.056935470551252365, + -0.019262658432126045, + -0.005856715142726898, + -0.00361971789970994, + 0.014742489904165268, + -0.0173240564763546, + 0.025849811732769012, + -0.03633483499288559, + 0.05162259563803673, + -0.024835949763655663, + -0.04847341403365135, + -0.03159399703145027, + -0.03467343747615814, + 0.036358628422021866, + -0.03581903874874115, + 0.002909073606133461, + -0.06491775810718536, + 0.02263971231877804, + 0.0016398467123508451, + 0.02446398138999939, + -0.07746433466672897, + -0.006726226769387722, + -0.000519428460393101, + -0.039504919201135635, + -0.005563349928706884, + -0.020594995468854904, + 0.061375197023153305, + -0.04385501146316528, + -0.020819365978240967, + 0.0002135665708919987, + 0.0025394882541149855, + 0.03940146788954735, + 0.04535587877035141, + 0.022408338263630867, + 0.010107740759849548, + -0.02910368889570236, + 0.023004544898867607, + -0.0777907446026802, + -0.03995157033205032, + -0.007604190148413181, + -0.01633376069366932, + 0.03180794045329094, + -0.001723665394820273, + 0.008649897761642933, + 0.0242207832634449, + -0.010647157207131386, + -0.026367707177996635, + 0.04031673073768616, + -0.05165720731019974, + -0.03284695744514465, + -0.02335844747722149, + -0.03349415957927704, + 0.025802014395594597, + -0.03694309666752815, + -0.006044459994882345, + 0.06736567616462708, + 0.01603505201637745, + -0.02328784205019474, + -0.012791356071829796, + 0.013516776263713837, + -0.03699612617492676, + 0.01060064509510994, + 0.00883965939283371, + -0.009064657613635063, + 0.0350169874727726, + -0.02685544267296791, + -0.014185672625899317, + 0.016354434192180634, + 0.036822687834501266, + 0.023291006684303284, + -0.059676602482795715, + 0.018569037318229675, + -0.035254210233688354, + 0.03186021000146866, + -0.006412920076400042, + 0.006461815442889929, + -0.0018794521456584337, + -0.004147578962147236, + -0.011934665031731129, + -0.0030684741213917732, + -0.011600416153669356, + 0.014210240915417671, + 0.035710278898477554, + -0.0347076840698719, + 0.024610867723822594, + -0.02708994224667549, + -0.05045025795698166, + -0.010565407574176788, + -0.033687181770801544, + -0.02122747339308262, + -0.04409955069422722, + -0.003069423837587238, + 0.044485583901405334, + -0.05378193408250809, + 0.072037473320961, + -0.07409116625785828, + 0.015786299481987953, + -0.06721299141645432, + 0.025938687846064568, + 0.010510837659239767, + -0.023115744814276695, + -0.03091544844210148, + 0.050648219883441925, + 0.035482946783304214, + 0.04307528957724571, + -0.04726636782288551, + -0.04310080036520958, + -0.013828760012984276, + 0.048286303877830505, + -0.02076721377670765, + -0.01085709035396576, + -0.03584962338209152, + -0.014488843269646168, + -0.0027554789558053017, + -0.06005162000656128, + 0.04566371068358421, + -0.08098234236240387, + -0.0007054588641040027, + 0.023113127797842022, + 0.013891058973968027, + -0.06299350410699844, + 0.013442540541291235, + -0.0063631776720285416, + 0.03821553662419319, + 0.042192913591861725, + -0.011878528632223606, + 0.025002310052514076, + -0.03168347105383873, + 0.00921724271029234, + 0.05588514357805252, + -0.019194696098566055, + -0.013231540098786354, + 0.013922672718763351, + 0.050090741366147995, + -0.009419753216207027, + 0.030472371727228165, + 0.02902497723698616, + 0.00012655452883336693, + 0.02010628953576088, + -0.017804551869630814, + 0.02543807215988636, + -0.0017418548231944442, + 0.03014679066836834, + -0.002393407514318824, + 0.01539027225226164, + -0.013939744792878628, + 0.04250369220972061, + -0.028016269207000732, + -0.0010314607061445713, + 0.00945567712187767, + 0.01606564037501812, + 0.03212505206465721, + 0.02634749934077263, + -0.04875859245657921, + -0.02948666177690029, + -0.010389791801571846, + -0.02731900289654732, + 0.008594093844294548, + -0.0005823180545121431, + 0.054062556475400925, + 0.0035941607784479856, + 0.0543292835354805, + -0.004254109226167202, + 0.08106452226638794, + 0.00023218353453557936, + 0.008525514975190163, + 0.010739163495600224, + -0.06044655293226242, + 0.02740525454282761, + 0.024431807920336723, + -0.07784923911094666, + -0.011249307543039322, + 0.042149681597948074, + 0.05080077797174454, + 0.012841291725635529, + -0.01869971305131912, + -0.0298676285892725, + -0.030107680708169937, + 0.007617079187184572, + -0.03927510604262352, + 0.005952583160251379, + -0.04362985119223595, + -0.056472595781087875, + -0.05122603103518486, + 0.030536439269781113, + 0.06711754202842712, + 0.030769379809498787, + -0.08917279541492462, + 0.030519621446728703, + -0.018731193616986275, + 0.025107961148023605, + -0.04443630948662758, + -0.03170761838555336, + 0.05583782494068146, + 0.028091464191675183, + 0.022955838590860367, + 0.033636752516031265, + -0.02531679160892963, + -0.012428611516952516, + 0.019952984526753426, + 0.02082655392587185, + 0.07539939135313034, + -0.06182907521724701, + 0.02644423581659794, + -0.0031414111144840717, + -0.03931447118520737, + 0.03972741961479187, + -0.06503785401582718, + -0.02640126273036003, + -0.026757026091217995, + 0.02259722352027893, + -0.026944443583488464, + -0.04200126603245735, + 0.06589224189519882, + -0.0060363225638866425, + 0.014422483742237093, + -0.047794267535209656, + -0.03258788213133812, + 0.0013760939473286271, + -0.009353984147310255, + 0.012716212309896946, + 0.04360601305961609, + 0.0045635453425347805, + 0.038450006395578384, + 0.032771769911050797, + 0.0030687032267451286, + -0.04321933165192604, + 0.006499011069536209, + 0.0028769823256880045, + 0.012420333921909332, + 0.013525757007300854, + -0.006150753237307072, + -0.004118023905903101, + 0.023745615035295486, + -0.042544446885585785, + 0.01779933273792267, + 0.0738072544336319, + -0.03007355146110058, + -0.009512661024928091, + -0.03289958834648132, + -0.004790752660483122, + 0.0004558037326205522, + 0.0720517635345459, + -0.06180300563573837, + -0.0042299022898077965, + 0.00017941815895028412, + 0.026685943827033043, + 0.0046829464845359325, + -0.0006890723598189652, + 0.008649819530546665, + -0.019310785457491875, + 0.03345974162220955, + -0.02027411200106144, + 0.0454903170466423, + 0.004120772238820791, + -0.028732268139719963, + 0.002070050220936537, + 0.03910873085260391, + -0.034626252949237823, + -0.06625950336456299, + -0.057161930948495865, + -0.027074122801423073, + -0.03852885961532593, + 0.036027777940034866, + -0.03378047049045563, + -0.04209835082292557, + 0.02349921129643917, + 0.03960388153791427, + 0.0015966565115377307, + -0.003795675467699766, + 0.008811083622276783, + -0.02891468815505505, + -0.08621173352003098, + 0.03072702139616013, + -0.04263502359390259, + 0.0518559105694294, + -0.014513948932290075, + 0.00426185317337513, + -0.042820628732442856, + 0.061024997383356094, + 0.008177947252988815, + -0.025654304772615433, + -0.01994758658111095, + 0.03115339018404484, + -0.06122246012091637, + -0.00973520614206791, + 0.026119912043213844, + 0.018067168071866035, + 0.046298809349536896, + -0.0637248307466507, + -0.003924540244042873, + 0.05164488032460213, + -0.03986351564526558, + 0.012143593281507492, + -0.01493164524435997, + 0.012364163994789124, + 0.0033910535275936127, + 0.03926117718219757, + 0.0160888209939003, + 0.022147519513964653, + 0.040994029492139816, + 0.03238851949572563, + 0.031068911775946617, + -0.0019339561695232987, + -0.04030238837003708, + 0.018413899466395375, + 0.009558942168951036, + 0.024898380041122437, + -0.02646373026072979, + -0.027966918423771855, + 0.03851816430687904, + -0.018016686663031575, + 0.01169034279882908, + -0.041716981679201126, + -0.012398135848343372, + -0.040918245911598206, + 0.049635518342256546, + 0.019493695348501205, + 0.010355286300182344, + -0.005950144957751036, + -0.022309331223368645, + -0.0430804155766964, + 0.0156959630548954, + 0.01119300164282322, + -0.008492423221468925, + 0.014949626289308071, + -0.053723081946372986, + 0.027443569153547287, + 0.03662879765033722, + -0.03641078248620033, + 0.04629331827163696, + 0.004617750179022551, + -0.03654378652572632, + 0.013454713858664036, + 0.0032841702923178673, + -0.01309528760612011, + -0.0006306404829956591, + -0.010712265968322754, + -0.0031115366145968437, + 0.06719954311847687, + -0.041091009974479675, + 0.052047744393348694, + 0.015360930003225803, + 0.017123648896813393, + -0.016294341534376144, + 0.04660823196172714, + -0.024207523092627525, + -0.04300165921449661, + -0.05108120292425155, + 0.09737501293420792, + -0.01331926416605711, + 0.06842294335365295, + -0.002399123040959239, + 0.012122059240937231, + 0.06719434261322021, + -0.05437808856368065, + 0.004240202717483044, + -0.027191925793886185, + -0.040218885987997055, + -0.02375097759068012, + 0.012262600474059582, + 0.014219674281775951, + -0.006157959345728159, + 0.011399772949516771, + -0.05200403183698654, + -0.017264649271965027, + 0.016833636909723282, + -0.009583424776792526, + -0.03376639261841774, + -0.00961976870894432, + 0.001210652757436037, + -0.0612335205078125, + -0.0336930938065052, + -0.025393076241016388, + -0.02714981697499752, + 0.004886742681264877, + 0.013395018875598907, + -0.02571096643805504, + -0.03276616707444191, + -0.030069544911384583, + 0.036591000854969025, + -0.07458269596099854, + 0.05744070932269096, + 0.028478343039751053, + -0.0028876815922558308, + 0.02639182470738888, + 0.018080219626426697, + 0.04396456852555275, + 0.003018079325556755, + -0.03397033363580704, + -0.02141541987657547, + 0.010896582156419754, + -0.03434125706553459, + -0.05253784731030464, + -0.025020217522978783, + -0.005296454764902592, + 0.019587192684412003, + 0.03784740716218949, + -0.01990439184010029, + 0.02046854794025421, + -0.02455652691423893, + -0.020822890102863312, + 0.003083446528762579, + 0.07859235256910324, + -0.08430628478527069, + -0.02872663363814354, + 0.05072060227394104, + 0.043463632464408875, + 0.017734138295054436, + -0.04160630330443382, + -0.04641241580247879, + -0.02498893067240715, + -0.03297220170497894, + -0.09785742312669754, + -0.006121875252574682, + -0.022711746394634247, + -0.01429930329322815, + -0.00412411242723465, + 0.007504432462155819, + -0.000563237292226404, + 0.01013818196952343, + -0.06896454840898514, + 0.006575733423233032, + -0.10310959815979004, + -0.012512778863310814, + 0.03036043606698513, + -0.015878431499004364, + 0.022684166207909584, + 0.02066022157669067, + 0.016029203310608864, + -0.028443187475204468, + -0.01416606828570366, + 0.0071391211822628975, + 0.034776851534843445, + 0.002298222854733467, + 0.033520814031362534, + 0.05799320712685585, + -0.0030665509402751923, + 0.013703178614377975, + 0.04346451908349991, + -0.08736324310302734, + -0.04443465545773506, + -0.09507574141025545, + -0.007938905619084835, + 0.005520000122487545, + -0.043095000088214874, + -0.03352028876543045, + 0.021385299041867256, + 0.02366030216217041, + -0.02853614091873169, + 0.002117573283612728, + 0.055353257805109024, + 0.027501529082655907, + -0.015763575211167336, + 0.0570647306740284, + -0.029892882332205772, + 0.02390587143599987, + -0.013306232169270515, + 0.018932240083813667, + 0.0071633001789450645, + 0.006233749445527792, + 0.03482261300086975, + -0.0009497640421614052, + 0.04889736324548721, + -0.010756379924714564, + -0.10233137756586076, + 0.032568227499723434, + -0.0017232495592907071, + 0.0197619441896677, + -0.01157362200319767, + -0.022340090945363045, + 0.03321876749396324, + -0.03730887547135353, + -0.004980842582881451, + 0.031003642827272415, + 0.04853849858045578, + 0.00792314950376749, + -0.016585927456617355, + -0.00377306598238647, + 0.009732725098729134, + -0.026165375486016273, + 0.0068840766325592995, + 0.02659326232969761, + -0.005413031205534935, + -0.0209831390529871, + -0.029614845290780067, + 0.01654200442135334, + -0.03843202814459801, + 0.016572654247283936, + -0.022821595892310143, + 0.02077091671526432, + -0.033952746540308, + 0.06542537361383438, + -0.08189623057842255, + 0.0031411293894052505, + -0.01395489927381277, + 0.01906730607151985, + -0.05683666840195656, + -0.03671567142009735, + 0.001987523166462779, + 0.006716572213917971, + 0.058880213648080826, + -0.028976114466786385, + -0.10136104375123978, + -0.01454504206776619, + -0.06632363796234131, + 0.012023151852190496, + -0.039696235209703445, + -0.10271679610013962, + -0.00566994259133935, + -0.011019215919077396, + 0.022908398881554604, + 0.00902929063886404, + -0.02031330019235611, + 0.02893255092203617, + -0.020042693242430687, + -0.02361901104450226, + 0.038222216069698334, + 0.008589942008256912, + 0.03230403736233711, + 0.002454438945278526, + 0.004391937050968409, + -0.0484878346323967, + -0.002869164338335395, + -0.05096660554409027, + -0.028733370825648308, + 0.03479108586907387, + 0.03205372020602226, + -0.004485339857637882, + 0.017057575285434723, + 0.0132388761267066, + -0.04253086820244789, + 0.021169882267713547, + -0.008464457467198372, + -0.009780851192772388, + 0.02306952327489853, + -0.04061064124107361, + 0.0140217337757349, + -0.003301902674138546, + 0.005067829042673111 + ], + "index": 0 + } + ], + "model": "text-embedding-005", + "usage": { + "prompt_tokens": 0, + "total_tokens": 0 + } + }, + { + "object": "list", + "data": [ + { + "object": "embedding", + "embedding": [ + -0.058164194226264954, + -0.00003622031363192946, + 0.010542492382228374, + -0.004728350788354874, + 0.07369722425937653, + -0.02481695637106895, + -0.00031316516106016934, + -0.017290938645601273, + 0.03166302293539047, + 0.014893381856381891, + -0.04859609156847, + -0.05490480735898018, + -0.005848468281328678, + -0.06573579460382462, + -0.013973977416753767, + 0.03232813626527786, + 0.07840143144130707, + -0.05846800282597542, + -0.041564371436834335, + -0.017742950469255447, + 0.022528981789946556, + -0.05958662927150726, + -0.0955798402428627, + -0.009678563103079796, + 0.044648200273513794, + -0.043353594839572906, + -0.01671011932194233, + -0.02975669503211975, + -0.05829453468322754, + -0.0157438013702631, + 0.0006426912150345743, + -0.05014248937368393, + 0.011643724516034126, + -0.0007280845893546939, + 0.03767689689993858, + -0.010895035229623318, + 0.033650316298007965, + -0.037673596292734146, + 0.018698105588555336, + -0.03840488940477371, + 0.03343287855386734, + -0.05688348412513733, + -0.012943455018103124, + -0.0692962184548378, + -0.03782666474580765, + 0.010393713600933552, + -0.025529509410262108, + 0.01568876951932907, + 0.07156006246805191, + -0.014751105569303036, + 0.08142535388469696, + 0.029754770919680595, + -0.007077757269144058, + 0.031249215826392177, + 0.022206788882613186, + 0.05383630096912384, + 0.005256577394902706, + -0.013356782495975494, + 0.008688163012266159, + 0.02924143336713314, + -0.026365751400589943, + -0.036567822098731995, + 0.013740355148911476, + 0.0014254077104851604, + -0.04947865009307861, + -0.01049752440303564, + -0.007019080687314272, + -0.0033643722999840975, + -0.0020064576528966427, + -0.07127232104539871, + -0.05643607676029205, + -0.007050491403788328, + 0.005696943495422602, + 0.0319971963763237, + -0.045856233686208725, + -0.0382072851061821, + 0.024022594094276428, + 0.07401637732982635, + -0.01796848513185978, + -0.023768220096826553, + -0.059311170130968094, + -0.02001041918992996, + -0.053349319845438, + 0.0029365948867052794, + 0.010357838124036787, + -0.03372623398900032, + 0.005034816917032003, + -0.06332722306251526, + 0.0042638652957975864, + -0.015453161671757698, + -0.039690133184194565, + -0.020585861057043076, + -0.08410325646400452, + -0.020636729896068573, + 0.022761065512895584, + -0.02659504860639572, + 0.008869532495737076, + 0.06127539649605751, + 0.016054663807153702, + 0.01801091432571411, + -0.0068725040182471275, + 0.038399890065193176, + -0.01656283810734749, + -0.02084347791969776, + 0.008902153931558132, + 0.06902532279491425, + -0.0018741635140031576, + -0.04490096867084503, + 0.06339003145694733, + -0.017102815210819244, + -0.057325396686792374, + 0.022083261981606483, + -0.04266951605677605, + 0.019720112904906273, + 0.05673870071768761, + 0.02355301007628441, + -0.04308970272541046, + 0.0002606247435323894, + -0.00685822544619441, + -0.03939145803451538, + -0.02690181694924831, + -0.055103152990341187, + 0.1029508337378502, + 0.046327341347932816, + 0.0023325744550675154, + 0.018498506397008896, + -0.06048314645886421, + -0.013803904876112938, + 0.03132600709795952, + -0.006520519964396954, + 0.028858399018645287, + -0.04834062233567238, + 0.04562418535351753, + 0.07403726130723953, + 0.0036133721005171537, + -0.011329884640872478, + -0.0112222321331501, + -0.008675935678184032, + 0.016003990545868874, + 0.02360924705862999, + -0.03237585723400116, + 0.062091924250125885, + 0.0534723736345768, + 0.06908244639635086, + 0.01992947794497013, + -0.021924395114183422, + -0.08472655713558197, + 0.010171602480113506, + 0.013133247382938862, + -0.02523472346365452, + -0.06846307218074799, + 0.0004721606965176761, + -0.02166888676583767, + -0.0005694524152204394, + -0.008681336417794228, + -0.05947762727737427, + -0.04814690351486206, + -0.013798982836306097, + 0.01617482490837574, + -0.02504643611609936, + 0.009110392071306704, + -0.013774625957012177, + -0.019712207838892937, + -0.016054371371865273, + -0.018327657133340836, + -0.012811604887247086, + 0.08344585448503494, + 0.0004540338122751564, + 0.019656607881188393, + 0.019389579072594643, + -0.014049646444618702, + 0.017445947974920273, + -0.00820555817335844, + -0.029353104531764984, + 0.0435597263276577, + 0.009650807827711104, + -0.0388045459985733, + -0.04784759134054184, + -0.038223911076784134, + -0.03691287711262703, + -0.03876909241080284, + -0.06724806874990463, + -0.04394567012786865, + 0.04173814505338669, + -0.09444724023342133, + 0.007763924542814493, + -0.008699805475771427, + -0.007599780336022377, + 0.0023920757230371237, + 0.029335761442780495, + -0.07895313203334808, + -0.04035546630620957, + -0.008500908501446247, + 0.030348196625709537, + 0.02277581207454205, + 0.05779244005680084, + 0.049121756106615067, + -0.005412466358393431, + 0.007729559671133757, + -0.01292573381215334, + -0.025097647681832314, + 0.004094319883733988, + 0.06612378358840942, + -0.019531669095158577, + -0.005063635762780905, + -0.005468557123094797, + 0.07955626398324966, + -0.002157465321943164, + 0.009207960218191149, + -0.06414847075939178, + -0.0035572517663240433, + -0.0020771902054548264, + -0.1227332055568695, + -0.03706011176109314, + 0.0008404941763728857, + -0.046963952481746674, + 0.04012263193726539, + -0.027263401076197624, + 0.016582122072577477, + 0.04703010618686676, + 0.03132076933979988, + -0.010051103308796884, + -0.03994416818022728, + 0.05056227371096611, + -0.005183490924537182, + -0.03397025540471077, + 0.05630888789892197, + -0.00752260722219944, + 0.056935470551252365, + -0.019262658432126045, + -0.005856715142726898, + -0.00361971789970994, + 0.014742489904165268, + -0.0173240564763546, + 0.025849811732769012, + -0.03633483499288559, + 0.05162259563803673, + -0.024835949763655663, + -0.04847341403365135, + -0.03159399703145027, + -0.03467343747615814, + 0.036358628422021866, + -0.03581903874874115, + 0.002909073606133461, + -0.06491775810718536, + 0.02263971231877804, + 0.0016398467123508451, + 0.02446398138999939, + -0.07746433466672897, + -0.006726226769387722, + -0.000519428460393101, + -0.039504919201135635, + -0.005563349928706884, + -0.020594995468854904, + 0.061375197023153305, + -0.04385501146316528, + -0.020819365978240967, + 0.0002135665708919987, + 0.0025394882541149855, + 0.03940146788954735, + 0.04535587877035141, + 0.022408338263630867, + 0.010107740759849548, + -0.02910368889570236, + 0.023004544898867607, + -0.0777907446026802, + -0.03995157033205032, + -0.007604190148413181, + -0.01633376069366932, + 0.03180794045329094, + -0.001723665394820273, + 0.008649897761642933, + 0.0242207832634449, + -0.010647157207131386, + -0.026367707177996635, + 0.04031673073768616, + -0.05165720731019974, + -0.03284695744514465, + -0.02335844747722149, + -0.03349415957927704, + 0.025802014395594597, + -0.03694309666752815, + -0.006044459994882345, + 0.06736567616462708, + 0.01603505201637745, + -0.02328784205019474, + -0.012791356071829796, + 0.013516776263713837, + -0.03699612617492676, + 0.01060064509510994, + 0.00883965939283371, + -0.009064657613635063, + 0.0350169874727726, + -0.02685544267296791, + -0.014185672625899317, + 0.016354434192180634, + 0.036822687834501266, + 0.023291006684303284, + -0.059676602482795715, + 0.018569037318229675, + -0.035254210233688354, + 0.03186021000146866, + -0.006412920076400042, + 0.006461815442889929, + -0.0018794521456584337, + -0.004147578962147236, + -0.011934665031731129, + -0.0030684741213917732, + -0.011600416153669356, + 0.014210240915417671, + 0.035710278898477554, + -0.0347076840698719, + 0.024610867723822594, + -0.02708994224667549, + -0.05045025795698166, + -0.010565407574176788, + -0.033687181770801544, + -0.02122747339308262, + -0.04409955069422722, + -0.003069423837587238, + 0.044485583901405334, + -0.05378193408250809, + 0.072037473320961, + -0.07409116625785828, + 0.015786299481987953, + -0.06721299141645432, + 0.025938687846064568, + 0.010510837659239767, + -0.023115744814276695, + -0.03091544844210148, + 0.050648219883441925, + 0.035482946783304214, + 0.04307528957724571, + -0.04726636782288551, + -0.04310080036520958, + -0.013828760012984276, + 0.048286303877830505, + -0.02076721377670765, + -0.01085709035396576, + -0.03584962338209152, + -0.014488843269646168, + -0.0027554789558053017, + -0.06005162000656128, + 0.04566371068358421, + -0.08098234236240387, + -0.0007054588641040027, + 0.023113127797842022, + 0.013891058973968027, + -0.06299350410699844, + 0.013442540541291235, + -0.0063631776720285416, + 0.03821553662419319, + 0.042192913591861725, + -0.011878528632223606, + 0.025002310052514076, + -0.03168347105383873, + 0.00921724271029234, + 0.05588514357805252, + -0.019194696098566055, + -0.013231540098786354, + 0.013922672718763351, + 0.050090741366147995, + -0.009419753216207027, + 0.030472371727228165, + 0.02902497723698616, + 0.00012655452883336693, + 0.02010628953576088, + -0.017804551869630814, + 0.02543807215988636, + -0.0017418548231944442, + 0.03014679066836834, + -0.002393407514318824, + 0.01539027225226164, + -0.013939744792878628, + 0.04250369220972061, + -0.028016269207000732, + -0.0010314607061445713, + 0.00945567712187767, + 0.01606564037501812, + 0.03212505206465721, + 0.02634749934077263, + -0.04875859245657921, + -0.02948666177690029, + -0.010389791801571846, + -0.02731900289654732, + 0.008594093844294548, + -0.0005823180545121431, + 0.054062556475400925, + 0.0035941607784479856, + 0.0543292835354805, + -0.004254109226167202, + 0.08106452226638794, + 0.00023218353453557936, + 0.008525514975190163, + 0.010739163495600224, + -0.06044655293226242, + 0.02740525454282761, + 0.024431807920336723, + -0.07784923911094666, + -0.011249307543039322, + 0.042149681597948074, + 0.05080077797174454, + 0.012841291725635529, + -0.01869971305131912, + -0.0298676285892725, + -0.030107680708169937, + 0.007617079187184572, + -0.03927510604262352, + 0.005952583160251379, + -0.04362985119223595, + -0.056472595781087875, + -0.05122603103518486, + 0.030536439269781113, + 0.06711754202842712, + 0.030769379809498787, + -0.08917279541492462, + 0.030519621446728703, + -0.018731193616986275, + 0.025107961148023605, + -0.04443630948662758, + -0.03170761838555336, + 0.05583782494068146, + 0.028091464191675183, + 0.022955838590860367, + 0.033636752516031265, + -0.02531679160892963, + -0.012428611516952516, + 0.019952984526753426, + 0.02082655392587185, + 0.07539939135313034, + -0.06182907521724701, + 0.02644423581659794, + -0.0031414111144840717, + -0.03931447118520737, + 0.03972741961479187, + -0.06503785401582718, + -0.02640126273036003, + -0.026757026091217995, + 0.02259722352027893, + -0.026944443583488464, + -0.04200126603245735, + 0.06589224189519882, + -0.0060363225638866425, + 0.014422483742237093, + -0.047794267535209656, + -0.03258788213133812, + 0.0013760939473286271, + -0.009353984147310255, + 0.012716212309896946, + 0.04360601305961609, + 0.0045635453425347805, + 0.038450006395578384, + 0.032771769911050797, + 0.0030687032267451286, + -0.04321933165192604, + 0.006499011069536209, + 0.0028769823256880045, + 0.012420333921909332, + 0.013525757007300854, + -0.006150753237307072, + -0.004118023905903101, + 0.023745615035295486, + -0.042544446885585785, + 0.01779933273792267, + 0.0738072544336319, + -0.03007355146110058, + -0.009512661024928091, + -0.03289958834648132, + -0.004790752660483122, + 0.0004558037326205522, + 0.0720517635345459, + -0.06180300563573837, + -0.0042299022898077965, + 0.00017941815895028412, + 0.026685943827033043, + 0.0046829464845359325, + -0.0006890723598189652, + 0.008649819530546665, + -0.019310785457491875, + 0.03345974162220955, + -0.02027411200106144, + 0.0454903170466423, + 0.004120772238820791, + -0.028732268139719963, + 0.002070050220936537, + 0.03910873085260391, + -0.034626252949237823, + -0.06625950336456299, + -0.057161930948495865, + -0.027074122801423073, + -0.03852885961532593, + 0.036027777940034866, + -0.03378047049045563, + -0.04209835082292557, + 0.02349921129643917, + 0.03960388153791427, + 0.0015966565115377307, + -0.003795675467699766, + 0.008811083622276783, + -0.02891468815505505, + -0.08621173352003098, + 0.03072702139616013, + -0.04263502359390259, + 0.0518559105694294, + -0.014513948932290075, + 0.00426185317337513, + -0.042820628732442856, + 0.061024997383356094, + 0.008177947252988815, + -0.025654304772615433, + -0.01994758658111095, + 0.03115339018404484, + -0.06122246012091637, + -0.00973520614206791, + 0.026119912043213844, + 0.018067168071866035, + 0.046298809349536896, + -0.0637248307466507, + -0.003924540244042873, + 0.05164488032460213, + -0.03986351564526558, + 0.012143593281507492, + -0.01493164524435997, + 0.012364163994789124, + 0.0033910535275936127, + 0.03926117718219757, + 0.0160888209939003, + 0.022147519513964653, + 0.040994029492139816, + 0.03238851949572563, + 0.031068911775946617, + -0.0019339561695232987, + -0.04030238837003708, + 0.018413899466395375, + 0.009558942168951036, + 0.024898380041122437, + -0.02646373026072979, + -0.027966918423771855, + 0.03851816430687904, + -0.018016686663031575, + 0.01169034279882908, + -0.041716981679201126, + -0.012398135848343372, + -0.040918245911598206, + 0.049635518342256546, + 0.019493695348501205, + 0.010355286300182344, + -0.005950144957751036, + -0.022309331223368645, + -0.0430804155766964, + 0.0156959630548954, + 0.01119300164282322, + -0.008492423221468925, + 0.014949626289308071, + -0.053723081946372986, + 0.027443569153547287, + 0.03662879765033722, + -0.03641078248620033, + 0.04629331827163696, + 0.004617750179022551, + -0.03654378652572632, + 0.013454713858664036, + 0.0032841702923178673, + -0.01309528760612011, + -0.0006306404829956591, + -0.010712265968322754, + -0.0031115366145968437, + 0.06719954311847687, + -0.041091009974479675, + 0.052047744393348694, + 0.015360930003225803, + 0.017123648896813393, + -0.016294341534376144, + 0.04660823196172714, + -0.024207523092627525, + -0.04300165921449661, + -0.05108120292425155, + 0.09737501293420792, + -0.01331926416605711, + 0.06842294335365295, + -0.002399123040959239, + 0.012122059240937231, + 0.06719434261322021, + -0.05437808856368065, + 0.004240202717483044, + -0.027191925793886185, + -0.040218885987997055, + -0.02375097759068012, + 0.012262600474059582, + 0.014219674281775951, + -0.006157959345728159, + 0.011399772949516771, + -0.05200403183698654, + -0.017264649271965027, + 0.016833636909723282, + -0.009583424776792526, + -0.03376639261841774, + -0.00961976870894432, + 0.001210652757436037, + -0.0612335205078125, + -0.0336930938065052, + -0.025393076241016388, + -0.02714981697499752, + 0.004886742681264877, + 0.013395018875598907, + -0.02571096643805504, + -0.03276616707444191, + -0.030069544911384583, + 0.036591000854969025, + -0.07458269596099854, + 0.05744070932269096, + 0.028478343039751053, + -0.0028876815922558308, + 0.02639182470738888, + 0.018080219626426697, + 0.04396456852555275, + 0.003018079325556755, + -0.03397033363580704, + -0.02141541987657547, + 0.010896582156419754, + -0.03434125706553459, + -0.05253784731030464, + -0.025020217522978783, + -0.005296454764902592, + 0.019587192684412003, + 0.03784740716218949, + -0.01990439184010029, + 0.02046854794025421, + -0.02455652691423893, + -0.020822890102863312, + 0.003083446528762579, + 0.07859235256910324, + -0.08430628478527069, + -0.02872663363814354, + 0.05072060227394104, + 0.043463632464408875, + 0.017734138295054436, + -0.04160630330443382, + -0.04641241580247879, + -0.02498893067240715, + -0.03297220170497894, + -0.09785742312669754, + -0.006121875252574682, + -0.022711746394634247, + -0.01429930329322815, + -0.00412411242723465, + 0.007504432462155819, + -0.000563237292226404, + 0.01013818196952343, + -0.06896454840898514, + 0.006575733423233032, + -0.10310959815979004, + -0.012512778863310814, + 0.03036043606698513, + -0.015878431499004364, + 0.022684166207909584, + 0.02066022157669067, + 0.016029203310608864, + -0.028443187475204468, + -0.01416606828570366, + 0.0071391211822628975, + 0.034776851534843445, + 0.002298222854733467, + 0.033520814031362534, + 0.05799320712685585, + -0.0030665509402751923, + 0.013703178614377975, + 0.04346451908349991, + -0.08736324310302734, + -0.04443465545773506, + -0.09507574141025545, + -0.007938905619084835, + 0.005520000122487545, + -0.043095000088214874, + -0.03352028876543045, + 0.021385299041867256, + 0.02366030216217041, + -0.02853614091873169, + 0.002117573283612728, + 0.055353257805109024, + 0.027501529082655907, + -0.015763575211167336, + 0.0570647306740284, + -0.029892882332205772, + 0.02390587143599987, + -0.013306232169270515, + 0.018932240083813667, + 0.0071633001789450645, + 0.006233749445527792, + 0.03482261300086975, + -0.0009497640421614052, + 0.04889736324548721, + -0.010756379924714564, + -0.10233137756586076, + 0.032568227499723434, + -0.0017232495592907071, + 0.0197619441896677, + -0.01157362200319767, + -0.022340090945363045, + 0.03321876749396324, + -0.03730887547135353, + -0.004980842582881451, + 0.031003642827272415, + 0.04853849858045578, + 0.00792314950376749, + -0.016585927456617355, + -0.00377306598238647, + 0.009732725098729134, + -0.026165375486016273, + 0.0068840766325592995, + 0.02659326232969761, + -0.005413031205534935, + -0.0209831390529871, + -0.029614845290780067, + 0.01654200442135334, + -0.03843202814459801, + 0.016572654247283936, + -0.022821595892310143, + 0.02077091671526432, + -0.033952746540308, + 0.06542537361383438, + -0.08189623057842255, + 0.0031411293894052505, + -0.01395489927381277, + 0.01906730607151985, + -0.05683666840195656, + -0.03671567142009735, + 0.001987523166462779, + 0.006716572213917971, + 0.058880213648080826, + -0.028976114466786385, + -0.10136104375123978, + -0.01454504206776619, + -0.06632363796234131, + 0.012023151852190496, + -0.039696235209703445, + -0.10271679610013962, + -0.00566994259133935, + -0.011019215919077396, + 0.022908398881554604, + 0.00902929063886404, + -0.02031330019235611, + 0.02893255092203617, + -0.020042693242430687, + -0.02361901104450226, + 0.038222216069698334, + 0.008589942008256912, + 0.03230403736233711, + 0.002454438945278526, + 0.004391937050968409, + -0.0484878346323967, + -0.002869164338335395, + -0.05096660554409027, + -0.028733370825648308, + 0.03479108586907387, + 0.03205372020602226, + -0.004485339857637882, + 0.017057575285434723, + 0.0132388761267066, + -0.04253086820244789, + 0.021169882267713547, + -0.008464457467198372, + -0.009780851192772388, + 0.02306952327489853, + -0.04061064124107361, + 0.0140217337757349, + -0.003301902674138546, + 0.005067829042673111 + ], + "index": 0 + } + ], + "model": "text-embedding-005", + "usage": { + "prompt_tokens": 0, + "total_tokens": 0 + } + }, + { + "object": "list", + "data": [ + { + "object": "embedding", + "embedding": [ + -0.058164194226264954, + -0.00003622031363192946, + 0.010542492382228374, + -0.004728350788354874, + 0.07369722425937653, + -0.02481695637106895, + -0.00031316516106016934, + -0.017290938645601273, + 0.03166302293539047, + 0.014893381856381891, + -0.04859609156847, + -0.05490480735898018, + -0.005848468281328678, + -0.06573579460382462, + -0.013973977416753767, + 0.03232813626527786, + 0.07840143144130707, + -0.05846800282597542, + -0.041564371436834335, + -0.017742950469255447, + 0.022528981789946556, + -0.05958662927150726, + -0.0955798402428627, + -0.009678563103079796, + 0.044648200273513794, + -0.043353594839572906, + -0.01671011932194233, + -0.02975669503211975, + -0.05829453468322754, + -0.0157438013702631, + 0.0006426912150345743, + -0.05014248937368393, + 0.011643724516034126, + -0.0007280845893546939, + 0.03767689689993858, + -0.010895035229623318, + 0.033650316298007965, + -0.037673596292734146, + 0.018698105588555336, + -0.03840488940477371, + 0.03343287855386734, + -0.05688348412513733, + -0.012943455018103124, + -0.0692962184548378, + -0.03782666474580765, + 0.010393713600933552, + -0.025529509410262108, + 0.01568876951932907, + 0.07156006246805191, + -0.014751105569303036, + 0.08142535388469696, + 0.029754770919680595, + -0.007077757269144058, + 0.031249215826392177, + 0.022206788882613186, + 0.05383630096912384, + 0.005256577394902706, + -0.013356782495975494, + 0.008688163012266159, + 0.02924143336713314, + -0.026365751400589943, + -0.036567822098731995, + 0.013740355148911476, + 0.0014254077104851604, + -0.04947865009307861, + -0.01049752440303564, + -0.007019080687314272, + -0.0033643722999840975, + -0.0020064576528966427, + -0.07127232104539871, + -0.05643607676029205, + -0.007050491403788328, + 0.005696943495422602, + 0.0319971963763237, + -0.045856233686208725, + -0.0382072851061821, + 0.024022594094276428, + 0.07401637732982635, + -0.01796848513185978, + -0.023768220096826553, + -0.059311170130968094, + -0.02001041918992996, + -0.053349319845438, + 0.0029365948867052794, + 0.010357838124036787, + -0.03372623398900032, + 0.005034816917032003, + -0.06332722306251526, + 0.0042638652957975864, + -0.015453161671757698, + -0.039690133184194565, + -0.020585861057043076, + -0.08410325646400452, + -0.020636729896068573, + 0.022761065512895584, + -0.02659504860639572, + 0.008869532495737076, + 0.06127539649605751, + 0.016054663807153702, + 0.01801091432571411, + -0.0068725040182471275, + 0.038399890065193176, + -0.01656283810734749, + -0.02084347791969776, + 0.008902153931558132, + 0.06902532279491425, + -0.0018741635140031576, + -0.04490096867084503, + 0.06339003145694733, + -0.017102815210819244, + -0.057325396686792374, + 0.022083261981606483, + -0.04266951605677605, + 0.019720112904906273, + 0.05673870071768761, + 0.02355301007628441, + -0.04308970272541046, + 0.0002606247435323894, + -0.00685822544619441, + -0.03939145803451538, + -0.02690181694924831, + -0.055103152990341187, + 0.1029508337378502, + 0.046327341347932816, + 0.0023325744550675154, + 0.018498506397008896, + -0.06048314645886421, + -0.013803904876112938, + 0.03132600709795952, + -0.006520519964396954, + 0.028858399018645287, + -0.04834062233567238, + 0.04562418535351753, + 0.07403726130723953, + 0.0036133721005171537, + -0.011329884640872478, + -0.0112222321331501, + -0.008675935678184032, + 0.016003990545868874, + 0.02360924705862999, + -0.03237585723400116, + 0.062091924250125885, + 0.0534723736345768, + 0.06908244639635086, + 0.01992947794497013, + -0.021924395114183422, + -0.08472655713558197, + 0.010171602480113506, + 0.013133247382938862, + -0.02523472346365452, + -0.06846307218074799, + 0.0004721606965176761, + -0.02166888676583767, + -0.0005694524152204394, + -0.008681336417794228, + -0.05947762727737427, + -0.04814690351486206, + -0.013798982836306097, + 0.01617482490837574, + -0.02504643611609936, + 0.009110392071306704, + -0.013774625957012177, + -0.019712207838892937, + -0.016054371371865273, + -0.018327657133340836, + -0.012811604887247086, + 0.08344585448503494, + 0.0004540338122751564, + 0.019656607881188393, + 0.019389579072594643, + -0.014049646444618702, + 0.017445947974920273, + -0.00820555817335844, + -0.029353104531764984, + 0.0435597263276577, + 0.009650807827711104, + -0.0388045459985733, + -0.04784759134054184, + -0.038223911076784134, + -0.03691287711262703, + -0.03876909241080284, + -0.06724806874990463, + -0.04394567012786865, + 0.04173814505338669, + -0.09444724023342133, + 0.007763924542814493, + -0.008699805475771427, + -0.007599780336022377, + 0.0023920757230371237, + 0.029335761442780495, + -0.07895313203334808, + -0.04035546630620957, + -0.008500908501446247, + 0.030348196625709537, + 0.02277581207454205, + 0.05779244005680084, + 0.049121756106615067, + -0.005412466358393431, + 0.007729559671133757, + -0.01292573381215334, + -0.025097647681832314, + 0.004094319883733988, + 0.06612378358840942, + -0.019531669095158577, + -0.005063635762780905, + -0.005468557123094797, + 0.07955626398324966, + -0.002157465321943164, + 0.009207960218191149, + -0.06414847075939178, + -0.0035572517663240433, + -0.0020771902054548264, + -0.1227332055568695, + -0.03706011176109314, + 0.0008404941763728857, + -0.046963952481746674, + 0.04012263193726539, + -0.027263401076197624, + 0.016582122072577477, + 0.04703010618686676, + 0.03132076933979988, + -0.010051103308796884, + -0.03994416818022728, + 0.05056227371096611, + -0.005183490924537182, + -0.03397025540471077, + 0.05630888789892197, + -0.00752260722219944, + 0.056935470551252365, + -0.019262658432126045, + -0.005856715142726898, + -0.00361971789970994, + 0.014742489904165268, + -0.0173240564763546, + 0.025849811732769012, + -0.03633483499288559, + 0.05162259563803673, + -0.024835949763655663, + -0.04847341403365135, + -0.03159399703145027, + -0.03467343747615814, + 0.036358628422021866, + -0.03581903874874115, + 0.002909073606133461, + -0.06491775810718536, + 0.02263971231877804, + 0.0016398467123508451, + 0.02446398138999939, + -0.07746433466672897, + -0.006726226769387722, + -0.000519428460393101, + -0.039504919201135635, + -0.005563349928706884, + -0.020594995468854904, + 0.061375197023153305, + -0.04385501146316528, + -0.020819365978240967, + 0.0002135665708919987, + 0.0025394882541149855, + 0.03940146788954735, + 0.04535587877035141, + 0.022408338263630867, + 0.010107740759849548, + -0.02910368889570236, + 0.023004544898867607, + -0.0777907446026802, + -0.03995157033205032, + -0.007604190148413181, + -0.01633376069366932, + 0.03180794045329094, + -0.001723665394820273, + 0.008649897761642933, + 0.0242207832634449, + -0.010647157207131386, + -0.026367707177996635, + 0.04031673073768616, + -0.05165720731019974, + -0.03284695744514465, + -0.02335844747722149, + -0.03349415957927704, + 0.025802014395594597, + -0.03694309666752815, + -0.006044459994882345, + 0.06736567616462708, + 0.01603505201637745, + -0.02328784205019474, + -0.012791356071829796, + 0.013516776263713837, + -0.03699612617492676, + 0.01060064509510994, + 0.00883965939283371, + -0.009064657613635063, + 0.0350169874727726, + -0.02685544267296791, + -0.014185672625899317, + 0.016354434192180634, + 0.036822687834501266, + 0.023291006684303284, + -0.059676602482795715, + 0.018569037318229675, + -0.035254210233688354, + 0.03186021000146866, + -0.006412920076400042, + 0.006461815442889929, + -0.0018794521456584337, + -0.004147578962147236, + -0.011934665031731129, + -0.0030684741213917732, + -0.011600416153669356, + 0.014210240915417671, + 0.035710278898477554, + -0.0347076840698719, + 0.024610867723822594, + -0.02708994224667549, + -0.05045025795698166, + -0.010565407574176788, + -0.033687181770801544, + -0.02122747339308262, + -0.04409955069422722, + -0.003069423837587238, + 0.044485583901405334, + -0.05378193408250809, + 0.072037473320961, + -0.07409116625785828, + 0.015786299481987953, + -0.06721299141645432, + 0.025938687846064568, + 0.010510837659239767, + -0.023115744814276695, + -0.03091544844210148, + 0.050648219883441925, + 0.035482946783304214, + 0.04307528957724571, + -0.04726636782288551, + -0.04310080036520958, + -0.013828760012984276, + 0.048286303877830505, + -0.02076721377670765, + -0.01085709035396576, + -0.03584962338209152, + -0.014488843269646168, + -0.0027554789558053017, + -0.06005162000656128, + 0.04566371068358421, + -0.08098234236240387, + -0.0007054588641040027, + 0.023113127797842022, + 0.013891058973968027, + -0.06299350410699844, + 0.013442540541291235, + -0.0063631776720285416, + 0.03821553662419319, + 0.042192913591861725, + -0.011878528632223606, + 0.025002310052514076, + -0.03168347105383873, + 0.00921724271029234, + 0.05588514357805252, + -0.019194696098566055, + -0.013231540098786354, + 0.013922672718763351, + 0.050090741366147995, + -0.009419753216207027, + 0.030472371727228165, + 0.02902497723698616, + 0.00012655452883336693, + 0.02010628953576088, + -0.017804551869630814, + 0.02543807215988636, + -0.0017418548231944442, + 0.03014679066836834, + -0.002393407514318824, + 0.01539027225226164, + -0.013939744792878628, + 0.04250369220972061, + -0.028016269207000732, + -0.0010314607061445713, + 0.00945567712187767, + 0.01606564037501812, + 0.03212505206465721, + 0.02634749934077263, + -0.04875859245657921, + -0.02948666177690029, + -0.010389791801571846, + -0.02731900289654732, + 0.008594093844294548, + -0.0005823180545121431, + 0.054062556475400925, + 0.0035941607784479856, + 0.0543292835354805, + -0.004254109226167202, + 0.08106452226638794, + 0.00023218353453557936, + 0.008525514975190163, + 0.010739163495600224, + -0.06044655293226242, + 0.02740525454282761, + 0.024431807920336723, + -0.07784923911094666, + -0.011249307543039322, + 0.042149681597948074, + 0.05080077797174454, + 0.012841291725635529, + -0.01869971305131912, + -0.0298676285892725, + -0.030107680708169937, + 0.007617079187184572, + -0.03927510604262352, + 0.005952583160251379, + -0.04362985119223595, + -0.056472595781087875, + -0.05122603103518486, + 0.030536439269781113, + 0.06711754202842712, + 0.030769379809498787, + -0.08917279541492462, + 0.030519621446728703, + -0.018731193616986275, + 0.025107961148023605, + -0.04443630948662758, + -0.03170761838555336, + 0.05583782494068146, + 0.028091464191675183, + 0.022955838590860367, + 0.033636752516031265, + -0.02531679160892963, + -0.012428611516952516, + 0.019952984526753426, + 0.02082655392587185, + 0.07539939135313034, + -0.06182907521724701, + 0.02644423581659794, + -0.0031414111144840717, + -0.03931447118520737, + 0.03972741961479187, + -0.06503785401582718, + -0.02640126273036003, + -0.026757026091217995, + 0.02259722352027893, + -0.026944443583488464, + -0.04200126603245735, + 0.06589224189519882, + -0.0060363225638866425, + 0.014422483742237093, + -0.047794267535209656, + -0.03258788213133812, + 0.0013760939473286271, + -0.009353984147310255, + 0.012716212309896946, + 0.04360601305961609, + 0.0045635453425347805, + 0.038450006395578384, + 0.032771769911050797, + 0.0030687032267451286, + -0.04321933165192604, + 0.006499011069536209, + 0.0028769823256880045, + 0.012420333921909332, + 0.013525757007300854, + -0.006150753237307072, + -0.004118023905903101, + 0.023745615035295486, + -0.042544446885585785, + 0.01779933273792267, + 0.0738072544336319, + -0.03007355146110058, + -0.009512661024928091, + -0.03289958834648132, + -0.004790752660483122, + 0.0004558037326205522, + 0.0720517635345459, + -0.06180300563573837, + -0.0042299022898077965, + 0.00017941815895028412, + 0.026685943827033043, + 0.0046829464845359325, + -0.0006890723598189652, + 0.008649819530546665, + -0.019310785457491875, + 0.03345974162220955, + -0.02027411200106144, + 0.0454903170466423, + 0.004120772238820791, + -0.028732268139719963, + 0.002070050220936537, + 0.03910873085260391, + -0.034626252949237823, + -0.06625950336456299, + -0.057161930948495865, + -0.027074122801423073, + -0.03852885961532593, + 0.036027777940034866, + -0.03378047049045563, + -0.04209835082292557, + 0.02349921129643917, + 0.03960388153791427, + 0.0015966565115377307, + -0.003795675467699766, + 0.008811083622276783, + -0.02891468815505505, + -0.08621173352003098, + 0.03072702139616013, + -0.04263502359390259, + 0.0518559105694294, + -0.014513948932290075, + 0.00426185317337513, + -0.042820628732442856, + 0.061024997383356094, + 0.008177947252988815, + -0.025654304772615433, + -0.01994758658111095, + 0.03115339018404484, + -0.06122246012091637, + -0.00973520614206791, + 0.026119912043213844, + 0.018067168071866035, + 0.046298809349536896, + -0.0637248307466507, + -0.003924540244042873, + 0.05164488032460213, + -0.03986351564526558, + 0.012143593281507492, + -0.01493164524435997, + 0.012364163994789124, + 0.0033910535275936127, + 0.03926117718219757, + 0.0160888209939003, + 0.022147519513964653, + 0.040994029492139816, + 0.03238851949572563, + 0.031068911775946617, + -0.0019339561695232987, + -0.04030238837003708, + 0.018413899466395375, + 0.009558942168951036, + 0.024898380041122437, + -0.02646373026072979, + -0.027966918423771855, + 0.03851816430687904, + -0.018016686663031575, + 0.01169034279882908, + -0.041716981679201126, + -0.012398135848343372, + -0.040918245911598206, + 0.049635518342256546, + 0.019493695348501205, + 0.010355286300182344, + -0.005950144957751036, + -0.022309331223368645, + -0.0430804155766964, + 0.0156959630548954, + 0.01119300164282322, + -0.008492423221468925, + 0.014949626289308071, + -0.053723081946372986, + 0.027443569153547287, + 0.03662879765033722, + -0.03641078248620033, + 0.04629331827163696, + 0.004617750179022551, + -0.03654378652572632, + 0.013454713858664036, + 0.0032841702923178673, + -0.01309528760612011, + -0.0006306404829956591, + -0.010712265968322754, + -0.0031115366145968437, + 0.06719954311847687, + -0.041091009974479675, + 0.052047744393348694, + 0.015360930003225803, + 0.017123648896813393, + -0.016294341534376144, + 0.04660823196172714, + -0.024207523092627525, + -0.04300165921449661, + -0.05108120292425155, + 0.09737501293420792, + -0.01331926416605711, + 0.06842294335365295, + -0.002399123040959239, + 0.012122059240937231, + 0.06719434261322021, + -0.05437808856368065, + 0.004240202717483044, + -0.027191925793886185, + -0.040218885987997055, + -0.02375097759068012, + 0.012262600474059582, + 0.014219674281775951, + -0.006157959345728159, + 0.011399772949516771, + -0.05200403183698654, + -0.017264649271965027, + 0.016833636909723282, + -0.009583424776792526, + -0.03376639261841774, + -0.00961976870894432, + 0.001210652757436037, + -0.0612335205078125, + -0.0336930938065052, + -0.025393076241016388, + -0.02714981697499752, + 0.004886742681264877, + 0.013395018875598907, + -0.02571096643805504, + -0.03276616707444191, + -0.030069544911384583, + 0.036591000854969025, + -0.07458269596099854, + 0.05744070932269096, + 0.028478343039751053, + -0.0028876815922558308, + 0.02639182470738888, + 0.018080219626426697, + 0.04396456852555275, + 0.003018079325556755, + -0.03397033363580704, + -0.02141541987657547, + 0.010896582156419754, + -0.03434125706553459, + -0.05253784731030464, + -0.025020217522978783, + -0.005296454764902592, + 0.019587192684412003, + 0.03784740716218949, + -0.01990439184010029, + 0.02046854794025421, + -0.02455652691423893, + -0.020822890102863312, + 0.003083446528762579, + 0.07859235256910324, + -0.08430628478527069, + -0.02872663363814354, + 0.05072060227394104, + 0.043463632464408875, + 0.017734138295054436, + -0.04160630330443382, + -0.04641241580247879, + -0.02498893067240715, + -0.03297220170497894, + -0.09785742312669754, + -0.006121875252574682, + -0.022711746394634247, + -0.01429930329322815, + -0.00412411242723465, + 0.007504432462155819, + -0.000563237292226404, + 0.01013818196952343, + -0.06896454840898514, + 0.006575733423233032, + -0.10310959815979004, + -0.012512778863310814, + 0.03036043606698513, + -0.015878431499004364, + 0.022684166207909584, + 0.02066022157669067, + 0.016029203310608864, + -0.028443187475204468, + -0.01416606828570366, + 0.0071391211822628975, + 0.034776851534843445, + 0.002298222854733467, + 0.033520814031362534, + 0.05799320712685585, + -0.0030665509402751923, + 0.013703178614377975, + 0.04346451908349991, + -0.08736324310302734, + -0.04443465545773506, + -0.09507574141025545, + -0.007938905619084835, + 0.005520000122487545, + -0.043095000088214874, + -0.03352028876543045, + 0.021385299041867256, + 0.02366030216217041, + -0.02853614091873169, + 0.002117573283612728, + 0.055353257805109024, + 0.027501529082655907, + -0.015763575211167336, + 0.0570647306740284, + -0.029892882332205772, + 0.02390587143599987, + -0.013306232169270515, + 0.018932240083813667, + 0.0071633001789450645, + 0.006233749445527792, + 0.03482261300086975, + -0.0009497640421614052, + 0.04889736324548721, + -0.010756379924714564, + -0.10233137756586076, + 0.032568227499723434, + -0.0017232495592907071, + 0.0197619441896677, + -0.01157362200319767, + -0.022340090945363045, + 0.03321876749396324, + -0.03730887547135353, + -0.004980842582881451, + 0.031003642827272415, + 0.04853849858045578, + 0.00792314950376749, + -0.016585927456617355, + -0.00377306598238647, + 0.009732725098729134, + -0.026165375486016273, + 0.0068840766325592995, + 0.02659326232969761, + -0.005413031205534935, + -0.0209831390529871, + -0.029614845290780067, + 0.01654200442135334, + -0.03843202814459801, + 0.016572654247283936, + -0.022821595892310143, + 0.02077091671526432, + -0.033952746540308, + 0.06542537361383438, + -0.08189623057842255, + 0.0031411293894052505, + -0.01395489927381277, + 0.01906730607151985, + -0.05683666840195656, + -0.03671567142009735, + 0.001987523166462779, + 0.006716572213917971, + 0.058880213648080826, + -0.028976114466786385, + -0.10136104375123978, + -0.01454504206776619, + -0.06632363796234131, + 0.012023151852190496, + -0.039696235209703445, + -0.10271679610013962, + -0.00566994259133935, + -0.011019215919077396, + 0.022908398881554604, + 0.00902929063886404, + -0.02031330019235611, + 0.02893255092203617, + -0.020042693242430687, + -0.02361901104450226, + 0.038222216069698334, + 0.008589942008256912, + 0.03230403736233711, + 0.002454438945278526, + 0.004391937050968409, + -0.0484878346323967, + -0.002869164338335395, + -0.05096660554409027, + -0.028733370825648308, + 0.03479108586907387, + 0.03205372020602226, + -0.004485339857637882, + 0.017057575285434723, + 0.0132388761267066, + -0.04253086820244789, + 0.021169882267713547, + -0.008464457467198372, + -0.009780851192772388, + 0.02306952327489853, + -0.04061064124107361, + 0.0140217337757349, + -0.003301902674138546, + 0.005067829042673111 + ], + "index": 0 + } + ], + "model": "text-embedding-005", + "usage": { + "prompt_tokens": 0, + "total_tokens": 0 + } + }, + { + "object": "list", + "data": [ + { + "object": "embedding", + "embedding": [ + -0.058164194226264954, + -0.00003622031363192946, + 0.010542492382228374, + -0.004728350788354874, + 0.07369722425937653, + -0.02481695637106895, + -0.00031316516106016934, + -0.017290938645601273, + 0.03166302293539047, + 0.014893381856381891, + -0.04859609156847, + -0.05490480735898018, + -0.005848468281328678, + -0.06573579460382462, + -0.013973977416753767, + 0.03232813626527786, + 0.07840143144130707, + -0.05846800282597542, + -0.041564371436834335, + -0.017742950469255447, + 0.022528981789946556, + -0.05958662927150726, + -0.0955798402428627, + -0.009678563103079796, + 0.044648200273513794, + -0.043353594839572906, + -0.01671011932194233, + -0.02975669503211975, + -0.05829453468322754, + -0.0157438013702631, + 0.0006426912150345743, + -0.05014248937368393, + 0.011643724516034126, + -0.0007280845893546939, + 0.03767689689993858, + -0.010895035229623318, + 0.033650316298007965, + -0.037673596292734146, + 0.018698105588555336, + -0.03840488940477371, + 0.03343287855386734, + -0.05688348412513733, + -0.012943455018103124, + -0.0692962184548378, + -0.03782666474580765, + 0.010393713600933552, + -0.025529509410262108, + 0.01568876951932907, + 0.07156006246805191, + -0.014751105569303036, + 0.08142535388469696, + 0.029754770919680595, + -0.007077757269144058, + 0.031249215826392177, + 0.022206788882613186, + 0.05383630096912384, + 0.005256577394902706, + -0.013356782495975494, + 0.008688163012266159, + 0.02924143336713314, + -0.026365751400589943, + -0.036567822098731995, + 0.013740355148911476, + 0.0014254077104851604, + -0.04947865009307861, + -0.01049752440303564, + -0.007019080687314272, + -0.0033643722999840975, + -0.0020064576528966427, + -0.07127232104539871, + -0.05643607676029205, + -0.007050491403788328, + 0.005696943495422602, + 0.0319971963763237, + -0.045856233686208725, + -0.0382072851061821, + 0.024022594094276428, + 0.07401637732982635, + -0.01796848513185978, + -0.023768220096826553, + -0.059311170130968094, + -0.02001041918992996, + -0.053349319845438, + 0.0029365948867052794, + 0.010357838124036787, + -0.03372623398900032, + 0.005034816917032003, + -0.06332722306251526, + 0.0042638652957975864, + -0.015453161671757698, + -0.039690133184194565, + -0.020585861057043076, + -0.08410325646400452, + -0.020636729896068573, + 0.022761065512895584, + -0.02659504860639572, + 0.008869532495737076, + 0.06127539649605751, + 0.016054663807153702, + 0.01801091432571411, + -0.0068725040182471275, + 0.038399890065193176, + -0.01656283810734749, + -0.02084347791969776, + 0.008902153931558132, + 0.06902532279491425, + -0.0018741635140031576, + -0.04490096867084503, + 0.06339003145694733, + -0.017102815210819244, + -0.057325396686792374, + 0.022083261981606483, + -0.04266951605677605, + 0.019720112904906273, + 0.05673870071768761, + 0.02355301007628441, + -0.04308970272541046, + 0.0002606247435323894, + -0.00685822544619441, + -0.03939145803451538, + -0.02690181694924831, + -0.055103152990341187, + 0.1029508337378502, + 0.046327341347932816, + 0.0023325744550675154, + 0.018498506397008896, + -0.06048314645886421, + -0.013803904876112938, + 0.03132600709795952, + -0.006520519964396954, + 0.028858399018645287, + -0.04834062233567238, + 0.04562418535351753, + 0.07403726130723953, + 0.0036133721005171537, + -0.011329884640872478, + -0.0112222321331501, + -0.008675935678184032, + 0.016003990545868874, + 0.02360924705862999, + -0.03237585723400116, + 0.062091924250125885, + 0.0534723736345768, + 0.06908244639635086, + 0.01992947794497013, + -0.021924395114183422, + -0.08472655713558197, + 0.010171602480113506, + 0.013133247382938862, + -0.02523472346365452, + -0.06846307218074799, + 0.0004721606965176761, + -0.02166888676583767, + -0.0005694524152204394, + -0.008681336417794228, + -0.05947762727737427, + -0.04814690351486206, + -0.013798982836306097, + 0.01617482490837574, + -0.02504643611609936, + 0.009110392071306704, + -0.013774625957012177, + -0.019712207838892937, + -0.016054371371865273, + -0.018327657133340836, + -0.012811604887247086, + 0.08344585448503494, + 0.0004540338122751564, + 0.019656607881188393, + 0.019389579072594643, + -0.014049646444618702, + 0.017445947974920273, + -0.00820555817335844, + -0.029353104531764984, + 0.0435597263276577, + 0.009650807827711104, + -0.0388045459985733, + -0.04784759134054184, + -0.038223911076784134, + -0.03691287711262703, + -0.03876909241080284, + -0.06724806874990463, + -0.04394567012786865, + 0.04173814505338669, + -0.09444724023342133, + 0.007763924542814493, + -0.008699805475771427, + -0.007599780336022377, + 0.0023920757230371237, + 0.029335761442780495, + -0.07895313203334808, + -0.04035546630620957, + -0.008500908501446247, + 0.030348196625709537, + 0.02277581207454205, + 0.05779244005680084, + 0.049121756106615067, + -0.005412466358393431, + 0.007729559671133757, + -0.01292573381215334, + -0.025097647681832314, + 0.004094319883733988, + 0.06612378358840942, + -0.019531669095158577, + -0.005063635762780905, + -0.005468557123094797, + 0.07955626398324966, + -0.002157465321943164, + 0.009207960218191149, + -0.06414847075939178, + -0.0035572517663240433, + -0.0020771902054548264, + -0.1227332055568695, + -0.03706011176109314, + 0.0008404941763728857, + -0.046963952481746674, + 0.04012263193726539, + -0.027263401076197624, + 0.016582122072577477, + 0.04703010618686676, + 0.03132076933979988, + -0.010051103308796884, + -0.03994416818022728, + 0.05056227371096611, + -0.005183490924537182, + -0.03397025540471077, + 0.05630888789892197, + -0.00752260722219944, + 0.056935470551252365, + -0.019262658432126045, + -0.005856715142726898, + -0.00361971789970994, + 0.014742489904165268, + -0.0173240564763546, + 0.025849811732769012, + -0.03633483499288559, + 0.05162259563803673, + -0.024835949763655663, + -0.04847341403365135, + -0.03159399703145027, + -0.03467343747615814, + 0.036358628422021866, + -0.03581903874874115, + 0.002909073606133461, + -0.06491775810718536, + 0.02263971231877804, + 0.0016398467123508451, + 0.02446398138999939, + -0.07746433466672897, + -0.006726226769387722, + -0.000519428460393101, + -0.039504919201135635, + -0.005563349928706884, + -0.020594995468854904, + 0.061375197023153305, + -0.04385501146316528, + -0.020819365978240967, + 0.0002135665708919987, + 0.0025394882541149855, + 0.03940146788954735, + 0.04535587877035141, + 0.022408338263630867, + 0.010107740759849548, + -0.02910368889570236, + 0.023004544898867607, + -0.0777907446026802, + -0.03995157033205032, + -0.007604190148413181, + -0.01633376069366932, + 0.03180794045329094, + -0.001723665394820273, + 0.008649897761642933, + 0.0242207832634449, + -0.010647157207131386, + -0.026367707177996635, + 0.04031673073768616, + -0.05165720731019974, + -0.03284695744514465, + -0.02335844747722149, + -0.03349415957927704, + 0.025802014395594597, + -0.03694309666752815, + -0.006044459994882345, + 0.06736567616462708, + 0.01603505201637745, + -0.02328784205019474, + -0.012791356071829796, + 0.013516776263713837, + -0.03699612617492676, + 0.01060064509510994, + 0.00883965939283371, + -0.009064657613635063, + 0.0350169874727726, + -0.02685544267296791, + -0.014185672625899317, + 0.016354434192180634, + 0.036822687834501266, + 0.023291006684303284, + -0.059676602482795715, + 0.018569037318229675, + -0.035254210233688354, + 0.03186021000146866, + -0.006412920076400042, + 0.006461815442889929, + -0.0018794521456584337, + -0.004147578962147236, + -0.011934665031731129, + -0.0030684741213917732, + -0.011600416153669356, + 0.014210240915417671, + 0.035710278898477554, + -0.0347076840698719, + 0.024610867723822594, + -0.02708994224667549, + -0.05045025795698166, + -0.010565407574176788, + -0.033687181770801544, + -0.02122747339308262, + -0.04409955069422722, + -0.003069423837587238, + 0.044485583901405334, + -0.05378193408250809, + 0.072037473320961, + -0.07409116625785828, + 0.015786299481987953, + -0.06721299141645432, + 0.025938687846064568, + 0.010510837659239767, + -0.023115744814276695, + -0.03091544844210148, + 0.050648219883441925, + 0.035482946783304214, + 0.04307528957724571, + -0.04726636782288551, + -0.04310080036520958, + -0.013828760012984276, + 0.048286303877830505, + -0.02076721377670765, + -0.01085709035396576, + -0.03584962338209152, + -0.014488843269646168, + -0.0027554789558053017, + -0.06005162000656128, + 0.04566371068358421, + -0.08098234236240387, + -0.0007054588641040027, + 0.023113127797842022, + 0.013891058973968027, + -0.06299350410699844, + 0.013442540541291235, + -0.0063631776720285416, + 0.03821553662419319, + 0.042192913591861725, + -0.011878528632223606, + 0.025002310052514076, + -0.03168347105383873, + 0.00921724271029234, + 0.05588514357805252, + -0.019194696098566055, + -0.013231540098786354, + 0.013922672718763351, + 0.050090741366147995, + -0.009419753216207027, + 0.030472371727228165, + 0.02902497723698616, + 0.00012655452883336693, + 0.02010628953576088, + -0.017804551869630814, + 0.02543807215988636, + -0.0017418548231944442, + 0.03014679066836834, + -0.002393407514318824, + 0.01539027225226164, + -0.013939744792878628, + 0.04250369220972061, + -0.028016269207000732, + -0.0010314607061445713, + 0.00945567712187767, + 0.01606564037501812, + 0.03212505206465721, + 0.02634749934077263, + -0.04875859245657921, + -0.02948666177690029, + -0.010389791801571846, + -0.02731900289654732, + 0.008594093844294548, + -0.0005823180545121431, + 0.054062556475400925, + 0.0035941607784479856, + 0.0543292835354805, + -0.004254109226167202, + 0.08106452226638794, + 0.00023218353453557936, + 0.008525514975190163, + 0.010739163495600224, + -0.06044655293226242, + 0.02740525454282761, + 0.024431807920336723, + -0.07784923911094666, + -0.011249307543039322, + 0.042149681597948074, + 0.05080077797174454, + 0.012841291725635529, + -0.01869971305131912, + -0.0298676285892725, + -0.030107680708169937, + 0.007617079187184572, + -0.03927510604262352, + 0.005952583160251379, + -0.04362985119223595, + -0.056472595781087875, + -0.05122603103518486, + 0.030536439269781113, + 0.06711754202842712, + 0.030769379809498787, + -0.08917279541492462, + 0.030519621446728703, + -0.018731193616986275, + 0.025107961148023605, + -0.04443630948662758, + -0.03170761838555336, + 0.05583782494068146, + 0.028091464191675183, + 0.022955838590860367, + 0.033636752516031265, + -0.02531679160892963, + -0.012428611516952516, + 0.019952984526753426, + 0.02082655392587185, + 0.07539939135313034, + -0.06182907521724701, + 0.02644423581659794, + -0.0031414111144840717, + -0.03931447118520737, + 0.03972741961479187, + -0.06503785401582718, + -0.02640126273036003, + -0.026757026091217995, + 0.02259722352027893, + -0.026944443583488464, + -0.04200126603245735, + 0.06589224189519882, + -0.0060363225638866425, + 0.014422483742237093, + -0.047794267535209656, + -0.03258788213133812, + 0.0013760939473286271, + -0.009353984147310255, + 0.012716212309896946, + 0.04360601305961609, + 0.0045635453425347805, + 0.038450006395578384, + 0.032771769911050797, + 0.0030687032267451286, + -0.04321933165192604, + 0.006499011069536209, + 0.0028769823256880045, + 0.012420333921909332, + 0.013525757007300854, + -0.006150753237307072, + -0.004118023905903101, + 0.023745615035295486, + -0.042544446885585785, + 0.01779933273792267, + 0.0738072544336319, + -0.03007355146110058, + -0.009512661024928091, + -0.03289958834648132, + -0.004790752660483122, + 0.0004558037326205522, + 0.0720517635345459, + -0.06180300563573837, + -0.0042299022898077965, + 0.00017941815895028412, + 0.026685943827033043, + 0.0046829464845359325, + -0.0006890723598189652, + 0.008649819530546665, + -0.019310785457491875, + 0.03345974162220955, + -0.02027411200106144, + 0.0454903170466423, + 0.004120772238820791, + -0.028732268139719963, + 0.002070050220936537, + 0.03910873085260391, + -0.034626252949237823, + -0.06625950336456299, + -0.057161930948495865, + -0.027074122801423073, + -0.03852885961532593, + 0.036027777940034866, + -0.03378047049045563, + -0.04209835082292557, + 0.02349921129643917, + 0.03960388153791427, + 0.0015966565115377307, + -0.003795675467699766, + 0.008811083622276783, + -0.02891468815505505, + -0.08621173352003098, + 0.03072702139616013, + -0.04263502359390259, + 0.0518559105694294, + -0.014513948932290075, + 0.00426185317337513, + -0.042820628732442856, + 0.061024997383356094, + 0.008177947252988815, + -0.025654304772615433, + -0.01994758658111095, + 0.03115339018404484, + -0.06122246012091637, + -0.00973520614206791, + 0.026119912043213844, + 0.018067168071866035, + 0.046298809349536896, + -0.0637248307466507, + -0.003924540244042873, + 0.05164488032460213, + -0.03986351564526558, + 0.012143593281507492, + -0.01493164524435997, + 0.012364163994789124, + 0.0033910535275936127, + 0.03926117718219757, + 0.0160888209939003, + 0.022147519513964653, + 0.040994029492139816, + 0.03238851949572563, + 0.031068911775946617, + -0.0019339561695232987, + -0.04030238837003708, + 0.018413899466395375, + 0.009558942168951036, + 0.024898380041122437, + -0.02646373026072979, + -0.027966918423771855, + 0.03851816430687904, + -0.018016686663031575, + 0.01169034279882908, + -0.041716981679201126, + -0.012398135848343372, + -0.040918245911598206, + 0.049635518342256546, + 0.019493695348501205, + 0.010355286300182344, + -0.005950144957751036, + -0.022309331223368645, + -0.0430804155766964, + 0.0156959630548954, + 0.01119300164282322, + -0.008492423221468925, + 0.014949626289308071, + -0.053723081946372986, + 0.027443569153547287, + 0.03662879765033722, + -0.03641078248620033, + 0.04629331827163696, + 0.004617750179022551, + -0.03654378652572632, + 0.013454713858664036, + 0.0032841702923178673, + -0.01309528760612011, + -0.0006306404829956591, + -0.010712265968322754, + -0.0031115366145968437, + 0.06719954311847687, + -0.041091009974479675, + 0.052047744393348694, + 0.015360930003225803, + 0.017123648896813393, + -0.016294341534376144, + 0.04660823196172714, + -0.024207523092627525, + -0.04300165921449661, + -0.05108120292425155, + 0.09737501293420792, + -0.01331926416605711, + 0.06842294335365295, + -0.002399123040959239, + 0.012122059240937231, + 0.06719434261322021, + -0.05437808856368065, + 0.004240202717483044, + -0.027191925793886185, + -0.040218885987997055, + -0.02375097759068012, + 0.012262600474059582, + 0.014219674281775951, + -0.006157959345728159, + 0.011399772949516771, + -0.05200403183698654, + -0.017264649271965027, + 0.016833636909723282, + -0.009583424776792526, + -0.03376639261841774, + -0.00961976870894432, + 0.001210652757436037, + -0.0612335205078125, + -0.0336930938065052, + -0.025393076241016388, + -0.02714981697499752, + 0.004886742681264877, + 0.013395018875598907, + -0.02571096643805504, + -0.03276616707444191, + -0.030069544911384583, + 0.036591000854969025, + -0.07458269596099854, + 0.05744070932269096, + 0.028478343039751053, + -0.0028876815922558308, + 0.02639182470738888, + 0.018080219626426697, + 0.04396456852555275, + 0.003018079325556755, + -0.03397033363580704, + -0.02141541987657547, + 0.010896582156419754, + -0.03434125706553459, + -0.05253784731030464, + -0.025020217522978783, + -0.005296454764902592, + 0.019587192684412003, + 0.03784740716218949, + -0.01990439184010029, + 0.02046854794025421, + -0.02455652691423893, + -0.020822890102863312, + 0.003083446528762579, + 0.07859235256910324, + -0.08430628478527069, + -0.02872663363814354, + 0.05072060227394104, + 0.043463632464408875, + 0.017734138295054436, + -0.04160630330443382, + -0.04641241580247879, + -0.02498893067240715, + -0.03297220170497894, + -0.09785742312669754, + -0.006121875252574682, + -0.022711746394634247, + -0.01429930329322815, + -0.00412411242723465, + 0.007504432462155819, + -0.000563237292226404, + 0.01013818196952343, + -0.06896454840898514, + 0.006575733423233032, + -0.10310959815979004, + -0.012512778863310814, + 0.03036043606698513, + -0.015878431499004364, + 0.022684166207909584, + 0.02066022157669067, + 0.016029203310608864, + -0.028443187475204468, + -0.01416606828570366, + 0.0071391211822628975, + 0.034776851534843445, + 0.002298222854733467, + 0.033520814031362534, + 0.05799320712685585, + -0.0030665509402751923, + 0.013703178614377975, + 0.04346451908349991, + -0.08736324310302734, + -0.04443465545773506, + -0.09507574141025545, + -0.007938905619084835, + 0.005520000122487545, + -0.043095000088214874, + -0.03352028876543045, + 0.021385299041867256, + 0.02366030216217041, + -0.02853614091873169, + 0.002117573283612728, + 0.055353257805109024, + 0.027501529082655907, + -0.015763575211167336, + 0.0570647306740284, + -0.029892882332205772, + 0.02390587143599987, + -0.013306232169270515, + 0.018932240083813667, + 0.0071633001789450645, + 0.006233749445527792, + 0.03482261300086975, + -0.0009497640421614052, + 0.04889736324548721, + -0.010756379924714564, + -0.10233137756586076, + 0.032568227499723434, + -0.0017232495592907071, + 0.0197619441896677, + -0.01157362200319767, + -0.022340090945363045, + 0.03321876749396324, + -0.03730887547135353, + -0.004980842582881451, + 0.031003642827272415, + 0.04853849858045578, + 0.00792314950376749, + -0.016585927456617355, + -0.00377306598238647, + 0.009732725098729134, + -0.026165375486016273, + 0.0068840766325592995, + 0.02659326232969761, + -0.005413031205534935, + -0.0209831390529871, + -0.029614845290780067, + 0.01654200442135334, + -0.03843202814459801, + 0.016572654247283936, + -0.022821595892310143, + 0.02077091671526432, + -0.033952746540308, + 0.06542537361383438, + -0.08189623057842255, + 0.0031411293894052505, + -0.01395489927381277, + 0.01906730607151985, + -0.05683666840195656, + -0.03671567142009735, + 0.001987523166462779, + 0.006716572213917971, + 0.058880213648080826, + -0.028976114466786385, + -0.10136104375123978, + -0.01454504206776619, + -0.06632363796234131, + 0.012023151852190496, + -0.039696235209703445, + -0.10271679610013962, + -0.00566994259133935, + -0.011019215919077396, + 0.022908398881554604, + 0.00902929063886404, + -0.02031330019235611, + 0.02893255092203617, + -0.020042693242430687, + -0.02361901104450226, + 0.038222216069698334, + 0.008589942008256912, + 0.03230403736233711, + 0.002454438945278526, + 0.004391937050968409, + -0.0484878346323967, + -0.002869164338335395, + -0.05096660554409027, + -0.028733370825648308, + 0.03479108586907387, + 0.03205372020602226, + -0.004485339857637882, + 0.017057575285434723, + 0.0132388761267066, + -0.04253086820244789, + 0.021169882267713547, + -0.008464457467198372, + -0.009780851192772388, + 0.02306952327489853, + -0.04061064124107361, + 0.0140217337757349, + -0.003301902674138546, + 0.005067829042673111 + ], + "index": 0 + } + ], + "model": "text-embedding-005", + "usage": { + "prompt_tokens": 0, + "total_tokens": 0 + } + }, + { + "object": "list", "data": [ { + "object": "embedding", "embedding": [ -0.058164194226264954, -0.00003622031363192946, @@ -772,14 +3910,11 @@ -0.003301902674138546, 0.005067829042673111 ], - "index": 0, - "object": "embedding" + "index": 0 } ], "model": "text-embedding-005", - "object": "list", "usage": { - "completion_tokens": 0, "prompt_tokens": 0, "total_tokens": 0 } From e7e15857155cfd44bf1eb9b398138a82ec52cfb8 Mon Sep 17 00:00:00 2001 From: David Anyatonwu Date: Mon, 12 May 2025 22:41:01 +0100 Subject: [PATCH 9/9] chore: remove multiple test embedding data --- tests/cassettes/vertexai/embeddings.json | 3136 ---------------------- 1 file changed, 3136 deletions(-) diff --git a/tests/cassettes/vertexai/embeddings.json b/tests/cassettes/vertexai/embeddings.json index 458aaf9..3ae0569 100644 --- a/tests/cassettes/vertexai/embeddings.json +++ b/tests/cassettes/vertexai/embeddings.json @@ -1,3140 +1,4 @@ [ - { - "object": "list", - "data": [ - { - "object": "embedding", - "embedding": [ - -0.058164194226264954, - -0.00003622031363192946, - 0.010542492382228374, - -0.004728350788354874, - 0.07369722425937653, - -0.02481695637106895, - -0.00031316516106016934, - -0.017290938645601273, - 0.03166302293539047, - 0.014893381856381891, - -0.04859609156847, - -0.05490480735898018, - -0.005848468281328678, - -0.06573579460382462, - -0.013973977416753767, - 0.03232813626527786, - 0.07840143144130707, - -0.05846800282597542, - -0.041564371436834335, - -0.017742950469255447, - 0.022528981789946556, - -0.05958662927150726, - -0.0955798402428627, - -0.009678563103079796, - 0.044648200273513794, - -0.043353594839572906, - -0.01671011932194233, - -0.02975669503211975, - -0.05829453468322754, - -0.0157438013702631, - 0.0006426912150345743, - -0.05014248937368393, - 0.011643724516034126, - -0.0007280845893546939, - 0.03767689689993858, - -0.010895035229623318, - 0.033650316298007965, - -0.037673596292734146, - 0.018698105588555336, - -0.03840488940477371, - 0.03343287855386734, - -0.05688348412513733, - -0.012943455018103124, - -0.0692962184548378, - -0.03782666474580765, - 0.010393713600933552, - -0.025529509410262108, - 0.01568876951932907, - 0.07156006246805191, - -0.014751105569303036, - 0.08142535388469696, - 0.029754770919680595, - -0.007077757269144058, - 0.031249215826392177, - 0.022206788882613186, - 0.05383630096912384, - 0.005256577394902706, - -0.013356782495975494, - 0.008688163012266159, - 0.02924143336713314, - -0.026365751400589943, - -0.036567822098731995, - 0.013740355148911476, - 0.0014254077104851604, - -0.04947865009307861, - -0.01049752440303564, - -0.007019080687314272, - -0.0033643722999840975, - -0.0020064576528966427, - -0.07127232104539871, - -0.05643607676029205, - -0.007050491403788328, - 0.005696943495422602, - 0.0319971963763237, - -0.045856233686208725, - -0.0382072851061821, - 0.024022594094276428, - 0.07401637732982635, - -0.01796848513185978, - -0.023768220096826553, - -0.059311170130968094, - -0.02001041918992996, - -0.053349319845438, - 0.0029365948867052794, - 0.010357838124036787, - -0.03372623398900032, - 0.005034816917032003, - -0.06332722306251526, - 0.0042638652957975864, - -0.015453161671757698, - -0.039690133184194565, - -0.020585861057043076, - -0.08410325646400452, - -0.020636729896068573, - 0.022761065512895584, - -0.02659504860639572, - 0.008869532495737076, - 0.06127539649605751, - 0.016054663807153702, - 0.01801091432571411, - -0.0068725040182471275, - 0.038399890065193176, - -0.01656283810734749, - -0.02084347791969776, - 0.008902153931558132, - 0.06902532279491425, - -0.0018741635140031576, - -0.04490096867084503, - 0.06339003145694733, - -0.017102815210819244, - -0.057325396686792374, - 0.022083261981606483, - -0.04266951605677605, - 0.019720112904906273, - 0.05673870071768761, - 0.02355301007628441, - -0.04308970272541046, - 0.0002606247435323894, - -0.00685822544619441, - -0.03939145803451538, - -0.02690181694924831, - -0.055103152990341187, - 0.1029508337378502, - 0.046327341347932816, - 0.0023325744550675154, - 0.018498506397008896, - -0.06048314645886421, - -0.013803904876112938, - 0.03132600709795952, - -0.006520519964396954, - 0.028858399018645287, - -0.04834062233567238, - 0.04562418535351753, - 0.07403726130723953, - 0.0036133721005171537, - -0.011329884640872478, - -0.0112222321331501, - -0.008675935678184032, - 0.016003990545868874, - 0.02360924705862999, - -0.03237585723400116, - 0.062091924250125885, - 0.0534723736345768, - 0.06908244639635086, - 0.01992947794497013, - -0.021924395114183422, - -0.08472655713558197, - 0.010171602480113506, - 0.013133247382938862, - -0.02523472346365452, - -0.06846307218074799, - 0.0004721606965176761, - -0.02166888676583767, - -0.0005694524152204394, - -0.008681336417794228, - -0.05947762727737427, - -0.04814690351486206, - -0.013798982836306097, - 0.01617482490837574, - -0.02504643611609936, - 0.009110392071306704, - -0.013774625957012177, - -0.019712207838892937, - -0.016054371371865273, - -0.018327657133340836, - -0.012811604887247086, - 0.08344585448503494, - 0.0004540338122751564, - 0.019656607881188393, - 0.019389579072594643, - -0.014049646444618702, - 0.017445947974920273, - -0.00820555817335844, - -0.029353104531764984, - 0.0435597263276577, - 0.009650807827711104, - -0.0388045459985733, - -0.04784759134054184, - -0.038223911076784134, - -0.03691287711262703, - -0.03876909241080284, - -0.06724806874990463, - -0.04394567012786865, - 0.04173814505338669, - -0.09444724023342133, - 0.007763924542814493, - -0.008699805475771427, - -0.007599780336022377, - 0.0023920757230371237, - 0.029335761442780495, - -0.07895313203334808, - -0.04035546630620957, - -0.008500908501446247, - 0.030348196625709537, - 0.02277581207454205, - 0.05779244005680084, - 0.049121756106615067, - -0.005412466358393431, - 0.007729559671133757, - -0.01292573381215334, - -0.025097647681832314, - 0.004094319883733988, - 0.06612378358840942, - -0.019531669095158577, - -0.005063635762780905, - -0.005468557123094797, - 0.07955626398324966, - -0.002157465321943164, - 0.009207960218191149, - -0.06414847075939178, - -0.0035572517663240433, - -0.0020771902054548264, - -0.1227332055568695, - -0.03706011176109314, - 0.0008404941763728857, - -0.046963952481746674, - 0.04012263193726539, - -0.027263401076197624, - 0.016582122072577477, - 0.04703010618686676, - 0.03132076933979988, - -0.010051103308796884, - -0.03994416818022728, - 0.05056227371096611, - -0.005183490924537182, - -0.03397025540471077, - 0.05630888789892197, - -0.00752260722219944, - 0.056935470551252365, - -0.019262658432126045, - -0.005856715142726898, - -0.00361971789970994, - 0.014742489904165268, - -0.0173240564763546, - 0.025849811732769012, - -0.03633483499288559, - 0.05162259563803673, - -0.024835949763655663, - -0.04847341403365135, - -0.03159399703145027, - -0.03467343747615814, - 0.036358628422021866, - -0.03581903874874115, - 0.002909073606133461, - -0.06491775810718536, - 0.02263971231877804, - 0.0016398467123508451, - 0.02446398138999939, - -0.07746433466672897, - -0.006726226769387722, - -0.000519428460393101, - -0.039504919201135635, - -0.005563349928706884, - -0.020594995468854904, - 0.061375197023153305, - -0.04385501146316528, - -0.020819365978240967, - 0.0002135665708919987, - 0.0025394882541149855, - 0.03940146788954735, - 0.04535587877035141, - 0.022408338263630867, - 0.010107740759849548, - -0.02910368889570236, - 0.023004544898867607, - -0.0777907446026802, - -0.03995157033205032, - -0.007604190148413181, - -0.01633376069366932, - 0.03180794045329094, - -0.001723665394820273, - 0.008649897761642933, - 0.0242207832634449, - -0.010647157207131386, - -0.026367707177996635, - 0.04031673073768616, - -0.05165720731019974, - -0.03284695744514465, - -0.02335844747722149, - -0.03349415957927704, - 0.025802014395594597, - -0.03694309666752815, - -0.006044459994882345, - 0.06736567616462708, - 0.01603505201637745, - -0.02328784205019474, - -0.012791356071829796, - 0.013516776263713837, - -0.03699612617492676, - 0.01060064509510994, - 0.00883965939283371, - -0.009064657613635063, - 0.0350169874727726, - -0.02685544267296791, - -0.014185672625899317, - 0.016354434192180634, - 0.036822687834501266, - 0.023291006684303284, - -0.059676602482795715, - 0.018569037318229675, - -0.035254210233688354, - 0.03186021000146866, - -0.006412920076400042, - 0.006461815442889929, - -0.0018794521456584337, - -0.004147578962147236, - -0.011934665031731129, - -0.0030684741213917732, - -0.011600416153669356, - 0.014210240915417671, - 0.035710278898477554, - -0.0347076840698719, - 0.024610867723822594, - -0.02708994224667549, - -0.05045025795698166, - -0.010565407574176788, - -0.033687181770801544, - -0.02122747339308262, - -0.04409955069422722, - -0.003069423837587238, - 0.044485583901405334, - -0.05378193408250809, - 0.072037473320961, - -0.07409116625785828, - 0.015786299481987953, - -0.06721299141645432, - 0.025938687846064568, - 0.010510837659239767, - -0.023115744814276695, - -0.03091544844210148, - 0.050648219883441925, - 0.035482946783304214, - 0.04307528957724571, - -0.04726636782288551, - -0.04310080036520958, - -0.013828760012984276, - 0.048286303877830505, - -0.02076721377670765, - -0.01085709035396576, - -0.03584962338209152, - -0.014488843269646168, - -0.0027554789558053017, - -0.06005162000656128, - 0.04566371068358421, - -0.08098234236240387, - -0.0007054588641040027, - 0.023113127797842022, - 0.013891058973968027, - -0.06299350410699844, - 0.013442540541291235, - -0.0063631776720285416, - 0.03821553662419319, - 0.042192913591861725, - -0.011878528632223606, - 0.025002310052514076, - -0.03168347105383873, - 0.00921724271029234, - 0.05588514357805252, - -0.019194696098566055, - -0.013231540098786354, - 0.013922672718763351, - 0.050090741366147995, - -0.009419753216207027, - 0.030472371727228165, - 0.02902497723698616, - 0.00012655452883336693, - 0.02010628953576088, - -0.017804551869630814, - 0.02543807215988636, - -0.0017418548231944442, - 0.03014679066836834, - -0.002393407514318824, - 0.01539027225226164, - -0.013939744792878628, - 0.04250369220972061, - -0.028016269207000732, - -0.0010314607061445713, - 0.00945567712187767, - 0.01606564037501812, - 0.03212505206465721, - 0.02634749934077263, - -0.04875859245657921, - -0.02948666177690029, - -0.010389791801571846, - -0.02731900289654732, - 0.008594093844294548, - -0.0005823180545121431, - 0.054062556475400925, - 0.0035941607784479856, - 0.0543292835354805, - -0.004254109226167202, - 0.08106452226638794, - 0.00023218353453557936, - 0.008525514975190163, - 0.010739163495600224, - -0.06044655293226242, - 0.02740525454282761, - 0.024431807920336723, - -0.07784923911094666, - -0.011249307543039322, - 0.042149681597948074, - 0.05080077797174454, - 0.012841291725635529, - -0.01869971305131912, - -0.0298676285892725, - -0.030107680708169937, - 0.007617079187184572, - -0.03927510604262352, - 0.005952583160251379, - -0.04362985119223595, - -0.056472595781087875, - -0.05122603103518486, - 0.030536439269781113, - 0.06711754202842712, - 0.030769379809498787, - -0.08917279541492462, - 0.030519621446728703, - -0.018731193616986275, - 0.025107961148023605, - -0.04443630948662758, - -0.03170761838555336, - 0.05583782494068146, - 0.028091464191675183, - 0.022955838590860367, - 0.033636752516031265, - -0.02531679160892963, - -0.012428611516952516, - 0.019952984526753426, - 0.02082655392587185, - 0.07539939135313034, - -0.06182907521724701, - 0.02644423581659794, - -0.0031414111144840717, - -0.03931447118520737, - 0.03972741961479187, - -0.06503785401582718, - -0.02640126273036003, - -0.026757026091217995, - 0.02259722352027893, - -0.026944443583488464, - -0.04200126603245735, - 0.06589224189519882, - -0.0060363225638866425, - 0.014422483742237093, - -0.047794267535209656, - -0.03258788213133812, - 0.0013760939473286271, - -0.009353984147310255, - 0.012716212309896946, - 0.04360601305961609, - 0.0045635453425347805, - 0.038450006395578384, - 0.032771769911050797, - 0.0030687032267451286, - -0.04321933165192604, - 0.006499011069536209, - 0.0028769823256880045, - 0.012420333921909332, - 0.013525757007300854, - -0.006150753237307072, - -0.004118023905903101, - 0.023745615035295486, - -0.042544446885585785, - 0.01779933273792267, - 0.0738072544336319, - -0.03007355146110058, - -0.009512661024928091, - -0.03289958834648132, - -0.004790752660483122, - 0.0004558037326205522, - 0.0720517635345459, - -0.06180300563573837, - -0.0042299022898077965, - 0.00017941815895028412, - 0.026685943827033043, - 0.0046829464845359325, - -0.0006890723598189652, - 0.008649819530546665, - -0.019310785457491875, - 0.03345974162220955, - -0.02027411200106144, - 0.0454903170466423, - 0.004120772238820791, - -0.028732268139719963, - 0.002070050220936537, - 0.03910873085260391, - -0.034626252949237823, - -0.06625950336456299, - -0.057161930948495865, - -0.027074122801423073, - -0.03852885961532593, - 0.036027777940034866, - -0.03378047049045563, - -0.04209835082292557, - 0.02349921129643917, - 0.03960388153791427, - 0.0015966565115377307, - -0.003795675467699766, - 0.008811083622276783, - -0.02891468815505505, - -0.08621173352003098, - 0.03072702139616013, - -0.04263502359390259, - 0.0518559105694294, - -0.014513948932290075, - 0.00426185317337513, - -0.042820628732442856, - 0.061024997383356094, - 0.008177947252988815, - -0.025654304772615433, - -0.01994758658111095, - 0.03115339018404484, - -0.06122246012091637, - -0.00973520614206791, - 0.026119912043213844, - 0.018067168071866035, - 0.046298809349536896, - -0.0637248307466507, - -0.003924540244042873, - 0.05164488032460213, - -0.03986351564526558, - 0.012143593281507492, - -0.01493164524435997, - 0.012364163994789124, - 0.0033910535275936127, - 0.03926117718219757, - 0.0160888209939003, - 0.022147519513964653, - 0.040994029492139816, - 0.03238851949572563, - 0.031068911775946617, - -0.0019339561695232987, - -0.04030238837003708, - 0.018413899466395375, - 0.009558942168951036, - 0.024898380041122437, - -0.02646373026072979, - -0.027966918423771855, - 0.03851816430687904, - -0.018016686663031575, - 0.01169034279882908, - -0.041716981679201126, - -0.012398135848343372, - -0.040918245911598206, - 0.049635518342256546, - 0.019493695348501205, - 0.010355286300182344, - -0.005950144957751036, - -0.022309331223368645, - -0.0430804155766964, - 0.0156959630548954, - 0.01119300164282322, - -0.008492423221468925, - 0.014949626289308071, - -0.053723081946372986, - 0.027443569153547287, - 0.03662879765033722, - -0.03641078248620033, - 0.04629331827163696, - 0.004617750179022551, - -0.03654378652572632, - 0.013454713858664036, - 0.0032841702923178673, - -0.01309528760612011, - -0.0006306404829956591, - -0.010712265968322754, - -0.0031115366145968437, - 0.06719954311847687, - -0.041091009974479675, - 0.052047744393348694, - 0.015360930003225803, - 0.017123648896813393, - -0.016294341534376144, - 0.04660823196172714, - -0.024207523092627525, - -0.04300165921449661, - -0.05108120292425155, - 0.09737501293420792, - -0.01331926416605711, - 0.06842294335365295, - -0.002399123040959239, - 0.012122059240937231, - 0.06719434261322021, - -0.05437808856368065, - 0.004240202717483044, - -0.027191925793886185, - -0.040218885987997055, - -0.02375097759068012, - 0.012262600474059582, - 0.014219674281775951, - -0.006157959345728159, - 0.011399772949516771, - -0.05200403183698654, - -0.017264649271965027, - 0.016833636909723282, - -0.009583424776792526, - -0.03376639261841774, - -0.00961976870894432, - 0.001210652757436037, - -0.0612335205078125, - -0.0336930938065052, - -0.025393076241016388, - -0.02714981697499752, - 0.004886742681264877, - 0.013395018875598907, - -0.02571096643805504, - -0.03276616707444191, - -0.030069544911384583, - 0.036591000854969025, - -0.07458269596099854, - 0.05744070932269096, - 0.028478343039751053, - -0.0028876815922558308, - 0.02639182470738888, - 0.018080219626426697, - 0.04396456852555275, - 0.003018079325556755, - -0.03397033363580704, - -0.02141541987657547, - 0.010896582156419754, - -0.03434125706553459, - -0.05253784731030464, - -0.025020217522978783, - -0.005296454764902592, - 0.019587192684412003, - 0.03784740716218949, - -0.01990439184010029, - 0.02046854794025421, - -0.02455652691423893, - -0.020822890102863312, - 0.003083446528762579, - 0.07859235256910324, - -0.08430628478527069, - -0.02872663363814354, - 0.05072060227394104, - 0.043463632464408875, - 0.017734138295054436, - -0.04160630330443382, - -0.04641241580247879, - -0.02498893067240715, - -0.03297220170497894, - -0.09785742312669754, - -0.006121875252574682, - -0.022711746394634247, - -0.01429930329322815, - -0.00412411242723465, - 0.007504432462155819, - -0.000563237292226404, - 0.01013818196952343, - -0.06896454840898514, - 0.006575733423233032, - -0.10310959815979004, - -0.012512778863310814, - 0.03036043606698513, - -0.015878431499004364, - 0.022684166207909584, - 0.02066022157669067, - 0.016029203310608864, - -0.028443187475204468, - -0.01416606828570366, - 0.0071391211822628975, - 0.034776851534843445, - 0.002298222854733467, - 0.033520814031362534, - 0.05799320712685585, - -0.0030665509402751923, - 0.013703178614377975, - 0.04346451908349991, - -0.08736324310302734, - -0.04443465545773506, - -0.09507574141025545, - -0.007938905619084835, - 0.005520000122487545, - -0.043095000088214874, - -0.03352028876543045, - 0.021385299041867256, - 0.02366030216217041, - -0.02853614091873169, - 0.002117573283612728, - 0.055353257805109024, - 0.027501529082655907, - -0.015763575211167336, - 0.0570647306740284, - -0.029892882332205772, - 0.02390587143599987, - -0.013306232169270515, - 0.018932240083813667, - 0.0071633001789450645, - 0.006233749445527792, - 0.03482261300086975, - -0.0009497640421614052, - 0.04889736324548721, - -0.010756379924714564, - -0.10233137756586076, - 0.032568227499723434, - -0.0017232495592907071, - 0.0197619441896677, - -0.01157362200319767, - -0.022340090945363045, - 0.03321876749396324, - -0.03730887547135353, - -0.004980842582881451, - 0.031003642827272415, - 0.04853849858045578, - 0.00792314950376749, - -0.016585927456617355, - -0.00377306598238647, - 0.009732725098729134, - -0.026165375486016273, - 0.0068840766325592995, - 0.02659326232969761, - -0.005413031205534935, - -0.0209831390529871, - -0.029614845290780067, - 0.01654200442135334, - -0.03843202814459801, - 0.016572654247283936, - -0.022821595892310143, - 0.02077091671526432, - -0.033952746540308, - 0.06542537361383438, - -0.08189623057842255, - 0.0031411293894052505, - -0.01395489927381277, - 0.01906730607151985, - -0.05683666840195656, - -0.03671567142009735, - 0.001987523166462779, - 0.006716572213917971, - 0.058880213648080826, - -0.028976114466786385, - -0.10136104375123978, - -0.01454504206776619, - -0.06632363796234131, - 0.012023151852190496, - -0.039696235209703445, - -0.10271679610013962, - -0.00566994259133935, - -0.011019215919077396, - 0.022908398881554604, - 0.00902929063886404, - -0.02031330019235611, - 0.02893255092203617, - -0.020042693242430687, - -0.02361901104450226, - 0.038222216069698334, - 0.008589942008256912, - 0.03230403736233711, - 0.002454438945278526, - 0.004391937050968409, - -0.0484878346323967, - -0.002869164338335395, - -0.05096660554409027, - -0.028733370825648308, - 0.03479108586907387, - 0.03205372020602226, - -0.004485339857637882, - 0.017057575285434723, - 0.0132388761267066, - -0.04253086820244789, - 0.021169882267713547, - -0.008464457467198372, - -0.009780851192772388, - 0.02306952327489853, - -0.04061064124107361, - 0.0140217337757349, - -0.003301902674138546, - 0.005067829042673111 - ], - "index": 0 - } - ], - "model": "text-embedding-005", - "usage": { - "prompt_tokens": 0, - "total_tokens": 0 - } - }, - { - "object": "list", - "data": [ - { - "object": "embedding", - "embedding": [ - -0.058164194226264954, - -0.00003622031363192946, - 0.010542492382228374, - -0.004728350788354874, - 0.07369722425937653, - -0.02481695637106895, - -0.00031316516106016934, - -0.017290938645601273, - 0.03166302293539047, - 0.014893381856381891, - -0.04859609156847, - -0.05490480735898018, - -0.005848468281328678, - -0.06573579460382462, - -0.013973977416753767, - 0.03232813626527786, - 0.07840143144130707, - -0.05846800282597542, - -0.041564371436834335, - -0.017742950469255447, - 0.022528981789946556, - -0.05958662927150726, - -0.0955798402428627, - -0.009678563103079796, - 0.044648200273513794, - -0.043353594839572906, - -0.01671011932194233, - -0.02975669503211975, - -0.05829453468322754, - -0.0157438013702631, - 0.0006426912150345743, - -0.05014248937368393, - 0.011643724516034126, - -0.0007280845893546939, - 0.03767689689993858, - -0.010895035229623318, - 0.033650316298007965, - -0.037673596292734146, - 0.018698105588555336, - -0.03840488940477371, - 0.03343287855386734, - -0.05688348412513733, - -0.012943455018103124, - -0.0692962184548378, - -0.03782666474580765, - 0.010393713600933552, - -0.025529509410262108, - 0.01568876951932907, - 0.07156006246805191, - -0.014751105569303036, - 0.08142535388469696, - 0.029754770919680595, - -0.007077757269144058, - 0.031249215826392177, - 0.022206788882613186, - 0.05383630096912384, - 0.005256577394902706, - -0.013356782495975494, - 0.008688163012266159, - 0.02924143336713314, - -0.026365751400589943, - -0.036567822098731995, - 0.013740355148911476, - 0.0014254077104851604, - -0.04947865009307861, - -0.01049752440303564, - -0.007019080687314272, - -0.0033643722999840975, - -0.0020064576528966427, - -0.07127232104539871, - -0.05643607676029205, - -0.007050491403788328, - 0.005696943495422602, - 0.0319971963763237, - -0.045856233686208725, - -0.0382072851061821, - 0.024022594094276428, - 0.07401637732982635, - -0.01796848513185978, - -0.023768220096826553, - -0.059311170130968094, - -0.02001041918992996, - -0.053349319845438, - 0.0029365948867052794, - 0.010357838124036787, - -0.03372623398900032, - 0.005034816917032003, - -0.06332722306251526, - 0.0042638652957975864, - -0.015453161671757698, - -0.039690133184194565, - -0.020585861057043076, - -0.08410325646400452, - -0.020636729896068573, - 0.022761065512895584, - -0.02659504860639572, - 0.008869532495737076, - 0.06127539649605751, - 0.016054663807153702, - 0.01801091432571411, - -0.0068725040182471275, - 0.038399890065193176, - -0.01656283810734749, - -0.02084347791969776, - 0.008902153931558132, - 0.06902532279491425, - -0.0018741635140031576, - -0.04490096867084503, - 0.06339003145694733, - -0.017102815210819244, - -0.057325396686792374, - 0.022083261981606483, - -0.04266951605677605, - 0.019720112904906273, - 0.05673870071768761, - 0.02355301007628441, - -0.04308970272541046, - 0.0002606247435323894, - -0.00685822544619441, - -0.03939145803451538, - -0.02690181694924831, - -0.055103152990341187, - 0.1029508337378502, - 0.046327341347932816, - 0.0023325744550675154, - 0.018498506397008896, - -0.06048314645886421, - -0.013803904876112938, - 0.03132600709795952, - -0.006520519964396954, - 0.028858399018645287, - -0.04834062233567238, - 0.04562418535351753, - 0.07403726130723953, - 0.0036133721005171537, - -0.011329884640872478, - -0.0112222321331501, - -0.008675935678184032, - 0.016003990545868874, - 0.02360924705862999, - -0.03237585723400116, - 0.062091924250125885, - 0.0534723736345768, - 0.06908244639635086, - 0.01992947794497013, - -0.021924395114183422, - -0.08472655713558197, - 0.010171602480113506, - 0.013133247382938862, - -0.02523472346365452, - -0.06846307218074799, - 0.0004721606965176761, - -0.02166888676583767, - -0.0005694524152204394, - -0.008681336417794228, - -0.05947762727737427, - -0.04814690351486206, - -0.013798982836306097, - 0.01617482490837574, - -0.02504643611609936, - 0.009110392071306704, - -0.013774625957012177, - -0.019712207838892937, - -0.016054371371865273, - -0.018327657133340836, - -0.012811604887247086, - 0.08344585448503494, - 0.0004540338122751564, - 0.019656607881188393, - 0.019389579072594643, - -0.014049646444618702, - 0.017445947974920273, - -0.00820555817335844, - -0.029353104531764984, - 0.0435597263276577, - 0.009650807827711104, - -0.0388045459985733, - -0.04784759134054184, - -0.038223911076784134, - -0.03691287711262703, - -0.03876909241080284, - -0.06724806874990463, - -0.04394567012786865, - 0.04173814505338669, - -0.09444724023342133, - 0.007763924542814493, - -0.008699805475771427, - -0.007599780336022377, - 0.0023920757230371237, - 0.029335761442780495, - -0.07895313203334808, - -0.04035546630620957, - -0.008500908501446247, - 0.030348196625709537, - 0.02277581207454205, - 0.05779244005680084, - 0.049121756106615067, - -0.005412466358393431, - 0.007729559671133757, - -0.01292573381215334, - -0.025097647681832314, - 0.004094319883733988, - 0.06612378358840942, - -0.019531669095158577, - -0.005063635762780905, - -0.005468557123094797, - 0.07955626398324966, - -0.002157465321943164, - 0.009207960218191149, - -0.06414847075939178, - -0.0035572517663240433, - -0.0020771902054548264, - -0.1227332055568695, - -0.03706011176109314, - 0.0008404941763728857, - -0.046963952481746674, - 0.04012263193726539, - -0.027263401076197624, - 0.016582122072577477, - 0.04703010618686676, - 0.03132076933979988, - -0.010051103308796884, - -0.03994416818022728, - 0.05056227371096611, - -0.005183490924537182, - -0.03397025540471077, - 0.05630888789892197, - -0.00752260722219944, - 0.056935470551252365, - -0.019262658432126045, - -0.005856715142726898, - -0.00361971789970994, - 0.014742489904165268, - -0.0173240564763546, - 0.025849811732769012, - -0.03633483499288559, - 0.05162259563803673, - -0.024835949763655663, - -0.04847341403365135, - -0.03159399703145027, - -0.03467343747615814, - 0.036358628422021866, - -0.03581903874874115, - 0.002909073606133461, - -0.06491775810718536, - 0.02263971231877804, - 0.0016398467123508451, - 0.02446398138999939, - -0.07746433466672897, - -0.006726226769387722, - -0.000519428460393101, - -0.039504919201135635, - -0.005563349928706884, - -0.020594995468854904, - 0.061375197023153305, - -0.04385501146316528, - -0.020819365978240967, - 0.0002135665708919987, - 0.0025394882541149855, - 0.03940146788954735, - 0.04535587877035141, - 0.022408338263630867, - 0.010107740759849548, - -0.02910368889570236, - 0.023004544898867607, - -0.0777907446026802, - -0.03995157033205032, - -0.007604190148413181, - -0.01633376069366932, - 0.03180794045329094, - -0.001723665394820273, - 0.008649897761642933, - 0.0242207832634449, - -0.010647157207131386, - -0.026367707177996635, - 0.04031673073768616, - -0.05165720731019974, - -0.03284695744514465, - -0.02335844747722149, - -0.03349415957927704, - 0.025802014395594597, - -0.03694309666752815, - -0.006044459994882345, - 0.06736567616462708, - 0.01603505201637745, - -0.02328784205019474, - -0.012791356071829796, - 0.013516776263713837, - -0.03699612617492676, - 0.01060064509510994, - 0.00883965939283371, - -0.009064657613635063, - 0.0350169874727726, - -0.02685544267296791, - -0.014185672625899317, - 0.016354434192180634, - 0.036822687834501266, - 0.023291006684303284, - -0.059676602482795715, - 0.018569037318229675, - -0.035254210233688354, - 0.03186021000146866, - -0.006412920076400042, - 0.006461815442889929, - -0.0018794521456584337, - -0.004147578962147236, - -0.011934665031731129, - -0.0030684741213917732, - -0.011600416153669356, - 0.014210240915417671, - 0.035710278898477554, - -0.0347076840698719, - 0.024610867723822594, - -0.02708994224667549, - -0.05045025795698166, - -0.010565407574176788, - -0.033687181770801544, - -0.02122747339308262, - -0.04409955069422722, - -0.003069423837587238, - 0.044485583901405334, - -0.05378193408250809, - 0.072037473320961, - -0.07409116625785828, - 0.015786299481987953, - -0.06721299141645432, - 0.025938687846064568, - 0.010510837659239767, - -0.023115744814276695, - -0.03091544844210148, - 0.050648219883441925, - 0.035482946783304214, - 0.04307528957724571, - -0.04726636782288551, - -0.04310080036520958, - -0.013828760012984276, - 0.048286303877830505, - -0.02076721377670765, - -0.01085709035396576, - -0.03584962338209152, - -0.014488843269646168, - -0.0027554789558053017, - -0.06005162000656128, - 0.04566371068358421, - -0.08098234236240387, - -0.0007054588641040027, - 0.023113127797842022, - 0.013891058973968027, - -0.06299350410699844, - 0.013442540541291235, - -0.0063631776720285416, - 0.03821553662419319, - 0.042192913591861725, - -0.011878528632223606, - 0.025002310052514076, - -0.03168347105383873, - 0.00921724271029234, - 0.05588514357805252, - -0.019194696098566055, - -0.013231540098786354, - 0.013922672718763351, - 0.050090741366147995, - -0.009419753216207027, - 0.030472371727228165, - 0.02902497723698616, - 0.00012655452883336693, - 0.02010628953576088, - -0.017804551869630814, - 0.02543807215988636, - -0.0017418548231944442, - 0.03014679066836834, - -0.002393407514318824, - 0.01539027225226164, - -0.013939744792878628, - 0.04250369220972061, - -0.028016269207000732, - -0.0010314607061445713, - 0.00945567712187767, - 0.01606564037501812, - 0.03212505206465721, - 0.02634749934077263, - -0.04875859245657921, - -0.02948666177690029, - -0.010389791801571846, - -0.02731900289654732, - 0.008594093844294548, - -0.0005823180545121431, - 0.054062556475400925, - 0.0035941607784479856, - 0.0543292835354805, - -0.004254109226167202, - 0.08106452226638794, - 0.00023218353453557936, - 0.008525514975190163, - 0.010739163495600224, - -0.06044655293226242, - 0.02740525454282761, - 0.024431807920336723, - -0.07784923911094666, - -0.011249307543039322, - 0.042149681597948074, - 0.05080077797174454, - 0.012841291725635529, - -0.01869971305131912, - -0.0298676285892725, - -0.030107680708169937, - 0.007617079187184572, - -0.03927510604262352, - 0.005952583160251379, - -0.04362985119223595, - -0.056472595781087875, - -0.05122603103518486, - 0.030536439269781113, - 0.06711754202842712, - 0.030769379809498787, - -0.08917279541492462, - 0.030519621446728703, - -0.018731193616986275, - 0.025107961148023605, - -0.04443630948662758, - -0.03170761838555336, - 0.05583782494068146, - 0.028091464191675183, - 0.022955838590860367, - 0.033636752516031265, - -0.02531679160892963, - -0.012428611516952516, - 0.019952984526753426, - 0.02082655392587185, - 0.07539939135313034, - -0.06182907521724701, - 0.02644423581659794, - -0.0031414111144840717, - -0.03931447118520737, - 0.03972741961479187, - -0.06503785401582718, - -0.02640126273036003, - -0.026757026091217995, - 0.02259722352027893, - -0.026944443583488464, - -0.04200126603245735, - 0.06589224189519882, - -0.0060363225638866425, - 0.014422483742237093, - -0.047794267535209656, - -0.03258788213133812, - 0.0013760939473286271, - -0.009353984147310255, - 0.012716212309896946, - 0.04360601305961609, - 0.0045635453425347805, - 0.038450006395578384, - 0.032771769911050797, - 0.0030687032267451286, - -0.04321933165192604, - 0.006499011069536209, - 0.0028769823256880045, - 0.012420333921909332, - 0.013525757007300854, - -0.006150753237307072, - -0.004118023905903101, - 0.023745615035295486, - -0.042544446885585785, - 0.01779933273792267, - 0.0738072544336319, - -0.03007355146110058, - -0.009512661024928091, - -0.03289958834648132, - -0.004790752660483122, - 0.0004558037326205522, - 0.0720517635345459, - -0.06180300563573837, - -0.0042299022898077965, - 0.00017941815895028412, - 0.026685943827033043, - 0.0046829464845359325, - -0.0006890723598189652, - 0.008649819530546665, - -0.019310785457491875, - 0.03345974162220955, - -0.02027411200106144, - 0.0454903170466423, - 0.004120772238820791, - -0.028732268139719963, - 0.002070050220936537, - 0.03910873085260391, - -0.034626252949237823, - -0.06625950336456299, - -0.057161930948495865, - -0.027074122801423073, - -0.03852885961532593, - 0.036027777940034866, - -0.03378047049045563, - -0.04209835082292557, - 0.02349921129643917, - 0.03960388153791427, - 0.0015966565115377307, - -0.003795675467699766, - 0.008811083622276783, - -0.02891468815505505, - -0.08621173352003098, - 0.03072702139616013, - -0.04263502359390259, - 0.0518559105694294, - -0.014513948932290075, - 0.00426185317337513, - -0.042820628732442856, - 0.061024997383356094, - 0.008177947252988815, - -0.025654304772615433, - -0.01994758658111095, - 0.03115339018404484, - -0.06122246012091637, - -0.00973520614206791, - 0.026119912043213844, - 0.018067168071866035, - 0.046298809349536896, - -0.0637248307466507, - -0.003924540244042873, - 0.05164488032460213, - -0.03986351564526558, - 0.012143593281507492, - -0.01493164524435997, - 0.012364163994789124, - 0.0033910535275936127, - 0.03926117718219757, - 0.0160888209939003, - 0.022147519513964653, - 0.040994029492139816, - 0.03238851949572563, - 0.031068911775946617, - -0.0019339561695232987, - -0.04030238837003708, - 0.018413899466395375, - 0.009558942168951036, - 0.024898380041122437, - -0.02646373026072979, - -0.027966918423771855, - 0.03851816430687904, - -0.018016686663031575, - 0.01169034279882908, - -0.041716981679201126, - -0.012398135848343372, - -0.040918245911598206, - 0.049635518342256546, - 0.019493695348501205, - 0.010355286300182344, - -0.005950144957751036, - -0.022309331223368645, - -0.0430804155766964, - 0.0156959630548954, - 0.01119300164282322, - -0.008492423221468925, - 0.014949626289308071, - -0.053723081946372986, - 0.027443569153547287, - 0.03662879765033722, - -0.03641078248620033, - 0.04629331827163696, - 0.004617750179022551, - -0.03654378652572632, - 0.013454713858664036, - 0.0032841702923178673, - -0.01309528760612011, - -0.0006306404829956591, - -0.010712265968322754, - -0.0031115366145968437, - 0.06719954311847687, - -0.041091009974479675, - 0.052047744393348694, - 0.015360930003225803, - 0.017123648896813393, - -0.016294341534376144, - 0.04660823196172714, - -0.024207523092627525, - -0.04300165921449661, - -0.05108120292425155, - 0.09737501293420792, - -0.01331926416605711, - 0.06842294335365295, - -0.002399123040959239, - 0.012122059240937231, - 0.06719434261322021, - -0.05437808856368065, - 0.004240202717483044, - -0.027191925793886185, - -0.040218885987997055, - -0.02375097759068012, - 0.012262600474059582, - 0.014219674281775951, - -0.006157959345728159, - 0.011399772949516771, - -0.05200403183698654, - -0.017264649271965027, - 0.016833636909723282, - -0.009583424776792526, - -0.03376639261841774, - -0.00961976870894432, - 0.001210652757436037, - -0.0612335205078125, - -0.0336930938065052, - -0.025393076241016388, - -0.02714981697499752, - 0.004886742681264877, - 0.013395018875598907, - -0.02571096643805504, - -0.03276616707444191, - -0.030069544911384583, - 0.036591000854969025, - -0.07458269596099854, - 0.05744070932269096, - 0.028478343039751053, - -0.0028876815922558308, - 0.02639182470738888, - 0.018080219626426697, - 0.04396456852555275, - 0.003018079325556755, - -0.03397033363580704, - -0.02141541987657547, - 0.010896582156419754, - -0.03434125706553459, - -0.05253784731030464, - -0.025020217522978783, - -0.005296454764902592, - 0.019587192684412003, - 0.03784740716218949, - -0.01990439184010029, - 0.02046854794025421, - -0.02455652691423893, - -0.020822890102863312, - 0.003083446528762579, - 0.07859235256910324, - -0.08430628478527069, - -0.02872663363814354, - 0.05072060227394104, - 0.043463632464408875, - 0.017734138295054436, - -0.04160630330443382, - -0.04641241580247879, - -0.02498893067240715, - -0.03297220170497894, - -0.09785742312669754, - -0.006121875252574682, - -0.022711746394634247, - -0.01429930329322815, - -0.00412411242723465, - 0.007504432462155819, - -0.000563237292226404, - 0.01013818196952343, - -0.06896454840898514, - 0.006575733423233032, - -0.10310959815979004, - -0.012512778863310814, - 0.03036043606698513, - -0.015878431499004364, - 0.022684166207909584, - 0.02066022157669067, - 0.016029203310608864, - -0.028443187475204468, - -0.01416606828570366, - 0.0071391211822628975, - 0.034776851534843445, - 0.002298222854733467, - 0.033520814031362534, - 0.05799320712685585, - -0.0030665509402751923, - 0.013703178614377975, - 0.04346451908349991, - -0.08736324310302734, - -0.04443465545773506, - -0.09507574141025545, - -0.007938905619084835, - 0.005520000122487545, - -0.043095000088214874, - -0.03352028876543045, - 0.021385299041867256, - 0.02366030216217041, - -0.02853614091873169, - 0.002117573283612728, - 0.055353257805109024, - 0.027501529082655907, - -0.015763575211167336, - 0.0570647306740284, - -0.029892882332205772, - 0.02390587143599987, - -0.013306232169270515, - 0.018932240083813667, - 0.0071633001789450645, - 0.006233749445527792, - 0.03482261300086975, - -0.0009497640421614052, - 0.04889736324548721, - -0.010756379924714564, - -0.10233137756586076, - 0.032568227499723434, - -0.0017232495592907071, - 0.0197619441896677, - -0.01157362200319767, - -0.022340090945363045, - 0.03321876749396324, - -0.03730887547135353, - -0.004980842582881451, - 0.031003642827272415, - 0.04853849858045578, - 0.00792314950376749, - -0.016585927456617355, - -0.00377306598238647, - 0.009732725098729134, - -0.026165375486016273, - 0.0068840766325592995, - 0.02659326232969761, - -0.005413031205534935, - -0.0209831390529871, - -0.029614845290780067, - 0.01654200442135334, - -0.03843202814459801, - 0.016572654247283936, - -0.022821595892310143, - 0.02077091671526432, - -0.033952746540308, - 0.06542537361383438, - -0.08189623057842255, - 0.0031411293894052505, - -0.01395489927381277, - 0.01906730607151985, - -0.05683666840195656, - -0.03671567142009735, - 0.001987523166462779, - 0.006716572213917971, - 0.058880213648080826, - -0.028976114466786385, - -0.10136104375123978, - -0.01454504206776619, - -0.06632363796234131, - 0.012023151852190496, - -0.039696235209703445, - -0.10271679610013962, - -0.00566994259133935, - -0.011019215919077396, - 0.022908398881554604, - 0.00902929063886404, - -0.02031330019235611, - 0.02893255092203617, - -0.020042693242430687, - -0.02361901104450226, - 0.038222216069698334, - 0.008589942008256912, - 0.03230403736233711, - 0.002454438945278526, - 0.004391937050968409, - -0.0484878346323967, - -0.002869164338335395, - -0.05096660554409027, - -0.028733370825648308, - 0.03479108586907387, - 0.03205372020602226, - -0.004485339857637882, - 0.017057575285434723, - 0.0132388761267066, - -0.04253086820244789, - 0.021169882267713547, - -0.008464457467198372, - -0.009780851192772388, - 0.02306952327489853, - -0.04061064124107361, - 0.0140217337757349, - -0.003301902674138546, - 0.005067829042673111 - ], - "index": 0 - } - ], - "model": "text-embedding-005", - "usage": { - "prompt_tokens": 0, - "total_tokens": 0 - } - }, - { - "object": "list", - "data": [ - { - "object": "embedding", - "embedding": [ - -0.058164194226264954, - -0.00003622031363192946, - 0.010542492382228374, - -0.004728350788354874, - 0.07369722425937653, - -0.02481695637106895, - -0.00031316516106016934, - -0.017290938645601273, - 0.03166302293539047, - 0.014893381856381891, - -0.04859609156847, - -0.05490480735898018, - -0.005848468281328678, - -0.06573579460382462, - -0.013973977416753767, - 0.03232813626527786, - 0.07840143144130707, - -0.05846800282597542, - -0.041564371436834335, - -0.017742950469255447, - 0.022528981789946556, - -0.05958662927150726, - -0.0955798402428627, - -0.009678563103079796, - 0.044648200273513794, - -0.043353594839572906, - -0.01671011932194233, - -0.02975669503211975, - -0.05829453468322754, - -0.0157438013702631, - 0.0006426912150345743, - -0.05014248937368393, - 0.011643724516034126, - -0.0007280845893546939, - 0.03767689689993858, - -0.010895035229623318, - 0.033650316298007965, - -0.037673596292734146, - 0.018698105588555336, - -0.03840488940477371, - 0.03343287855386734, - -0.05688348412513733, - -0.012943455018103124, - -0.0692962184548378, - -0.03782666474580765, - 0.010393713600933552, - -0.025529509410262108, - 0.01568876951932907, - 0.07156006246805191, - -0.014751105569303036, - 0.08142535388469696, - 0.029754770919680595, - -0.007077757269144058, - 0.031249215826392177, - 0.022206788882613186, - 0.05383630096912384, - 0.005256577394902706, - -0.013356782495975494, - 0.008688163012266159, - 0.02924143336713314, - -0.026365751400589943, - -0.036567822098731995, - 0.013740355148911476, - 0.0014254077104851604, - -0.04947865009307861, - -0.01049752440303564, - -0.007019080687314272, - -0.0033643722999840975, - -0.0020064576528966427, - -0.07127232104539871, - -0.05643607676029205, - -0.007050491403788328, - 0.005696943495422602, - 0.0319971963763237, - -0.045856233686208725, - -0.0382072851061821, - 0.024022594094276428, - 0.07401637732982635, - -0.01796848513185978, - -0.023768220096826553, - -0.059311170130968094, - -0.02001041918992996, - -0.053349319845438, - 0.0029365948867052794, - 0.010357838124036787, - -0.03372623398900032, - 0.005034816917032003, - -0.06332722306251526, - 0.0042638652957975864, - -0.015453161671757698, - -0.039690133184194565, - -0.020585861057043076, - -0.08410325646400452, - -0.020636729896068573, - 0.022761065512895584, - -0.02659504860639572, - 0.008869532495737076, - 0.06127539649605751, - 0.016054663807153702, - 0.01801091432571411, - -0.0068725040182471275, - 0.038399890065193176, - -0.01656283810734749, - -0.02084347791969776, - 0.008902153931558132, - 0.06902532279491425, - -0.0018741635140031576, - -0.04490096867084503, - 0.06339003145694733, - -0.017102815210819244, - -0.057325396686792374, - 0.022083261981606483, - -0.04266951605677605, - 0.019720112904906273, - 0.05673870071768761, - 0.02355301007628441, - -0.04308970272541046, - 0.0002606247435323894, - -0.00685822544619441, - -0.03939145803451538, - -0.02690181694924831, - -0.055103152990341187, - 0.1029508337378502, - 0.046327341347932816, - 0.0023325744550675154, - 0.018498506397008896, - -0.06048314645886421, - -0.013803904876112938, - 0.03132600709795952, - -0.006520519964396954, - 0.028858399018645287, - -0.04834062233567238, - 0.04562418535351753, - 0.07403726130723953, - 0.0036133721005171537, - -0.011329884640872478, - -0.0112222321331501, - -0.008675935678184032, - 0.016003990545868874, - 0.02360924705862999, - -0.03237585723400116, - 0.062091924250125885, - 0.0534723736345768, - 0.06908244639635086, - 0.01992947794497013, - -0.021924395114183422, - -0.08472655713558197, - 0.010171602480113506, - 0.013133247382938862, - -0.02523472346365452, - -0.06846307218074799, - 0.0004721606965176761, - -0.02166888676583767, - -0.0005694524152204394, - -0.008681336417794228, - -0.05947762727737427, - -0.04814690351486206, - -0.013798982836306097, - 0.01617482490837574, - -0.02504643611609936, - 0.009110392071306704, - -0.013774625957012177, - -0.019712207838892937, - -0.016054371371865273, - -0.018327657133340836, - -0.012811604887247086, - 0.08344585448503494, - 0.0004540338122751564, - 0.019656607881188393, - 0.019389579072594643, - -0.014049646444618702, - 0.017445947974920273, - -0.00820555817335844, - -0.029353104531764984, - 0.0435597263276577, - 0.009650807827711104, - -0.0388045459985733, - -0.04784759134054184, - -0.038223911076784134, - -0.03691287711262703, - -0.03876909241080284, - -0.06724806874990463, - -0.04394567012786865, - 0.04173814505338669, - -0.09444724023342133, - 0.007763924542814493, - -0.008699805475771427, - -0.007599780336022377, - 0.0023920757230371237, - 0.029335761442780495, - -0.07895313203334808, - -0.04035546630620957, - -0.008500908501446247, - 0.030348196625709537, - 0.02277581207454205, - 0.05779244005680084, - 0.049121756106615067, - -0.005412466358393431, - 0.007729559671133757, - -0.01292573381215334, - -0.025097647681832314, - 0.004094319883733988, - 0.06612378358840942, - -0.019531669095158577, - -0.005063635762780905, - -0.005468557123094797, - 0.07955626398324966, - -0.002157465321943164, - 0.009207960218191149, - -0.06414847075939178, - -0.0035572517663240433, - -0.0020771902054548264, - -0.1227332055568695, - -0.03706011176109314, - 0.0008404941763728857, - -0.046963952481746674, - 0.04012263193726539, - -0.027263401076197624, - 0.016582122072577477, - 0.04703010618686676, - 0.03132076933979988, - -0.010051103308796884, - -0.03994416818022728, - 0.05056227371096611, - -0.005183490924537182, - -0.03397025540471077, - 0.05630888789892197, - -0.00752260722219944, - 0.056935470551252365, - -0.019262658432126045, - -0.005856715142726898, - -0.00361971789970994, - 0.014742489904165268, - -0.0173240564763546, - 0.025849811732769012, - -0.03633483499288559, - 0.05162259563803673, - -0.024835949763655663, - -0.04847341403365135, - -0.03159399703145027, - -0.03467343747615814, - 0.036358628422021866, - -0.03581903874874115, - 0.002909073606133461, - -0.06491775810718536, - 0.02263971231877804, - 0.0016398467123508451, - 0.02446398138999939, - -0.07746433466672897, - -0.006726226769387722, - -0.000519428460393101, - -0.039504919201135635, - -0.005563349928706884, - -0.020594995468854904, - 0.061375197023153305, - -0.04385501146316528, - -0.020819365978240967, - 0.0002135665708919987, - 0.0025394882541149855, - 0.03940146788954735, - 0.04535587877035141, - 0.022408338263630867, - 0.010107740759849548, - -0.02910368889570236, - 0.023004544898867607, - -0.0777907446026802, - -0.03995157033205032, - -0.007604190148413181, - -0.01633376069366932, - 0.03180794045329094, - -0.001723665394820273, - 0.008649897761642933, - 0.0242207832634449, - -0.010647157207131386, - -0.026367707177996635, - 0.04031673073768616, - -0.05165720731019974, - -0.03284695744514465, - -0.02335844747722149, - -0.03349415957927704, - 0.025802014395594597, - -0.03694309666752815, - -0.006044459994882345, - 0.06736567616462708, - 0.01603505201637745, - -0.02328784205019474, - -0.012791356071829796, - 0.013516776263713837, - -0.03699612617492676, - 0.01060064509510994, - 0.00883965939283371, - -0.009064657613635063, - 0.0350169874727726, - -0.02685544267296791, - -0.014185672625899317, - 0.016354434192180634, - 0.036822687834501266, - 0.023291006684303284, - -0.059676602482795715, - 0.018569037318229675, - -0.035254210233688354, - 0.03186021000146866, - -0.006412920076400042, - 0.006461815442889929, - -0.0018794521456584337, - -0.004147578962147236, - -0.011934665031731129, - -0.0030684741213917732, - -0.011600416153669356, - 0.014210240915417671, - 0.035710278898477554, - -0.0347076840698719, - 0.024610867723822594, - -0.02708994224667549, - -0.05045025795698166, - -0.010565407574176788, - -0.033687181770801544, - -0.02122747339308262, - -0.04409955069422722, - -0.003069423837587238, - 0.044485583901405334, - -0.05378193408250809, - 0.072037473320961, - -0.07409116625785828, - 0.015786299481987953, - -0.06721299141645432, - 0.025938687846064568, - 0.010510837659239767, - -0.023115744814276695, - -0.03091544844210148, - 0.050648219883441925, - 0.035482946783304214, - 0.04307528957724571, - -0.04726636782288551, - -0.04310080036520958, - -0.013828760012984276, - 0.048286303877830505, - -0.02076721377670765, - -0.01085709035396576, - -0.03584962338209152, - -0.014488843269646168, - -0.0027554789558053017, - -0.06005162000656128, - 0.04566371068358421, - -0.08098234236240387, - -0.0007054588641040027, - 0.023113127797842022, - 0.013891058973968027, - -0.06299350410699844, - 0.013442540541291235, - -0.0063631776720285416, - 0.03821553662419319, - 0.042192913591861725, - -0.011878528632223606, - 0.025002310052514076, - -0.03168347105383873, - 0.00921724271029234, - 0.05588514357805252, - -0.019194696098566055, - -0.013231540098786354, - 0.013922672718763351, - 0.050090741366147995, - -0.009419753216207027, - 0.030472371727228165, - 0.02902497723698616, - 0.00012655452883336693, - 0.02010628953576088, - -0.017804551869630814, - 0.02543807215988636, - -0.0017418548231944442, - 0.03014679066836834, - -0.002393407514318824, - 0.01539027225226164, - -0.013939744792878628, - 0.04250369220972061, - -0.028016269207000732, - -0.0010314607061445713, - 0.00945567712187767, - 0.01606564037501812, - 0.03212505206465721, - 0.02634749934077263, - -0.04875859245657921, - -0.02948666177690029, - -0.010389791801571846, - -0.02731900289654732, - 0.008594093844294548, - -0.0005823180545121431, - 0.054062556475400925, - 0.0035941607784479856, - 0.0543292835354805, - -0.004254109226167202, - 0.08106452226638794, - 0.00023218353453557936, - 0.008525514975190163, - 0.010739163495600224, - -0.06044655293226242, - 0.02740525454282761, - 0.024431807920336723, - -0.07784923911094666, - -0.011249307543039322, - 0.042149681597948074, - 0.05080077797174454, - 0.012841291725635529, - -0.01869971305131912, - -0.0298676285892725, - -0.030107680708169937, - 0.007617079187184572, - -0.03927510604262352, - 0.005952583160251379, - -0.04362985119223595, - -0.056472595781087875, - -0.05122603103518486, - 0.030536439269781113, - 0.06711754202842712, - 0.030769379809498787, - -0.08917279541492462, - 0.030519621446728703, - -0.018731193616986275, - 0.025107961148023605, - -0.04443630948662758, - -0.03170761838555336, - 0.05583782494068146, - 0.028091464191675183, - 0.022955838590860367, - 0.033636752516031265, - -0.02531679160892963, - -0.012428611516952516, - 0.019952984526753426, - 0.02082655392587185, - 0.07539939135313034, - -0.06182907521724701, - 0.02644423581659794, - -0.0031414111144840717, - -0.03931447118520737, - 0.03972741961479187, - -0.06503785401582718, - -0.02640126273036003, - -0.026757026091217995, - 0.02259722352027893, - -0.026944443583488464, - -0.04200126603245735, - 0.06589224189519882, - -0.0060363225638866425, - 0.014422483742237093, - -0.047794267535209656, - -0.03258788213133812, - 0.0013760939473286271, - -0.009353984147310255, - 0.012716212309896946, - 0.04360601305961609, - 0.0045635453425347805, - 0.038450006395578384, - 0.032771769911050797, - 0.0030687032267451286, - -0.04321933165192604, - 0.006499011069536209, - 0.0028769823256880045, - 0.012420333921909332, - 0.013525757007300854, - -0.006150753237307072, - -0.004118023905903101, - 0.023745615035295486, - -0.042544446885585785, - 0.01779933273792267, - 0.0738072544336319, - -0.03007355146110058, - -0.009512661024928091, - -0.03289958834648132, - -0.004790752660483122, - 0.0004558037326205522, - 0.0720517635345459, - -0.06180300563573837, - -0.0042299022898077965, - 0.00017941815895028412, - 0.026685943827033043, - 0.0046829464845359325, - -0.0006890723598189652, - 0.008649819530546665, - -0.019310785457491875, - 0.03345974162220955, - -0.02027411200106144, - 0.0454903170466423, - 0.004120772238820791, - -0.028732268139719963, - 0.002070050220936537, - 0.03910873085260391, - -0.034626252949237823, - -0.06625950336456299, - -0.057161930948495865, - -0.027074122801423073, - -0.03852885961532593, - 0.036027777940034866, - -0.03378047049045563, - -0.04209835082292557, - 0.02349921129643917, - 0.03960388153791427, - 0.0015966565115377307, - -0.003795675467699766, - 0.008811083622276783, - -0.02891468815505505, - -0.08621173352003098, - 0.03072702139616013, - -0.04263502359390259, - 0.0518559105694294, - -0.014513948932290075, - 0.00426185317337513, - -0.042820628732442856, - 0.061024997383356094, - 0.008177947252988815, - -0.025654304772615433, - -0.01994758658111095, - 0.03115339018404484, - -0.06122246012091637, - -0.00973520614206791, - 0.026119912043213844, - 0.018067168071866035, - 0.046298809349536896, - -0.0637248307466507, - -0.003924540244042873, - 0.05164488032460213, - -0.03986351564526558, - 0.012143593281507492, - -0.01493164524435997, - 0.012364163994789124, - 0.0033910535275936127, - 0.03926117718219757, - 0.0160888209939003, - 0.022147519513964653, - 0.040994029492139816, - 0.03238851949572563, - 0.031068911775946617, - -0.0019339561695232987, - -0.04030238837003708, - 0.018413899466395375, - 0.009558942168951036, - 0.024898380041122437, - -0.02646373026072979, - -0.027966918423771855, - 0.03851816430687904, - -0.018016686663031575, - 0.01169034279882908, - -0.041716981679201126, - -0.012398135848343372, - -0.040918245911598206, - 0.049635518342256546, - 0.019493695348501205, - 0.010355286300182344, - -0.005950144957751036, - -0.022309331223368645, - -0.0430804155766964, - 0.0156959630548954, - 0.01119300164282322, - -0.008492423221468925, - 0.014949626289308071, - -0.053723081946372986, - 0.027443569153547287, - 0.03662879765033722, - -0.03641078248620033, - 0.04629331827163696, - 0.004617750179022551, - -0.03654378652572632, - 0.013454713858664036, - 0.0032841702923178673, - -0.01309528760612011, - -0.0006306404829956591, - -0.010712265968322754, - -0.0031115366145968437, - 0.06719954311847687, - -0.041091009974479675, - 0.052047744393348694, - 0.015360930003225803, - 0.017123648896813393, - -0.016294341534376144, - 0.04660823196172714, - -0.024207523092627525, - -0.04300165921449661, - -0.05108120292425155, - 0.09737501293420792, - -0.01331926416605711, - 0.06842294335365295, - -0.002399123040959239, - 0.012122059240937231, - 0.06719434261322021, - -0.05437808856368065, - 0.004240202717483044, - -0.027191925793886185, - -0.040218885987997055, - -0.02375097759068012, - 0.012262600474059582, - 0.014219674281775951, - -0.006157959345728159, - 0.011399772949516771, - -0.05200403183698654, - -0.017264649271965027, - 0.016833636909723282, - -0.009583424776792526, - -0.03376639261841774, - -0.00961976870894432, - 0.001210652757436037, - -0.0612335205078125, - -0.0336930938065052, - -0.025393076241016388, - -0.02714981697499752, - 0.004886742681264877, - 0.013395018875598907, - -0.02571096643805504, - -0.03276616707444191, - -0.030069544911384583, - 0.036591000854969025, - -0.07458269596099854, - 0.05744070932269096, - 0.028478343039751053, - -0.0028876815922558308, - 0.02639182470738888, - 0.018080219626426697, - 0.04396456852555275, - 0.003018079325556755, - -0.03397033363580704, - -0.02141541987657547, - 0.010896582156419754, - -0.03434125706553459, - -0.05253784731030464, - -0.025020217522978783, - -0.005296454764902592, - 0.019587192684412003, - 0.03784740716218949, - -0.01990439184010029, - 0.02046854794025421, - -0.02455652691423893, - -0.020822890102863312, - 0.003083446528762579, - 0.07859235256910324, - -0.08430628478527069, - -0.02872663363814354, - 0.05072060227394104, - 0.043463632464408875, - 0.017734138295054436, - -0.04160630330443382, - -0.04641241580247879, - -0.02498893067240715, - -0.03297220170497894, - -0.09785742312669754, - -0.006121875252574682, - -0.022711746394634247, - -0.01429930329322815, - -0.00412411242723465, - 0.007504432462155819, - -0.000563237292226404, - 0.01013818196952343, - -0.06896454840898514, - 0.006575733423233032, - -0.10310959815979004, - -0.012512778863310814, - 0.03036043606698513, - -0.015878431499004364, - 0.022684166207909584, - 0.02066022157669067, - 0.016029203310608864, - -0.028443187475204468, - -0.01416606828570366, - 0.0071391211822628975, - 0.034776851534843445, - 0.002298222854733467, - 0.033520814031362534, - 0.05799320712685585, - -0.0030665509402751923, - 0.013703178614377975, - 0.04346451908349991, - -0.08736324310302734, - -0.04443465545773506, - -0.09507574141025545, - -0.007938905619084835, - 0.005520000122487545, - -0.043095000088214874, - -0.03352028876543045, - 0.021385299041867256, - 0.02366030216217041, - -0.02853614091873169, - 0.002117573283612728, - 0.055353257805109024, - 0.027501529082655907, - -0.015763575211167336, - 0.0570647306740284, - -0.029892882332205772, - 0.02390587143599987, - -0.013306232169270515, - 0.018932240083813667, - 0.0071633001789450645, - 0.006233749445527792, - 0.03482261300086975, - -0.0009497640421614052, - 0.04889736324548721, - -0.010756379924714564, - -0.10233137756586076, - 0.032568227499723434, - -0.0017232495592907071, - 0.0197619441896677, - -0.01157362200319767, - -0.022340090945363045, - 0.03321876749396324, - -0.03730887547135353, - -0.004980842582881451, - 0.031003642827272415, - 0.04853849858045578, - 0.00792314950376749, - -0.016585927456617355, - -0.00377306598238647, - 0.009732725098729134, - -0.026165375486016273, - 0.0068840766325592995, - 0.02659326232969761, - -0.005413031205534935, - -0.0209831390529871, - -0.029614845290780067, - 0.01654200442135334, - -0.03843202814459801, - 0.016572654247283936, - -0.022821595892310143, - 0.02077091671526432, - -0.033952746540308, - 0.06542537361383438, - -0.08189623057842255, - 0.0031411293894052505, - -0.01395489927381277, - 0.01906730607151985, - -0.05683666840195656, - -0.03671567142009735, - 0.001987523166462779, - 0.006716572213917971, - 0.058880213648080826, - -0.028976114466786385, - -0.10136104375123978, - -0.01454504206776619, - -0.06632363796234131, - 0.012023151852190496, - -0.039696235209703445, - -0.10271679610013962, - -0.00566994259133935, - -0.011019215919077396, - 0.022908398881554604, - 0.00902929063886404, - -0.02031330019235611, - 0.02893255092203617, - -0.020042693242430687, - -0.02361901104450226, - 0.038222216069698334, - 0.008589942008256912, - 0.03230403736233711, - 0.002454438945278526, - 0.004391937050968409, - -0.0484878346323967, - -0.002869164338335395, - -0.05096660554409027, - -0.028733370825648308, - 0.03479108586907387, - 0.03205372020602226, - -0.004485339857637882, - 0.017057575285434723, - 0.0132388761267066, - -0.04253086820244789, - 0.021169882267713547, - -0.008464457467198372, - -0.009780851192772388, - 0.02306952327489853, - -0.04061064124107361, - 0.0140217337757349, - -0.003301902674138546, - 0.005067829042673111 - ], - "index": 0 - } - ], - "model": "text-embedding-005", - "usage": { - "prompt_tokens": 0, - "total_tokens": 0 - } - }, - { - "object": "list", - "data": [ - { - "object": "embedding", - "embedding": [ - -0.058164194226264954, - -0.00003622031363192946, - 0.010542492382228374, - -0.004728350788354874, - 0.07369722425937653, - -0.02481695637106895, - -0.00031316516106016934, - -0.017290938645601273, - 0.03166302293539047, - 0.014893381856381891, - -0.04859609156847, - -0.05490480735898018, - -0.005848468281328678, - -0.06573579460382462, - -0.013973977416753767, - 0.03232813626527786, - 0.07840143144130707, - -0.05846800282597542, - -0.041564371436834335, - -0.017742950469255447, - 0.022528981789946556, - -0.05958662927150726, - -0.0955798402428627, - -0.009678563103079796, - 0.044648200273513794, - -0.043353594839572906, - -0.01671011932194233, - -0.02975669503211975, - -0.05829453468322754, - -0.0157438013702631, - 0.0006426912150345743, - -0.05014248937368393, - 0.011643724516034126, - -0.0007280845893546939, - 0.03767689689993858, - -0.010895035229623318, - 0.033650316298007965, - -0.037673596292734146, - 0.018698105588555336, - -0.03840488940477371, - 0.03343287855386734, - -0.05688348412513733, - -0.012943455018103124, - -0.0692962184548378, - -0.03782666474580765, - 0.010393713600933552, - -0.025529509410262108, - 0.01568876951932907, - 0.07156006246805191, - -0.014751105569303036, - 0.08142535388469696, - 0.029754770919680595, - -0.007077757269144058, - 0.031249215826392177, - 0.022206788882613186, - 0.05383630096912384, - 0.005256577394902706, - -0.013356782495975494, - 0.008688163012266159, - 0.02924143336713314, - -0.026365751400589943, - -0.036567822098731995, - 0.013740355148911476, - 0.0014254077104851604, - -0.04947865009307861, - -0.01049752440303564, - -0.007019080687314272, - -0.0033643722999840975, - -0.0020064576528966427, - -0.07127232104539871, - -0.05643607676029205, - -0.007050491403788328, - 0.005696943495422602, - 0.0319971963763237, - -0.045856233686208725, - -0.0382072851061821, - 0.024022594094276428, - 0.07401637732982635, - -0.01796848513185978, - -0.023768220096826553, - -0.059311170130968094, - -0.02001041918992996, - -0.053349319845438, - 0.0029365948867052794, - 0.010357838124036787, - -0.03372623398900032, - 0.005034816917032003, - -0.06332722306251526, - 0.0042638652957975864, - -0.015453161671757698, - -0.039690133184194565, - -0.020585861057043076, - -0.08410325646400452, - -0.020636729896068573, - 0.022761065512895584, - -0.02659504860639572, - 0.008869532495737076, - 0.06127539649605751, - 0.016054663807153702, - 0.01801091432571411, - -0.0068725040182471275, - 0.038399890065193176, - -0.01656283810734749, - -0.02084347791969776, - 0.008902153931558132, - 0.06902532279491425, - -0.0018741635140031576, - -0.04490096867084503, - 0.06339003145694733, - -0.017102815210819244, - -0.057325396686792374, - 0.022083261981606483, - -0.04266951605677605, - 0.019720112904906273, - 0.05673870071768761, - 0.02355301007628441, - -0.04308970272541046, - 0.0002606247435323894, - -0.00685822544619441, - -0.03939145803451538, - -0.02690181694924831, - -0.055103152990341187, - 0.1029508337378502, - 0.046327341347932816, - 0.0023325744550675154, - 0.018498506397008896, - -0.06048314645886421, - -0.013803904876112938, - 0.03132600709795952, - -0.006520519964396954, - 0.028858399018645287, - -0.04834062233567238, - 0.04562418535351753, - 0.07403726130723953, - 0.0036133721005171537, - -0.011329884640872478, - -0.0112222321331501, - -0.008675935678184032, - 0.016003990545868874, - 0.02360924705862999, - -0.03237585723400116, - 0.062091924250125885, - 0.0534723736345768, - 0.06908244639635086, - 0.01992947794497013, - -0.021924395114183422, - -0.08472655713558197, - 0.010171602480113506, - 0.013133247382938862, - -0.02523472346365452, - -0.06846307218074799, - 0.0004721606965176761, - -0.02166888676583767, - -0.0005694524152204394, - -0.008681336417794228, - -0.05947762727737427, - -0.04814690351486206, - -0.013798982836306097, - 0.01617482490837574, - -0.02504643611609936, - 0.009110392071306704, - -0.013774625957012177, - -0.019712207838892937, - -0.016054371371865273, - -0.018327657133340836, - -0.012811604887247086, - 0.08344585448503494, - 0.0004540338122751564, - 0.019656607881188393, - 0.019389579072594643, - -0.014049646444618702, - 0.017445947974920273, - -0.00820555817335844, - -0.029353104531764984, - 0.0435597263276577, - 0.009650807827711104, - -0.0388045459985733, - -0.04784759134054184, - -0.038223911076784134, - -0.03691287711262703, - -0.03876909241080284, - -0.06724806874990463, - -0.04394567012786865, - 0.04173814505338669, - -0.09444724023342133, - 0.007763924542814493, - -0.008699805475771427, - -0.007599780336022377, - 0.0023920757230371237, - 0.029335761442780495, - -0.07895313203334808, - -0.04035546630620957, - -0.008500908501446247, - 0.030348196625709537, - 0.02277581207454205, - 0.05779244005680084, - 0.049121756106615067, - -0.005412466358393431, - 0.007729559671133757, - -0.01292573381215334, - -0.025097647681832314, - 0.004094319883733988, - 0.06612378358840942, - -0.019531669095158577, - -0.005063635762780905, - -0.005468557123094797, - 0.07955626398324966, - -0.002157465321943164, - 0.009207960218191149, - -0.06414847075939178, - -0.0035572517663240433, - -0.0020771902054548264, - -0.1227332055568695, - -0.03706011176109314, - 0.0008404941763728857, - -0.046963952481746674, - 0.04012263193726539, - -0.027263401076197624, - 0.016582122072577477, - 0.04703010618686676, - 0.03132076933979988, - -0.010051103308796884, - -0.03994416818022728, - 0.05056227371096611, - -0.005183490924537182, - -0.03397025540471077, - 0.05630888789892197, - -0.00752260722219944, - 0.056935470551252365, - -0.019262658432126045, - -0.005856715142726898, - -0.00361971789970994, - 0.014742489904165268, - -0.0173240564763546, - 0.025849811732769012, - -0.03633483499288559, - 0.05162259563803673, - -0.024835949763655663, - -0.04847341403365135, - -0.03159399703145027, - -0.03467343747615814, - 0.036358628422021866, - -0.03581903874874115, - 0.002909073606133461, - -0.06491775810718536, - 0.02263971231877804, - 0.0016398467123508451, - 0.02446398138999939, - -0.07746433466672897, - -0.006726226769387722, - -0.000519428460393101, - -0.039504919201135635, - -0.005563349928706884, - -0.020594995468854904, - 0.061375197023153305, - -0.04385501146316528, - -0.020819365978240967, - 0.0002135665708919987, - 0.0025394882541149855, - 0.03940146788954735, - 0.04535587877035141, - 0.022408338263630867, - 0.010107740759849548, - -0.02910368889570236, - 0.023004544898867607, - -0.0777907446026802, - -0.03995157033205032, - -0.007604190148413181, - -0.01633376069366932, - 0.03180794045329094, - -0.001723665394820273, - 0.008649897761642933, - 0.0242207832634449, - -0.010647157207131386, - -0.026367707177996635, - 0.04031673073768616, - -0.05165720731019974, - -0.03284695744514465, - -0.02335844747722149, - -0.03349415957927704, - 0.025802014395594597, - -0.03694309666752815, - -0.006044459994882345, - 0.06736567616462708, - 0.01603505201637745, - -0.02328784205019474, - -0.012791356071829796, - 0.013516776263713837, - -0.03699612617492676, - 0.01060064509510994, - 0.00883965939283371, - -0.009064657613635063, - 0.0350169874727726, - -0.02685544267296791, - -0.014185672625899317, - 0.016354434192180634, - 0.036822687834501266, - 0.023291006684303284, - -0.059676602482795715, - 0.018569037318229675, - -0.035254210233688354, - 0.03186021000146866, - -0.006412920076400042, - 0.006461815442889929, - -0.0018794521456584337, - -0.004147578962147236, - -0.011934665031731129, - -0.0030684741213917732, - -0.011600416153669356, - 0.014210240915417671, - 0.035710278898477554, - -0.0347076840698719, - 0.024610867723822594, - -0.02708994224667549, - -0.05045025795698166, - -0.010565407574176788, - -0.033687181770801544, - -0.02122747339308262, - -0.04409955069422722, - -0.003069423837587238, - 0.044485583901405334, - -0.05378193408250809, - 0.072037473320961, - -0.07409116625785828, - 0.015786299481987953, - -0.06721299141645432, - 0.025938687846064568, - 0.010510837659239767, - -0.023115744814276695, - -0.03091544844210148, - 0.050648219883441925, - 0.035482946783304214, - 0.04307528957724571, - -0.04726636782288551, - -0.04310080036520958, - -0.013828760012984276, - 0.048286303877830505, - -0.02076721377670765, - -0.01085709035396576, - -0.03584962338209152, - -0.014488843269646168, - -0.0027554789558053017, - -0.06005162000656128, - 0.04566371068358421, - -0.08098234236240387, - -0.0007054588641040027, - 0.023113127797842022, - 0.013891058973968027, - -0.06299350410699844, - 0.013442540541291235, - -0.0063631776720285416, - 0.03821553662419319, - 0.042192913591861725, - -0.011878528632223606, - 0.025002310052514076, - -0.03168347105383873, - 0.00921724271029234, - 0.05588514357805252, - -0.019194696098566055, - -0.013231540098786354, - 0.013922672718763351, - 0.050090741366147995, - -0.009419753216207027, - 0.030472371727228165, - 0.02902497723698616, - 0.00012655452883336693, - 0.02010628953576088, - -0.017804551869630814, - 0.02543807215988636, - -0.0017418548231944442, - 0.03014679066836834, - -0.002393407514318824, - 0.01539027225226164, - -0.013939744792878628, - 0.04250369220972061, - -0.028016269207000732, - -0.0010314607061445713, - 0.00945567712187767, - 0.01606564037501812, - 0.03212505206465721, - 0.02634749934077263, - -0.04875859245657921, - -0.02948666177690029, - -0.010389791801571846, - -0.02731900289654732, - 0.008594093844294548, - -0.0005823180545121431, - 0.054062556475400925, - 0.0035941607784479856, - 0.0543292835354805, - -0.004254109226167202, - 0.08106452226638794, - 0.00023218353453557936, - 0.008525514975190163, - 0.010739163495600224, - -0.06044655293226242, - 0.02740525454282761, - 0.024431807920336723, - -0.07784923911094666, - -0.011249307543039322, - 0.042149681597948074, - 0.05080077797174454, - 0.012841291725635529, - -0.01869971305131912, - -0.0298676285892725, - -0.030107680708169937, - 0.007617079187184572, - -0.03927510604262352, - 0.005952583160251379, - -0.04362985119223595, - -0.056472595781087875, - -0.05122603103518486, - 0.030536439269781113, - 0.06711754202842712, - 0.030769379809498787, - -0.08917279541492462, - 0.030519621446728703, - -0.018731193616986275, - 0.025107961148023605, - -0.04443630948662758, - -0.03170761838555336, - 0.05583782494068146, - 0.028091464191675183, - 0.022955838590860367, - 0.033636752516031265, - -0.02531679160892963, - -0.012428611516952516, - 0.019952984526753426, - 0.02082655392587185, - 0.07539939135313034, - -0.06182907521724701, - 0.02644423581659794, - -0.0031414111144840717, - -0.03931447118520737, - 0.03972741961479187, - -0.06503785401582718, - -0.02640126273036003, - -0.026757026091217995, - 0.02259722352027893, - -0.026944443583488464, - -0.04200126603245735, - 0.06589224189519882, - -0.0060363225638866425, - 0.014422483742237093, - -0.047794267535209656, - -0.03258788213133812, - 0.0013760939473286271, - -0.009353984147310255, - 0.012716212309896946, - 0.04360601305961609, - 0.0045635453425347805, - 0.038450006395578384, - 0.032771769911050797, - 0.0030687032267451286, - -0.04321933165192604, - 0.006499011069536209, - 0.0028769823256880045, - 0.012420333921909332, - 0.013525757007300854, - -0.006150753237307072, - -0.004118023905903101, - 0.023745615035295486, - -0.042544446885585785, - 0.01779933273792267, - 0.0738072544336319, - -0.03007355146110058, - -0.009512661024928091, - -0.03289958834648132, - -0.004790752660483122, - 0.0004558037326205522, - 0.0720517635345459, - -0.06180300563573837, - -0.0042299022898077965, - 0.00017941815895028412, - 0.026685943827033043, - 0.0046829464845359325, - -0.0006890723598189652, - 0.008649819530546665, - -0.019310785457491875, - 0.03345974162220955, - -0.02027411200106144, - 0.0454903170466423, - 0.004120772238820791, - -0.028732268139719963, - 0.002070050220936537, - 0.03910873085260391, - -0.034626252949237823, - -0.06625950336456299, - -0.057161930948495865, - -0.027074122801423073, - -0.03852885961532593, - 0.036027777940034866, - -0.03378047049045563, - -0.04209835082292557, - 0.02349921129643917, - 0.03960388153791427, - 0.0015966565115377307, - -0.003795675467699766, - 0.008811083622276783, - -0.02891468815505505, - -0.08621173352003098, - 0.03072702139616013, - -0.04263502359390259, - 0.0518559105694294, - -0.014513948932290075, - 0.00426185317337513, - -0.042820628732442856, - 0.061024997383356094, - 0.008177947252988815, - -0.025654304772615433, - -0.01994758658111095, - 0.03115339018404484, - -0.06122246012091637, - -0.00973520614206791, - 0.026119912043213844, - 0.018067168071866035, - 0.046298809349536896, - -0.0637248307466507, - -0.003924540244042873, - 0.05164488032460213, - -0.03986351564526558, - 0.012143593281507492, - -0.01493164524435997, - 0.012364163994789124, - 0.0033910535275936127, - 0.03926117718219757, - 0.0160888209939003, - 0.022147519513964653, - 0.040994029492139816, - 0.03238851949572563, - 0.031068911775946617, - -0.0019339561695232987, - -0.04030238837003708, - 0.018413899466395375, - 0.009558942168951036, - 0.024898380041122437, - -0.02646373026072979, - -0.027966918423771855, - 0.03851816430687904, - -0.018016686663031575, - 0.01169034279882908, - -0.041716981679201126, - -0.012398135848343372, - -0.040918245911598206, - 0.049635518342256546, - 0.019493695348501205, - 0.010355286300182344, - -0.005950144957751036, - -0.022309331223368645, - -0.0430804155766964, - 0.0156959630548954, - 0.01119300164282322, - -0.008492423221468925, - 0.014949626289308071, - -0.053723081946372986, - 0.027443569153547287, - 0.03662879765033722, - -0.03641078248620033, - 0.04629331827163696, - 0.004617750179022551, - -0.03654378652572632, - 0.013454713858664036, - 0.0032841702923178673, - -0.01309528760612011, - -0.0006306404829956591, - -0.010712265968322754, - -0.0031115366145968437, - 0.06719954311847687, - -0.041091009974479675, - 0.052047744393348694, - 0.015360930003225803, - 0.017123648896813393, - -0.016294341534376144, - 0.04660823196172714, - -0.024207523092627525, - -0.04300165921449661, - -0.05108120292425155, - 0.09737501293420792, - -0.01331926416605711, - 0.06842294335365295, - -0.002399123040959239, - 0.012122059240937231, - 0.06719434261322021, - -0.05437808856368065, - 0.004240202717483044, - -0.027191925793886185, - -0.040218885987997055, - -0.02375097759068012, - 0.012262600474059582, - 0.014219674281775951, - -0.006157959345728159, - 0.011399772949516771, - -0.05200403183698654, - -0.017264649271965027, - 0.016833636909723282, - -0.009583424776792526, - -0.03376639261841774, - -0.00961976870894432, - 0.001210652757436037, - -0.0612335205078125, - -0.0336930938065052, - -0.025393076241016388, - -0.02714981697499752, - 0.004886742681264877, - 0.013395018875598907, - -0.02571096643805504, - -0.03276616707444191, - -0.030069544911384583, - 0.036591000854969025, - -0.07458269596099854, - 0.05744070932269096, - 0.028478343039751053, - -0.0028876815922558308, - 0.02639182470738888, - 0.018080219626426697, - 0.04396456852555275, - 0.003018079325556755, - -0.03397033363580704, - -0.02141541987657547, - 0.010896582156419754, - -0.03434125706553459, - -0.05253784731030464, - -0.025020217522978783, - -0.005296454764902592, - 0.019587192684412003, - 0.03784740716218949, - -0.01990439184010029, - 0.02046854794025421, - -0.02455652691423893, - -0.020822890102863312, - 0.003083446528762579, - 0.07859235256910324, - -0.08430628478527069, - -0.02872663363814354, - 0.05072060227394104, - 0.043463632464408875, - 0.017734138295054436, - -0.04160630330443382, - -0.04641241580247879, - -0.02498893067240715, - -0.03297220170497894, - -0.09785742312669754, - -0.006121875252574682, - -0.022711746394634247, - -0.01429930329322815, - -0.00412411242723465, - 0.007504432462155819, - -0.000563237292226404, - 0.01013818196952343, - -0.06896454840898514, - 0.006575733423233032, - -0.10310959815979004, - -0.012512778863310814, - 0.03036043606698513, - -0.015878431499004364, - 0.022684166207909584, - 0.02066022157669067, - 0.016029203310608864, - -0.028443187475204468, - -0.01416606828570366, - 0.0071391211822628975, - 0.034776851534843445, - 0.002298222854733467, - 0.033520814031362534, - 0.05799320712685585, - -0.0030665509402751923, - 0.013703178614377975, - 0.04346451908349991, - -0.08736324310302734, - -0.04443465545773506, - -0.09507574141025545, - -0.007938905619084835, - 0.005520000122487545, - -0.043095000088214874, - -0.03352028876543045, - 0.021385299041867256, - 0.02366030216217041, - -0.02853614091873169, - 0.002117573283612728, - 0.055353257805109024, - 0.027501529082655907, - -0.015763575211167336, - 0.0570647306740284, - -0.029892882332205772, - 0.02390587143599987, - -0.013306232169270515, - 0.018932240083813667, - 0.0071633001789450645, - 0.006233749445527792, - 0.03482261300086975, - -0.0009497640421614052, - 0.04889736324548721, - -0.010756379924714564, - -0.10233137756586076, - 0.032568227499723434, - -0.0017232495592907071, - 0.0197619441896677, - -0.01157362200319767, - -0.022340090945363045, - 0.03321876749396324, - -0.03730887547135353, - -0.004980842582881451, - 0.031003642827272415, - 0.04853849858045578, - 0.00792314950376749, - -0.016585927456617355, - -0.00377306598238647, - 0.009732725098729134, - -0.026165375486016273, - 0.0068840766325592995, - 0.02659326232969761, - -0.005413031205534935, - -0.0209831390529871, - -0.029614845290780067, - 0.01654200442135334, - -0.03843202814459801, - 0.016572654247283936, - -0.022821595892310143, - 0.02077091671526432, - -0.033952746540308, - 0.06542537361383438, - -0.08189623057842255, - 0.0031411293894052505, - -0.01395489927381277, - 0.01906730607151985, - -0.05683666840195656, - -0.03671567142009735, - 0.001987523166462779, - 0.006716572213917971, - 0.058880213648080826, - -0.028976114466786385, - -0.10136104375123978, - -0.01454504206776619, - -0.06632363796234131, - 0.012023151852190496, - -0.039696235209703445, - -0.10271679610013962, - -0.00566994259133935, - -0.011019215919077396, - 0.022908398881554604, - 0.00902929063886404, - -0.02031330019235611, - 0.02893255092203617, - -0.020042693242430687, - -0.02361901104450226, - 0.038222216069698334, - 0.008589942008256912, - 0.03230403736233711, - 0.002454438945278526, - 0.004391937050968409, - -0.0484878346323967, - -0.002869164338335395, - -0.05096660554409027, - -0.028733370825648308, - 0.03479108586907387, - 0.03205372020602226, - -0.004485339857637882, - 0.017057575285434723, - 0.0132388761267066, - -0.04253086820244789, - 0.021169882267713547, - -0.008464457467198372, - -0.009780851192772388, - 0.02306952327489853, - -0.04061064124107361, - 0.0140217337757349, - -0.003301902674138546, - 0.005067829042673111 - ], - "index": 0 - } - ], - "model": "text-embedding-005", - "usage": { - "prompt_tokens": 0, - "total_tokens": 0 - } - }, { "object": "list", "data": [