diff --git a/crates/brk_interface/src/deser.rs b/crates/brk_interface/src/deser.rs new file mode 100644 index 000000000..bc0caecce --- /dev/null +++ b/crates/brk_interface/src/deser.rs @@ -0,0 +1,55 @@ +use serde::{Deserialize, Deserializer}; + +pub fn de_unquote_i64<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let value: Option = Option::deserialize(deserializer)?; + + match value { + None => Ok(None), + Some(serde_json::Value::String(mut s)) => { + if s.starts_with('"') && s.ends_with('"') && s.len() >= 2 { + s = s[1..s.len() - 1].to_string(); + } + s.parse::().map(Some).map_err(serde::de::Error::custom) + } + Some(serde_json::Value::Number(n)) => { + // If it's a number, convert it to i64 + n.as_i64() + .ok_or_else(|| serde::de::Error::custom("number out of range")) + .map(Some) + } + _ => Err(serde::de::Error::custom("expected a string or number")), + } +} + +pub fn de_unquote_usize<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let value: Option = Option::deserialize(deserializer)?; + + match value { + None => Ok(None), + Some(serde_json::Value::String(mut s)) => { + if s.starts_with('"') && s.ends_with('"') && s.len() >= 2 { + s = s[1..s.len() - 1].to_string(); + } + s.parse::() + .map(Some) + .map_err(serde::de::Error::custom) + } + Some(serde_json::Value::Number(n)) => { + // If it's a number, convert it to usize + n.as_u64() + .ok_or_else(|| serde::de::Error::custom("number out of range")) + .map(|v| v as usize) + .map(Some) + } + _ => { + dbg!(value); + Err(serde::de::Error::custom("expected a string or number")) + } + } +} diff --git a/crates/brk_interface/src/lib.rs b/crates/brk_interface/src/lib.rs index 23a2708b0..59de7ea9d 100644 --- a/crates/brk_interface/src/lib.rs +++ b/crates/brk_interface/src/lib.rs @@ -11,6 +11,7 @@ use brk_indexer::Indexer; use brk_vec::AnyCollectableVec; use tabled::settings::Style; +mod deser; mod format; mod index; mod maybe_ids; diff --git a/crates/brk_interface/src/pagination.rs b/crates/brk_interface/src/pagination.rs index cfbe22a5e..164259167 100644 --- a/crates/brk_interface/src/pagination.rs +++ b/crates/brk_interface/src/pagination.rs @@ -1,25 +1,24 @@ use schemars::JsonSchema; use serde::Deserialize; -use crate::Index; +use crate::{Index, deser::de_unquote_usize}; #[derive(Debug, Default, Deserialize, JsonSchema)] pub struct PaginationParam { - #[serde(alias = "p")] #[schemars(description = "Pagination index")] - #[serde(default)] - pub page: usize, + #[serde(default, alias = "p", deserialize_with = "de_unquote_usize")] + pub page: Option, } impl PaginationParam { const PER_PAGE: usize = 1_000; pub fn start(&self, len: usize) -> usize { - (self.page * Self::PER_PAGE).clamp(0, len) + (self.page.unwrap_or_default() * Self::PER_PAGE).clamp(0, len) } pub fn end(&self, len: usize) -> usize { - ((self.page + 1) * Self::PER_PAGE).clamp(0, len) + ((self.page.unwrap_or_default() + 1) * Self::PER_PAGE).clamp(0, len) } } diff --git a/crates/brk_interface/src/params.rs b/crates/brk_interface/src/params.rs index 196d5aab6..6fa25f39e 100644 --- a/crates/brk_interface/src/params.rs +++ b/crates/brk_interface/src/params.rs @@ -1,9 +1,13 @@ use std::ops::Deref; use brk_rmcp::schemars::{self, JsonSchema}; -use serde::{Deserialize, Deserializer}; +use serde::Deserialize; -use crate::{Format, Index, maybe_ids::MaybeIds}; +use crate::{ + Format, Index, + deser::{de_unquote_i64, de_unquote_usize}, + maybe_ids::MaybeIds, +}; #[derive(Debug, Deserialize, JsonSchema)] pub struct Params { @@ -106,57 +110,3 @@ impl ParamsOpt { pub struct IdParam { pub id: String, } - -fn de_unquote_i64<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let value: Option = Option::deserialize(deserializer)?; - - match value { - None => Ok(None), - Some(serde_json::Value::String(mut s)) => { - if s.starts_with('"') && s.ends_with('"') && s.len() >= 2 { - s = s[1..s.len() - 1].to_string(); - } - s.parse::().map(Some).map_err(serde::de::Error::custom) - } - Some(serde_json::Value::Number(n)) => { - // If it's a number, convert it to i64 - n.as_i64() - .ok_or_else(|| serde::de::Error::custom("number out of range")) - .map(Some) - } - _ => Err(serde::de::Error::custom("expected a string or number")), - } -} - -fn de_unquote_usize<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let value: Option = Option::deserialize(deserializer)?; - - match value { - None => Ok(None), - Some(serde_json::Value::String(mut s)) => { - if s.starts_with('"') && s.ends_with('"') && s.len() >= 2 { - s = s[1..s.len() - 1].to_string(); - } - s.parse::() - .map(Some) - .map_err(serde::de::Error::custom) - } - Some(serde_json::Value::Number(n)) => { - // If it's a number, convert it to usize - n.as_u64() - .ok_or_else(|| serde::de::Error::custom("number out of range")) - .map(|v| v as usize) - .map(Some) - } - _ => { - dbg!(value); - Err(serde::de::Error::custom("expected a string or number")) - } - } -} diff --git a/crates/brk_mcp/src/lib.rs b/crates/brk_mcp/src/lib.rs index 40d0ee568..118aceb6c 100644 --- a/crates/brk_mcp/src/lib.rs +++ b/crates/brk_mcp/src/lib.rs @@ -84,7 +84,7 @@ Get an object which has all existing indexes as keys and a list of their accepte #[tool(description = " Get a paginated list of all existing vec ids. There are up to 1,000 values per page. -If the `page` param is omitted, it will default to page `0`. +If the `page` param is omitted, it will default to the first page. ")] async fn get_vecids( &self, @@ -99,7 +99,7 @@ If the `page` param is omitted, it will default to page `0`. #[tool(description = " Get a paginated list of all vec ids which support a given index. There are up to 1,000 values per page. -If the `page` param is omitted, it will default to page `0`. +If the `page` param is omitted, it will default to the first page. ")] async fn get_index_to_vecids( &self, diff --git a/crates/brk_server/README.md b/crates/brk_server/README.md index dc669bf97..2a0d632d0 100644 --- a/crates/brk_server/README.md +++ b/crates/brk_server/README.md @@ -68,17 +68,16 @@ Get a paginated list of all existing vec ids. \ There are up to 1,000 values per page. \ If the `page` param is omitted, it will default to page `0`. -#### [`GET /api/vecs/variants`](https://bitcoinresearchkit.org/api/vecs/variants) +#### [`GET /api/vecs/index-to-ids`](https://bitcoinresearchkit.org/api/vecs/index-to-ids) -A list of all possible variants +Get a paginated list of all vec ids which support a given index. +There are up to 1,000 values per page. +If the `page` param is omitted, it will default to the first page. #### [`GET /api/vecs/id-to-indexes`](https://bitcoinresearchkit.org/api/vecs/id-to-indexes) -A list of all possible vec ids and their supported vec indexes - -#### [`GET /api/vecs/index-to-ids`](https://bitcoinresearchkit.org/api/vecs/index-to-ids) - -A list of all possible vec indexes and their supported vec ids +Get a list of all indexes supported by a given vec id. +The list will be empty if the vec id isn't correct. #### `GET /api/vecs/{INDEX}-to-{ID}` @@ -108,7 +107,13 @@ curl https://bitcoinresearchkit.org/api/vecs/date-to-close?count=100&format=csv #### `GET /api/vecs/query` -This endpoint retrieves data based on the specified vector index and ids. +Get one or multiple vecs depending on given parameters. +If you'd like to request multiple vec ids, simply separate them with a ','. \ +To get the last value set `-1` to the `from` parameter. \ +The response's format will depend on the given parameters, it will be: +- A value: If requested only one vec and the given range returns one value (for example: `from=-1`) +- A list: If requested only one vec and the given range returns multiple values (for example: `from=-1000&count=100` or `from=-444&to=-333`) +- A matrix: When multiple vecs are requested, even if they each return one value. **Parameters:** diff --git a/websites/default/scripts/main.js b/websites/default/scripts/main.js index 7d6743df2..8b18ea0b1 100644 --- a/websites/default/scripts/main.js +++ b/websites/default/scripts/main.js @@ -1454,12 +1454,19 @@ function createUtils() { * @param {number} [to] */ function genPath(index, vecId, from, to) { - let path = `/query?index=${serde.index.serialize(index)}&ids=${vecId}`; + let path = `/${serde.index.serialize(index)}-to-${vecId.replaceAll( + "_", + "-" + )}?`; + if (from !== undefined) { - path += `&from=${from}`; + path += `from=${from}`; } if (to !== undefined) { - path += `&to=${to}`; + if (!path.endsWith("?")) { + path += `&`; + } + path += `to=${to}`; } return path; } diff --git a/websites/default/scripts/options.js b/websites/default/scripts/options.js index 94feb8e54..0d663d748 100644 --- a/websites/default/scripts/options.js +++ b/websites/default/scripts/options.js @@ -3325,9 +3325,53 @@ function createPartialOptions(colors) { }, ], }, + { + name: "Tools", + tree: [ + { + name: "API", + url: () => "/api", + }, + { + name: "MCP", + url: () => + "https://github.com/bitcoinresearchkit/brk/tree/main/crates/brk_mcp#brk-mcp", + }, + { + name: "Crates", + url: () => "https://crates.io/crates/brk", + }, + { + name: "Source", + url: () => "https://github.com/bitcoinresearchkit/brk", + }, + ], + }, + { + name: "Hosting", + tree: [ + { + name: "Status", + url: () => "https://status.bitcoinresearchkit.org/", + }, + { + name: "Self", + url: () => "https://crates.io/crates/brk_cli", + }, + { + name: "As a service", + url: () => + "https://github.com/bitcoinresearchkit/brk?tab=readme-ov-file#hosting-as-a-service", + }, + ], + }, { name: "Social", tree: [ + { + name: "GitHub", + url: () => "https://github.com/bitcoinresearchkit/brk", + }, { name: "Nostr", url: () => @@ -3347,41 +3391,6 @@ function createPartialOptions(colors) { }, ], }, - { - name: "Hosting", - tree: [ - { - name: "Self", - url: () => "https://crates.io/crates/brk_cli", - }, - { - name: "As a service", - url: () => - "https://github.com/bitcoinresearchkit/brk?tab=readme_ov_file#hosting_as_a_service", - }, - ], - }, - { - name: "Developers", - tree: [ - { - name: "API", - url: () => "/api", - }, - { - name: "Source", - url: () => "https://github.com/bitcoinresearchkit/brk", - }, - { - name: "Status", - url: () => "https://status.bitcoinresearchkit.org/", - }, - { - name: "Crates", - url: () => "https://crates.io/crates/brk", - }, - ], - }, { name: "Donate", tree: [