global: snapshot

This commit is contained in:
nym21
2025-06-24 11:56:54 +02:00
parent b91120e8d4
commit c0cd4cba6f
8 changed files with 136 additions and 110 deletions

View File

@@ -0,0 +1,55 @@
use serde::{Deserialize, Deserializer};
pub fn de_unquote_i64<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
where
D: Deserializer<'de>,
{
let value: Option<serde_json::Value> = 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::<i64>().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<Option<usize>, D::Error>
where
D: Deserializer<'de>,
{
let value: Option<serde_json::Value> = 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::<usize>()
.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"))
}
}
}

View File

@@ -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;

View File

@@ -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<usize>,
}
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)
}
}

View File

@@ -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<Option<i64>, D::Error>
where
D: Deserializer<'de>,
{
let value: Option<serde_json::Value> = 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::<i64>().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<Option<usize>, D::Error>
where
D: Deserializer<'de>,
{
let value: Option<serde_json::Value> = 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::<usize>()
.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"))
}
}
}

View File

@@ -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,

View File

@@ -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:**

View File

@@ -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;
}

View File

@@ -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: [