├── .cargo-ok
├── .github
└── FUNDING.yml
├── examples
├── create-wasm-app
│ ├── .gitignore
│ ├── .travis.yml
│ ├── performance.js
│ ├── bootstrap.js
│ ├── log.js
│ ├── webpack.config.js
│ ├── .bin
│ │ └── create-wasm-app.js
│ ├── LICENSE-MIT
│ ├── package.json
│ ├── index.html
│ ├── README.md
│ ├── index.js
│ ├── LICENSE-APACHE
│ └── phrases.js
├── voy-with-nextjs
│ ├── .prettierrc
│ ├── public
│ │ ├── voy.gif
│ │ ├── favicon.ico
│ │ ├── vercel.svg
│ │ ├── thirteen.svg
│ │ └── next.svg
│ ├── src
│ │ ├── styles
│ │ │ ├── Home.module.css
│ │ │ └── globals.css
│ │ ├── pages
│ │ │ ├── _document.tsx
│ │ │ ├── _app.tsx
│ │ │ ├── api
│ │ │ │ ├── process.ts
│ │ │ │ └── embeddings.ts
│ │ │ ├── index.tsx
│ │ │ ├── server-side.tsx
│ │ │ └── client-side.tsx
│ │ ├── components
│ │ │ ├── NavigationBar.module.css
│ │ │ └── NavigationBar.tsx
│ │ └── context
│ │ │ └── VoyContext.tsx
│ ├── README.md
│ ├── next.config.js
│ ├── .gitignore
│ ├── tsconfig.json
│ ├── package.json
│ ├── LICENSE_MIT
│ └── LICENSE_APACHE
└── nextjs-transformersjs
│ ├── .eslintrc.json
│ ├── public
│ ├── favicon.ico
│ ├── vercel.svg
│ └── next.svg
│ ├── postcss.config.js
│ ├── pages
│ ├── _app.tsx
│ ├── _document.tsx
│ ├── api
│ │ └── hello.ts
│ └── index.tsx
│ ├── next.config.js
│ ├── .gitignore
│ ├── tailwind.config.js
│ ├── tsconfig.json
│ ├── styles
│ └── globals.css
│ ├── package.json
│ └── README.md
├── voy.gif
├── .gitignore
├── src
├── wasm
│ ├── mod.rs
│ ├── types.rs
│ ├── voy.rs
│ └── fns.rs
├── engine
│ ├── mod.rs
│ ├── hash.rs
│ ├── tests
│ │ └── mod.rs
│ └── engine.rs
├── lib.rs
└── utils.rs
├── tests
└── web.rs
├── .appveyor.yml
├── books.json
├── LICENSE_MIT
├── Cargo.toml
├── .travis.yml
├── README.md
└── LICENSE_APACHE
/.cargo-ok:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: DawChihLiou
2 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
--------------------------------------------------------------------------------
/voy.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tantaraio/voy/HEAD/voy.gif
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | **/*.rs.bk
3 | Cargo.lock
4 | bin/
5 | pkg/
6 | wasm-pack.log
7 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 2,
3 | "useTabs": false
4 | }
5 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/src/wasm/mod.rs:
--------------------------------------------------------------------------------
1 | mod fns;
2 | mod types;
3 | mod voy;
4 |
5 | pub use fns::*;
6 | pub use types::*;
7 | pub use voy::*;
8 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/public/voy.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tantaraio/voy/HEAD/examples/voy-with-nextjs/public/voy.gif
--------------------------------------------------------------------------------
/examples/create-wasm-app/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js: "10"
3 |
4 | script:
5 | - ./node_modules/.bin/webpack
6 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tantaraio/voy/HEAD/examples/voy-with-nextjs/public/favicon.ico
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tantaraio/voy/HEAD/examples/nextjs-transformersjs/public/favicon.ico
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/src/engine/mod.rs:
--------------------------------------------------------------------------------
1 | mod engine;
2 | mod hash;
3 |
4 | #[cfg(test)]
5 | mod tests;
6 |
7 | pub use engine::{add, clear, index, remove, search, size, Index, Query};
8 | pub use hash::hash;
9 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/styles/Home.module.css:
--------------------------------------------------------------------------------
1 | #example {
2 | display: block;
3 | width: 100%;
4 | }
5 |
6 | .primary {
7 | font-weight: bold;
8 | }
9 |
10 | .secondary {
11 | font-weight: 100;
12 | color: gray;
13 | }
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import '@/styles/globals.css'
2 | import type { AppProps } from 'next/app'
3 |
4 | export default function App({ Component, pageProps }: AppProps) {
5 | return
6 | }
7 |
--------------------------------------------------------------------------------
/src/engine/hash.rs:
--------------------------------------------------------------------------------
1 | use std::collections::hash_map::DefaultHasher;
2 | use std::hash::{Hash, Hasher};
3 |
4 | pub fn hash(target: &T) -> u64 {
5 | let mut hasher = DefaultHasher::new();
6 | target.hash(&mut hasher);
7 |
8 | hasher.finish()
9 | }
10 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/performance.js:
--------------------------------------------------------------------------------
1 | export const perf = () => {
2 | const t0 = performance.now();
3 | return {
4 | stop() {
5 | const t1 = performance.now();
6 | const seconds = ((t1 - t0) / 1000).toFixed(2);
7 | return seconds;
8 | },
9 | };
10 | };
11 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod engine;
2 | mod utils;
3 | mod wasm;
4 |
5 | pub use wasm::*;
6 |
7 | // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
8 | // allocator.
9 | #[cfg(feature = "wee_alloc")]
10 | #[global_allocator]
11 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
12 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | webpack: function (config, options) {
5 | config.experiments = { asyncWebAssembly: true };
6 | return config;
7 | },
8 | };
9 |
10 | module.exports = nextConfig;
11 |
--------------------------------------------------------------------------------
/tests/web.rs:
--------------------------------------------------------------------------------
1 | //! Test suite for the Web and headless browsers.
2 |
3 | #![cfg(target_arch = "wasm32")]
4 |
5 | extern crate wasm_bindgen_test;
6 | use wasm_bindgen_test::*;
7 |
8 | wasm_bindgen_test_configure!(run_in_browser);
9 |
10 | #[wasm_bindgen_test]
11 | fn pass() {
12 | assert_eq!(1 + 1, 2);
13 | }
14 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/bootstrap.js:
--------------------------------------------------------------------------------
1 | // A dependency graph that contains any wasm must all be imported
2 | // asynchronously. This `bootstrap.js` file does the single async import, so
3 | // that no one else needs to worry about it again.
4 | import("./index.js")
5 | .catch(e => console.error("Error importing `index.js`:", e));
6 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from 'next/document'
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from "next/document";
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import { VoyProvider } from "@/context/VoyContext";
2 | import "@/styles/globals.css";
3 | import type { AppProps } from "next/app";
4 |
5 | export default function App({ Component, pageProps }: AppProps) {
6 | return (
7 |
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/.appveyor.yml:
--------------------------------------------------------------------------------
1 | install:
2 | - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
3 | - if not defined RUSTFLAGS rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly
4 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
5 | - rustc -V
6 | - cargo -V
7 |
8 | build: false
9 |
10 | test_script:
11 | - cargo test --locked
12 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/pages/api/hello.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 | import type { NextApiRequest, NextApiResponse } from 'next'
3 |
4 | type Data = {
5 | name: string
6 | }
7 |
8 | export default function handler(
9 | req: NextApiRequest,
10 | res: NextApiResponse
11 | ) {
12 | res.status(200).json({ name: 'John Doe' })
13 | }
14 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | yarn dev
9 | ```
10 |
11 | Open [http://localhost:3000](http://localhost:3000) with your browser to see Voy and Next.js.
12 |
--------------------------------------------------------------------------------
/src/utils.rs:
--------------------------------------------------------------------------------
1 | pub fn set_panic_hook() {
2 | // When the `console_error_panic_hook` feature is enabled, we can call the
3 | // `set_panic_hook` function at least once during initialization, and then
4 | // we will get better error messages if our code ever panics.
5 | //
6 | // For more details see
7 | // https://github.com/rustwasm/console_error_panic_hook#readme
8 | #[cfg(feature = "console_error_panic_hook")]
9 | console_error_panic_hook::set_once();
10 | }
11 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/components/NavigationBar.module.css:
--------------------------------------------------------------------------------
1 | .ul {
2 | display: block;
3 |
4 | margin-left: 0;
5 | padding-left: 0;
6 | }
7 |
8 | .ul li {
9 | display: inline;
10 | }
11 |
12 | .ul li a {
13 | text-decoration: none;
14 | color: #fff;
15 | background-color: rgb(55, 55, 60);
16 | padding: 1rem 1rem;
17 | border-radius: 0.5rem;
18 | box-shadow: rgba(0, 0, 0, 0.25) 0px 25px 50px -12px;
19 | font-weight: bold;
20 | font-family: Arial;
21 | margin: 0.1rem;
22 |
23 | }
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | webpack: (config, context) => {
5 | config.experiments = {
6 | ...config.experiments,
7 | topLevelAwait: true,
8 | asyncWebAssembly: true,
9 | };
10 |
11 | config.module.rules.push({
12 | test: /\.md$/i,
13 | use: "raw-loader",
14 | });
15 |
16 | return config;
17 | },
18 | transpilePackages: ["@visheratin/web-ai"],
19 | };
20 |
21 | module.exports = nextConfig;
22 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env*.local
29 |
30 | # vercel
31 | .vercel
32 |
33 | # typescript
34 | *.tsbuildinfo
35 | next-env.d.ts
36 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | body {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: center;
5 | align-items: center;
6 | min-height: 100vh;
7 | background-color: #121212;
8 | color: #ffffff;
9 | font-size: 16px;
10 | font-family: Arial, Helvetica, sans-serif;
11 | }
12 |
13 | section {
14 | background-color: rgb(36, 36, 36);
15 | padding: 1rem 2rem;
16 | border-radius: 1rem;
17 | width: 48rem;
18 | box-shadow: rgba(0, 0, 0, 0.25) 0px 25px 50px -12px;
19 | }
20 |
21 |
22 | img {
23 | max-width: 100%;
24 | }
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './pages/**/*.{js,ts,jsx,tsx,mdx}',
5 | './components/**/*.{js,ts,jsx,tsx,mdx}',
6 | './app/**/*.{js,ts,jsx,tsx,mdx}',
7 | ],
8 | theme: {
9 | extend: {
10 | backgroundImage: {
11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
12 | 'gradient-conic':
13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
14 | },
15 | },
16 | },
17 | plugins: [],
18 | }
19 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/context/VoyContext.tsx:
--------------------------------------------------------------------------------
1 | import { createContext, useContext, PropsWithChildren } from "react";
2 |
3 | import * as voy from "voy-search";
4 |
5 | const VoyContext = createContext(null);
6 |
7 | export const useVoy = () => {
8 | const context = useContext(VoyContext);
9 | if (context === null) {
10 | throw new Error("useVoy must be used within a VoyProvider");
11 | }
12 | return context;
13 | };
14 |
15 | export const VoyProvider = ({ children }: PropsWithChildren) => {
16 | return {children} ;
17 | };
18 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/log.js:
--------------------------------------------------------------------------------
1 | const append = (box) => (str) => {
2 | const input = Array.isArray(str) ? str : [str];
3 |
4 | input.forEach((s) => {
5 | const para = document.createElement("p");
6 | const text = document.createTextNode(s);
7 |
8 | para.appendChild(text);
9 | box.appendChild(para);
10 | });
11 | };
12 | const intro = document.querySelector("#intro");
13 | const index = document.querySelector("#index");
14 | const resource = document.querySelector("#resource");
15 |
16 | export const logIntro = append(intro);
17 | export const logIndex = append(index);
18 | export const logResource = append(resource);
19 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/webpack.config.js:
--------------------------------------------------------------------------------
1 | const CopyWebpackPlugin = require("copy-webpack-plugin");
2 | const path = require("path");
3 |
4 | module.exports = {
5 | mode: "development",
6 | entry: "./bootstrap.js",
7 | output: {
8 | path: path.resolve(__dirname, "dist"),
9 | filename: "bootstrap.js",
10 | },
11 | plugins: [new CopyWebpackPlugin(["index.html"])],
12 | experiments: {
13 | asyncWebAssembly: true,
14 | syncWebAssembly: true,
15 | },
16 | devServer: {
17 | static: {
18 | directory: path.join(__dirname, "dist"),
19 | },
20 | compress: true,
21 | port: 3000,
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/.bin/create-wasm-app.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const { spawn } = require("child_process");
4 | const fs = require("fs");
5 |
6 | let folderName = '.';
7 |
8 | if (process.argv.length >= 3) {
9 | folderName = process.argv[2];
10 | if (!fs.existsSync(folderName)) {
11 | fs.mkdirSync(folderName);
12 | }
13 | }
14 |
15 | const clone = spawn("git", ["clone", "https://github.com/rustwasm/create-wasm-app.git", folderName]);
16 |
17 | clone.on("close", code => {
18 | if (code !== 0) {
19 | console.error("cloning the template failed!")
20 | process.exit(code);
21 | } else {
22 | console.log("🦀 Rust + 🕸 Wasm = ❤");
23 | }
24 | });
25 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "paths": {
18 | "@/*": ["./*"]
19 | }
20 | },
21 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
22 | "exclude": ["node_modules"]
23 | }
24 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2017",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "paths": {
18 | "@/*": ["./src/*"]
19 | }
20 | },
21 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
22 | "exclude": ["node_modules"]
23 | }
24 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(
22 | to bottom,
23 | transparent,
24 | rgb(var(--background-end-rgb))
25 | )
26 | rgb(var(--background-start-rgb));
27 | }
28 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/components/NavigationBar.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 |
3 | import classes from "./NavigationBar.module.css";
4 |
5 | export const NavigationBar = () => {
6 | return (
7 | <>
8 | Voy
9 | 🕸️🦀 A WASM vector similarity search written in Rust
10 |
11 |
12 | ⭐ Start
13 |
14 |
15 |
16 | 🌐 Server Side Example
17 |
18 |
19 |
20 | 🧑🏽💻 Client Side Example
21 |
22 |
23 | >
24 | );
25 | };
26 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/pages/api/process.ts:
--------------------------------------------------------------------------------
1 | import { NextApiRequest, NextApiResponse } from "next";
2 |
3 | import { load } from "@tensorflow-models/universal-sentence-encoder";
4 |
5 | require("@tensorflow/tfjs-node");
6 |
7 | import { index, search } from "voy-search";
8 |
9 | const model = await load();
10 |
11 | export default async function handler(
12 | req: NextApiRequest,
13 | res: NextApiResponse
14 | ) {
15 | const { embeddings = [], searchQuery = "" } = JSON.parse(req.body);
16 |
17 | const indexed = index({ embeddings });
18 |
19 | const q = await model.embed([searchQuery.toString()]);
20 | const result = search(indexed, q.arraySync()[0] as any, 4);
21 |
22 | res.status(200).json(result);
23 | }
24 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "voy-nextjs-transformersjs",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@types/node": "20.4.1",
13 | "@types/react": "18.2.14",
14 | "@types/react-dom": "18.2.6",
15 | "@xenova/transformers": "^2.4.0",
16 | "autoprefixer": "10.4.14",
17 | "eslint": "8.44.0",
18 | "eslint-config-next": "13.4.9",
19 | "next": "13.4.9",
20 | "postcss": "8.4.25",
21 | "react": "18.2.0",
22 | "react-dom": "18.2.0",
23 | "tailwindcss": "3.3.2",
24 | "typescript": "5.1.6",
25 | "voy-search": "file:../../pkg"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/books.json:
--------------------------------------------------------------------------------
1 | {
2 | "books": [
3 | {
4 | "title": "The Great Gatsby",
5 | "author": "F. Scott Fitzgerald",
6 | "summary": "The story primarily concerns the young and mysterious millionaire Jay Gatsby and his quixotic passion and obsession with the beautiful former debutante Daisy Buchanan."
7 | },
8 | {
9 | "title": "The Catcher in the Rye",
10 | "author": "J. D. Salinger",
11 | "summary": "The story is told in the first person by Holden Caulfield, a cynical teenager who recently has been expelled from prep school."
12 | },
13 | {
14 | "title": "The Grapes of Wrath",
15 | "author": "John Steinbeck",
16 | "summary": "The novel tells the story of the Joad family, who are driven from their Oklahoma homestead and forced to travel west to the promised land of California."
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/pages/api/embeddings.ts:
--------------------------------------------------------------------------------
1 | import { NextApiRequest, NextApiResponse } from "next";
2 |
3 | import { load } from "@tensorflow-models/universal-sentence-encoder";
4 |
5 | require("@tensorflow/tfjs-node");
6 |
7 | const model = await load();
8 |
9 | export default async function handler(
10 | _req: NextApiRequest,
11 | res: NextApiResponse
12 | ) {
13 | const phrases = [
14 | "That is a very happy Person",
15 | "That is a Happy Dog",
16 | "Today is a sunny day",
17 | "Yesterday is a sunny day",
18 | ];
19 |
20 | // Create text embeddings
21 | const processed = await model.embed(phrases);
22 | const data = processed.arraySync().map((result: number[], i: number) => ({
23 | id: String(i),
24 | title: phrases[i],
25 | url: `/path/${i}`,
26 | embeddings: result,
27 | }));
28 |
29 | res.status(200).json({ embeddings: data });
30 | }
31 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "voy-with-nextjs",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@tensorflow-models/universal-sentence-encoder": "1.3.1",
13 | "@tensorflow/tfjs": "^4.2.0",
14 | "@tensorflow/tfjs-converter": "^2.0.1",
15 | "@tensorflow/tfjs-core": "^4.2.0",
16 | "@tensorflow/tfjs-node": "^4.2.0",
17 | "@types/node": "18.15.11",
18 | "@types/react": "18.0.31",
19 | "@types/react-dom": "18.0.11",
20 | "@visheratin/web-ai": "^0.7.4",
21 | "jimp": "^0.22.7",
22 | "next": "13.2.4",
23 | "node-localstorage": "^2.2.1",
24 | "raw-loader": "^4.0.2",
25 | "react": "18.2.0",
26 | "react-dom": "18.2.0",
27 | "react-markdown": "^8.0.6",
28 | "rehype-raw": "^6.1.1",
29 | "typescript": "5.0.3",
30 | "voy-search": "file:../../pkg"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import Head from "next/head";
2 |
3 | import ReactMarkdown from "react-markdown";
4 | import rehypeRaw from "rehype-raw";
5 |
6 | import { NavigationBar } from "@/components/NavigationBar";
7 |
8 | const readme = require("./../../../../README.md").default;
9 |
10 | export default function Home() {
11 | return (
12 | <>
13 |
14 | Voy & Next.js Example
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | This example project includes a client side project using
23 | @visheratin/web-ai for the embeddings, and a server side project
24 | using @tensorflow-models/universal-sentence-encoder for the
25 | embeddings.
26 |
27 |
28 | {readme}
29 |
30 |
31 | >
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/public/thirteen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/wasm/types.rs:
--------------------------------------------------------------------------------
1 | use serde::{Deserialize, Serialize};
2 | use tsify::Tsify;
3 |
4 | pub type NumberOfResult = usize;
5 | pub type Query = Vec;
6 | pub type SerializedIndex = String;
7 |
8 | #[derive(Serialize, Deserialize, Debug, Clone, Tsify)]
9 | #[tsify(into_wasm_abi, from_wasm_abi)]
10 | pub struct EmbeddedResource {
11 | pub id: String,
12 | pub title: String,
13 | pub url: String,
14 | pub embeddings: Vec,
15 | }
16 |
17 | #[derive(Serialize, Deserialize, Debug, Tsify)]
18 | #[tsify(into_wasm_abi, from_wasm_abi)]
19 | pub struct Resource {
20 | // TODO: Support different type of resources
21 | // pub documents: Vec,
22 | // pub audio: Vec,
23 | // pub video: Vec,
24 | pub embeddings: Vec,
25 | }
26 |
27 | #[derive(Serialize, Deserialize, Debug, Clone, Tsify)]
28 | #[tsify(into_wasm_abi)]
29 | pub struct Neighbor {
30 | pub id: String,
31 | pub title: String,
32 | pub url: String,
33 | }
34 |
35 | #[derive(Serialize, Deserialize, Debug, Clone, Tsify)]
36 | #[tsify(into_wasm_abi, from_wasm_abi)]
37 | pub struct SearchResult {
38 | pub neighbors: Vec,
39 | }
40 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) [year] [name]
2 |
3 | Permission is hereby granted, free of charge, to any
4 | person obtaining a copy of this software and associated
5 | documentation files (the "Software"), to deal in the
6 | Software without restriction, including without
7 | limitation the rights to use, copy, modify, merge,
8 | publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following
11 | conditions:
12 |
13 | The above copyright notice and this permission notice
14 | shall be included in all copies or substantial portions
15 | of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 | DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/LICENSE_MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2018 Daw-Chih Liou
2 |
3 | Permission is hereby granted, free of charge, to any
4 | person obtaining a copy of this software and associated
5 | documentation files (the "Software"), to deal in the
6 | Software without restriction, including without
7 | limitation the rights to use, copy, modify, merge,
8 | publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following
11 | conditions:
12 |
13 | The above copyright notice and this permission notice
14 | shall be included in all copies or substantial portions
15 | of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 | DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/LICENSE_MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2018 Daw-Chih Liou
2 |
3 | Permission is hereby granted, free of charge, to any
4 | person obtaining a copy of this software and associated
5 | documentation files (the "Software"), to deal in the
6 | Software without restriction, including without
7 | limitation the rights to use, copy, modify, merge,
8 | publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following
11 | conditions:
12 |
13 | The above copyright notice and this permission notice
14 | shall be included in all copies or substantial portions
15 | of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 | DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "voy-search",
3 | "version": "0.1.0",
4 | "description": "a vector similarity search engine in WASM",
5 | "main": "index.js",
6 | "bin": {
7 | "create-wasm-app": ".bin/create-wasm-app.js"
8 | },
9 | "scripts": {
10 | "build": "webpack --config webpack.config.js",
11 | "dev": "webpack serve"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/rustwasm/create-wasm-app.git"
16 | },
17 | "keywords": [
18 | "webassembly",
19 | "wasm",
20 | "rust",
21 | "kd-tree",
22 | "embeddings",
23 | "vector search",
24 | "similarity search",
25 | "nearest neighbor"
26 | ],
27 | "author": "Daw-Chih ",
28 | "license": "(MIT OR Apache-2.0)",
29 | "bugs": {
30 | "url": "https://github.com/tantaraio/voy"
31 | },
32 | "homepage": "https://github.com/tantaraio/voy#readme",
33 | "dependencies": {
34 | "@visheratin/web-ai": "^0.4.9",
35 | "jimp": "^0.22.7",
36 | "voy-search": "file:../../pkg"
37 | },
38 | "devDependencies": {
39 | "copy-webpack-plugin": "^5.0.0",
40 | "hello-wasm-pack": "^0.1.0",
41 | "webpack": "^5.75.0",
42 | "webpack-cli": "^5.0.1",
43 | "webpack-dev-server": "^4.11.1"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello Voy!
6 |
48 |
49 |
50 | This page contains webassembly and javascript content, please enable
52 | javascript in your browser.
54 |
55 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "voy-search"
3 | version = "0.6.3"
4 | authors = ["Daw-Chih Liou "]
5 | edition = "2018"
6 | description = "a vector similarity search engine in WASM"
7 | documentation = "https://github.com/tantaraio/voy#readme"
8 | readme = "https://github.com/tantaraio/voy#readme"
9 | homepage = "https://github.com/tantaraio/voy"
10 | repository = "https://github.com/tantaraio/voy"
11 | license = "MIT OR Apache 2.0"
12 | keywords = ["webassembly", "wasm", "rust", "kd-tree", "embeddings", "vector search", "similarity search", "nearest neighbor"]
13 |
14 |
15 | [lib]
16 | crate-type = ["cdylib", "rlib"]
17 |
18 | [features]
19 | default = ["console_error_panic_hook"]
20 |
21 | [dependencies]
22 | wasm-bindgen = "0.2.63"
23 |
24 | # The `console_error_panic_hook` crate provides better debugging of panics by
25 | # logging them with `console.error`. This is great for development, but requires
26 | # all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
27 | # code size when deploying.
28 | console_error_panic_hook = { version = "0.1.6", optional = true }
29 |
30 | # `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
31 | # compared to the default allocator's ~10K. It is slower than the default
32 | # allocator, however.
33 | wee_alloc = { version = "0.4.5", optional = true }
34 | serde = { version = "1.0.152", features = ["derive"] }
35 | anyhow = "1.0.69"
36 | getrandom = { version = "0.2", features = ["js"] }
37 | serde_json = "1.0.93"
38 | serde-wasm-bindgen = "0.4.5"
39 | js-sys = "0.3.61"
40 | tsify = "0.4.5"
41 | kiddo = { version = "2.1.0", features = ["serialize"] }
42 |
43 | [dev-dependencies]
44 | rstest = "0.17.0"
45 | wasm-bindgen-test = "0.3.13"
46 |
47 | [profile.release]
48 | # Tell `rustc` to optimize for small code size.
49 | opt-level = "s"
50 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | ```
14 |
15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
16 |
17 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
18 |
19 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
20 |
21 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
22 |
23 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
24 |
25 | ## Learn More
26 |
27 | To learn more about Next.js, take a look at the following resources:
28 |
29 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
30 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
31 |
32 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
33 |
34 | ## Deploy on Vercel
35 |
36 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
37 |
38 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
39 |
--------------------------------------------------------------------------------
/src/wasm/voy.rs:
--------------------------------------------------------------------------------
1 | use crate::utils::set_panic_hook;
2 | use crate::{engine, Neighbor, NumberOfResult, Query, Resource, SearchResult, SerializedIndex};
3 |
4 | use wasm_bindgen::prelude::*;
5 |
6 | #[wasm_bindgen]
7 | pub struct Voy {
8 | index: engine::Index,
9 | }
10 |
11 | #[wasm_bindgen]
12 | impl Voy {
13 | #[wasm_bindgen(constructor)]
14 | pub fn new(resource: Option) -> Voy {
15 | set_panic_hook();
16 |
17 | let resource: Resource = match resource {
18 | Some(res) => res,
19 | _ => Resource { embeddings: vec![] },
20 | };
21 | let index = engine::index(resource).unwrap();
22 | Voy { index }
23 | }
24 |
25 | pub fn serialize(&self) -> SerializedIndex {
26 | serde_json::to_string(&self.index).unwrap()
27 | }
28 |
29 | pub fn deserialize(serialized_index: SerializedIndex) -> Voy {
30 | let index: engine::Index = serde_json::from_str(&serialized_index).unwrap();
31 | Voy { index }
32 | }
33 |
34 | pub fn index(&mut self, resource: Resource) {
35 | let index = engine::index(resource).unwrap();
36 | self.index = index
37 | }
38 |
39 | pub fn search(&self, query: Query, k: NumberOfResult) -> SearchResult {
40 | let query: engine::Query = engine::Query::Embeddings(query);
41 | let neighbors = engine::search(&self.index, &query, k).unwrap();
42 | let neighbors: Vec = neighbors
43 | .into_iter()
44 | .map(|x| Neighbor {
45 | id: x.id,
46 | title: x.title,
47 | url: x.url,
48 | })
49 | .collect();
50 |
51 | SearchResult { neighbors }
52 | }
53 |
54 | pub fn add(&mut self, resource: Resource) {
55 | engine::add(&mut self.index, &resource);
56 | }
57 |
58 | pub fn remove(&mut self, resource: Resource) {
59 | engine::remove(&mut self.index, &resource);
60 | }
61 |
62 | pub fn clear(&mut self) {
63 | engine::clear(&mut self.index);
64 | }
65 |
66 | pub fn size(&self) -> usize {
67 | engine::size(&self.index)
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/wasm/fns.rs:
--------------------------------------------------------------------------------
1 | use crate::{
2 | engine, utils::set_panic_hook, Neighbor, NumberOfResult, Query, Resource, SearchResult,
3 | SerializedIndex,
4 | };
5 | use wasm_bindgen::prelude::*;
6 |
7 | #[wasm_bindgen]
8 | pub fn index(resource: Resource) -> SerializedIndex {
9 | set_panic_hook();
10 |
11 | let index = engine::index(resource);
12 | match index {
13 | Ok(idx) => serde_json::to_string(&idx).unwrap(),
14 | _ => "".to_owned(),
15 | }
16 | }
17 |
18 | #[wasm_bindgen]
19 | pub fn search(index: SerializedIndex, query: Query, k: NumberOfResult) -> SearchResult {
20 | set_panic_hook();
21 |
22 | let index: engine::Index = serde_json::from_str(&index).unwrap();
23 | let query: engine::Query = engine::Query::Embeddings(query);
24 |
25 | let neighbors = engine::search(&index, &query, k).unwrap();
26 | let neighbors: Vec = neighbors
27 | .into_iter()
28 | .map(|x| Neighbor {
29 | id: x.id,
30 | title: x.title,
31 | url: x.url,
32 | })
33 | .collect();
34 |
35 | SearchResult { neighbors }
36 | }
37 |
38 | #[wasm_bindgen]
39 | pub fn add(index: SerializedIndex, resource: Resource) -> SerializedIndex {
40 | set_panic_hook();
41 |
42 | let mut index: engine::Index = serde_json::from_str(&index).unwrap();
43 | engine::add(&mut index, &resource);
44 |
45 | serde_json::to_string(&index).unwrap()
46 | }
47 |
48 | #[wasm_bindgen]
49 | pub fn remove(index: SerializedIndex, resource: Resource) -> SerializedIndex {
50 | set_panic_hook();
51 |
52 | let mut index: engine::Index = serde_json::from_str(&index).unwrap();
53 | engine::remove(&mut index, &resource);
54 |
55 | serde_json::to_string(&index).unwrap()
56 | }
57 |
58 | #[wasm_bindgen]
59 | pub fn clear(index: SerializedIndex) -> SerializedIndex {
60 | set_panic_hook();
61 |
62 | let mut index: engine::Index = serde_json::from_str(&index).unwrap();
63 | engine::clear(&mut index);
64 |
65 | serde_json::to_string(&index).unwrap()
66 | }
67 |
68 | #[wasm_bindgen]
69 | pub fn size(index: SerializedIndex) -> usize {
70 | set_panic_hook();
71 |
72 | let index: engine::Index = serde_json::from_str(&index).unwrap();
73 |
74 | engine::size(&index)
75 | }
76 |
--------------------------------------------------------------------------------
/examples/nextjs-transformersjs/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { Pipeline, pipeline } from "@xenova/transformers";
2 | import { Inter } from "next/font/google";
3 | import { useCallback, useEffect, useState } from "react";
4 | import { SearchResult, Voy } from "voy-search";
5 |
6 | const inter = Inter({ subsets: ["latin"] });
7 |
8 | const phrases = [
9 | "That is a very happy Person",
10 | "That is a Happy Dog",
11 | "Today is a sunny day",
12 | ];
13 |
14 | const query = "Is it summer yet?";
15 |
16 | async function getExtractor() {
17 | const extractor = await pipeline(
18 | "feature-extraction",
19 | "Xenova/all-MiniLM-L6-v2"
20 | );
21 | return extractor;
22 | }
23 |
24 | async function extract(extractor: Pipeline, text: string) {
25 | const result = await extractor(text, { pooling: "mean", normalize: true });
26 | return result.data;
27 | }
28 |
29 | export default function Home() {
30 | const [result, setResult] = useState();
31 |
32 | const run = useCallback(async (extractor: Pipeline) => {
33 | const embeddings = await Promise.all(
34 | phrases.map((phrase) => extract(extractor, phrase))
35 | );
36 |
37 | const data = embeddings.map((embeddings, i) => ({
38 | id: String(i),
39 | title: phrases[i],
40 | url: `/path/${i}`,
41 | embeddings: Array.from(embeddings) as number[],
42 | }));
43 |
44 | const index = new Voy({ embeddings: data });
45 |
46 | const q = await extract(extractor, query);
47 |
48 | const result = index.search(q, 1);
49 |
50 | setResult(result);
51 | }, []);
52 |
53 | useEffect(() => {
54 | getExtractor().then(run);
55 | }, []);
56 |
57 | return (
58 |
61 |
62 |
📚 Index:
63 | {phrases.map((phrases) => (
64 |
{phrases}
65 | ))}
66 |
67 |
68 |
❓ Query:
69 |
{query}
70 |
71 |
72 |
✨ Search Result
73 | {!result &&
...
}
74 | {result?.neighbors.map((n) => (
75 |
{n.title}
76 | ))}
77 |
78 |
79 | );
80 | }
81 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/pages/server-side.tsx:
--------------------------------------------------------------------------------
1 | import Head from "next/head";
2 |
3 | import styles from "@/styles/Home.module.css";
4 |
5 | import { useCallback, useEffect, useRef, useState } from "react";
6 |
7 | import { NavigationBar } from "@/components/NavigationBar";
8 |
9 | export default function ServerSide() {
10 | const inputRef = useRef(null);
11 | const [embeddings, setEmbeddings] = useState[] | null>(
12 | null
13 | );
14 |
15 | const [results, setResults] = useState([]);
16 |
17 | useEffect(() => {
18 | fetch("/api/embeddings")
19 | .then((res) => res.json())
20 | .then((result) => {
21 | setEmbeddings(result.embeddings);
22 | });
23 | }, []);
24 |
25 | const onSubmit = useCallback(() => {
26 | if (inputRef.current?.value) {
27 | setResults([]);
28 | fetch("/api/process", {
29 | method: "POST",
30 | body: JSON.stringify({
31 | embeddings,
32 | searchQuery: inputRef.current?.value,
33 | }),
34 | })
35 | .then((res) => res.json())
36 | .then((result) => {
37 | setResults(result.neighbors);
38 | });
39 | }
40 | }, [embeddings]);
41 |
42 | return (
43 | <>
44 |
45 | Voy & Next.js Example - Server Side
46 |
47 |
48 |
49 |
50 |
51 |
52 |
87 |
88 | >
89 | );
90 | }
91 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
create-wasm-app
4 |
5 |
An npm init template for kick starting a project that uses NPM packages containing Rust-generated WebAssembly and bundles them with Webpack.
6 |
7 |
8 |
9 |
10 |
11 |
12 | Usage
13 | |
14 | Chat
15 |
16 |
17 |
Built with 🦀🕸 by The Rust and WebAssembly Working Group
18 |
19 |
20 | ## About
21 |
22 | This template is designed for depending on NPM packages that contain
23 | Rust-generated WebAssembly and using them to create a Website.
24 |
25 | * Want to create an NPM package with Rust and WebAssembly? [Check out
26 | `wasm-pack-template`.](https://github.com/rustwasm/wasm-pack-template)
27 | * Want to make a monorepo-style Website without publishing to NPM? Check out
28 | [`rust-webpack-template`](https://github.com/rustwasm/rust-webpack-template)
29 | and/or
30 | [`rust-parcel-template`](https://github.com/rustwasm/rust-parcel-template).
31 |
32 | ## 🚴 Usage
33 |
34 | ```
35 | npm init wasm-app
36 | ```
37 |
38 | ## 🔋 Batteries Included
39 |
40 | - `.gitignore`: ignores `node_modules`
41 | - `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you
42 | - `README.md`: the file you are reading now!
43 | - `index.html`: a bare bones html document that includes the webpack bundle
44 | - `index.js`: example js file with a comment showing how to import and use a wasm pkg
45 | - `package.json` and `package-lock.json`:
46 | - pulls in devDependencies for using webpack:
47 | - [`webpack`](https://www.npmjs.com/package/webpack)
48 | - [`webpack-cli`](https://www.npmjs.com/package/webpack-cli)
49 | - [`webpack-dev-server`](https://www.npmjs.com/package/webpack-dev-server)
50 | - defines a `start` script to run `webpack-dev-server`
51 | - `webpack.config.js`: configuration file for bundling your js with webpack
52 |
53 | ## License
54 |
55 | Licensed under either of
56 |
57 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
58 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
59 |
60 | at your option.
61 |
62 | ### Contribution
63 |
64 | Unless you explicitly state otherwise, any contribution intentionally
65 | submitted for inclusion in the work by you, as defined in the Apache-2.0
66 | license, shall be dual licensed as above, without any additional terms or
67 | conditions.
68 |
--------------------------------------------------------------------------------
/src/engine/tests/mod.rs:
--------------------------------------------------------------------------------
1 | mod fixtures;
2 |
3 | use crate::engine;
4 | use crate::{EmbeddedResource, Resource};
5 | use fixtures::*;
6 | use rstest::*;
7 |
8 | #[rstest]
9 | fn it_indexes_embeddings(resource_fixture: Resource) {
10 | let index = engine::index(resource_fixture).unwrap();
11 |
12 | assert_eq!(index.tree.size(), 6);
13 | }
14 |
15 | #[rstest]
16 | fn it_returns_vector_search_result(
17 | resource_fixture: Resource,
18 | question_fixture: [f32; 768],
19 | content_fixture: [&'static str; 6],
20 | ) {
21 | let index = engine::index(resource_fixture).unwrap();
22 | let query = engine::Query::Embeddings(question_fixture.to_vec());
23 | let result = engine::search(&index, &query, 6).unwrap();
24 |
25 | assert_eq!(result.get(0).unwrap().title, content_fixture[0]);
26 | assert_eq!(result.get(1).unwrap().title, content_fixture[1]);
27 | assert_eq!(result.get(2).unwrap().title, content_fixture[2]);
28 | assert_eq!(result.get(3).unwrap().title, content_fixture[4]);
29 | assert_eq!(result.get(4).unwrap().title, content_fixture[5]);
30 | assert_eq!(result.get(5).unwrap().title, content_fixture[3]);
31 | }
32 |
33 | #[rstest]
34 | fn it_adds_embeddings_to_index(
35 | resource_fixture: Resource,
36 | content_fixture: [&'static str; 6],
37 | embedding_fixture: [[f32; 768]; 6],
38 | ) {
39 | let mut index = engine::index(resource_fixture).unwrap();
40 | let addition = Resource {
41 | embeddings: vec![EmbeddedResource {
42 | id: "5".to_owned(),
43 | title: content_fixture.get(5).unwrap().to_string(),
44 | url: "".to_owned(),
45 | embeddings: embedding_fixture[5].to_vec(),
46 | }],
47 | };
48 |
49 | engine::add(&mut index, &addition);
50 | assert_eq!(index.tree.size(), 7);
51 | }
52 |
53 | #[rstest]
54 | fn it_removes_embeddings_from_index(
55 | resource_fixture: Resource,
56 | content_fixture: [&'static str; 6],
57 | embedding_fixture: [[f32; 768]; 6],
58 | ) {
59 | let mut index = engine::index(resource_fixture).unwrap();
60 | let target = Resource {
61 | embeddings: vec![EmbeddedResource {
62 | id: "1".to_owned(),
63 | title: content_fixture.get(1).unwrap().to_string(),
64 | url: "".to_owned(),
65 | embeddings: embedding_fixture[1].to_vec(),
66 | }],
67 | };
68 |
69 | engine::remove(&mut index, &target);
70 | assert_eq!(index.tree.size(), 5);
71 | }
72 |
73 | #[rstest]
74 | fn it_clears_all_embeddings_from_index(resource_fixture: Resource) {
75 | let mut index = engine::index(resource_fixture).unwrap();
76 | assert_eq!(index.tree.size(), 6);
77 | assert_eq!(index.data.len(), 6);
78 |
79 | engine::clear(&mut index);
80 | assert_eq!(index.tree.size(), 0);
81 | assert_eq!(index.data.len(), 0);
82 | }
83 |
84 | #[rstest]
85 | fn it_returns_the_size_of_index(resource_fixture: Resource) {
86 | let index = engine::index(resource_fixture).unwrap();
87 | assert_eq!(index.tree.size(), 6);
88 | assert_eq!(index.data.len(), 6);
89 | assert_eq!(engine::size(&index), 6);
90 | }
91 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: rust
2 | sudo: false
3 |
4 | cache: cargo
5 |
6 | matrix:
7 | include:
8 |
9 | # Builds with wasm-pack.
10 | - rust: beta
11 | env: RUST_BACKTRACE=1
12 | addons:
13 | firefox: latest
14 | chrome: stable
15 | before_script:
16 | - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
17 | - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
18 | - cargo install-update -a
19 | - curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
20 | script:
21 | - cargo generate --git . --name testing
22 | # Having a broken Cargo.toml (in that it has curlies in fields) anywhere
23 | # in any of our parent dirs is problematic.
24 | - mv Cargo.toml Cargo.toml.tmpl
25 | - cd testing
26 | - wasm-pack build
27 | - wasm-pack test --chrome --firefox --headless
28 |
29 | # Builds on nightly.
30 | - rust: nightly
31 | env: RUST_BACKTRACE=1
32 | before_script:
33 | - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
34 | - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
35 | - cargo install-update -a
36 | - rustup target add wasm32-unknown-unknown
37 | script:
38 | - cargo generate --git . --name testing
39 | - mv Cargo.toml Cargo.toml.tmpl
40 | - cd testing
41 | - cargo check
42 | - cargo check --target wasm32-unknown-unknown
43 | - cargo check --no-default-features
44 | - cargo check --target wasm32-unknown-unknown --no-default-features
45 | - cargo check --no-default-features --features console_error_panic_hook
46 | - cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook
47 | - cargo check --no-default-features --features "console_error_panic_hook wee_alloc"
48 | - cargo check --target wasm32-unknown-unknown --no-default-features --features "console_error_panic_hook wee_alloc"
49 |
50 | # Builds on beta.
51 | - rust: beta
52 | env: RUST_BACKTRACE=1
53 | before_script:
54 | - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
55 | - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
56 | - cargo install-update -a
57 | - rustup target add wasm32-unknown-unknown
58 | script:
59 | - cargo generate --git . --name testing
60 | - mv Cargo.toml Cargo.toml.tmpl
61 | - cd testing
62 | - cargo check
63 | - cargo check --target wasm32-unknown-unknown
64 | - cargo check --no-default-features
65 | - cargo check --target wasm32-unknown-unknown --no-default-features
66 | - cargo check --no-default-features --features console_error_panic_hook
67 | - cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook
68 | # Note: no enabling the `wee_alloc` feature here because it requires
69 | # nightly for now.
70 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/src/pages/client-side.tsx:
--------------------------------------------------------------------------------
1 | import Head from "next/head";
2 |
3 | import styles from "@/styles/Home.module.css";
4 |
5 | import { useCallback, useEffect, useRef, useState } from "react";
6 |
7 | import { NavigationBar } from "@/components/NavigationBar";
8 | import { useVoy } from "@/context/VoyContext";
9 |
10 | import { TextModel } from "@visheratin/web-ai";
11 |
12 | const phrases = [
13 | "That is a very happy Person",
14 | "That is a Happy Dog",
15 | "Today is a sunny day",
16 | "Yesterday is a sunny day",
17 | ];
18 |
19 | export default function ServerSide() {
20 | const voy = useVoy();
21 | const [index, setIndex] = useState(null);
22 |
23 | const [results, setResults] = useState([]);
24 |
25 | const inputRef = useRef(null);
26 |
27 | const [model, setModel] = useState(null);
28 |
29 | useEffect(() => {
30 | (async () => {
31 | if (!model) {
32 | const modelName = "gtr-t5-quant";
33 |
34 | console.log("Loading model: ", modelName);
35 |
36 | // Create text embeddings
37 | const model = await (await TextModel.create(modelName)).model;
38 | setModel(model);
39 | }
40 | })();
41 | }, [model, setModel]);
42 |
43 | useEffect(() => {
44 | if (!model) return;
45 |
46 | (async () => {
47 | console.log("Creating embeddings for ", phrases);
48 | console.log("Processing for model", model);
49 |
50 | const processed = await Promise.all(phrases.map((q) => model.process(q)));
51 |
52 | // Index embeddings with voy
53 | const data = processed.map(({ result }, i) => ({
54 | id: String(i),
55 | title: phrases[i],
56 | url: `/path/${i}`,
57 | embeddings: result,
58 | }));
59 |
60 | const input = { embeddings: data };
61 | console.log("Indexing", input);
62 |
63 | setIndex(voy.index(input));
64 | })();
65 | }, [voy, model]);
66 |
67 | const onSubmit = useCallback(async () => {
68 | const query = inputRef.current?.value;
69 | if (!query || !index) return;
70 |
71 | const q = await model.process(query);
72 | const result = voy.search(index, q.result, 4);
73 |
74 | setResults(result.neighbors);
75 | }, [index]);
76 |
77 | return (
78 | <>
79 |
80 | Voy & Next.js Example - Client Side
81 |
82 |
83 |
84 |
85 |
86 |
87 |
124 |
125 | >
126 | );
127 | }
128 |
--------------------------------------------------------------------------------
/src/engine/engine.rs:
--------------------------------------------------------------------------------
1 | use crate::Resource;
2 | use kiddo::float::{distance::squared_euclidean, kdtree::KdTree};
3 | use serde::{Deserialize, Serialize};
4 | use std::{collections::HashMap, convert::TryInto};
5 |
6 | use super::hash;
7 |
8 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
9 |
10 | pub struct Document {
11 | pub id: String,
12 | pub title: String,
13 | pub url: String,
14 | }
15 |
16 | #[derive(Serialize, Deserialize, Debug, Clone)]
17 | pub enum Query {
18 | // TODO: support query in string
19 | // Phrase(String)
20 | Embeddings(Vec),
21 | }
22 |
23 | // Wasm has a 4GB memory limit. Should make sure the bucket size and capacity
24 | // doesn't exceed it and cause stack overflow.
25 | // More detail: https://v8.dev/blog/4gb-wasm-memory
26 | const BUCKET_SIZE: usize = 32;
27 |
28 | pub type Tree = KdTree;
29 |
30 | #[derive(Serialize, Deserialize, Debug, Clone)]
31 | pub struct Index {
32 | // "IDX" is set to u16 to optimize CPU cache.
33 | // Read more: https://github.com/sdd/kiddo/blob/7a0bb6ecce39963b27ffdca913c6be7a265e3523/src/types.rs#L35
34 | pub tree: Tree,
35 | pub data: HashMap,
36 | }
37 |
38 | pub fn index(resource: Resource) -> anyhow::Result {
39 | let data_vec: Vec<(u64, Document)> = resource
40 | .embeddings
41 | .iter()
42 | .map(|resource| Document {
43 | id: resource.id.to_owned(),
44 | title: resource.title.to_owned(),
45 | url: resource.url.to_owned(),
46 | })
47 | .map(|document| (hash(&document), document))
48 | .collect();
49 |
50 | let data: HashMap = data_vec.clone().into_iter().collect();
51 |
52 | let mut tree: Tree = KdTree::new();
53 |
54 | resource
55 | .embeddings
56 | .iter()
57 | .zip(data_vec.iter())
58 | .for_each(|(resource, data)| {
59 | let mut embeddings = resource.embeddings.clone();
60 | embeddings.resize(768, 0.0);
61 |
62 | let query: &[f32; 768] = &embeddings.try_into().unwrap();
63 | // "item" holds the position of the document in "data"
64 | tree.add(query, data.0);
65 | });
66 |
67 | Ok(Index { tree, data })
68 | }
69 |
70 | pub fn search<'a>(index: &'a Index, query: &'a Query, k: usize) -> anyhow::Result> {
71 | let mut query: Vec = match query {
72 | Query::Embeddings(q) => q.to_owned(),
73 | };
74 | query.resize(768, 0.0);
75 |
76 | let query: &[f32; 768] = &query.try_into().unwrap();
77 | let neighbors = index.tree.nearest_n(query, k, &squared_euclidean);
78 |
79 | let mut result: Vec = vec![];
80 |
81 | for neighbor in &neighbors {
82 | let doc = index.data.get(&neighbor.item);
83 | if let Some(document) = doc {
84 | result.push(document.to_owned());
85 | }
86 | }
87 |
88 | Ok(result)
89 | }
90 |
91 | pub fn add<'a>(index: &'a mut Index, resource: &'a Resource) {
92 | for item in &resource.embeddings {
93 | let mut embeddings = item.embeddings.clone();
94 | embeddings.resize(768, 0.0);
95 |
96 | let query: &[f32; 768] = &embeddings.try_into().unwrap();
97 | let doc = Document {
98 | id: item.id.to_owned(),
99 | title: item.title.to_owned(),
100 | url: item.url.to_owned(),
101 | };
102 | let id = hash(&doc);
103 | index.data.insert(id, doc);
104 | index.tree.add(query, id);
105 | }
106 | }
107 |
108 | pub fn remove<'a>(index: &'a mut Index, resource: &'a Resource) {
109 | for item in &resource.embeddings {
110 | let mut embeddings = item.embeddings.clone();
111 | embeddings.resize(768, 0.0);
112 |
113 | let query: &[f32; 768] = &embeddings.try_into().unwrap();
114 | let id = hash(&Document {
115 | id: item.id.to_owned(),
116 | title: item.title.to_owned(),
117 | url: item.url.to_owned(),
118 | });
119 |
120 | index.tree.remove(query, id);
121 | index.data.remove(&id);
122 | }
123 | }
124 |
125 | pub fn clear<'a>(index: &'a mut Index) {
126 | // simply assign a new tree and data because traversing the nodes to perform removal is the only alternative.
127 | // Kiddo provides only basic removal. See more: https://github.com/sdd/kiddo/issues/76
128 | index.tree = KdTree::new();
129 | index.data = HashMap::new();
130 | }
131 |
132 | pub fn size<'a>(index: &'a Index) -> usize {
133 | index.data.len()
134 | }
135 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/index.js:
--------------------------------------------------------------------------------
1 | import { TextModel } from "@visheratin/web-ai";
2 | import { logIndex, logIntro, logResource } from "./log";
3 | import { phrases } from "./phrases";
4 | import { perf } from "./performance";
5 |
6 | const initialQuery =
7 | "Which name is also used to describe the Amazon rainforest in English?";
8 |
9 | const initialPhrases = phrases.slice(0, 6);
10 |
11 | const main = async () => {
12 | const timer = perf();
13 |
14 | logIntro("🎉 Welcome to Voy");
15 | logIntro("🕸️ Loading Voy ...");
16 |
17 | // Loading voy WebAssembly module asynchronously
18 | const { Voy } = await import("voy-search");
19 |
20 | logIntro(`🕸️ Voy is loaded ✔️ ...`);
21 | logIntro("🕸️ Voy is indexing [");
22 |
23 | logResource([...initialPhrases.map((p) => `・ "${p}",`)]);
24 |
25 | logIndex(`・ ] (${initialPhrases.length} phrases) ...`);
26 |
27 | // Create text embeddings
28 | const model = await (await TextModel.create("gtr-t5-quant")).model;
29 | const processed = await Promise.all(
30 | initialPhrases.map((q) => model.process(q))
31 | );
32 |
33 | // Index embeddings with voy
34 | const data = processed.map(({ result }, i) => ({
35 | id: String(i),
36 | title: initialPhrases[i],
37 | url: `/path/${i}`,
38 | embeddings: result,
39 | }));
40 | const resource = { embeddings: data };
41 |
42 | const voy = new Voy(resource);
43 |
44 | logIndex(`🕸️ Voy is indexed ✔️ ...`);
45 | logIndex(
46 | `🕸️ Voy is searching for the nearest neighbors of "${initialQuery}" ...`
47 | );
48 |
49 | // Perform similarity search for the query embeddings
50 | const q = await model.process(initialQuery);
51 | const result = voy.search(q.result, 3);
52 |
53 | // Display search result
54 | logIndex("🕸️ --- Voy similarity search result ---");
55 |
56 | result.neighbors.forEach((result, i) => {
57 | if (i === 0) {
58 | logIndex(`🥇 "${result.title}"`);
59 | } else if (i === 1) {
60 | logIndex(`🥈 "${result.title}"`);
61 | } else if (i === 2) {
62 | logIndex(`🥉 "${result.title}"`);
63 | } else {
64 | logIndex(`🕸️ "${result.title}"`);
65 | }
66 | });
67 |
68 | logIndex("⮐");
69 |
70 | const newPhrase = phrases.slice(6, 7);
71 |
72 | logIndex(`🕸️ Voy is adding a new phrase "${newPhrase[0]}" to the index ...`);
73 |
74 | const newEmbeddings = await Promise.all(
75 | newPhrase.map((q) => model.process(q))
76 | );
77 |
78 | const addition = newEmbeddings.map(({ result }, i) => ({
79 | id: String(6),
80 | title: newPhrase[i],
81 | url: `/path/${6}`,
82 | embeddings: result,
83 | }));
84 |
85 | index = voy.add({ embeddings: addition });
86 |
87 | logIndex(`🕸️ Voy is indexed ✔️ ...`);
88 | logIndex(
89 | `🕸️ Voy is searching for the nearest neighbors of "${initialQuery}" ...`
90 | );
91 | logIndex("🕸️ --- Voy similarity search result ---");
92 |
93 | voy.search(q.result, 3).neighbors.forEach((result, i) => {
94 | if (i === 0) {
95 | logIndex(`🥇 "${result.title}"`);
96 | } else if (i === 1) {
97 | logIndex(`🥈 "${result.title}"`);
98 | } else if (i === 2) {
99 | logIndex(`🥉 "${result.title}"`);
100 | } else {
101 | logIndex(`🕸️ "${result.title}"`);
102 | }
103 | });
104 |
105 | logIndex("⮐");
106 | logIndex(
107 | `🕸️ Voy is removing the new phrase "${newPhrase[0]}" from the index ...`
108 | );
109 |
110 | index = voy.remove({ embeddings: addition });
111 | logIndex(
112 | `🕸️ Voy is searching for the nearest neighbors of "${initialQuery}" ...`
113 | );
114 |
115 | logIndex(`🕸️ Voy is indexed ✔️ ...`);
116 | logIndex("🕸️ --- Voy similarity search result ---");
117 |
118 | voy.search(q.result, 3).neighbors.forEach((result, i) => {
119 | if (i === 0) {
120 | logIndex(`🥇 "${result.title}"`);
121 | } else if (i === 1) {
122 | logIndex(`🥈 "${result.title}"`);
123 | } else if (i === 2) {
124 | logIndex(`🥉 "${result.title}"`);
125 | } else {
126 | logIndex(`🕸️ "${result.title}"`);
127 | }
128 | });
129 |
130 | logIndex("⮐");
131 | logIndex(`🕸️ Voy is serializing ...`);
132 |
133 | const serialized = voy.serialize();
134 | logIndex(`🕸️ Voy is serialized ✔️ ...`);
135 |
136 | logIndex(`🕸️ Voy is deserializing ...`);
137 |
138 | const deserializedVoy = Voy.deserialize(serialized);
139 | logIndex(`🕸️ Voy is deserialized ✔️ ...`);
140 |
141 | logIndex("🕸️ --- Deserialized Voy similarity search result ---");
142 | deserializedVoy.search(q.result, 3).neighbors.forEach((result, i) => {
143 | if (i === 0) {
144 | logIndex(`🥇 "${result.title}"`);
145 | } else if (i === 1) {
146 | logIndex(`🥈 "${result.title}"`);
147 | } else if (i === 2) {
148 | logIndex(`🥉 "${result.title}"`);
149 | } else {
150 | logIndex(`🕸️ "${result.title}"`);
151 | }
152 | });
153 |
154 | logIndex("⮐");
155 | logIndex(`🕸️ Voy is clearing the index ...`);
156 |
157 | voy.clear();
158 | deserializedVoy.clear();
159 |
160 | logIndex(`🕸️ Voy is cleared ✔️ ...`);
161 | logIndex(`✨ Done in ${timer.stop()}s`);
162 | };
163 |
164 | main();
165 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
Voy
3 | A WASM vector similarity search engine written in Rust
4 |
5 |
6 | ![voy: a vector similarity search engine in WebAssembly][demo]
7 |
8 | [](https://badge.fury.io/js/voy-search)
9 |
10 | - **Tiny**: 75KB gzipped, 69KB brotli.
11 | - **Fast**: Create the best search experience for the users. Voy uses [k-d tree][k-d-tree] to index and provide fast search
12 | - **Tree Shakable**: Optimize bundle size and enable asynchronous capabilities for modern Web API, such as [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers).
13 | - **Resumable**: Generate portable embeddings index anywhere, anytime.
14 | - **Worldwide**: Designed to deploy and run on CDN edge servers.
15 |
16 | > **🚜 Work in Progress**
17 | >
18 | > Voy is under active development. As a result, the API is not stable. Please be aware that there might be breaking changes before the upcoming 1.0 release.
19 | >
20 | > A sneak peek of what we are working on:
21 | >
22 | > - [ ] Built-in text transformation in WebAssembly: As of now, voy relies on JavaScript libraries like [`transformers.js`][transformers.js] to generate text embeddings. See [Usage](#usage) for more detail.
23 | > - [x] Index update: Currently it's required to [re-build the index](#indexresource-resource-serializedindex) when a resource update occurs.
24 | > - [x] TypeScript support: Due to the limitation of WASM tooling, complex data types are not auto-generated.
25 |
26 | ## Installation
27 |
28 | ```bash
29 | # with npm
30 | npm i voy-search
31 |
32 | # with Yarn
33 | yarn add voy-search
34 |
35 | # with pnpm
36 | pnpm add voy-search
37 | ```
38 |
39 | ## APIs
40 |
41 | ### `class Voy`
42 |
43 | The Voy class encapsulates an index and exposes all the public methods Voy has to offer.
44 |
45 | ```ts
46 | class Voy {
47 | /**
48 | * By instantiating with a resource, Voy will construct the index. If the resource is
49 | * absent, it will construct an empty index. Calling Voy.index() later on will override
50 | * the empty index.
51 | * @param {Resource | undefined} resource
52 | */
53 | constructor(resource?: Resource);
54 | /**
55 | * Index given resource. Voy.index() is designed for the use case where a Voy instance
56 | * is instantiated without a resource. It will override the existing index. If you'd like
57 | * to keep the existing index, you can use Voy.add() to add your resource to the index.
58 | * @param {Resource} resource
59 | */
60 | index(resource: Resource): void;
61 | /**
62 | * Search top k results with given query embedding.
63 | * @param {Float32Array} query: Query Embedding
64 | * @param {number} k: Number of items in the search result
65 | * @returns {SearchResult}
66 | */
67 | search(query: Float32Array, k: number): SearchResult;
68 | /**
69 | * Add given resource to the index.
70 | * @param {Resource} resource
71 | */
72 | add(resource: Resource): void;
73 | /**
74 | * Remove given resource from the index.
75 | * @param {Resource} resource
76 | */
77 | remove(resource: Resource): void;
78 | /**
79 | * Remove all resources from the index.
80 | */
81 | clear(): void;
82 | /**
83 | * @returns {number}
84 | */
85 | size(): number;
86 | /**
87 | * Serialize a Voy instance.
88 | * @returns {string}
89 | */
90 | serialize(): string;
91 | /**
92 | * Deserialize a serialized index into a Voy instance.
93 | * @param {string} serialized_index
94 | * @returns {Voy}
95 | */
96 | static deserialize(serialized_index: string): Voy;
97 | }
98 |
99 | interface Resource {
100 | embeddings: Array<{
101 | id: string; // id of the resource
102 | title: string; // title of the resource
103 | url: string; // url to the resource
104 | embeddings: number[]; // embeddings of the resource
105 | }>;
106 | }
107 |
108 | interface SearchResult {
109 | neighbors: Array<{
110 | id: string; // id of the resource
111 | title: string; // title of the resource
112 | url: string; // url to the resource
113 | }>;
114 | }
115 | ```
116 |
117 | ### Individual Functions
118 |
119 | Besides the Voy class, Voy also exports all the instance methods as individual functions.
120 |
121 | #### `index(resource: Resource): SerializedIndex`
122 |
123 | It indexes the given resource and returns a serialized index.
124 |
125 | **Parameters**
126 |
127 | ```ts
128 | interface Resource {
129 | embeddings: Array<{
130 | id: string; // id of the resource
131 | title: string; // title of the resource
132 | url: string; // url to the resource
133 | embeddings: number[]; // embeddings of the resource
134 | }>;
135 | }
136 | ```
137 |
138 | **Return**
139 |
140 | ```ts
141 | type SerializedIndex = string;
142 | ```
143 |
144 | #### `search(index: SerializedIndex, query: Query, k: NumberOfResult): SearchResult`
145 |
146 | It deserializes the given index and search for the `k` nearest neighbors of the query.
147 |
148 | **Parameter**
149 |
150 | ```ts
151 | type SerializedIndex = string;
152 |
153 | type Query = Float32Array; // embeddings of the search query
154 |
155 | type NumberOfResult = number; // K top results to return
156 | ```
157 |
158 | **Return**
159 |
160 | ```ts
161 | interface SearchResult {
162 | neighbors: Array<{
163 | id: string; // id of the resource
164 | title: string; // title of the resource
165 | url: string; // url to the resource
166 | }>;
167 | }
168 | ```
169 |
170 | #### `add(index: SerializedIndex, resource: Resource): SerializedIndex`
171 |
172 | It adds resources to the index and returns an updated serialized index.
173 |
174 | **Parameter**
175 |
176 | ```ts
177 | type SerializedIndex = string;
178 |
179 | interface Resource {
180 | embeddings: Array<{
181 | id: string; // id of the resource
182 | title: string; // title of the resource
183 | url: string; // url to the resource
184 | embeddings: number[]; // embeddings of the resource
185 | }>;
186 | }
187 | ```
188 |
189 | **Return**
190 |
191 | ```ts
192 | type SerializedIndex = string;
193 | ```
194 |
195 | #### `remove(index: SerializedIndex, resource: Resource): SerializedIndex`
196 |
197 | It removes resources from the index and returns an updated serialized index.
198 |
199 | **Parameter**
200 |
201 | ```ts
202 | type SerializedIndex = string;
203 |
204 | interface Resource {
205 | embeddings: Array<{
206 | id: string; // id of the resource
207 | title: string; // title of the resource
208 | url: string; // url to the resource
209 | embeddings: number[]; // embeddings of the resource
210 | }>;
211 | }
212 | ```
213 |
214 | **Return**
215 |
216 | ```ts
217 | type SerializedIndex = string;
218 | ```
219 |
220 | #### `clear(index: SerializedIndex): SerializedIndex`
221 |
222 | It removes all items from the index and returns an empty serialized index.
223 |
224 | **Parameter**
225 |
226 | ```ts
227 | type SerializedIndex = string;
228 | ```
229 |
230 | **Return**
231 |
232 | ```ts
233 | type SerializedIndex = string;
234 | ```
235 |
236 | #### `size(index: SerializedIndex): number;`
237 |
238 | It returns the size of the index.
239 |
240 | **Parameter**
241 |
242 | ```ts
243 | type SerializedIndex = string;
244 | ```
245 |
246 | ## Usage
247 |
248 | ### With Transformers
249 |
250 | As of now, voy relies on libraries like [`transformers.js`][transformers.js] and [`web-ai`][web-ai] to generate embeddings for text:
251 |
252 | ```js
253 | import { TextModel } from "@visheratin/web-ai";
254 |
255 | const { Voy } = await import("voy-search");
256 |
257 | const phrases = [
258 | "That is a very happy Person",
259 | "That is a Happy Dog",
260 | "Today is a sunny day",
261 | ];
262 | const query = "That is a happy person";
263 |
264 | // Create text embeddings
265 | const model = await (await TextModel.create("gtr-t5-quant")).model;
266 | const processed = await Promise.all(phrases.map((q) => model.process(q)));
267 |
268 | // Index embeddings with voy
269 | const data = processed.map(({ result }, i) => ({
270 | id: String(i),
271 | title: phrases[i],
272 | url: `/path/${i}`,
273 | embeddings: result,
274 | }));
275 | const resource = { embeddings: data };
276 | const index = new Voy(resource);
277 |
278 | // Perform similarity search for a query embeddings
279 | const q = await model.process(query);
280 | const result = index.search(q.result, 1);
281 |
282 | // Display search result
283 | result.neighbors.forEach((result) =>
284 | console.log(`✨ voy similarity search result: "${result.title}"`)
285 | );
286 | ```
287 |
288 | ### Multiple Indexes
289 |
290 | ```js
291 | import { TextModel } from "@visheratin/web-ai";
292 |
293 | const { Voy } = await import("voy-search");
294 | const phrases = [
295 | "That is a very happy Person",
296 | "That is a Happy Dog",
297 | "Today is a sunny day",
298 | "Sun flowers are blooming",
299 | ];
300 | const model = await (await TextModel.create("gtr-t5-quant")).model;
301 | const processed = await Promise.all(phrases.map((q) => model.process(q)));
302 |
303 | const data = processed.map(({ result }, i) => ({
304 | id: String(i),
305 | title: phrases[i],
306 | url: `/path/${i}`,
307 | embeddings: result,
308 | }));
309 | const resourceA = { embeddings: data.slice(0, 2) };
310 | const resourceB = { embeddings: data.slice(2) };
311 |
312 | const indexA = new Voy(resourceA);
313 | const indexB = new Voy(resourceB);
314 | ```
315 |
316 | ## License
317 |
318 | Licensed under either of
319 |
320 | - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
321 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
322 |
323 | at your option.
324 |
325 | ## Sponsor
326 |
327 |
328 |
329 |
330 | ### Contribution
331 |
332 | Unless you explicitly state otherwise, any contribution intentionally
333 | submitted for inclusion in the work by you, as defined in the Apache-2.0
334 | license, shall be dual licensed as above, without any additional terms or
335 | conditions.
336 |
337 | [demo]: ./voy.gif "voy demo"
338 | [web-ai]: https://github.com/visheratin/web-ai
339 | [k-d-tree]: https://en.wikipedia.org/wiki/K-d_tree
340 | [transformers.js]: https://github.com/xenova/transformers.js
341 |
--------------------------------------------------------------------------------
/LICENSE_APACHE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/examples/voy-with-nextjs/LICENSE_APACHE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/examples/create-wasm-app/phrases.js:
--------------------------------------------------------------------------------
1 | export const phrases = [
2 | "The Amazon rainforest,[a] also called Amazon jungle or Amazonia, is a moist broadleaf tropical rainforest in the",
3 | "in the Amazon biome that covers most of the Amazon basin of South America. This basin encompasses 7,000,000 km2",
4 | "(2,700,000 sq mi), of which 5,500,000 km2 (2,100,000 sq mi) are covered by the rainforest. This region includes",
5 | "includes territory belonging to nine nations and 3,344 formally acknowledged indigenous territories.",
6 | "The majority of the forest, 60%, is in Brazil, followed by Peru with 13%, Colombia with 10%, and with minor amounts in",
7 | 'amounts in Bolivia, Ecuador, French Guiana, Guyana, Suriname, and Venezuela. Four nations have "Amazonas" as the',
8 | 'as the name of one of their first-level administrative regions, and France uses the name "Guiana Amazonian Park" for',
9 | "Park\" for French Guiana's protected rainforest area. The Amazon represents over half of the planet's remaining",
10 | "remaining rainforests,[2] and comprises the largest and most biodiverse tract of tropical rainforest in the world,",
11 | "the world, with an estimated 390 billion individual trees in about 16,000 species.[3]",
12 | "More than 30 million people of 350 different ethnic groups live in the Amazon, which are subdivided into 9 different",
13 | "9 different national political systems and 3,344 formally acknowledged indigenous territories. Indigenous",
14 | "Indigenous peoples make up 9% of the total population, and 60 of the groups remain largely isolated.[4]",
15 | "Etymology",
16 | "The name Amazon is said to arise from a war Francisco de Orellana fought with the Tapuyas and other tribes. The women of",
17 | "The women of the tribe fought alongside the men, as was their custom.[5] Orellana derived the name Amazonas from the",
18 | "from the Amazons of Greek mythology, described by Herodotus and Diodorus.[5]",
19 | "History",
20 | "In the Amazonas, there has been fighting and wars between the neighboring tribes of the Jivaro. Several tribes of the",
21 | "of the Jivaroan group, including the Shuar, practised headhunting for trophies and headshrinking.[6] The accounts",
22 | "accounts of missionaries to the area in the borderlands between Brazil and Venezuela have recounted constant",
23 | "constant infighting in the Yanomami tribes. More than a third of the Yanomamo males, on average, died from",
24 | "died from warfare.[7]",
25 | "The Munduruku were a warlike tribe that expanded along the Tapajós river and its tributaries and were feared by",
26 | "feared by neighboring tribes. In the early 19th century, the Munduruku were pacified and subjugated by the",
27 | "by the Brazilians.[8]",
28 | "During the Amazon rubber boom it is estimated that diseases brought by immigrants, such as typhus and malaria, killed",
29 | "killed 40,000 native Amazonians.[9]",
30 | "In the 1950s, Brazilian explorer and defender of indigenous people, Cândido Rondon, supported the Villas-Bôas",
31 | "brothers' campaign, which faced strong opposition from the government and the ranchers of Mato Grosso and led to the",
32 | "led to the establishment of the first Brazilian National Park for indigenous people along the Xingu River in",
33 | "River in 1961.[10]",
34 | "In 1961, British explorer Richard Mason was killed by an uncontacted Amazon tribe known as the Panará.[11]",
35 | "The Matsés made their first permanent contact with the outside world in 1969. Before that date, they were effectively",
36 | "at-war with the Peruvian government.[12]",
37 | "Geography",
38 | "Location",
39 | "Nine countries share the Amazon basin—most of the rainforest, 58.4%, is contained within the borders of Brazil. The",
40 | "Brazil. The other eight countries include Peru with 12.8%, Bolivia with 7.7%, Colombia with 7.1%, Venezuela with",
41 | "with 6.1%, Guyana with 3.1%, Suriname with 2.5%, French Guiana with 1.4%, and Ecuador with 1%.[13]",
42 | "Natural\n\nAmazon rainforest in Colombia\n\nAerial view of the Amazon rainforest, near Manaus",
43 | "The rainforest likely formed during the Eocene era (from 56 million years to 33.9 million years ago). It appeared",
44 | "It appeared following a global reduction of tropical temperatures when the Atlantic Ocean had widened sufficiently",
45 | "to provide a warm, moist climate to the Amazon basin. The rainforest has been in existence for at least 55 million",
46 | "55 million years, and most of the region remained free of savanna-type biomes at least until the current ice age when",
47 | "ice age when the climate was drier and savanna more widespread.[14][15]",
48 | "Following the Cretaceous–Paleogene extinction event, the extinction of the dinosaurs and the wetter climate may",
49 | "climate may have allowed the tropical rainforest to spread out across the continent. From 66 to 34 Mya, the rainforest",
50 | "rainforest extended as far south as 45°. Climate fluctuations during the last 34 million years have allowed savanna",
51 | "savanna regions to expand into the tropics. During the Oligocene, for example, the rainforest spanned a relatively",
52 | "relatively narrow band. It expanded again during the Middle Miocene, then retracted to a mostly inland formation at",
53 | "at the last glacial maximum.[16] However, the rainforest still managed to thrive during these glacial periods,",
54 | "periods, allowing for the survival and evolution of a broad diversity of species.[17]",
55 | "Aerial view of the Amazon rainforest",
56 | "During the mid-Eocene, it is believed that the drainage basin of the Amazon was split along the middle of the continent",
57 | "continent by the Púrus Arch. Water on the eastern side flowed toward the Atlantic, while to the west water flowed",
58 | "flowed toward the Pacific across the Amazonas Basin. As the Andes Mountains rose, however, a large basin was created",
59 | "was created that enclosed a lake; now known as the Solimões Basin. Within the last 5–10 million years, this",
60 | "years, this accumulating water broke through the Púrus Arch, joining the easterly flow toward the",
61 | "toward the Atlantic.[18][19]",
62 | "There is evidence that there have been significant changes in the Amazon rainforest vegetation over the last 21,000",
63 | "last 21,000 years through the last glacial maximum (LGM) and subsequent deglaciation. Analyses of sediment",
64 | "of sediment deposits from Amazon basin paleolakes and the Amazon Fan indicate that rainfall in the basin during the",
65 | "during the LGM was lower than for the present, and this was almost certainly associated with reduced moist tropical",
66 | "tropical vegetation cover in the basin.[20] In present day, the Amazon receives approximately 9 feet of rainfall",
67 | "of rainfall annually. There is a debate, however, over how extensive this reduction was. Some scientists argue that",
68 | "argue that the rainforest was reduced to small, isolated refugia separated by open forest and grassland;[21] other",
69 | "other scientists argue that the rainforest remained largely intact but extended less far to the north, south, and",
70 | "south, and east than is seen today.[22] This debate has proved difficult to resolve because the practical",
71 | "practical limitations of working in the rainforest mean that data sampling is biased away from the center of the",
72 | "of the Amazon basin, and both explanations are reasonably well supported by the available data.",
73 | "Sahara Desert dust windblown to the Amazon",
74 | "More than 56% of the dust fertilizing the Amazon rainforest comes from the Bodélé depression in Northern Chad in the",
75 | "Chad in the Sahara desert. The dust contains phosphorus, important for plant growth. The yearly Sahara dust replaces",
76 | "replaces the equivalent amount of phosphorus washed away yearly in Amazon soil from rains and floods.[23]",
77 | "NASA's CALIPSO satellite has measured the amount of dust transported by wind from the Sahara to the Amazon: an average",
78 | "an average of 182 million tons of dust are windblown out of the Sahara each year, at 15 degrees west longitude, across",
79 | "across 2,600 km (1,600 mi) over the Atlantic Ocean (some dust falls into the Atlantic), then at 35 degrees West",
80 | "West longitude at the eastern coast of South America, 27.7 million tons (15%) of dust fall over the Amazon basin (22",
81 | "basin (22 million tons of it consisting of phosphorus), 132 million tons of dust remain in the air, 43 million tons of",
82 | "tons of dust are windblown and falls on the Caribbean Sea, past 75 degrees west longitude.[24]",
83 | "CALIPSO uses a laser range finder to scan the Earth's atmosphere for the vertical distribution of dust and other",
84 | "and other aerosols. CALIPSO regularly tracks the Sahara-Amazon dust plume. CALIPSO has measured variations in the",
85 | "in the dust amounts transported – an 86 percent drop between the highest amount of dust transported in 2007 and the",
86 | "2007 and the lowest in 2011.",
87 | "A possibility causing the variation is the Sahel, a strip of semi-arid land on the southern border of the Sahara. When",
88 | "When rain amounts in the Sahel are higher, the volume of dust is lower. The higher rainfall could make more vegetation",
89 | "vegetation grow in the Sahel, leaving less sand exposed to winds to blow away.[25]",
90 | "Amazon phosphorus also comes as smoke due to biomass burning in Africa.[26][27]\n\nHuman activity",
91 | "Manaus, with 2.2 million inhabitants, is the largest city in the Amazon basin",
92 | "The Yanomami are a group of approximately 32,000 indigenous people who live in the Amazon rainforest.[28]",
93 | "Based on archaeological evidence from an excavation at Caverna da Pedra Pintada, human inhabitants first settled in",
94 | "settled in the Amazon region at least 11,200 years ago.[29] Subsequent development led to late-prehistoric",
95 | "settlements along the periphery of the forest by AD 1250, which induced alterations in the forest cover.[30]",
96 | "For a long time, it was thought that the Amazon rainforest was never more than sparsely populated, as it was impossible",
97 | "impossible to sustain a large population through agriculture given the poor soil. Archeologist Betty Meggers was a",
98 | "was a prominent proponent of this idea, as described in her book Amazonia: Man and Culture in a Counterfeit Paradise.",
99 | "Paradise. She claimed that a population density of 0.2 inhabitants per square kilometre (0.52/sq mi) is the maximum",
100 | "the maximum that can be sustained in the rainforest through hunting, with agriculture needed to host a larger",
101 | "a larger population.[31] However, recent anthropological findings have suggested that the region was actually",
102 | "actually densely populated. Some 5 million people may have lived in the Amazon region in AD 1500, divided between",
103 | "between dense coastal settlements, such as that at Marajó, and inland dwellers.[32] By 1900, the population had",
104 | "had fallen to 1 million and by the early 1980s it was less than 200,000.[32]",
105 | "The first European to travel the length of the Amazon River was Francisco de Orellana in 1542.[33] The BBC's Unnatural",
106 | "Unnatural Histories presents evidence that Orellana, rather than exaggerating his claims as previously thought,",
107 | "thought, was correct in his observations that a complex civilization was flourishing along the Amazon in the 1540s.",
108 | "the 1540s. It is believed that civilization was later devastated by the spread of diseases from Europe, such as",
109 | "such as smallpox.[34] This civilization was investigated by the British explorer Percy Fawcett in the early",
110 | "in the early twentieth century. The results of his expeditions were inconclusive and he disappeared mysteriously on",
111 | "on his last trip. His name for this lost civilization was the City of Z.",
112 | "Since the 1970s, numerous geoglyphs have been discovered on deforested land dating between AD 1–1250, furthering",
113 | "furthering claims about Pre-Columbian civilizations.[35][36] Ondemar Dias is accredited with first discovering",
114 | "the geoglyphs in 1977, and Alceu Ranzi is credited with furthering their discovery after flying over Acre.[34][37]",
115 | "The BBC's Unnatural Histories presented evidence that the Amazon rainforest, rather than being a pristine",
116 | "a pristine wilderness, has been shaped by man for at least 11,000 years through practices such as forest gardening and",
117 | "and terra preta.[34] Terra preta is found over large areas in the Amazon forest; and is now widely accepted as a product",
118 | "as a product of indigenous soil management. The development of this fertile soil allowed agriculture and",
119 | "and silviculture in the previously hostile environment; meaning that large portions of the Amazon rainforest are",
120 | "are probably the result of centuries of human management, rather than naturally occurring as has previously been",
121 | "been supposed.[38] In the region of the Xingu tribe, remains of some of these large settlements in the middle of the",
122 | "of the Amazon forest were found in 2003 by Michael Heckenberger and colleagues of the University of Florida. Among",
123 | "Among those were evidence of roads, bridges and large plazas.[39]",
124 | "Biodiversity, flora and fauna",
125 | "Deforestation in the Amazon rainforest threatens many species of tree frogs, which are very sensitive to",
126 | "to environmental changes (pictured: giant leaf frog)",
127 | "A giant, bundled liana in western Brazil",
128 | "Wet tropical forests are the most species-rich biome, and tropical forests in the Americas are consistently more",
129 | "more species rich than the wet forests in Africa and Asia.[40] As the largest tract of tropical rainforest in the",
130 | "in the Americas, the Amazonian rainforests have unparalleled biodiversity. One in ten known species in the world",
131 | "in the world lives in the Amazon rainforest.[41] This constitutes the largest collection of living plants and animal",
132 | "and animal species in the world.",
133 | "The region is home to about 2.5 million insect species,[42] tens of thousands of plants, and some 2,000 birds and",
134 | "birds and mammals. To date, at least 40,000 plant species,[43] 2,200 fishes,[44] 1,294 birds, 427 mammals, 428",
135 | "428 amphibians, and 378 reptiles have been scientifically classified in the region.[45] One in five of all bird",
136 | "of all bird species are found in the Amazon rainforest, and one in five of the fish species live in Amazonian rivers and",
137 | "rivers and streams. Scientists have described between 96,660 and 128,843 invertebrate species in Brazil",
138 | "in Brazil alone.[46]",
139 | "The biodiversity of plant species is the highest on Earth with one 2001 study finding a quarter square kilometer (62",
140 | "(62 acres) of Ecuadorian rainforest supports more than 1,100 tree species.[47] A study in 1999 found one square",
141 | "one square kilometer (247 acres) of Amazon rainforest can contain about 90,790 tonnes of living plants. The average",
142 | "The average plant biomass is estimated at 356 ± 47 tonnes per hectare.[48] To date, an estimated 438,000 species of",
143 | "species of plants of economic and social interest have been registered in the region with many more remaining to be",
144 | "to be discovered or catalogued.[49] The total number of tree species in the region is estimated at 16,000.[3]",
145 | "The green leaf area of plants and trees in the rainforest varies by about 25% as a result of seasonal changes. Leaves",
146 | "Leaves expand during the dry season when sunlight is at a maximum, then undergo abscission in the cloudy wet season.",
147 | "wet season. These changes provide a balance of carbon between photosynthesis and respiration.[50]",
148 | "The rainforest contains several species that can pose a hazard. Among the largest predatory creatures are the black",
149 | "the black caiman, jaguar, cougar, and anaconda. In the river, electric eels can produce an electric shock that can",
150 | "that can stun or kill, while piranha are known to bite and injure humans.[51] Various species of poison dart frogs",
151 | "dart frogs secrete lipophilic alkaloid toxins through their flesh. There are also numerous parasites and disease",
152 | "and disease vectors. Vampire bats dwell in the rainforest and can spread the rabies virus.[52] Malaria, yellow fever",
153 | "fever and dengue fever can also be contracted in the Amazon region.",
154 | "The biodiversity in the Amazon is becoming increasingly threatened, primarily by habitat loss from deforestation",
155 | "as well as increased frequency of fires. Over 90% of Amazonian plant and vertebrate species (13,000-14,000 in total)",
156 | "in total) may have been impacted to some degree by fires.[53]",
157 | "Pipa pipa, a species of frog found within the Amazon.\n\nDeforestation",
158 | "Timelapse of the deforestation 1984–2018 (bottom right)",
159 | "Deforestation in the Maranhão state of Brazil, 2016",
160 | "Home to much of the Amazon rainforest, Brazil's tropical primary (old-growth) forest loss greatly exceeds that of",
161 | "that of other countries.[54]",
162 | 'Overall, 20% of the Amazon rainforest has been "transformed" (deforested) and another 6% has been "highly',
163 | '"highly degraded", causing Amazon Watch to warn that the Amazonia is in the midst of a tipping point crisis.[55]',
164 | "Deforestation is the conversion of forested areas to non-forested areas. The main sources of deforestation in the",
165 | "in the Amazon are human settlement and the development of the land.[56] In 2018, about 17% of the Amazon rainforest was",
166 | "was already destroyed. Research suggests that upon reaching about 20–25% (hence 3–8% more), the tipping point to",
167 | "point to flip it into a non-forest ecosystem – degraded savannah – (in eastern, southern and central Amazonia) will be",
168 | "will be reached.[57][58]",
169 | "Prior to the early 1960s, access to the forest's interior was highly restricted, and the forest remained basically",
170 | "basically intact.[59] Farms established during the 1960s were based on crop cultivation and the slash and burn",
171 | "and burn method. However, the colonists were unable to manage their fields and the crops because of the loss of soil",
172 | "loss of soil fertility and weed invasion.[60] The soils in the Amazon are productive for just a short period of time, so",
173 | "of time, so farmers are constantly moving to new areas and clearing more land.[60] These farming practices led to",
174 | "led to deforestation and caused extensive environmental damage.[61] Deforestation is considerable, and areas",
175 | "and areas cleared of forest are visible to the naked eye from outer space.",
176 | "In the 1970s, construction began on the Trans-Amazonian highway. This highway represented a major threat to the",
177 | "to the Amazon rainforest.[62] The highway still has not been completed, limiting the environmental damage.",
178 | "Between 1991 and 2000, the total area of forest lost in the Amazon rose from 415,000 to 587,000 km2 (160,000 to",
179 | "(160,000 to 227,000 sq mi), with most of the lost forest becoming pasture for cattle.[63] Seventy percent of",
180 | "percent of formerly forested land in the Amazon, and 91% of land deforested since 1970, have been used for livestock",
181 | "livestock pasture.[64][65] Currently, Brazil is the largest global producer of soybeans. New research however,",
182 | "however, conducted by Leydimere Oliveira et al., has shown that the more rainforest is logged in the Amazon, the less",
183 | "the less precipitation reaches the area and so the lower the yield per hectare becomes. So despite the popular",
184 | "the popular perception, there has been no economical advantage for Brazil from logging rainforest zones and",
185 | "zones and converting these to pastoral fields.[66]",
186 | "The needs of soy farmers have been used to justify many of the controversial transportation projects that are",
187 | "that are currently developing in the Amazon. The first two highways successfully opened up the rainforest and led to",
188 | "and led to increased settlement and deforestation. The mean annual deforestation rate from 2000 to 2005 (22,392 km2",
189 | "or 8,646 sq mi per year) was 18% higher than in the previous five years (19,018 km2 or 7,343 sq mi per year).[67]",
190 | "year).[67] Although deforestation declined significantly in the Brazilian Amazon between 2004 and 2014, there has",
191 | "there has been an increase to the present day.[68]",
192 | "Brazilian mining operation in the Amazon Rainforest.",
193 | "Brazil's President, Jair Bolsonaro, has supported the relaxation of regulations placed on agricultural land. He",
194 | "land. He has used his time in office to allow for more deforestation and more exploitation of the Amazon's rich natural",
195 | "natural resources.",
196 | "Since the discovery of fossil fuel reservoirs in the Amazon rainforest, oil drilling activity has steadily",
197 | "steadily increased, peaking in the Western Amazon in the 1970s and ushering another drilling boom in the 2000s.[69]",
198 | "2000s.[69] Oil companies have to set up their operations by opening new roads through the forests, which often",
199 | "which often contributes to deforestation in the region.[70]",
200 | "The European Union–Mercosur free trade agreement, which would form one of the world's largest free trade areas, has",
201 | "areas, has been denounced by environmental activists and indigenous rights campaigners.[71] The fear is that the",
202 | "is that the deal could lead to more deforestation of the Amazon rainforest as it expands market access to Brazilian",
203 | "Brazilian beef.[72]",
204 | "According to a November 2021 report by Brazil's INPE, based on satellite data, deforestation has increased by 22%",
205 | "by 22% over 2020 and is at its highest level since 2006.[73][74]",
206 | "2019 fires",
207 | "There have been 72,843 fires in Brazil in 2019, with more than half within the Amazon region.[75][76][77] In August",
208 | "In August 2019 there were a record number of fires.[78] Deforestation in the Brazilian Amazon rose more than 88% in",
209 | "than 88% in June 2019 compared with the same month in 2018.[79]",
210 | "NASA satellite observation of deforestation in the Mato Grosso state of Brazil. The transformation from forest to",
211 | "forest to farm is evident by the paler square shaped areas under development.",
212 | "Fires and deforestation in the state of Rondônia",
213 | "One consequence of forest clearing in the Amazon: thick smoke that hangs over the forest",
214 | "Impact of deforestation on natural habitat of trees",
215 | "The increased area of fire-impacted forest coincided with a relaxation of environmental regulations from the",
216 | "from the Brazilian government. Notably, before those regulations were put in place in 2008 the fire-impacted area",
217 | "area was also larger compared to the regulation period of 2009–2018. As these fire continue to move closer to the heart",
218 | "to the heart of the Amazon Basin, their impact on biodiversity will only increase in scale, as the cumulative",
219 | "cumulative fire-impacted area is correlated with the number of species impacted.[53]",
220 | "Conservation and climate change",
221 | "Environmentalists are concerned about loss of biodiversity that will result from destruction of the forest, and",
222 | "forest, and also about the release of the carbon contained within the vegetation, which could accelerate global",
223 | "global warming. Amazonian evergreen forests account for about 10% of the world's terrestrial primary productivity",
224 | "and 10% of the carbon stores in ecosystems[80] – of the order of 1.1 × 1011 metric tonnes of carbon.[81] Amazonian",
225 | "Amazonian forests are estimated to have accumulated 0.62 ± 0.37 tons of carbon per hectare per year between 1975 and",
226 | "1975 and 1996.[81] In 2021 it was reported that the Amazon for the first time emitted more greenhouse gases than it",
227 | "than it absorbed.[82] Though often referenced as producing more than a quarter of the Earth's oxygen, this often",
228 | "this often stated, but misused statistic actually refers to oxygen turnover. The net contribution of the ecosystem",
229 | "ecosystem is approximately zero.[83]",
230 | "One computer model of future climate change caused by greenhouse gas emissions shows that the Amazon rainforest",
231 | "rainforest could become unsustainable under conditions of severely reduced rainfall and increased temperatures,",
232 | "leading to an almost complete loss of rainforest cover in the basin by 2100.[84][85], and severe economic, natural",
233 | "natural capital and ecosystem services impacts of not averting the tipping point.[86] However, simulations of",
234 | "of Amazon basin climate change across many different models are not consistent in their estimation of any rainfall",
235 | "rainfall response, ranging from weak increases to strong decreases.[87] The result indicates that the rainforest",
236 | "rainforest could be threatened through the 21st century by climate change in addition to deforestation.",
237 | "In 1989, environmentalist C.M. Peters and two colleagues stated there is economic as well as biological incentive to",
238 | "to protecting the rainforest. One hectare in the Peruvian Amazon has been calculated to have a value of $6820 if intact",
239 | "if intact forest is sustainably harvested for fruits, latex, and timber; $1000 if clear-cut for commercial timber",
240 | "timber (not sustainably harvested); or $148 if used as cattle pasture.[88]",
241 | "According to WWF, ecotourism could help the Amazon to reduce deforestation and climate change. Ecotourism is",
242 | "is currently still little practiced in the Amazon, partly due to lack of information about places where",
243 | "where implementation is possible. Ecotourism is a sector that can also be taken up by the Indigenous community in the",
244 | "in the Amazon as a source of income and revenue. An ecotourism project in the Brazilian-section of the Amazon",
245 | "the Amazon rainforest had been under consideration by Brazil's State Secretary for the Environment and Sustainable",
246 | "Development in 2009, along the Aripuanã river, in the Aripuanã Sustainable Development Reserve.[89] Also, some",
247 | "Also, some community-based ecotourism exists in the Mamirauá Sustainable Development Reserve.[90] Ecotourism is",
248 | "is also practiced in the Peruvian-section of the Amazon rainforest. A few ecolodges are for instance present between",
249 | "between Cusco and Madre de Dios.[91]",
250 | "As indigenous territories continue to be destroyed by deforestation and ecocide, such as in the Peruvian Amazon[92]",
251 | "Amazon[92] indigenous peoples' rainforest communities continue to disappear, while others, like the Urarina",
252 | "the Urarina continue to struggle to fight for their cultural survival and the fate of their forested territories.",
253 | "Meanwhile, the relationship between non-human primates in the subsistence and symbolism of indigenous lowland",
254 | "lowland South American peoples has gained increased attention, as have ethno-biology and community-based",
255 | "conservation efforts.",
256 | "From 2002 to 2006, the conserved land in the Amazon rainforest almost tripled and deforestation rates dropped up to",
257 | "up to 60%. About 1,000,000 km2 (250,000,000 acres) have been put onto some sort of conservation, which adds up to a",
258 | "adds up to a current amount of 1,730,000 km2 (430,000,000 acres).[93]",
259 | "In April 2019, the Ecuadorian court stopped oil exploration activities in 180,000 hectares (440,000 acres) of the",
260 | "of the Amazon rainforest.[94]",
261 | "In July 2019, the Ecuadorian court forbade the government to sell territory with forests to oil companies.[95]",
262 | "In September 2019, the US and Brazil agreed to promote private-sector development in the Amazon. They also pledged a",
263 | "pledged a $100m biodiversity conservation fund for the Amazon led by the private sector. Brazil's foreign minister",
264 | "minister stated that opening the rainforest to economic development was the only way to protect it.[96]",
265 | "Anthropogenic emission of greenhouse gases broken down by sector for the year 2000.",
266 | "Aerosols over the Amazon each September for four burning seasons (2005 through 2008). The aerosol scale (yellow to",
267 | "(yellow to dark reddish-brown) indicates the relative amount of particles that absorb sunlight.",
268 | "Aerial roots of red mangrove on an Amazonian river.",
269 | "Climate change disturbances of rainforests.[97]",
270 | "A 2009 study found that a 4 °C rise (above pre-industrial levels) in global temperatures by 2100 would kill 85% of the",
271 | "85% of the Amazon rainforest while a temperature rise of 3 °C would kill some 75% of the Amazon.[98]",
272 | "A new study by an international team of environmental scientists in the Brazilian Amazon shows that protection of",
273 | "of freshwater biodiversity can be increased by up to 600% through integrated freshwater-terrestrial planning",
274 | "planning .[99]",
275 | "Deforestation in the Amazon rainforest region has a negative impact on local climate.[100] It was one of the main",
276 | "of the main causes of the severe drought of 2014–2015 in Brazil.[101][102] This is because the moisture from the",
277 | "from the forests is important to the rainfall in Brazil, Paraguay and Argentina. Half of the rainfall in the Amazon",
278 | "the Amazon area is produced by the forests.[103]",
279 | "Results of a 2021 scientific synthesis indicate that, in terms of global warming, the Amazon basin with the Amazon",
280 | "the Amazon rainforest is currently emitting more greenhouse gases than it absorbs overall. Climate change impacts",
281 | "impacts and human activities in the area – mainly wildfires, current land-use and deforestation – are causing a",
282 | "causing a release of forcing agents that likely result in a net warming effect.[104][97][105]",
283 | 'In 2022 the supreme court of Ecuador decided that "“under no circumstances can a project be carried out that generates',
284 | "generates excessive sacrifices to the collective rights of communities and nature.” It also required the",
285 | "the government to respect the opinion of Indigenous peoples of the Americas about different industrial projects on",
286 | "projects on their land. Advocates of the decision argue that it will have consequences far beyond Ecuador. In",
287 | "Ecuador. In general, ecosystems are in better shape when indigenous peoples own or manage the land.[106]",
288 | "Remote sensing",
289 | 'This image reveals how the forest and the atmosphere interact to create a uniform layer of "popcorn-shaped" cumulus',
290 | "cumulus clouds.",
291 | "The use of remotely sensed data is dramatically improving conservationists' knowledge of the Amazon basin. Given",
292 | "Given the objectivity and lowered costs of satellite-based land cover and -change analysis, it appears likely that",
293 | "likely that remote sensing technology will be an integral part of assessing the extents, locations and damage of",
294 | "damage of deforestation in the basin.[107] Furthermore, remote sensing is the best and perhaps only possible way to",
295 | "way to study the Amazon on a large scale.[108]",
296 | "The use of remote sensing for the conservation of the Amazon is also being used by the indigenous tribes of the basin to",
297 | "the basin to protect their tribal lands from commercial interests. Using handheld GPS devices and programs like",
298 | "like Google Earth, members of the Trio Tribe, who live in the rainforests of southern Suriname, map out their",
299 | "out their ancestral lands to help strengthen their territorial claims.[109] Currently, most tribes in the Amazon do",
300 | "Amazon do not have clearly defined boundaries, making it easier for commercial ventures to target their",
301 | "their territories.",
302 | "To accurately map the Amazon's biomass and subsequent carbon-related emissions, the classification of tree growth",
303 | "tree growth stages within different parts of the forest is crucial. In 2006, Tatiana Kuplich organized the trees of",
304 | "the trees of the Amazon into four categories: mature forest, regenerating forest [less than three years],",
305 | "years], regenerating forest [between three and five years of regrowth], and regenerating forest [eleven to",
306 | "[eleven to eighteen years of continued development].[110] The researcher used a combination of synthetic aperture",
307 | "aperture radar (SAR) and Thematic Mapper (TM) to accurately place the different portions of the Amazon into one of the",
308 | "one of the four classifications.",
309 | "Impact of early 21st-century Amazon droughts",
310 | "In 2005, parts of the Amazon basin experienced the worst drought in one hundred years,[111] and there were",
311 | "there were indications that 2006 may have been a second successive year of drought.[112] A 2006 article in the UK",
312 | "in the UK newspaper The Independent reported the Woods Hole Research Center results, showing that the forest in its",
313 | "in its present form could survive only three years of drought.[113][114] Scientists at the Brazilian National",
314 | "National Institute of Amazonian Research argued in the article that this drought response, coupled with the effects",
315 | 'the effects of deforestation on regional climate, are pushing the rainforest towards a "tipping point" where it',
316 | "where it would irreversibly start to die.[115] It concluded that the forest is on the brink of[vague] being turned",
317 | "turned into savanna or desert, with catastrophic consequences for the world's climate.[citation needed] A study",
318 | "A study published in Nature Communications in October 2020 found that about 40% of the Amazon rainforest is at risk of",
319 | "is at risk of becoming a savanna-like ecosystem due to reduced rainfall.[116] A study published in Nature climate",
320 | "climate change provided direct empirical evidence that more than three-quarters of the Amazon rainforest has been",
321 | "has been losing resilience since the early 2000s, risking dieback with profound implications for biodiversity,",
322 | "carbon storage and climate change at a global scale.[117]",
323 | "According to the World Wide Fund for Nature, the combination of climate change and deforestation increases the",
324 | "the drying effect of dead trees that fuels forest fires.[118]",
325 | "In 2010, the Amazon rainforest experienced another severe drought, in some ways more extreme than the 2005 drought.",
326 | "drought. The affected region was approximately 3,000,000 km2 (1,160,000 sq mi) of rainforest, compared with",
327 | "with 1,900,000 km2 (734,000 sq mi) in 2005. The 2010 drought had three epicenters where vegetation died off,",
328 | "died off, whereas in 2005, the drought was focused on the southwestern part. The findings were published in the",
329 | "in the journal Science. In a typical year, the Amazon absorbs 1.5 gigatons of carbon dioxide; during 2005 instead 5",
330 | "instead 5 gigatons were released and in 2010 8 gigatons were released.[119][120] Additional severe droughts",
331 | "droughts occurred in 2010, 2015, and 2016.[121]",
332 | "In 2019 Brazil's protections of the Amazon rainforest were slashed, resulting in a severe loss of trees.[122]",
333 | "According to Brazil's National Institute for Space Research (INPE), deforestation in the Brazilian Amazon rose",
334 | "Amazon rose more than 50% in the first three months of 2020 compared to the same three-month period in 2019.[123]",
335 | "In 2020, a 17 percent rise was noted in the Amazon wildfires, marking the worst start to the fire season in a decade. The",
336 | "decade. The first 10 days of August 2020 witnessed 10,136 fires. An analysis of the government figures reflected 81",
337 | "81 per cent increase in fires in federal reserves, in comparison with the same period in 2019.[124] However,",
338 | 'However, President Jair Bolsonaro turned down the existence of fires, calling it a "lie", despite the data produced',
339 | "produced by his own government.[125] Satellites in September recorded 32,017 hotspots in the world's largest",
340 | "largest rainforest, a 61% rise from the same month in 2019.[126] In addition, October saw a huge surge in the number of",
341 | "number of hotspots in the forest (more than 17,000 fires are burning in the Amazon's rainforest) - with more than",
342 | "more than double the amount detected in the same month last year.[127]",
343 | ];
344 |
--------------------------------------------------------------------------------