jamaibase - v0.3.0

jamai-logo

JamAI

www.jamaibase.com

This is a TS/JS Client Library for JamAIBase.

GitHub | Documentation | TS/JS API Documentation | Issues | NPM Package

JamAI Base

JamAI Base Cover

Overview

Welcome to JamAI Base – the real-time database that orchestrates Large Language Models (LLMs) for you. Designed to simplify AI integration, JamAI Base offers a Backend as a Service (BaaS) platform with an intuitive, spreadsheet-like interface. Focus on defining your data requirements through natural language prompts, and let us handle the complexities of RAG, LLMOps, conversation histories, and LLM orchestration.

Key Benefits

Ease of Use

  • Interface: Simple, intuitive spreadsheet-like interface.
  • Focus: Define data requirements through natural language prompts.

Scalability

  • Foundation: Built on LanceDB, an open-source vector database designed for AI workloads.
  • Performance: Serverless design ensures optimal performance and seamless scalability.

Flexibility

  • LLM Support: Supports any LLMs, including OpenAI GPT-4, Anthropic Claude 3, and Meta Llama3.
  • Capabilities: Leverage state-of-the-art AI capabilities effortlessly.

Declarative Paradigm

  • Approach: Define the "what" rather than the "how."
  • Simplification: Simplifies complex data operations, making them accessible to users with varying levels of technical expertise.

Innovative RAG Techniques

  • Effortless RAG: Built-in RAG features, no need to build the RAG pipeline yourself.
  • Query Rewriting: Boosts the accuracy and relevance of your search queries.
  • Hybrid Search & Reranking: Combines keyword-based search, structured search, and vector search for the best results.
  • Structured RAG Content Management: Organizes and manages your structured content seamlessly.
  • Adaptive Chunking: Automatically determines the best way to chunk your data.
  • BGE M3-Embedding: Leverages multi-lingual, multi-functional, and multi-granular text embeddings for free.

Key Features

Generative Tables

Transform static database tables into dynamic, AI-enhanced entities.

  • Dynamic Data Generation: Automatically populate columns with relevant data generated by LLMs.
  • Built-in REST API Endpoint: Streamline the process of integrating AI capabilities into applications.

Action Tables

Facilitate real-time interactions between the application frontend and the LLM backend.

  • Real-Time Responsiveness: Provide a responsive AI interaction layer for applications.
  • Automated Backend Management: Eliminate the need for manual backend management of user inputs and outputs.
  • Complex Workflow Orchestration: Enable the creation of sophisticated LLM workflows.

Knowledge Tables

Act as repositories for structured data and documents, enhancing the LLM’s contextual understanding.

  • Rich Contextual Backdrop: Provide a rich contextual backdrop for LLM operations.
  • Enhanced Data Retrieval: Support other generative tables by supplying detailed, structured contextual information.
  • Efficient Document Management: Enable uploading and synchronization of documents and data.

Chat Tables

Simplify the creation and management of intelligent chatbot applications.

  • Intelligent Chatbot Development: Simplify the development and operational management of chatbots.
  • Context-Aware Interactions: Enhance user engagement through intelligent and context-aware interactions.
  • Seamless Integration: Integrate with Retrieval-Augmented Generation (RAG) to utilize content from any Knowledge Table.

LanceDB Integration

Efficient management and querying of large-scale multi-modal data.

  • Optimized Data Handling: Store, manage, query, and retrieve embeddings on large-scale multi-modal data efficiently.
  • Scalability: Ensure optimal performance and seamless scalability.

Declarative Paradigm

Focus on defining "what" you want to achieve rather than "how" to achieve it.

  • Simplified Development: Allow users to define relationships and desired outcomes.
  • Non-Procedural Approach: Eliminate the need to write procedures.
  • Functional Flexibility: Support functional programming through LLMs.

Installation

npm install jamaibase@latest

Usage

Create API Client

Create an API client with baseURL:

import JamAI from "jamaibase";

const jamai = new JamAI({ baseURL: "http://localhost:5173/" });

Create an API client with api key and project id:

import JamAI from "jamaibase";

const jamai = new JamAI({ apiKey: "jamai_apikey", projectId: "proj_id" });

Create an API client with custom HTTP client:

import axios from "axios";
import JamAI from "jamaibase";

const username = "user";
const password = "password";

const credentials = Buffer.from(`${username}:${password}`).toString("base64");

const httpClient = axios.create({
headers: {
Authorization: `Basic ${credentials}`,
"Content-Type": "application/json"
}
});

const jamai = new JamAI({
baseURL: "https://api.jamaibase.com",
httpClient: httpClient
});

Create an API client with maxretry and timeout:

import JamAI from "jamaibase";

const jamai = new JamAI({
baseURL: "https://api.jamaibase.com",
maxRetries: 3,
timeout: 500
});

Configure httpAgent/ httpsAgent:

import JamAI from "jamaibase";

const jamai = new JamAI({
baseURL: "https://api.jamaibase.com"
});

jamai.setHttpagentConfig({
maxSockets: 100,
maxFreeSockets: 10,
freeSocketTimeout: 30000 // free socket keepalive for 30 seconds
});

Can be imported from different modules depending on the need:

import JamAI from "jamaibase/index.umd.js";

Types

Types can be imported from resources:

import { ChatRequest } from "jamaibase/dist/resources/llm/chat";

let response: ChatRequest;

Use client object to call the methods

Example of adding a row to action table:

try {
const response = await jamai.table.addRow({
table_type: "action",
table_id: "workout-suggestion",
data: [
{
age: 30,
height_in_centimeters: 170,
weight_in_kg: 60
}
],
reindex: null,
concurrent: false
});
console.log("response: ", response);
} catch (err) {
console.error(err.message);
}

Example of adding row with streaming output

try {
const stream = await jamai.table.addRowStream({
table_type: "action",
table_id: "action-table-example-1",
data: [
{
Name: "Albert Eistein"
}
],
reindex: null,
concurrent: false
});

const reader = stream.getReader();

while (true) {
const { done, value } = await reader.read();
if (done) {
console.log("Done");
break;
}
console.log(value);
if (value) {
console.log(value?.choices[0]?.message.content);
}
}
} catch (err) {}

Constructor Parameters for APIClient Configuration

Parameter Type Description Default Value Required / Optional
baseURL string Base URL for the API requests. https://api.jamaibase.com optional
maxRetries number Maximum number of retries for failed requests. 0 Optional
httpClient AxiosInstance Axios instance for making HTTP requests. AxiosInstance Optional
timeout number | undefined Timeout for the requests. undefined Optional
apiKey string | undefined apiKey. undefined Rqruired if accessing cloud
projectId string | undefined projectId. undefined Optional if accessing cloud
dangerouslyAllowBrowser boolean Allowing the insecure usage of JamAI API Key on client side. false Optional if accessing cloud

Quick Start Guide

React JS

To integrate JamAI into a React application, follow these steps:

  1. Install React and Create a New Project
    npx create-react-app my-app
cd my-app
  1. Install jamai
    npm install jamaibase
  1. Create and Use the JamAI Client in your React component
// App.tsx

import { useEffect, useState } from "react";
import JamAI from "jamaibase";
import { PageListTableMetaResponse } from "jamaibase/dist/resources/gen_tables/tables";

export default function Home() {
const [tableData, setTableData] = useState<PageListTableMetaResponse>();

useEffect(() => {
const fetchData = async () => {
const jamai = new JamAI({
baseURL: process.env.NEXT_PUBLIC_JAMAI_BASEURL!,
apiKey: process.env.JAMAI_API_KEY,
projectId: process.env.JAMAI_PROJECT_ID,
});
try {
const response = await jamai.table.listTables({
table_type: "action",
});
setTableData(response);
} catch (err: any) {
console.error(err.message);
}
fetchData();
};
}, []);

return (
<div>
<h1>List of Tables</h1>
<ul>
{tableData?.items.map((table) => (
<li key={table.id}>
<h2>Table ID: {table.id}</h2>
<h3>Columns:</h3>
<ul>
{table.cols.map((column) => (
<li key={column.id}>
<p>ID: {column.id}</p>
<p>Data Type: {column.dtype}</p>
{/* Render other properties as needed */}
</li>
))}
</ul>
</li>
))}
</ul>
</div>
);
}

Next JS

To integrate JamAI into a Next.js application, follow these steps:

  1. Install Next.js and Create a New Project
    npx create-next-app@latest
cd (path/to/your/app)
  1. Install jamaibase
    npm install jamaibase
  1. Generate API Key -> Go to cloud.jamaibase.com/organization/secrets and collect API Key

  2. Collect Project ID -> Go to cloud.jamaibase.com/project and copy the project id.

  3. Create .env.local file at the root of your project and add the keys:

NEXT_PUBLIC_JAMAI_BASEURL=http://api.jamaibase.com/
JAMAI_API_KEY=your_jamai_sk_api_key
JAMAI_PROJECT_ID=your_proj_id
  1. Create a route handler to fetch data.
// src/app/api/list-tables/route.ts
import JamAI from "jamaibase";
import {
PageListTableMetaResponse,
TableTypes,
} from "jamaibase/resources/gen_tables/tables";
import { NextRequest, NextResponse } from "next/server";

const jamai = new JamAI({
baseURL: process.env.NEXT_PUBLIC_JAMAI_BASEURL!,
apiKey: process.env.JAMAI_API_KEY,
projectId: process.env.JAMAI_PROJECT_ID,
});

export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
const tableType = (searchParams.get("type") || "action") as TableTypes;

try {
let data: PageListTableMetaResponse = await jamai.table.listTables({
table_type: tableType,
});
return NextResponse.json(data);
} catch (error: any) {
console.error("Error fetching tables:", error.response);
return NextResponse.json(
{ message: "Internal server error" },
{ status: 500 }
);
}
}
  1. Then, in your Next.js component, you can fetch this data from the API route and render it:
// src/app/page.tsx

"use client";

import { PageListTableMetaResponse } from "jamaibase/dist/resources/gen_tables/tables";
import { ChangeEvent, useEffect, useState } from "react";

export default function Home() {
const [tableData, setTableData] = useState<PageListTableMetaResponse>();
const [tableType, setTableType] = useState("action");

const handleTableTypeChange = (e: ChangeEvent<HTMLSelectElement>) => {
setTableType(e.target.value);
};

useEffect(() => {
const fetchData = async () => {
console.log("fetch data");
const response = await fetch(`/api/list-tables?type=${tableType}`);
if (response.ok) {
const data: PageListTableMetaResponse = await response.json();
setTableData(data);
} else {
console.error("Failed to fetch data:", response.statusText);
}
};
fetchData();
}, [tableType]);
return (
<main className="flex min-h-screen flex-col p-24">
<div className="max-w-sm mx-auto my-10 p-5 bg-white rounded-lg shadow-md">
<label className="block text-sm font-medium text-gray-700 mb-2">
Choose Table Type:
</label>
<select
value={tableType}
onChange={handleTableTypeChange}
className="block w-full py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm text-black"
>
<option value="action">Action</option>
<option value="chat">Chat</option>
<option value="knowledge">Knowledge</option>
</select>
</div>

<div className="space-y-6">
<h1 className="text-4xl">List of Tables</h1>
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Table ID
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Columns
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Column Type
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Number of Rows
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-300 text-black">
{tableData?.items.map((table) => (
<tr key={table.id}>
<td className="px-6 py-4 whitespace-nowrap">
{table.id}
</td>
<td className="px-6 py-4 whitespace-nowrap">
<ul className="space-y-2">
{table.cols.map((column) => (
<li className="" key={column.id}>
<span>{column.id}: </span>
<span>{column.dtype}</span>
</li>
))}
</ul>
</td>
<td className="px-6 py-4 whitespace-nowrap">
<ul className="space-y-2">
{table.cols.map((column) => (
<li className="" key={column.id}>
<span>
{column.gen_config
? "Output"
: "Input"}
</span>
</li>
))}
</ul>
</td>
<td className="px-6 py-4 whitespace-nowrap">
{table.num_rows}
</td>
</tr>
))}
</tbody>
</table>
</div>
</main>
);
}
  1. Start the app
npm run dev

SvelteKit

  1. Setup SvelteKit Project
npm create svelte@latest jamai-example-app
cd jamai-example-app
npm install
  1. Install JamAI
npm i jamaibase
  1. Generate API Key -> Go to cloud.jamaibase.com/organization/secrets and collect API Key

  2. Collect Project ID -> Go to cloud.jamaibase.com/project and copy the project id.

  3. Create .env file at the root of your project and add the keys:

PUBLIC_JAMAI_BASEURL=http://api.jamaibase.com/
JAMAI_API_KEY=your_jamai_sk_api_key
JAMAI_PROJECT_ID=your_proj_id
  1. reate a new file src/routes/create-table/+page.svelte and add the following code:
<script>
<script lang="ts">
export let form;
</script>

<main>
<h1>Create Action Table</h1>

{#if form?.success}
<!-- this message is ephemeral; it exists because the page was rendered in
response to a form submission. it will vanish if the user reloads -->
<p>Successfully created the table.</p>
{/if}
{#if !form?.success}
<!-- this message is ephemeral; it exists because the page was rendered in
response to a form submission. it will vanish if the user reloads -->
<p>Sorry, something went wrong!</p>
{/if}

<form method="POST" action="/create-table">
<label>
Table ID
<input name="table_id" />
</label>
<label>
Column Name
<input name="column_name" />
</label>
<label>
Columng Data Type
<select name="column_d_type">
<option value="str">str</option>
<option value="int">int</option>
<option value="float">float</option>
<option value="bool">bool</option>
</select>
</label>
<button type="submit">Create</button>
</form>
</main>
  1. Create a form action in the +page.server.ts file in the same path to accept post data from the form.
import JamAI from "jamaibase";
import { fail } from "@sveltejs/kit";
import { PUBLIC_JAMAI_URL } from "$env/static/public";
import { JAMAI_API_KEY, JAMAI_PROJECT_ID } from "$env/static/private";

const jamai = new JamAI({
baseURL: PUBLIC_JAMAI_URL,
apiKey: JAMAI_API_KEY,
projectId: JAMAI_PROJECT_ID,
});

export const actions = {
default: async ({ request }) => {

type DTypes = "float" | "int" | "bool" | "str" | undefined;

const data = await request.formData();
const tableId = data.get("table_id")?.toString();
const columnName = data.get("column_name")?.toString();
const columnDType = data.get("column_d_type")?.toString() as DTypes;

console.log("data: ", data);
try {
const response = await jamai.table.createActionTable({
id: tableId!,
cols: [{ id: columnName!, dtype: columnDType! }],
});

return { success: true, data: response };
} catch (error) {
console.error(error);
fail(500, { message: "Something went wrong!" });
}
},
};
  1. Start the app
npm run dev

Nuxt

  1. Setup Nuxt Project
npx nuxi init jamai-example-app
cd jamai-example-app
npm install
  1. Install JamAI
npm i jamaibase
  1. Collect the secrets:
  1. Create .env file at the root of your project and add the keys:
PUBLIC_JAMAI_BASEURL=http://api.jamaibase.com/
JAMAI_API_KEY=your_jamai_sk_api_key
JAMAI_PROJECT_ID=your_proj_id
  1. In the nuxt.config.ts file, add runtimeConfig to use the environment variables:
runtimeConfig: {
JAMAI_API_KEY: process.env.JAMAI_API_KEY,
public: {
JAMAI_BASEURL: process.env.JAMAI_BASEURL,
JAMAI_PROJECT_ID: process.env.JAMAI_PROJECT_ID,
},
},
  1. create a new file /pages/index.vue and add the following code:
<template>
<main>
<div class="container">
<label>Choose Table Type:</label>
<select v-model="tableType" @change="fetchTables">
<option value="action">Action</option>
<option value="chat">Chat</option>
<option value="knowledge">Knowledge</option>
</select>
</div>

<div class="container">
<h1>List of Tables</h1>
<table>
<thead>
<tr>
<th>Table ID</th>
<th>Columns</th>
<th>Column Type</th>
<th>Number of Rows</th>
</tr>
</thead>
<tbody>
<tr v-for="table in tableData.items" :key="table.id">
<td>{{ table.id }}</td>
<td>
<ul>
<li v-for="column in table.cols" :key="column.id">{{ column.id }}: {{ column.dtype }}</li>
</ul>
</td>
<td>
<ul>
<li v-for="column in table.cols" :key="column.id">{{ column.gen_config ? "Output" : "Input" }}</li>
</ul>
</td>
<td>{{ table.num_rows }}</td>
</tr>
</tbody>
</table>
</div>
</main>
</template>

<script setup>
import { ref, onMounted } from "vue";

const tableType = ref("action");
const tableData = ref({ items: [] });

async function fetchTables() {
const response = await $fetch(`/api/list-tables?type=${tableType.value}`);

if (response.success) {
tableData.value = response.data;
} else {
console.error("Failed to fetch data");
}
}

onMounted(() => {
fetchTables();
});
</script>
  1. Add the following CSS to make the table look better:

<style scoped>
/* Main layout styling */
main {
display: flex;
flex-direction: column;
min-height: 100vh;
padding: 24px;
}

/* Container styling */
.container {
max-width: 600px;
margin: 40px auto;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

/* Label and select input styling */
label {
display: block;
margin-bottom: 8px;
font-size: 14px;
font-weight: 500;
color: #333;
}

select {
display: block;
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
background-color: #fff;
margin-bottom: 20px;
font-size: 14px;
}

/* Table styling */
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}

th,
td {
padding: 12px;
border: 1px solid #ddd;
text-align: left;
}

th {
background-color: #f4f4f4;
font-weight: 600;
}

tr:nth-child(even) {
background-color: #f9f9f9;
}

tr:hover {
background-color: #f1f1f1;
}

/* Responsive styling */
@media (max-width: 600px) {
.container {
padding: 10px;
}

table,
th,
td {
font-size: 12px;
}

th,
td {
padding: 8px;
}
}
</style>
  1. create a server handler at server/api/list-tables.js and add the following code:
import JamAI from "jamaibase";

const {
JAMAI_API_KEY,
public: { JAMAI_BASEURL, JAMAI_PROJECT_ID }
} = useRuntimeConfig();

const jamai = new JamAI({
baseURL: JAMAI_BASEURL,
apiKey: JAMAI_API_KEY,
projectId: JAMAI_PROJECT_ID
});

export default defineEventHandler(async (event) => {
const { type = "action" } = getQuery(event);

try {
const data = await jamai.table.listTables({ table_type: type });
return { success: true, data: data };
} catch (error) {
console.error("Error fetching tables:", error);
return { success: false, data: "Something went wrong" };
}
});
  1. Now, create another page (server/api/create-table.js) to create new action table:
<template>
<main>
<h1>Create Action Table</h1>

<div v-if="form.success">
<p>Successfully created the table.</p>
</div>
<div v-else-if="form.error">
<p>Sorry, something went wrong!</p>
</div>

<form @submit.prevent="submitForm">
<label>
Table ID
<input v-model="tableId" />
</label>
<label>
Column Name
<input v-model="columnName" />
</label>
<label>
Column Data Type
<select v-model="columnDType">
<option value="str">str</option>
<option value="int">int</option>
<option value="float">float</option>
<option value="bool">bool</option>
</select>
</label>
<button type="submit">Create</button>
</form>
</main>
</template>

<script setup>
import { ref } from "vue";
import { useRouter } from "vue-router";

const tableId = ref("");
const columnName = ref("");
const columnDType = ref("str");
const form = ref({ success: false, error: false });
const router = useRouter();

async function submitForm() {
const { data } = useFetch("/api/create-table", {
method: "post",
headers: {
"Content-Type": "application/json"
},
body: {
table_id: tableId.value,
column_name: columnName.value,
column_d_type: columnDType.value
}
});

if (data.value?.success) {
form.value.success = true;
form.value.error = false;
} else {
form.value.success = false;
form.value.error = true;
}
}
</script>
  1. Create a server handler at server/api/create-table.js to accept the request and create a new table:
import JamAI from "jamaibase";

const {
JAMAI_API_KEY,
public: { JAMAI_BASEURL, JAMAI_PROJECT_ID }
} = useRuntimeConfig();

const jamai = new JamAI({
baseURL: JAMAI_BASEURL,
apiKey: JAMAI_API_KEY,
projectId: JAMAI_PROJECT_ID
});

export default defineEventHandler(async (event) => {
const { table_id, column_name, column_d_type } = await readBody(event);

try {
const response = await jamai.table.createActionTable({
id: table_id,
cols: [{ id: column_name, dtype: column_d_type }]
});

return { success: true, data: response };
} catch (error) {
console.error("error: ", error.response);
return { success: false, message: "Something went wrong!" };
}
});
  1. Finally, create a defalut layout (layouts/defalut.vue) to navigate between pages:
<template>
<div>
<nav>
<ul>
<li><NuxtLink to="/">Home</NuxtLink></li>
<li><NuxtLink to="/create-table">Create Table</NuxtLink></li>
</ul>
</nav>
<slot />
</div>
</template>

<script setup></script>

<style scoped>
nav {
background-color: #f8f9fa;
padding: 10px;
}

nav ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
gap: 20px;
}

nav ul li {
display: inline;
}

nav a {
text-decoration: none;
color: #007bff;
}

nav a:hover {
text-decoration: underline;
}
</style>
  1. Start the app
npm run dev