mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-26 18:28:11 -07:00
global: snapshot
This commit is contained in:
@@ -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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ use brk_indexer::Indexer;
|
|||||||
use brk_vec::AnyCollectableVec;
|
use brk_vec::AnyCollectableVec;
|
||||||
use tabled::settings::Style;
|
use tabled::settings::Style;
|
||||||
|
|
||||||
|
mod deser;
|
||||||
mod format;
|
mod format;
|
||||||
mod index;
|
mod index;
|
||||||
mod maybe_ids;
|
mod maybe_ids;
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::Index;
|
use crate::{Index, deser::de_unquote_usize};
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, JsonSchema)]
|
#[derive(Debug, Default, Deserialize, JsonSchema)]
|
||||||
pub struct PaginationParam {
|
pub struct PaginationParam {
|
||||||
#[serde(alias = "p")]
|
|
||||||
#[schemars(description = "Pagination index")]
|
#[schemars(description = "Pagination index")]
|
||||||
#[serde(default)]
|
#[serde(default, alias = "p", deserialize_with = "de_unquote_usize")]
|
||||||
pub page: usize,
|
pub page: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PaginationParam {
|
impl PaginationParam {
|
||||||
const PER_PAGE: usize = 1_000;
|
const PER_PAGE: usize = 1_000;
|
||||||
|
|
||||||
pub fn start(&self, len: usize) -> usize {
|
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 {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use brk_rmcp::schemars::{self, JsonSchema};
|
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)]
|
#[derive(Debug, Deserialize, JsonSchema)]
|
||||||
pub struct Params {
|
pub struct Params {
|
||||||
@@ -106,57 +110,3 @@ impl ParamsOpt {
|
|||||||
pub struct IdParam {
|
pub struct IdParam {
|
||||||
pub id: String,
|
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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ Get an object which has all existing indexes as keys and a list of their accepte
|
|||||||
#[tool(description = "
|
#[tool(description = "
|
||||||
Get a paginated list of all existing vec ids.
|
Get a paginated list of all existing vec ids.
|
||||||
There are up to 1,000 values per page.
|
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(
|
async fn get_vecids(
|
||||||
&self,
|
&self,
|
||||||
@@ -99,7 +99,7 @@ If the `page` param is omitted, it will default to page `0`.
|
|||||||
#[tool(description = "
|
#[tool(description = "
|
||||||
Get a paginated list of all vec ids which support a given index.
|
Get a paginated list of all vec ids which support a given index.
|
||||||
There are up to 1,000 values per page.
|
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(
|
async fn get_index_to_vecids(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -68,17 +68,16 @@ Get a paginated list of all existing vec ids. \
|
|||||||
There are up to 1,000 values per page. \
|
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 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)
|
#### [`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 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-ids`](https://bitcoinresearchkit.org/api/vecs/index-to-ids)
|
|
||||||
|
|
||||||
A list of all possible vec indexes and their supported vec ids
|
|
||||||
|
|
||||||
#### `GET /api/vecs/{INDEX}-to-{ID}`
|
#### `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`
|
#### `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:**
|
**Parameters:**
|
||||||
|
|
||||||
|
|||||||
@@ -1454,12 +1454,19 @@ function createUtils() {
|
|||||||
* @param {number} [to]
|
* @param {number} [to]
|
||||||
*/
|
*/
|
||||||
function genPath(index, vecId, from, 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) {
|
if (from !== undefined) {
|
||||||
path += `&from=${from}`;
|
path += `from=${from}`;
|
||||||
}
|
}
|
||||||
if (to !== undefined) {
|
if (to !== undefined) {
|
||||||
path += `&to=${to}`;
|
if (!path.endsWith("?")) {
|
||||||
|
path += `&`;
|
||||||
|
}
|
||||||
|
path += `to=${to}`;
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
name: "Social",
|
||||||
tree: [
|
tree: [
|
||||||
|
{
|
||||||
|
name: "GitHub",
|
||||||
|
url: () => "https://github.com/bitcoinresearchkit/brk",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Nostr",
|
name: "Nostr",
|
||||||
url: () =>
|
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",
|
name: "Donate",
|
||||||
tree: [
|
tree: [
|
||||||
|
|||||||
Reference in New Issue
Block a user