mirror of
https://github.com/run-llama/LlamaIndexTS.git
synced 2026-07-01 22:14:03 -04:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f86a7a4fa3 | |||
| 35430d3609 | |||
| 3c162b2b4a | |||
| 5bb4531245 | |||
| 2ff0a89891 | |||
| d57917d782 | |||
| f231e0739f | |||
| 0765742ef3 | |||
| ec7fd6be5c | |||
| c7a918c3f5 | |||
| 00e681d43b | |||
| c01502fb84 | |||
| 075f88dbc3 | |||
| cc47ee0602 | |||
| 5e6ef55a5a | |||
| 9c73f0a530 | |||
| 52a4d2b83d | |||
| 0fd78d5434 |
@@ -1,84 +0,0 @@
|
||||
const { join } = require("node:path");
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
"turbo",
|
||||
"prettier",
|
||||
"plugin:@typescript-eslint/recommended-type-checked-only",
|
||||
],
|
||||
parserOptions: {
|
||||
project: join(__dirname, "tsconfig.eslint.json"),
|
||||
__tsconfigRootDir: __dirname,
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: "999.999.999",
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"max-params": ["error", 4],
|
||||
"prefer-const": "error",
|
||||
"@typescript-eslint/no-floating-promises": [
|
||||
"error",
|
||||
{
|
||||
ignoreIIFE: true,
|
||||
},
|
||||
],
|
||||
"no-debugger": "error",
|
||||
"@typescript-eslint/await-thenable": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"no-array-constructor": "off",
|
||||
"@typescript-eslint/no-array-constructor": "off",
|
||||
"@typescript-eslint/no-base-to-string": [
|
||||
"error",
|
||||
{
|
||||
ignoredTypeNames: ["Error", "RegExp", "URL", "URLSearchParams"],
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-duplicate-enum-values": "off",
|
||||
"@typescript-eslint/no-duplicate-type-constituents": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-extra-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-for-in-array": "off",
|
||||
"no-implied-eval": "off",
|
||||
"@typescript-eslint/no-implied-eval": "off",
|
||||
"no-loss-of-precision": "off",
|
||||
"@typescript-eslint/no-loss-of-precision": "off",
|
||||
"@typescript-eslint/no-misused-new": "off",
|
||||
"@typescript-eslint/no-misused-promises": "off",
|
||||
"@typescript-eslint/no-namespace": "off",
|
||||
"@typescript-eslint/no-non-null-asserted-optional-chain": "off",
|
||||
"@typescript-eslint/no-redundant-type-constituents": "off",
|
||||
"@typescript-eslint/no-this-alias": "off",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "off",
|
||||
"@typescript-eslint/no-unnecessary-type-constraint": "off",
|
||||
"@typescript-eslint/no-unsafe-argument": "off",
|
||||
"@typescript-eslint/no-unsafe-assignment": "off",
|
||||
"@typescript-eslint/no-unsafe-call": "off",
|
||||
"@typescript-eslint/no-unsafe-declaration-merging": "off",
|
||||
"@typescript-eslint/no-unsafe-enum-comparison": "off",
|
||||
"@typescript-eslint/no-unsafe-member-access": "off",
|
||||
"@typescript-eslint/no-unsafe-return": "off",
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"@typescript-eslint/prefer-as-const": "off",
|
||||
"require-await": "off",
|
||||
"@typescript-eslint/require-await": "off",
|
||||
"@typescript-eslint/restrict-plus-operands": "off",
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
"@typescript-eslint/triple-slash-reference": "off",
|
||||
"@typescript-eslint/unbound-method": "off",
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["examples/**/*.ts"],
|
||||
rules: {
|
||||
"turbo/no-undeclared-env-vars": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
ignorePatterns: ["dist/", "lib/", "deps/"],
|
||||
};
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [18.x, 20.x, 22.x]
|
||||
node-version: [20.x, 22.x, 23.x]
|
||||
name: E2E on Node.js ${{ matrix.node-version }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [18.x, 20.x, 22.x]
|
||||
node-version: [20.x, 22.x, 23.x]
|
||||
name: Test on Node.js ${{ matrix.node-version }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -84,7 +84,9 @@ jobs:
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
- name: Use Build For Examples
|
||||
run: pnpm link ../packages/llamaindex/
|
||||
run: |
|
||||
pnpm link ../packages/llamaindex/
|
||||
cd readers && pnpm link ../../packages/llamaindex/
|
||||
working-directory: ./examples
|
||||
- name: Run Type Check
|
||||
run: pnpm run type-check
|
||||
|
||||
@@ -25,7 +25,7 @@ LlamaIndex.TS aims to be a lightweight, easy to use set of libraries to help you
|
||||
|
||||
LlamaIndex.TS supports multiple JS environments, including:
|
||||
|
||||
- Node.js (18, 20, 22) ✅
|
||||
- Node.js >= 20 ✅
|
||||
- Deno ✅
|
||||
- Bun ✅
|
||||
- Nitro ✅
|
||||
@@ -57,213 +57,9 @@ pnpm install llamaindex
|
||||
yarn add llamaindex
|
||||
```
|
||||
|
||||
### Setup TypeScript
|
||||
### Setup in Node.js, Deno, Bun, TypeScript...?
|
||||
|
||||
```json5
|
||||
{
|
||||
compilerOptions: {
|
||||
// ⬇️ add this line to your tsconfig.json
|
||||
moduleResolution: "bundler", // or "node16"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Why?</summary>
|
||||
We are shipping both ESM and CJS module, and compatible with Vercel Edge, Cloudflare Workers, and other serverless platforms.
|
||||
|
||||
So we are using [conditional exports](https://nodejs.org/api/packages.html#conditional-exports) to support all environments.
|
||||
|
||||
This is a kind of modern way of shipping packages, but might cause TypeScript type check to fail because of legacy module resolution.
|
||||
|
||||
Imaging you put output file into `/dist/openai.js` but you are importing `llamaindex/openai` in your code, and set `package.json` like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"exports": {
|
||||
"./openai": "./dist/openai.js"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In old module resolution, TypeScript will not be able to find the module because it is not follow the file structure, even you run `node index.js` successfully. (on Node.js >=16)
|
||||
|
||||
See more about [moduleResolution](https://www.typescriptlang.org/docs/handbook/modules/theory.html#module-resolution) or
|
||||
[TypeScript 5.0 blog](https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#--moduleresolution-bundler7).
|
||||
|
||||
</details>
|
||||
|
||||
### Node.js
|
||||
|
||||
```ts
|
||||
import fs from "node:fs/promises";
|
||||
import { Document, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load essay from abramov.txt in Node
|
||||
const essay = await fs.readFile(
|
||||
"node_modules/llamaindex/examples/abramov.txt",
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
// Create Document object with essay
|
||||
const document = new Document({ text: essay });
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query({
|
||||
query: "What did the author do in college?",
|
||||
});
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
```bash
|
||||
# `pnpm install tsx` before running the script
|
||||
node --import tsx ./main.ts
|
||||
```
|
||||
|
||||
### Next.js
|
||||
|
||||
You will need to add a llamaindex plugin to your Next.js project.
|
||||
|
||||
```js
|
||||
// next.config.js
|
||||
const withLlamaIndex = require("llamaindex/next");
|
||||
|
||||
module.exports = withLlamaIndex({
|
||||
// your next.js config
|
||||
});
|
||||
```
|
||||
|
||||
### React Server Actions
|
||||
|
||||
You can combine `ai` with `llamaindex` in Next.js, Waku or Redwood.js with RSC (React Server Components).
|
||||
|
||||
```tsx
|
||||
"use client";
|
||||
import { chatWithAgent } from "@/actions";
|
||||
import type { JSX } from "react";
|
||||
import { useActionState } from "react";
|
||||
|
||||
export default function Home() {
|
||||
const [ui, action] = useActionState<JSX.Element | null>(async () => {
|
||||
return chatWithAgent("hello!", []);
|
||||
}, null);
|
||||
return (
|
||||
<main>
|
||||
{ui}
|
||||
<form action={action}>
|
||||
<button>Chat</button>
|
||||
</form>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// src/actions/index.ts
|
||||
"use server";
|
||||
import { createStreamableUI } from "ai/rsc";
|
||||
import { OpenAIAgent } from "llamaindex";
|
||||
import type { ChatMessage } from "llamaindex/llm/types";
|
||||
|
||||
export async function chatWithAgent(
|
||||
question: string,
|
||||
prevMessages: ChatMessage[] = [],
|
||||
) {
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [
|
||||
// ... adding your tools here
|
||||
],
|
||||
});
|
||||
const responseStream = await agent.chat(
|
||||
{
|
||||
message: question,
|
||||
chatHistory: prevMessages,
|
||||
},
|
||||
true,
|
||||
);
|
||||
const uiStream = createStreamableUI(<div>loading...</div>);
|
||||
responseStream
|
||||
.pipeTo(
|
||||
new WritableStream({
|
||||
start: () => {
|
||||
uiStream.update("response:");
|
||||
},
|
||||
write: async (message) => {
|
||||
uiStream.append(message.response.delta);
|
||||
},
|
||||
}),
|
||||
)
|
||||
.catch(console.error);
|
||||
return uiStream.value;
|
||||
}
|
||||
```
|
||||
|
||||
### Cloudflare Workers
|
||||
|
||||
> [!TIP]
|
||||
> Some modules are not supported in Cloudflare Workers which require Node.js APIs.
|
||||
|
||||
```ts
|
||||
// add `OPENAI_API_KEY` to the `.dev.vars` file
|
||||
interface Env {
|
||||
OPENAI_API_KEY: string;
|
||||
}
|
||||
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Env,
|
||||
ctx: ExecutionContext,
|
||||
): Promise<Response> {
|
||||
const { OpenAIAgent, OpenAI } = await import("@llamaindex/openai");
|
||||
const text = await request.text();
|
||||
const agent = new OpenAIAgent({
|
||||
llm: new OpenAI({
|
||||
apiKey: env.OPENAI_API_KEY,
|
||||
}),
|
||||
tools: [],
|
||||
});
|
||||
const responseStream = await agent.chat({
|
||||
stream: true,
|
||||
message: text,
|
||||
});
|
||||
const textEncoder = new TextEncoder();
|
||||
const response = responseStream.pipeThrough<Uint8Array>(
|
||||
new TransformStream({
|
||||
transform: (chunk, controller) => {
|
||||
controller.enqueue(textEncoder.encode(chunk.delta));
|
||||
},
|
||||
}),
|
||||
);
|
||||
return new Response(response);
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Vite
|
||||
|
||||
We have some wasm dependencies for better performance. You can use `vite-plugin-wasm` to load them.
|
||||
|
||||
```ts
|
||||
import wasm from "vite-plugin-wasm";
|
||||
|
||||
export default {
|
||||
plugins: [wasm()],
|
||||
ssr: {
|
||||
external: ["tiktoken"],
|
||||
},
|
||||
};
|
||||
```
|
||||
See our official document: <https://ts.llamaindex.ai/docs/llamaindex/setup/getting-started>
|
||||
|
||||
### Tips when using in non-Node.js environments
|
||||
|
||||
|
||||
@@ -1,5 +1,37 @@
|
||||
# docs
|
||||
|
||||
## 0.0.108
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [35430d3]
|
||||
- llamaindex@0.8.4
|
||||
|
||||
## 0.0.107
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.8.3
|
||||
|
||||
## 0.0.106
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @llamaindex/examples@0.0.12
|
||||
|
||||
## 0.0.105
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c7a918c]
|
||||
- llamaindex@0.8.2
|
||||
|
||||
## 0.0.104
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.8.1
|
||||
|
||||
## 0.0.103
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @ts-check
|
||||
// Note: type annotations allow type checking and IDEs autocompletion
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const renderer = require("prism-react-renderer");
|
||||
const lightCodeTheme = renderer.themes.github;
|
||||
const darkCodeTheme = renderer.themes.dracula;
|
||||
@@ -39,6 +40,7 @@ const config = {
|
||||
// editUrl:
|
||||
// "https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/",
|
||||
remarkPlugins: [
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
[require("@docusaurus/remark-plugin-npm2yarn"), { sync: true }],
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "0.0.103",
|
||||
"version": "0.0.108",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
@@ -33,7 +33,7 @@
|
||||
"@docusaurus/theme-classic": "3.5.2",
|
||||
"@docusaurus/types": "3.5.2",
|
||||
"@tsconfig/docusaurus": "2.0.3",
|
||||
"@types/node": "^22.5.1",
|
||||
"@types/node": "^22.8.4",
|
||||
"docusaurus-plugin-typedoc": "1.0.5",
|
||||
"typedoc": "0.26.6",
|
||||
"typedoc-plugin-markdown": "4.2.6",
|
||||
@@ -52,6 +52,6 @@
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,16 +11,19 @@ type FeatureItem = {
|
||||
const FeatureList: FeatureItem[] = [
|
||||
{
|
||||
title: "Data Driven",
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
Svg: require("@site/static/img/undraw_docusaurus_mountain.svg").default,
|
||||
description: <>LlamaIndex.TS is all about using your data with LLMs.</>,
|
||||
},
|
||||
{
|
||||
title: "Typescript Native",
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
Svg: require("@site/static/img/undraw_docusaurus_tree.svg").default,
|
||||
description: <>We ❤️ Typescript, and so do our users.</>,
|
||||
},
|
||||
{
|
||||
title: "Built by the Community",
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
Svg: require("@site/static/img/undraw_docusaurus_react.svg").default,
|
||||
description: (
|
||||
<>
|
||||
|
||||
@@ -29,3 +29,4 @@ next-env.d.ts
|
||||
|
||||
# build
|
||||
/src/content/docs/cloud/api
|
||||
./types
|
||||
|
||||
@@ -1,5 +1,46 @@
|
||||
# @llamaindex/doc
|
||||
|
||||
## 0.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [35430d3]
|
||||
- llamaindex@0.8.4
|
||||
- @llamaindex/readers@1.0.2
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2ff0a89]
|
||||
- @llamaindex/node-parser@0.0.2
|
||||
- llamaindex@0.8.3
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [0765742]
|
||||
- @llamaindex/workflow@0.0.2
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c7a918c]
|
||||
- llamaindex@0.8.2
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [9c73f0a]
|
||||
- @llamaindex/core@0.4.1
|
||||
- @llamaindex/cloud@2.0.1
|
||||
- llamaindex@0.8.1
|
||||
- @llamaindex/openai@0.1.26
|
||||
- @llamaindex/readers@1.0.1
|
||||
|
||||
## 0.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,10 +1,33 @@
|
||||
import { createMDX } from "fumadocs-mdx/next";
|
||||
|
||||
import MonacoWebpackPlugin from "monaco-editor-webpack-plugin";
|
||||
const withMDX = createMDX();
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const config = {
|
||||
reactStrictMode: true,
|
||||
transpilePackages: ["monaco-editor"],
|
||||
webpack: (config, { isServer }) => {
|
||||
if (Array.isArray(config.target) && config.target.includes("web")) {
|
||||
config.target = ["web", "es2020"];
|
||||
}
|
||||
|
||||
config.resolve.alias = {
|
||||
...config.resolve.alias,
|
||||
sharp$: false,
|
||||
"onnxruntime-node$": false,
|
||||
};
|
||||
config.resolve.fallback ??= {};
|
||||
config.resolve.fallback.fs = false;
|
||||
if (!isServer) {
|
||||
config.plugins.push(
|
||||
new MonacoWebpackPlugin({
|
||||
languages: ["typescript"],
|
||||
filename: "static/[name].worker.js",
|
||||
}),
|
||||
);
|
||||
}
|
||||
return config;
|
||||
},
|
||||
};
|
||||
|
||||
export default withMDX(config);
|
||||
|
||||
+37
-16
@@ -1,65 +1,86 @@
|
||||
{
|
||||
"name": "@llamaindex/doc",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.6",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "pnpm run build:docs && next build",
|
||||
"dev": "next dev",
|
||||
"start": "next start",
|
||||
"postdev": "fumadocs-mdx",
|
||||
"postbuild": "fumadocs-mdx",
|
||||
"postbuild": "fumadocs-mdx && tsx scripts/post-build.mts",
|
||||
"build:docs": "node ./scripts/generate-docs.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@icons-pack/react-simple-icons": "^10.1.0",
|
||||
"@llamaindex/cloud": "workspace:*",
|
||||
"@llamaindex/core": "workspace:*",
|
||||
"@llamaindex/node-parser": "workspace:*",
|
||||
"@llamaindex/openai": "workspace:*",
|
||||
"@llamaindex/readers": "workspace:*",
|
||||
"@llamaindex/workflow": "workspace:*",
|
||||
"@mdx-js/mdx": "^3.1.0",
|
||||
"@number-flow/react": "^0.3.0",
|
||||
"@radix-ui/react-dialog": "^1.1.2",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-icons": "^1.3.1",
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-slider": "^1.2.1",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@radix-ui/react-tooltip": "^1.1.3",
|
||||
"ai": "^3.3.21",
|
||||
"@vercel/functions": "^1.5.0",
|
||||
"ai": "^3.4.31",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "2.1.1",
|
||||
"foxact": "^0.2.39",
|
||||
"framer-motion": "^11.11.10",
|
||||
"fumadocs-core": "14.0.2",
|
||||
"fumadocs-docgen": "^1.3.0",
|
||||
"fumadocs-mdx": "11.0.0",
|
||||
"fumadocs-openapi": "^5.5.3",
|
||||
"fumadocs-twoslash": "^2.0.0",
|
||||
"fumadocs-ui": "14.0.2",
|
||||
"foxact": "^0.2.40",
|
||||
"framer-motion": "^11.11.11",
|
||||
"fumadocs-core": "14.2.0",
|
||||
"fumadocs-docgen": "^1.3.1",
|
||||
"fumadocs-mdx": "^11.1.1",
|
||||
"fumadocs-openapi": "^5.5.6",
|
||||
"fumadocs-twoslash": "^2.0.1",
|
||||
"fumadocs-typescript": "^3.0.1",
|
||||
"fumadocs-ui": "14.2.0",
|
||||
"hast-util-to-jsx-runtime": "^2.3.2",
|
||||
"llamaindex": "workspace:*",
|
||||
"lucide-react": "^0.436.0",
|
||||
"next": "15.0.1",
|
||||
"lucide-react": "^0.454.0",
|
||||
"next": "15.0.2",
|
||||
"next-themes": "^0.3.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-icons": "^5.3.0",
|
||||
"react-monaco-editor": "^0.56.2",
|
||||
"react-text-transition": "^3.1.0",
|
||||
"react-use-measure": "^2.1.1",
|
||||
"rehype-katex": "^7.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"rimraf": "^6.0.1",
|
||||
"shiki": "^1.22.0",
|
||||
"shiki": "^1.22.2",
|
||||
"shiki-magic-move": "^0.5.0",
|
||||
"swr": "^2.2.5",
|
||||
"tailwind-merge": "^2.5.2",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tree-sitter": "^0.22.0",
|
||||
"tree-sitter-typescript": "^0.23.0",
|
||||
"use-stick-to-bottom": "^1.0.41",
|
||||
"web-tree-sitter": "^0.24.3",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/env": "^15.0.2",
|
||||
"@types/mdx": "^2.0.13",
|
||||
"@types/node": "22.7.8",
|
||||
"@types/node": "22.8.6",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"fast-glob": "^3.3.2",
|
||||
"gray-matter": "^4.0.3",
|
||||
"monaco-editor-webpack-plugin": "^7.1.0",
|
||||
"postcss": "^8.4.47",
|
||||
"remark": "^15.0.1",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-mdx": "^3.1.0",
|
||||
"remark-stringify": "^11.0.0",
|
||||
"tailwindcss": "^3.4.14",
|
||||
"tsx": "^4.19.2",
|
||||
"typescript": "^5.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
import env from "@next/env";
|
||||
|
||||
import { updateLlamaCloud } from "./update-llamacloud.mjs";
|
||||
|
||||
env.loadEnvConfig(process.cwd());
|
||||
|
||||
await updateLlamaCloud();
|
||||
@@ -0,0 +1,110 @@
|
||||
import { PipelinesService } from "@llamaindex/cloud/api";
|
||||
import fg from "fast-glob";
|
||||
import {
|
||||
fileGenerator,
|
||||
remarkDocGen,
|
||||
remarkInstall,
|
||||
typescriptGenerator,
|
||||
} from "fumadocs-docgen";
|
||||
import matter from "gray-matter";
|
||||
import * as fs from "node:fs/promises";
|
||||
import path, { relative } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { remark } from "remark";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkMdx from "remark-mdx";
|
||||
import remarkStringify from "remark-stringify";
|
||||
|
||||
const baseDir = fileURLToPath(new URL("../src/content", import.meta.url));
|
||||
|
||||
async function processContent(content: string): Promise<string> {
|
||||
const file = await remark()
|
||||
.use(remarkMdx)
|
||||
.use(remarkGfm)
|
||||
.use(remarkDocGen, { generators: [typescriptGenerator(), fileGenerator()] })
|
||||
.use(remarkInstall, { persist: { id: "package-manager" } })
|
||||
.use(remarkStringify)
|
||||
.process(content);
|
||||
|
||||
return String(file);
|
||||
}
|
||||
|
||||
export async function updateLlamaCloud(): Promise<void> {
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
const apiKey = process.env.LLAMA_CLOUD_API_KEY;
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
const index = process.env.LLAMA_CLOUD_PIPELINE_ID;
|
||||
|
||||
if (!apiKey || !index) {
|
||||
console.log("no api key for LlamaCloud found, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
const files = await fg([
|
||||
"./src/content/docs/**/*.mdx",
|
||||
"!./src/content/docs/cloud/api/**/*",
|
||||
]);
|
||||
|
||||
const records: {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
content: string;
|
||||
category: string | undefined;
|
||||
}[] = [];
|
||||
|
||||
console.log("processing documents for AI");
|
||||
const scan = files.map(async (file) => {
|
||||
const fileContent = await fs.readFile(file);
|
||||
const { content, data } = matter(fileContent.toString());
|
||||
|
||||
const dir = path.dirname(file).split(path.sep).at(3);
|
||||
const category = {
|
||||
cloud: "LlamaCloud",
|
||||
llamaindex: "LlamaIndex.TS",
|
||||
}[dir ?? ""];
|
||||
|
||||
if (data._mdx?.mirror) {
|
||||
return;
|
||||
}
|
||||
|
||||
const processed = await processContent(content);
|
||||
const id = relative(baseDir, file);
|
||||
records.push({
|
||||
id,
|
||||
title: data.title as string,
|
||||
description: data.description as string,
|
||||
content: processed,
|
||||
category,
|
||||
});
|
||||
});
|
||||
|
||||
await Promise.all(scan);
|
||||
|
||||
console.log(`added ${records.length} records`);
|
||||
|
||||
await PipelinesService.upsertBatchPipelineDocumentsApiV1PipelinesPipelineIdDocumentsPut(
|
||||
{
|
||||
baseUrl: "https://api.cloud.llamaindex.ai/",
|
||||
body: records.map((record) => ({
|
||||
id: record.id,
|
||||
metadata: {
|
||||
title: record.title,
|
||||
description: record.description,
|
||||
documentUrl: record.id,
|
||||
category: record.category,
|
||||
},
|
||||
text: record.content,
|
||||
})),
|
||||
path: {
|
||||
pipeline_id: index,
|
||||
},
|
||||
throwOnError: true,
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
console.log("done");
|
||||
}
|
||||
@@ -1,15 +1,10 @@
|
||||
import { PipelinesService } from "@llamaindex/cloud/api";
|
||||
import { rehypeCodeDefaultOptions } from "fumadocs-core/mdx-plugins";
|
||||
import { fileGenerator, remarkDocGen, remarkInstall } from "fumadocs-docgen";
|
||||
import { defineConfig, defineDocs } from "fumadocs-mdx/config";
|
||||
import { transformerTwoslash } from "fumadocs-twoslash";
|
||||
import { relative } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import remarkMath from "remark-math";
|
||||
|
||||
const baseDir = fileURLToPath(new URL("../src/content", import.meta.url));
|
||||
|
||||
export const { docs, meta } = defineDocs({
|
||||
dir: "./src/content/docs",
|
||||
});
|
||||
@@ -49,68 +44,6 @@ export default defineConfig({
|
||||
remarkMath,
|
||||
[remarkInstall, { persist: { id: "package-manager" } }],
|
||||
[remarkDocGen, { generators: [fileGenerator()] }],
|
||||
() => {
|
||||
return (_, file, next) => {
|
||||
const metadata = file.data.frontmatter as Record<string, unknown>;
|
||||
const title = metadata.title as string;
|
||||
const description = metadata.description as string;
|
||||
let content: string;
|
||||
if (file.value instanceof Uint8Array) {
|
||||
content = file.value.toString();
|
||||
} else {
|
||||
content = file.value;
|
||||
}
|
||||
if (file.path.includes("content/docs/cloud/api")) {
|
||||
// skip cloud api docs
|
||||
return next();
|
||||
}
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
// skip development
|
||||
return next();
|
||||
}
|
||||
if (!title || !description) {
|
||||
throw new Error(`Missing title or description in ${file.path}`);
|
||||
}
|
||||
const id = relative(baseDir, file.path);
|
||||
|
||||
if (
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
process.env.LLAMA_CLOUD_UPSERT_PIPELINE_DOCUMENTS === "true" &&
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
process.env.LLAMA_CLOUD_PIPELINE_ID !== undefined
|
||||
) {
|
||||
PipelinesService.upsertBatchPipelineDocumentsApiV1PipelinesPipelineIdDocumentsPut(
|
||||
{
|
||||
baseUrl: "https://api.cloud.llamaindex.ai/",
|
||||
body: [
|
||||
{
|
||||
metadata: {
|
||||
title,
|
||||
description,
|
||||
documentUrl: id,
|
||||
},
|
||||
text: content,
|
||||
id,
|
||||
},
|
||||
],
|
||||
path: {
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
pipeline_id: process.env.LLAMA_CLOUD_PIPELINE_ID,
|
||||
},
|
||||
throwOnError: true,
|
||||
headers: {
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
Authorization: `Bearer ${process.env.LLAMA_CLOUD_API_KEY}`,
|
||||
},
|
||||
},
|
||||
).catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
return next();
|
||||
};
|
||||
},
|
||||
],
|
||||
rehypePlugins: (v) => [rehypeKatex, ...v],
|
||||
},
|
||||
|
||||
@@ -14,10 +14,9 @@ Settings.llm = new OpenAI({
|
||||
});
|
||||
|
||||
const retriever = new LlamaCloudRetriever({
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
apiKey: process.env.LLAMA_CLOUD_API_KEY!,
|
||||
baseUrl: "https://api.cloud.llamaindex.ai/",
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
|
||||
pipelineId: process.env.LLAMA_CLOUD_PIPELINE_ID!,
|
||||
});
|
||||
|
||||
@@ -27,7 +26,7 @@ const initialAIState = {
|
||||
messages: ChatMessage[];
|
||||
};
|
||||
|
||||
type UIMessage = {
|
||||
export type UIMessage = {
|
||||
id: number;
|
||||
display: ReactNode;
|
||||
};
|
||||
@@ -38,6 +37,7 @@ const initialUIState = {
|
||||
messages: UIMessage[];
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const runAsyncFnWithoutBlocking = (fn: (...args: any) => Promise<any>) => {
|
||||
fn().catch((error) => {
|
||||
console.error(error);
|
||||
|
||||
@@ -11,7 +11,7 @@ import { NpmInstall } from "@/components/npm-install";
|
||||
import { TextEffect } from "@/components/text-effect";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { DOCUMENT_URL } from "@/lib/const";
|
||||
import { LEGACY_DOCUMENT_URL } from "@/lib/const";
|
||||
import { SiStackblitz } from "@icons-pack/react-simple-icons";
|
||||
import {
|
||||
CodeBlock as FumaCodeBlock,
|
||||
@@ -38,7 +38,7 @@ export default function HomePage() {
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap justify-center gap-4">
|
||||
<Link href={DOCUMENT_URL}>
|
||||
<Link href={LEGACY_DOCUMENT_URL}>
|
||||
<Button variant="outline">Get Started</Button>
|
||||
</Link>
|
||||
<NpmInstall />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DOCUMENT_URL } from "@/lib/const";
|
||||
import { LEGACY_DOCUMENT_URL } from "@/lib/const";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default async function Page(props: {
|
||||
@@ -7,5 +7,5 @@ export default async function Page(props: {
|
||||
}>;
|
||||
}) {
|
||||
const path = await props.params.then(({ any }) => any.join("/"));
|
||||
return redirect(new URL(path, DOCUMENT_URL).toString());
|
||||
return redirect(new URL(path, LEGACY_DOCUMENT_URL).toString());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createMetadata, metadataImage } from "@/lib/metadata";
|
||||
import { openapi, source } from "@/lib/source";
|
||||
import { Popup, PopupContent, PopupTrigger } from "fumadocs-twoslash/ui";
|
||||
import { createTypeTable } from "fumadocs-typescript/ui";
|
||||
import defaultMdxComponents from "fumadocs-ui/mdx";
|
||||
import {
|
||||
DocsBody,
|
||||
@@ -10,6 +11,8 @@ import {
|
||||
} from "fumadocs-ui/page";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
const { AutoTypeTable } = createTypeTable();
|
||||
|
||||
export default async function Page(props: {
|
||||
params: Promise<{ slug?: string[] }>;
|
||||
}) {
|
||||
@@ -20,7 +23,16 @@ export default async function Page(props: {
|
||||
const MDX = page.data.body;
|
||||
|
||||
return (
|
||||
<DocsPage toc={page.data.toc} full={page.data.full}>
|
||||
<DocsPage
|
||||
toc={page.data.toc}
|
||||
full={page.data.full}
|
||||
editOnGithub={{
|
||||
owner: "run-llama",
|
||||
repo: "LlamaIndexTS",
|
||||
sha: "main",
|
||||
path: `apps/next/src/content/docs/${page.file.path}`,
|
||||
}}
|
||||
>
|
||||
<DocsTitle>{page.data.title}</DocsTitle>
|
||||
<DocsDescription>{page.data.description}</DocsDescription>
|
||||
<DocsBody>
|
||||
@@ -31,6 +43,7 @@ export default async function Page(props: {
|
||||
Popup,
|
||||
PopupContent,
|
||||
PopupTrigger,
|
||||
AutoTypeTable,
|
||||
}}
|
||||
/>
|
||||
</DocsBody>
|
||||
|
||||
@@ -1,38 +1,54 @@
|
||||
import { baseOptions } from "@/app/layout.config";
|
||||
import { AITrigger } from "@/components/ai-chat";
|
||||
import { buttonVariants } from "@/components/ui/button";
|
||||
import { LEGACY_DOCUMENT_URL } from "@/lib/const";
|
||||
import { source } from "@/lib/source";
|
||||
import { cn } from "@/lib/utils";
|
||||
import "fumadocs-twoslash/twoslash.css";
|
||||
import { Banner } from "fumadocs-ui/components/banner";
|
||||
import { DocsLayout } from "fumadocs-ui/layouts/docs";
|
||||
import { MessageCircle } from "lucide-react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<DocsLayout
|
||||
tree={source.pageTree}
|
||||
{...baseOptions}
|
||||
nav={{
|
||||
...baseOptions.nav,
|
||||
children: (
|
||||
<AITrigger
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
variant: "secondary",
|
||||
size: "xs",
|
||||
className:
|
||||
"md:flex-1 px-2 ms-2 gap-1.5 text-fd-muted-foreground rounded-full",
|
||||
}),
|
||||
)}
|
||||
>
|
||||
<MessageCircle className="size-3" />
|
||||
Ask LlamaCloud
|
||||
</AITrigger>
|
||||
),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</DocsLayout>
|
||||
<>
|
||||
<Banner variant="rainbow" id="welcome">
|
||||
Welcome to the new LlamaIndex.TS documentation! 🎉 If you are looking
|
||||
for the old documentation
|
||||
<a
|
||||
className="underline text-blue-500 ml-1"
|
||||
target="_blank"
|
||||
href={LEGACY_DOCUMENT_URL}
|
||||
>
|
||||
check it here
|
||||
</a>
|
||||
.
|
||||
</Banner>
|
||||
<DocsLayout
|
||||
tree={source.pageTree}
|
||||
{...baseOptions}
|
||||
nav={{
|
||||
...baseOptions.nav,
|
||||
children: (
|
||||
<AITrigger
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
variant: "secondary",
|
||||
size: "xs",
|
||||
className:
|
||||
"md:flex-1 px-2 ms-2 gap-1.5 text-fd-muted-foreground rounded-full",
|
||||
}),
|
||||
)}
|
||||
>
|
||||
<MessageCircle className="size-3" />
|
||||
Ask LlamaCloud
|
||||
</AITrigger>
|
||||
),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</DocsLayout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DOCUMENT_URL } from "@/lib/const";
|
||||
import { LEGACY_DOCUMENT_URL } from "@/lib/const";
|
||||
import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared";
|
||||
import Image from "next/image";
|
||||
|
||||
@@ -27,8 +27,8 @@ export const baseOptions: BaseLayoutProps = {
|
||||
githubUrl: "https://github.com/run-llama/LlamaIndexTS",
|
||||
links: [
|
||||
{
|
||||
text: "Documentation",
|
||||
url: DOCUMENT_URL,
|
||||
text: "Docs",
|
||||
url: LEGACY_DOCUMENT_URL,
|
||||
active: "nested-url",
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"use client";
|
||||
import type { AIProvider } from "@/actions";
|
||||
import type { AIProvider, UIMessage } from "@/actions";
|
||||
import { UserMessage } from "@/components/message";
|
||||
import { useActions, useUIState } from "ai/rsc";
|
||||
import { Info } from "lucide-react";
|
||||
@@ -21,7 +21,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
||||
|
||||
type AITriggerProps = ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
function ChatList({ messages }: { messages: any[] }) {
|
||||
function ChatList({ messages }: { messages: UIMessage[] }) {
|
||||
if (messages.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
"use client";
|
||||
import { createContextState } from "foxact/context-state";
|
||||
import { useIsClient } from "foxact/use-is-client";
|
||||
import { useShiki } from "fumadocs-core/utils/use-shiki";
|
||||
import { CodeBlock, Pre } from "fumadocs-ui/components/codeblock";
|
||||
import { lazy, Suspense, use, useMemo } from "react";
|
||||
import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
|
||||
import Parser from "web-tree-sitter";
|
||||
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Slider } from "@/components/ui/slider";
|
||||
import { CodeSplitter } from "@llamaindex/node-parser/code";
|
||||
|
||||
let promise: Promise<CodeSplitter>;
|
||||
if (typeof window !== "undefined") {
|
||||
promise = Parser.init({
|
||||
locateFile(scriptName: string) {
|
||||
return "/" + scriptName;
|
||||
},
|
||||
}).then(async () => {
|
||||
const parser = new Parser();
|
||||
const Lang = await Parser.Language.load("/tree-sitter-typescript.wasm");
|
||||
parser.setLanguage(Lang);
|
||||
return new CodeSplitter({
|
||||
getParser: () => parser,
|
||||
maxChars: 100,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const [SliderProvider, useSlider, useSetSlider] = createContextState(100);
|
||||
|
||||
const [CodeProvider, useCode, useSetCode] =
|
||||
createContextState(`interface Person {
|
||||
name: string;
|
||||
age: number;
|
||||
}
|
||||
|
||||
function greet(person: Person): string {
|
||||
return \`Hello, \${person.name}! You are \${person.age} years old.\`;
|
||||
}
|
||||
|
||||
const john: Person = {
|
||||
name: "John Doe",
|
||||
age: 30
|
||||
};
|
||||
|
||||
console.log(greet(john));`);
|
||||
|
||||
const Editor = lazy(() => import("react-monaco-editor"));
|
||||
|
||||
export const IDE = () => {
|
||||
const codeSplitter = use(promise);
|
||||
const code = useCode();
|
||||
const setCode = useSetCode();
|
||||
const maxChars = useSlider();
|
||||
const useSetMaxChars = useSetSlider();
|
||||
return (
|
||||
<div className="flex flex-col p-4 border-r max-h-96 overflow-scroll">
|
||||
<div>
|
||||
<Label>Max Chars {maxChars}</Label>
|
||||
<Slider
|
||||
className="my-4"
|
||||
min={10}
|
||||
max={300}
|
||||
step={10}
|
||||
value={[maxChars]}
|
||||
onValueChange={(value) => {
|
||||
useSetMaxChars(value[0]);
|
||||
codeSplitter.maxChars = value[0];
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Editor
|
||||
editorWillMount={() => {}}
|
||||
editorDidMount={() => {
|
||||
window.MonacoEnvironment!.getWorkerUrl = (
|
||||
_moduleId: string,
|
||||
label: string,
|
||||
) => {
|
||||
if (label === "json") return "/_next/static/json.worker.js";
|
||||
if (label === "css") return "/_next/static/css.worker.js";
|
||||
if (label === "html") return "/_next/static/html.worker.js";
|
||||
if (label === "typescript" || label === "javascript")
|
||||
return "/_next/static/ts.worker.js";
|
||||
return "/_next/static/editor.worker.js";
|
||||
};
|
||||
}}
|
||||
editorWillUnmount={() => {}}
|
||||
options={{
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
}}
|
||||
theme="vs-dark"
|
||||
height="100%"
|
||||
width="100%"
|
||||
language="typescript"
|
||||
onChange={setCode}
|
||||
value={code}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Preview = ({ text }: { text: string }) => {
|
||||
const rendered = useShiki(text, {
|
||||
lang: "ts",
|
||||
components: {
|
||||
pre: (props) => {
|
||||
return <Pre {...props}>{props.children}</Pre>;
|
||||
},
|
||||
},
|
||||
});
|
||||
return <CodeBlock className="py-0 m-2">{rendered}</CodeBlock>;
|
||||
};
|
||||
|
||||
function ScrollToBottom() {
|
||||
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
||||
|
||||
return (
|
||||
!isAtBottom && (
|
||||
<button
|
||||
className="absolute i-ph-arrow-circle-down-fill text-4xl rounded-lg left-[50%] translate-x-[-50%] bottom-0"
|
||||
onClick={() => scrollToBottom()}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export const NodePreview = () => {
|
||||
const parser = use(promise);
|
||||
const code = useCode();
|
||||
const maxChars = useSlider();
|
||||
const textChunks = useMemo(() => parser.splitText(code), [code, maxChars]);
|
||||
return (
|
||||
<StickToBottom
|
||||
className="block relative max-h-96 overflow-scroll"
|
||||
resize="smooth"
|
||||
initial="smooth"
|
||||
>
|
||||
<StickToBottom.Content>
|
||||
{textChunks.map((chunk, i) => (
|
||||
<Preview key={i} text={chunk} />
|
||||
))}
|
||||
</StickToBottom.Content>
|
||||
<ScrollToBottom />
|
||||
</StickToBottom>
|
||||
);
|
||||
};
|
||||
|
||||
export const CodeNodeParserDemo = () => {
|
||||
const isClient = useIsClient();
|
||||
if (!isClient) {
|
||||
return (
|
||||
<div className="my-2 grid grid-cols-1 md:grid-cols-2 gap-2 border rounded-xl w-full max-h-96">
|
||||
<Skeleton className="h-96" />
|
||||
<Skeleton className="h-96" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<SliderProvider>
|
||||
<CodeProvider>
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="my-2 grid grid-cols-1 md:grid-cols-2 gap-2 border rounded-xl w-full max-h-96">
|
||||
<Skeleton className="h-96" />
|
||||
<Skeleton className="h-96" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="my-2 grid grid-cols-1 md:grid-cols-2 gap-2 border rounded-xl w-full max-h-96">
|
||||
<IDE />
|
||||
<NodePreview />
|
||||
</div>
|
||||
</Suspense>
|
||||
</CodeProvider>
|
||||
</SliderProvider>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,152 @@
|
||||
"use client";
|
||||
import FlowInput from "@/components/flow-input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
StartEvent,
|
||||
StopEvent,
|
||||
Workflow,
|
||||
WorkflowEvent,
|
||||
} from "@llamaindex/workflow";
|
||||
import { ReactNode, startTransition, useState } from "react";
|
||||
import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
|
||||
|
||||
class ComputeEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class ComputeResultEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
type ContextData = {
|
||||
sum: number;
|
||||
};
|
||||
|
||||
const workflow = new Workflow<ContextData, number, number>();
|
||||
|
||||
const max = 1000;
|
||||
const min = 100;
|
||||
|
||||
workflow.addStep(
|
||||
{
|
||||
inputs: [StartEvent<number>],
|
||||
outputs: [StopEvent<number>],
|
||||
},
|
||||
async (context, event) => {
|
||||
const total = event.data;
|
||||
for (let i = 0; i < total; i++) {
|
||||
context.sendEvent(new ComputeEvent(i));
|
||||
}
|
||||
console.log("waiting");
|
||||
const computeResults = await Promise.all(
|
||||
Array.from({ length: total }).map(() =>
|
||||
context.requireEvent(ComputeResultEvent),
|
||||
),
|
||||
);
|
||||
context.data.sum = computeResults.reduce(
|
||||
(acc, result) => acc + result.data,
|
||||
0,
|
||||
);
|
||||
console.log("stop");
|
||||
return new StopEvent(context.data.sum);
|
||||
},
|
||||
);
|
||||
|
||||
workflow.addStep(
|
||||
{
|
||||
inputs: [ComputeEvent],
|
||||
outputs: [ComputeResultEvent],
|
||||
},
|
||||
async (context, event) => {
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, Math.floor(Math.random() * (max - min + 1) + min)),
|
||||
);
|
||||
return new ComputeResultEvent(event.data);
|
||||
},
|
||||
);
|
||||
|
||||
function ScrollToBottom() {
|
||||
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
||||
|
||||
return (
|
||||
!isAtBottom && (
|
||||
<button
|
||||
className="absolute i-ph-arrow-circle-down-fill text-4xl rounded-lg left-[50%] translate-x-[-50%] bottom-0"
|
||||
onClick={() => scrollToBottom()}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function WorkflowStreamingDemo() {
|
||||
const [ui, setUI] = useState<ReactNode[]>([
|
||||
<div key={0} className="bg-gray-100 dark:bg-gray-800">
|
||||
Waiting for workflow to start
|
||||
</div>,
|
||||
]);
|
||||
const [total, setTotal] = useState<number>(10);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-start w-full gap-2">
|
||||
<div className="flex flex-row justify-center items-center">
|
||||
<div className="text-lg mr-2">Compute total</div>{" "}
|
||||
<FlowInput value={total} onChange={(value) => setTotal(value)} />
|
||||
</div>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
startTransition(() => {
|
||||
setUI([]);
|
||||
});
|
||||
const context = workflow.run(total, {
|
||||
sum: 0,
|
||||
});
|
||||
let i = 0;
|
||||
for await (const event of context) {
|
||||
console.log(event);
|
||||
if (event instanceof ComputeEvent) {
|
||||
setUI((ui) => [
|
||||
...ui,
|
||||
<div key={i++} className="bg-yellow-100 dark:bg-yellow-800">
|
||||
Computing task id: {event.data}
|
||||
</div>,
|
||||
]);
|
||||
} else if (event instanceof ComputeResultEvent) {
|
||||
setUI((ui) => [
|
||||
...ui,
|
||||
<div key={i++} className="bg-green-100 dark:bg-green-800">
|
||||
Computed task id: {event.data}
|
||||
</div>,
|
||||
]);
|
||||
} else if (event instanceof StartEvent) {
|
||||
setUI((ui) => [
|
||||
...ui,
|
||||
<div key={i++} className="bg-blue-100 dark:bg-blue-800">
|
||||
Started workflow with total {event.data}
|
||||
</div>,
|
||||
]);
|
||||
} else if (event instanceof StopEvent) {
|
||||
setUI((ui) => [
|
||||
...ui,
|
||||
<div key={i++} className="bg-red-100 dark:bg-red-800">
|
||||
Workflow stopped
|
||||
</div>,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
Start Workflow
|
||||
</Button>
|
||||
<StickToBottom className="w-full flex flex-col gap-2 p-2 border border-gray-200 rounded-lg max-h-96 overflow-y-auto">
|
||||
<StickToBottom.Content className="flex flex-col gap-2">
|
||||
{ui}
|
||||
</StickToBottom.Content>
|
||||
<ScrollToBottom />
|
||||
</StickToBottom>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import NumberFlow from "@number-flow/react";
|
||||
import clsx from "clsx/lite";
|
||||
import { Minus, Plus } from "lucide-react";
|
||||
import * as React from "react";
|
||||
|
||||
type Props = {
|
||||
value?: number;
|
||||
min?: number;
|
||||
max?: number;
|
||||
onChange?: (value: number) => void;
|
||||
};
|
||||
export default function FlowInput({
|
||||
value = 0,
|
||||
min = -Infinity,
|
||||
max = Infinity,
|
||||
onChange,
|
||||
}: Props) {
|
||||
const defaultValue = React.useRef(value);
|
||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||
const [animated, setAnimated] = React.useState(true);
|
||||
const [showCaret, setShowCaret] = React.useState(true);
|
||||
const handleInput: React.ChangeEventHandler<HTMLInputElement> = ({
|
||||
currentTarget: el,
|
||||
}) => {
|
||||
setAnimated(false);
|
||||
let next = value;
|
||||
if (el.value === "") {
|
||||
next = defaultValue.current;
|
||||
} else {
|
||||
const num = parseInt(el.value);
|
||||
if (!isNaN(num) && min <= num && num <= max) next = num;
|
||||
}
|
||||
el.value = String(next);
|
||||
onChange?.(next);
|
||||
};
|
||||
const handlePointerDown =
|
||||
(diff: number) => (event: React.PointerEvent<HTMLButtonElement>) => {
|
||||
setAnimated(true);
|
||||
if (event.pointerType === "mouse") {
|
||||
event?.preventDefault();
|
||||
inputRef.current?.focus();
|
||||
}
|
||||
const newVal = Math.min(Math.max(value + diff, min), max);
|
||||
onChange?.(newVal);
|
||||
};
|
||||
return (
|
||||
<div className="group flex items-stretch rounded-md text-lg font-semibold ring ring-zinc-200 transition-[box-shadow] focus-within:ring-2 focus-within:ring-blue-500 dark:ring-zinc-800">
|
||||
<button
|
||||
aria-hidden
|
||||
tabIndex={-1}
|
||||
className="flex items-center pl-[.5em] pr-[.325em]"
|
||||
disabled={min != null && value <= min}
|
||||
onPointerDown={handlePointerDown(-1)}
|
||||
>
|
||||
<Minus className="size-4" absoluteStrokeWidth strokeWidth={3.5} />
|
||||
</button>
|
||||
<div className="relative grid items-center justify-items-center text-center [grid-template-areas:'overlap'] *:[grid-area:overlap]">
|
||||
<input
|
||||
ref={inputRef}
|
||||
className={clsx(
|
||||
showCaret ? "caret-primary" : "caret-transparent",
|
||||
"spin-hide w-[1.5em] bg-transparent py-2 text-center font-[inherit] text-transparent outline-none",
|
||||
"[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
|
||||
)}
|
||||
// Make sure to disable kerning, to match NumberFlow:
|
||||
style={{ fontKerning: "none" }}
|
||||
type="number"
|
||||
min={min}
|
||||
step={1}
|
||||
autoComplete="off"
|
||||
inputMode="numeric"
|
||||
max={max}
|
||||
value={value}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
<NumberFlow
|
||||
value={value}
|
||||
format={{ useGrouping: false }}
|
||||
aria-hidden
|
||||
animated={animated}
|
||||
onAnimationsStart={() => setShowCaret(false)}
|
||||
onAnimationsFinish={() => setShowCaret(true)}
|
||||
className="pointer-events-none"
|
||||
willChange
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
aria-hidden
|
||||
tabIndex={-1}
|
||||
className="flex items-center pl-[.325em] pr-[.5em]"
|
||||
disabled={max != null && value >= max}
|
||||
onPointerDown={handlePointerDown(1)}
|
||||
>
|
||||
<Plus className="size-4" absoluteStrokeWidth strokeWidth={3.5} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
||||
secondary:
|
||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof badgeVariants> {}
|
||||
|
||||
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||
return (
|
||||
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
export { Badge, badgeVariants };
|
||||
@@ -2,8 +2,7 @@ import * as React from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface InputProps
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
"use client";
|
||||
|
||||
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||
);
|
||||
|
||||
const Label = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
||||
VariantProps<typeof labelVariants>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<LabelPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(labelVariants(), className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
Label.displayName = LabelPrimitive.Root.displayName;
|
||||
|
||||
export { Label };
|
||||
@@ -0,0 +1,28 @@
|
||||
"use client";
|
||||
|
||||
import * as SliderPrimitive from "@radix-ui/react-slider";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const Slider = React.forwardRef<
|
||||
React.ElementRef<typeof SliderPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SliderPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full touch-none select-none items-center",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20">
|
||||
<SliderPrimitive.Range className="absolute h-full bg-primary" />
|
||||
</SliderPrimitive.Track>
|
||||
<SliderPrimitive.Thumb className="block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
|
||||
</SliderPrimitive.Root>
|
||||
));
|
||||
Slider.displayName = SliderPrimitive.Root.displayName;
|
||||
|
||||
export { Slider };
|
||||
@@ -2,8 +2,7 @@ import * as React from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface TextareaProps
|
||||
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
||||
|
||||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
|
||||
@@ -12,7 +12,9 @@ export interface TextProps {
|
||||
weight?: 400 | 500 | 600;
|
||||
children?: ReactNode;
|
||||
className?: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
as?: any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
maximumWidth?: any;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"title": "Guide",
|
||||
"description": "See our guide",
|
||||
"pages": ["workflow"]
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
---
|
||||
title: Inputs / Outputs
|
||||
description: Learn how to use different inputs and outputs in your workflows.
|
||||
---
|
||||
|
||||
Inputs and outputs are the way to communicate between steps in a workflow. In the previous example,
|
||||
we used `StartEvent` and `StopEvent` to communicate between steps. However, you can use any type of event to communicate between steps.
|
||||
|
||||
## Multiple inputs
|
||||
|
||||
You can define multiple inputs for a step.
|
||||
|
||||
In the following example, we define a complex workflow with multiple inputs and outputs.
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';
|
||||
|
||||
class AEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class BEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class ResultEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
First, let's define the events that we will use in the workflow.
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';
|
||||
|
||||
class AEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class BEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class ResultEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
const workflow = new Workflow<never, string, string>();
|
||||
|
||||
workflow.addStep({
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [StopEvent<string>]
|
||||
}, async (
|
||||
context,
|
||||
startEvent
|
||||
) => {
|
||||
const input = startEvent.data;
|
||||
const aEvent = await context.requireEvent(AEvent);
|
||||
const bEvent = await context.requireEvent(BEvent);
|
||||
const a = aEvent.data;
|
||||
const b = bEvent.data;
|
||||
return new StopEvent(`Hello, ${input}! A: ${a}, B: ${b}`);
|
||||
});
|
||||
|
||||
// ---cut---
|
||||
workflow.addStep({
|
||||
inputs: [AEvent, BEvent],
|
||||
outputs: [ResultEvent]
|
||||
}, async (
|
||||
context,
|
||||
aEvent,
|
||||
bEvent
|
||||
) => {
|
||||
const a = aEvent.data;
|
||||
const b = bEvent.data;
|
||||
return new ResultEvent(`A: ${a}, B: ${b}`);
|
||||
});
|
||||
```
|
||||
|
||||
This step means that it requires two events: `AEvent` and `BEvent`. It will return a `ResultEvent` with the data `A: ${a}, B: ${b}`.
|
||||
|
||||
## A or B input
|
||||
|
||||
If we want to have a step that can accept either `AEvent` or `BEvent`, we can define the step like this:
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';
|
||||
|
||||
class AEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class BEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class ResultEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
const workflow = new Workflow<never, string, string>();
|
||||
|
||||
workflow.addStep({
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [StopEvent<string>]
|
||||
}, async (
|
||||
context,
|
||||
startEvent
|
||||
) => {
|
||||
const input = startEvent.data;
|
||||
const aEvent = await context.requireEvent(AEvent);
|
||||
const bEvent = await context.requireEvent(BEvent);
|
||||
const a = aEvent.data;
|
||||
const b = bEvent.data;
|
||||
return new StopEvent(`Hello, ${input}! A: ${a}, B: ${b}`);
|
||||
});
|
||||
|
||||
// ---cut---
|
||||
workflow.addStep({
|
||||
inputs: [WorkflowEvent.or(AEvent, BEvent)],
|
||||
outputs: [ResultEvent]
|
||||
}, async (
|
||||
context,
|
||||
aOrBEvent
|
||||
) => {
|
||||
if (aOrBEvent instanceof AEvent) {
|
||||
// ^?
|
||||
|
||||
|
||||
const a = aOrBEvent.data;
|
||||
// ^?
|
||||
|
||||
|
||||
return new ResultEvent(`A: ${a}`);
|
||||
} else {
|
||||
const b = aOrBEvent.data;
|
||||
// ^?
|
||||
|
||||
|
||||
return new ResultEvent(`B: ${b}`);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
This step means that it requires either `AEvent` or `BEvent`. It will return a `ResultEvent` with the data `A: ${a}` or `B: ${b}`.
|
||||
|
||||
You can still combine the logic with `context.requireEvent` to get the data from the event.
|
||||
|
||||
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
|
||||
|
||||
<Accordions>
|
||||
<Accordion title="Under the hood">
|
||||
We use JavaScript Inheritance and the prototype chain to implement the `or` logic.
|
||||
The `or` method creates a new class that extends the two classes that you pass to it.
|
||||
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain"
|
||||
>
|
||||
MDN - Inheritance and the prototype chain
|
||||
</a>
|
||||
</Accordion>
|
||||
</Accordions>
|
||||
|
||||
## Multiple outputs
|
||||
|
||||
You can define multiple outputs for a step.
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';
|
||||
|
||||
class AEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class BEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class ResultEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
const workflow = new Workflow<never, string, string>();
|
||||
// ---cut---
|
||||
workflow.addStep({
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [AEvent, BEvent]
|
||||
}, async (
|
||||
context,
|
||||
startEvent
|
||||
) => {
|
||||
const input = startEvent.data;
|
||||
if (Math.random() > 0.5) {
|
||||
return new AEvent(`Hello, ${input}!`);
|
||||
} else {
|
||||
return new BEvent(42);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
This step will return either an `AEvent` or a `BEvent` based on a random number.
|
||||
@@ -0,0 +1,208 @@
|
||||
---
|
||||
title: Basic Usage
|
||||
description: Learn how to use the LlamaIndex workflow.
|
||||
---
|
||||
|
||||
A `Workflow` in LlamaIndex.TS is an event-driven abstraction used to chain together several events.
|
||||
Workflows are made up of steps, with each step responsible for handling certain event types and emitting new events.
|
||||
|
||||
Workflows are designed for any cases that benefit from event-driven programming, not only for LLM and AI tasks.
|
||||
|
||||
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
||||
|
||||
<Tabs groupId="install" items={["npm", "yarn", "pnpm"]} persist>
|
||||
```shell tab="npm"
|
||||
npm install @llamaindex/workflow
|
||||
```
|
||||
|
||||
```shell tab="yarn"
|
||||
yarn add @llamaindex/workflow
|
||||
```
|
||||
|
||||
```shell tab="pnpm"
|
||||
pnpm add @llamaindex/workflow
|
||||
```
|
||||
</Tabs>
|
||||
|
||||
## Start from scratch
|
||||
|
||||
Let's start from a Hello World workflow.
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow } from '@llamaindex/workflow';
|
||||
|
||||
type ContextData = {
|
||||
counter: number;
|
||||
}
|
||||
// ---cut---
|
||||
const contextData: ContextData = { counter: 0 };
|
||||
|
||||
const workflow = new Workflow<ContextData, string, string>();
|
||||
// ^?
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
First, we define a workflow with 3 generic types: `ContextData`, `Input`, and `Output`.
|
||||
|
||||
In general, `ContextData` is used to store the shared data between steps, `Input` is the type of the input event, and `Output` is the type of the output event.
|
||||
|
||||
In you code logic, you should **share state between steps via `ContextData`**.
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, StartEvent, StopEvent } from '@llamaindex/workflow';
|
||||
|
||||
type ContextData = {
|
||||
counter: number;
|
||||
}
|
||||
|
||||
const contextData: ContextData = { counter: 0 };
|
||||
|
||||
const workflow = new Workflow<ContextData, string, string>();
|
||||
// ---cut---
|
||||
workflow.addStep({
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [StopEvent<string>]
|
||||
}, async (context, startEvent) => {
|
||||
const input = startEvent.data;
|
||||
context.data.counter++;
|
||||
return new StopEvent(`Hello, ${input}!`);
|
||||
});
|
||||
```
|
||||
|
||||
In the workflow, we add a step that listens to `StartEvent<string>` and emits `StopEvent<string>`.
|
||||
|
||||
The step is an async function that takes two arguments: `context` and `event`.
|
||||
|
||||
### `context` type
|
||||
|
||||
<AutoTypeTable path="./src/deps/type.ts" name="HandlerContext" />
|
||||
|
||||
There are two more properties in `HandlerContext`:
|
||||
|
||||
- `sendEvent`: invoke another event in the workflow, other than `StartEvent`, `StopEvent`, or the current event. (Or there will have circular reference)
|
||||
- `requireEvent`: wait for a specific event to be emitted.
|
||||
|
||||
You can use `sendEvent` and `requireEvent` to build complex workflows.
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';
|
||||
|
||||
type ContextData = {
|
||||
counter: number;
|
||||
}
|
||||
|
||||
const contextData: ContextData = { counter: 0 };
|
||||
|
||||
const workflow = new Workflow<ContextData, string, string>();
|
||||
|
||||
// ---cut---
|
||||
class AnalysisStartEvent extends WorkflowEvent<string> {}
|
||||
class AnalysisStopEvent extends WorkflowEvent<boolean> {}
|
||||
workflow.addStep({
|
||||
inputs: [AnalysisStartEvent],
|
||||
outputs: [AnalysisStopEvent]
|
||||
}, async (...args) => {
|
||||
// do some analysis
|
||||
return new AnalysisStopEvent(true);
|
||||
})
|
||||
workflow.addStep({
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [StopEvent<string>]
|
||||
}, async (context, startEvent) => {
|
||||
const input = startEvent.data;
|
||||
context.sendEvent(new AnalysisStartEvent('start'));
|
||||
context.data.counter++;
|
||||
const { data } = await context.requireEvent(AnalysisStopEvent);
|
||||
return new StopEvent(`Hello, ${input}! Analysis result: ${data ? 'success' : 'fail'}`);
|
||||
});
|
||||
```
|
||||
|
||||
For example, you can compile `requireEvent` with `waitUntil` in [Vercel Functions](https://vercel.com/docs/functions/functions-api-reference#waituntil) or [Cloudflare Worker](https://developers.cloudflare.com/workers/runtime-apis/context/#waituntil)
|
||||
|
||||
```ts twoslash
|
||||
import { waitUntil } from '@vercel/functions';
|
||||
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';
|
||||
|
||||
type ContextData = {
|
||||
counter: number;
|
||||
}
|
||||
|
||||
const contextData: ContextData = { counter: 0 };
|
||||
|
||||
const workflow = new Workflow<ContextData, string, string>();
|
||||
|
||||
class AnalysisStartEvent extends WorkflowEvent<string> {}
|
||||
class AnalysisStopEvent extends WorkflowEvent<boolean> {}
|
||||
|
||||
// ---cut---
|
||||
workflow.addStep({
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [StopEvent<string>]
|
||||
}, async (context, startEvent) => {
|
||||
const input = startEvent.data;
|
||||
context.sendEvent(new AnalysisStartEvent('start'));
|
||||
context.data.counter++;
|
||||
waitUntil(context.requireEvent(AnalysisStopEvent));
|
||||
// note that `waitUntil` is not a promise, it will extend the lifetime of the workflow
|
||||
// you can wait for some background tasks to finish
|
||||
return new StopEvent(`Hello, ${input}!`);
|
||||
});
|
||||
```
|
||||
|
||||
## Multiple runs
|
||||
|
||||
You can run the same workflow multiple times with different inputs.
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, StartEvent, StopEvent } from '@llamaindex/workflow';
|
||||
|
||||
type ContextData = {
|
||||
counter: number;
|
||||
}
|
||||
|
||||
const contextData: ContextData = { counter: 0 };
|
||||
|
||||
const workflow = new Workflow<ContextData, string, string>();
|
||||
|
||||
workflow.addStep({
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [StopEvent<string>]
|
||||
}, async (context, startEvent) => {
|
||||
const input = startEvent.data;
|
||||
context.data.counter++;
|
||||
return new StopEvent(`Hello, ${input}!`);
|
||||
});
|
||||
|
||||
// ---cut---
|
||||
{
|
||||
const ret = await workflow.run('Alex', contextData);
|
||||
console.log(ret.data); // Hello, Alex!
|
||||
}
|
||||
|
||||
{
|
||||
const ret = await workflow.run('World', contextData);
|
||||
console.log(ret.data); // Hello, World!
|
||||
}
|
||||
```
|
||||
|
||||
Context is shared between runs, so the counter will be increased.
|
||||
|
||||
Ideally, it should be serializable to make sure it can be recovered from HTTP requests or other storage.
|
||||
|
||||
### Full example
|
||||
|
||||
<iframe
|
||||
className="w-full h-[440px]"
|
||||
aria-label="Workflow example"
|
||||
src="https://stackblitz.com/github/run-llama/LlamaIndexTS/tree/main/examples?file=node/workflow/basic.ts"
|
||||
/>
|
||||
|
||||
## `Workflow` type
|
||||
|
||||
<AutoTypeTable path="./src/deps/type.ts" name="Workflow" />
|
||||
|
||||
## `WorkflowContext` type
|
||||
|
||||
<AutoTypeTable path="./src/deps/type.ts" name="WorkflowContext" />
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"title": "Workflow",
|
||||
"description": "See how to use @llamaindex/workflow",
|
||||
"defaultOpen": false,
|
||||
"pages": ["index", "different-inputs-outputs", "streaming"]
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
---
|
||||
title: Streaming
|
||||
description: Learn how to use the LlamaIndex workflow with streaming.
|
||||
---
|
||||
import { WorkflowStreamingDemo } from '../../../../../components/demo/workflow-streaming-ui';
|
||||
|
||||
`Workflow` API by default is designed for streaming data. In this guide, we will show you how to use the `Workflow` API with streaming data.
|
||||
|
||||
Each `workflow.run` call returns `WorkflowContext`, which implements `AsyncIterable` interface. You can use it to stream data.
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, WorkflowEvent, StartEvent, StopEvent } from '@llamaindex/workflow';
|
||||
class ComputeEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
class ComputeResultEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
type ContextData = {
|
||||
sum: number;
|
||||
}
|
||||
|
||||
const workflow = new Workflow<ContextData, number, number>();
|
||||
workflow.addStep({
|
||||
inputs: [StartEvent<number>],
|
||||
outputs: [StopEvent<number>]
|
||||
}, async (context, startEvent) => {
|
||||
const total = startEvent.data;
|
||||
for (let i = 0; i < total; i++) {
|
||||
context.sendEvent(new ComputeEvent(i));
|
||||
}
|
||||
const computeResults = await Promise.all(Array.from({ length: total }).map(() => context.requireEvent(ComputeResultEvent)));
|
||||
// Workflow API allows you to start events in parallel and wait for all of them to finish
|
||||
context.data.sum = computeResults.reduce((acc, curr) => acc + curr.data, 0);
|
||||
return new StopEvent(context.data.sum);
|
||||
});
|
||||
```
|
||||
|
||||
We define a parallel computation workflow that computes the sum of numbers from 0 to `total`.
|
||||
|
||||
The workflow sends `ComputeEvent` events for each number and waits for `ComputeResultEvent` events. After receiving all `ComputeResultEvent` events, the workflow returns the sum as a `StopEvent`.
|
||||
|
||||
What if we want cutoff if the sum exceeds a certain value?
|
||||
|
||||
## Streaming
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, WorkflowEvent, StartEvent, StopEvent } from '@llamaindex/workflow';
|
||||
import { StopCircle } from 'lucide-react';
|
||||
class ComputeEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
class ComputeResultEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type ContextData = {
|
||||
sum: number;
|
||||
}
|
||||
|
||||
const workflow = new Workflow<ContextData, number, number>();
|
||||
// ---cut---
|
||||
const context = workflow.run(1000, {
|
||||
sum: 0
|
||||
});
|
||||
|
||||
for await (const event of context) {
|
||||
if (event instanceof ComputeEvent) {
|
||||
if (context.data.sum > 100) {
|
||||
throw new Error('Sum exceeds 100');
|
||||
}
|
||||
}
|
||||
if (event instanceof StopEvent) {
|
||||
console.log('result', event.data);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can define more custom logic using `AsyncIterable` interface.
|
||||
|
||||
For example. I just want to stop the workflow if I get a `ComputeResultEvent`
|
||||
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, WorkflowEvent, StartEvent, StopEvent } from '@llamaindex/workflow';
|
||||
import { StopCircle } from 'lucide-react';
|
||||
class ComputeEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
class ComputeResultEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type ContextData = {
|
||||
sum: number;
|
||||
}
|
||||
|
||||
const workflow = new Workflow<ContextData, number, number>();
|
||||
// ---cut---
|
||||
async function compute() {
|
||||
const context = workflow.run(1000, {
|
||||
sum: 0
|
||||
});
|
||||
for await (const event of context) {
|
||||
if (event instanceof ComputeResultEvent) {
|
||||
return event.data;
|
||||
}
|
||||
}
|
||||
throw new Error('UNREACHABLE');
|
||||
}
|
||||
|
||||
const result = await compute();
|
||||
```
|
||||
|
||||
### Streaming with UI
|
||||
|
||||
You can use the `Workflow` API with UI libraries like React.
|
||||
|
||||
```tsx twoslash
|
||||
// @filename: utils.ts
|
||||
export async function runWithoutBlocking(fn: () => Promise<void>) {
|
||||
fn();
|
||||
}
|
||||
// @filename: action.ts
|
||||
// ---cut---
|
||||
'use server';
|
||||
// "use server" is required to enable server side feature in React
|
||||
import { createStreamableUI } from 'ai/rsc';
|
||||
import { runWithoutBlocking } from './utils';
|
||||
// ---cut-start---
|
||||
import { Workflow, WorkflowEvent, StartEvent, StopEvent } from '@llamaindex/workflow';
|
||||
class ComputeEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
class ComputeResultEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type ContextData = {
|
||||
sum: number;
|
||||
}
|
||||
|
||||
const workflow = new Workflow<ContextData, number, number>();
|
||||
const min = 100;
|
||||
const max = 1000;
|
||||
workflow.addStep(
|
||||
{
|
||||
inputs: [ComputeEvent],
|
||||
outputs: [ComputeResultEvent]
|
||||
},
|
||||
async (context, event) => {
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, Math.floor(Math.random() * (max - min + 1) + min))
|
||||
);
|
||||
return new ComputeResultEvent(event.data);
|
||||
}
|
||||
);
|
||||
// ---cut-end---
|
||||
export async function compute() {
|
||||
'use server';
|
||||
const ui = createStreamableUI();
|
||||
const context = workflow.run(100, {
|
||||
sum: 0
|
||||
});
|
||||
runWithoutBlocking(async () => {
|
||||
for await (const event of context) {
|
||||
if (event instanceof ComputeResultEvent) {
|
||||
// Update UI
|
||||
} else if (event instanceof StopEvent) {
|
||||
// Update UI
|
||||
}
|
||||
// ...
|
||||
}
|
||||
});
|
||||
return ui.value;
|
||||
}
|
||||
```
|
||||
|
||||
<WorkflowStreamingDemo />
|
||||
@@ -5,42 +5,31 @@ description: Install llamaindex by running a single command.
|
||||
|
||||
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
||||
|
||||
<Tabs groupId="install-llamaindex" items={["npm", "yarn", "pnpm"]} persist>
|
||||
```shell tab="npm"
|
||||
npm install llamaindex
|
||||
```
|
||||
<Tabs groupId="install" items={["npm", "yarn", "pnpm"]} persist>
|
||||
```shell tab="npm"
|
||||
npm install llamaindex
|
||||
```
|
||||
|
||||
```shell tab="yarn"
|
||||
yarn add llamaindex
|
||||
```
|
||||
|
||||
```shell tab="pnpm"
|
||||
pnpm add llamaindex
|
||||
```
|
||||
```shell tab="yarn"
|
||||
yarn add llamaindex
|
||||
```
|
||||
|
||||
```shell tab="pnpm"
|
||||
pnpm add llamaindex
|
||||
```
|
||||
</Tabs>
|
||||
|
||||
## What's next?
|
||||
|
||||
<Cards>
|
||||
<Card
|
||||
title="I'm new to RAG"
|
||||
description="Learn more about RAG (Retrieval-augmented generation) using LlamaIndex.TS."
|
||||
href="/docs/llamaindex/setup/what-is-rag"
|
||||
/>
|
||||
<Card
|
||||
title="I want to try LlamaIndex.TS"
|
||||
description="Learn how to use LlamaIndex.TS with different JS runtime and frameworks."
|
||||
href="/docs/llamaindex/setup"
|
||||
/>
|
||||
<Card
|
||||
title="I want to improve performance when using LlamaIndex.TS"
|
||||
description="Learn how to improve performance, reduce bundle size, improve accuracy."
|
||||
href="/docs/llamaindex/performance"
|
||||
/>
|
||||
<Card
|
||||
title="Show me code examples"
|
||||
description="Explore code examples using LlamaIndex.TS."
|
||||
href="https://stackblitz.com/github/run-llama/LlamaIndexTS/tree/main/examples?file=README.md"
|
||||
/>
|
||||
<Card
|
||||
title="I want to try LlamaIndex.TS"
|
||||
description="Learn how to use LlamaIndex.TS with different JS runtime and frameworks."
|
||||
href="/docs/llamaindex/setup/getting-started"
|
||||
/>
|
||||
<Card
|
||||
title="Show me code examples"
|
||||
description="Explore code examples using LlamaIndex.TS."
|
||||
href="https://stackblitz.com/github/run-llama/LlamaIndexTS/tree/main/examples?file=README.md"
|
||||
/>
|
||||
</Cards>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
title: Langtrace
|
||||
description: Learn how to integrate LlamaIndex.TS with Langtrace.
|
||||
---
|
||||
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
||||
|
||||
Enhance your observability with Langtrace, a robust open-source tool supports OpenTelemetry and is designed to trace, evaluate, and manage LLM applications seamlessly. Langtrace integrates directly with LlamaIndex, offering detailed, real-time insights into performance metrics such as accuracy, evaluations, and latency.
|
||||
|
||||
## Install
|
||||
|
||||
- Self-host or sign-up and generate an API key using [Langtrace](https://www.langtrace.ai) Cloud
|
||||
|
||||
<Tabs groupId="install-langtrase" items={["npm", "yarn", "pnpm"]} persist>
|
||||
```shell tab="npm"
|
||||
npm install @langtrase/typescript-sdk
|
||||
```
|
||||
|
||||
```shell tab="yarn"
|
||||
yarn add @langtrase/typescript-sdk
|
||||
```
|
||||
|
||||
```shell tab="pnpm"
|
||||
pnpm add @langtrase/typescript-sdk
|
||||
```
|
||||
</Tabs>
|
||||
|
||||
## Initialize
|
||||
|
||||
```js
|
||||
import * as Langtrace from "@langtrase/typescript-sdk";
|
||||
Langtrace.init({ api_key: "<YOUR_API_KEY>" });
|
||||
```
|
||||
|
||||
Features:
|
||||
|
||||
- OpenTelemetry compliant, ensuring broad compatibility with observability platforms.
|
||||
- Provides comprehensive logs and detailed traces of all components.
|
||||
- Real-time monitoring of accuracy, evaluations, usage, costs, and latency.
|
||||
- For more configuration options and details, visit [Langtrace Docs](https://docs.langtrace.ai/introduction).
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"title": "Integration",
|
||||
"description": "See our integrations",
|
||||
"pages": ["open-llm-metry", "lang-trace"]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
title: OpenLLMetry
|
||||
description: Learn how to integrate LlamaIndex.TS with OpenLLMetry.
|
||||
---
|
||||
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
||||
|
||||
[OpenLLMetry](https://github.com/traceloop/openllmetry-js) is an open-source project based on OpenTelemetry for tracing and monitoring
|
||||
LLM applications. It connects to [all major observability platforms](https://www.traceloop.com/docs/openllmetry/integrations/introduction) and installs in minutes.
|
||||
|
||||
### Usage Pattern
|
||||
|
||||
|
||||
<Tabs groupId="install-traceloop" items={["npm", "yarn", "pnpm"]} persist>
|
||||
```shell tab="npm"
|
||||
npm install @traceloop/node-server-sdk
|
||||
```
|
||||
|
||||
```shell tab="yarn"
|
||||
yarn add @traceloop/node-server-sdk
|
||||
```
|
||||
|
||||
```shell tab="pnpm"
|
||||
pnpm add @traceloop/node-server-sdk
|
||||
```
|
||||
</Tabs>
|
||||
|
||||
```js
|
||||
import * as traceloop from "@traceloop/node-server-sdk";
|
||||
|
||||
traceloop.initialize({
|
||||
apiKey: process.env.TRACELOOP_API_KEY,
|
||||
disableBatch: true
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"title": "Loading Data",
|
||||
"description": "Loading Data using LlamaIndex.TS",
|
||||
"pages": ["index", "node-parser"]
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
---
|
||||
title: Node Parsers / Text Splitters
|
||||
description: Learn how to use Node Parsers and Text Splitters to extract data from documents.
|
||||
---
|
||||
import { CodeNodeParserDemo } from '../../../../components/demo/code-node-parser';
|
||||
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
||||
|
||||
Node parsers are a simple abstraction that take a list of documents, and chunk them into `Node` objects, such that each node is a specific chunk of the parent document. When a document is broken into nodes, all of it's attributes are inherited to the children nodes (i.e. `metadata`, text and metadata templates, etc.). You can read more about `Node` and `Document` properties [here](./).
|
||||
|
||||
## NodeParser
|
||||
|
||||
The `NodeParser` in LlamaIndex is responsible for splitting `Document` objects into more manageable `Node` objects.
|
||||
|
||||
By default, we will use `Settings.nodeParser` to split the document into nodes. You can also assign a custom `NodeParser` to the `Settings` object.
|
||||
|
||||
```ts twoslash
|
||||
import { TextFileReader } from '@llamaindex/readers/text'
|
||||
import { SentenceSplitter } from '@llamaindex/core/node-parser';
|
||||
import { Settings } from 'llamaindex';
|
||||
|
||||
const nodeParser = new SentenceSplitter();
|
||||
Settings.nodeParser = nodeParser;
|
||||
// ^?
|
||||
```
|
||||
|
||||
## TextSplitter
|
||||
|
||||
The underlying text splitter will split text by sentences. It can also be used as a standalone module for splitting raw text.
|
||||
|
||||
```ts twoslash
|
||||
import { SentenceSplitter } from "@llamaindex/core/node-parser";
|
||||
|
||||
const splitter = new SentenceSplitter({ chunkSize: 1 });
|
||||
|
||||
const texts = splitter.splitText("Hello World");
|
||||
// ^?
|
||||
```
|
||||
|
||||
## MarkdownNodeParser
|
||||
|
||||
The `MarkdownNodeParser` is a more advanced `NodeParser` that can handle markdown documents. It will split the markdown into nodes and then parse the nodes into a `Document` object.
|
||||
|
||||
<Tabs items={["with reader", "with node:fs"]}>
|
||||
```ts twoslash tab="with reader"
|
||||
import { MarkdownNodeParser } from "@llamaindex/core/node-parser";
|
||||
import { MarkdownReader } from '@llamaindex/readers/markdown'
|
||||
|
||||
const reader = new MarkdownReader();
|
||||
const markdownNodeParser = new MarkdownNodeParser();
|
||||
|
||||
const documents = await reader.loadData('path/to/file.md');
|
||||
const parsedDocuments = markdownNodeParser(documents);
|
||||
// ^?
|
||||
|
||||
```
|
||||
|
||||
```ts twoslash tab="with node:fs"
|
||||
import fs from 'node:fs/promises';
|
||||
import { MarkdownNodeParser } from "@llamaindex/core/node-parser";
|
||||
import { Document } from '@llamaindex/core/schema';
|
||||
|
||||
const markdownNodeParser = new MarkdownNodeParser();
|
||||
const text = await fs.readFile('path/to/file.md', 'utf-8');
|
||||
const document = new Document({ text });
|
||||
|
||||
const parsedDocuments = markdownNodeParser([document]);
|
||||
// ^?
|
||||
|
||||
```
|
||||
</Tabs>
|
||||
|
||||
## CodeSplitter
|
||||
|
||||
The `CodeSplitter` is a more advanced `NodeParser` that can handle code documents.
|
||||
It will split the code by AST nodes and then parse the nodes into a `Document` object.
|
||||
|
||||
<Tabs items={["with reader", "with node:fs"]}>
|
||||
```ts twoslash tab="with reader"
|
||||
import { TextFileReader } from '@llamaindex/readers/text'
|
||||
import { CodeSplitter } from '@llamaindex/node-parser/code'
|
||||
import Parser from "tree-sitter";
|
||||
import TS from "tree-sitter-typescript";
|
||||
|
||||
const parser = new Parser();
|
||||
parser.setLanguage(TS.typescript);
|
||||
const codeSplitter = new CodeSplitter({
|
||||
getParser: () => parser,
|
||||
});
|
||||
const reader = new TextFileReader();
|
||||
const documents = await reader.loadData('path/to/file.ts');
|
||||
|
||||
const parsedDocuments = codeSplitter(documents);
|
||||
// ^?
|
||||
```
|
||||
|
||||
```ts twoslash tab="with node:fs"
|
||||
import fs from 'node:fs/promises';
|
||||
import { CodeSplitter } from '@llamaindex/node-parser/code'
|
||||
import Parser from "tree-sitter";
|
||||
import TS from "tree-sitter-typescript";
|
||||
|
||||
const parser = new Parser();
|
||||
parser.setLanguage(TS.typescript);
|
||||
const codeSplitter = new CodeSplitter({
|
||||
getParser: () => parser,
|
||||
});
|
||||
|
||||
const parsedDocuments = codeSplitter.splitText(await fs.readFile('path/to/file.ts', 'utf-8'));
|
||||
// ^?
|
||||
```
|
||||
</Tabs>
|
||||
|
||||
Try it out ⬇️
|
||||
|
||||
<CodeNodeParserDemo/>
|
||||
|
||||
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
|
||||
|
||||
<Accordions>
|
||||
<Accordion title="Use it in browser">
|
||||
You might setup WASM files for `web-tree-sitter` and use it in the browser.
|
||||
|
||||
```ts
|
||||
import Parser from 'web-tree-sitter';
|
||||
|
||||
Parser.init({
|
||||
locateFile(scriptName: string) {
|
||||
return '/' + scriptName
|
||||
},
|
||||
}).then(async () => {
|
||||
const parser = new Parser();
|
||||
const Lang = await Parser.Language.load('/tree-sitter-typescript.wasm');
|
||||
parser.setLanguage(Lang);
|
||||
return new CodeSplitter({
|
||||
getParser: () => parser,
|
||||
maxChars: 100
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
In this example, you should put `tree-sitter-typescript.wasm` to the `public` folder for Next.js.
|
||||
|
||||
And also update the `next.config.js` to make `@llamaindex/env` work properly.
|
||||
|
||||
```js
|
||||
const config = {
|
||||
webpack: (config) => {
|
||||
if (Array.isArray(config.target) && config.target.includes('web')) {
|
||||
config.target = ["web", "es2020"];
|
||||
}
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
export default config;
|
||||
```
|
||||
</Accordion>
|
||||
</Accordions>
|
||||
@@ -8,6 +8,8 @@
|
||||
"index",
|
||||
"setup",
|
||||
"starter",
|
||||
"readers"
|
||||
"loading",
|
||||
"guide",
|
||||
"integration"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"title": "Loading",
|
||||
"description": "File Readers Collection",
|
||||
"pages": ["index"]
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
<>
|
||||
<SiTypescript className="inline" color="#3178C6" /> TypeScript
|
||||
</>
|
||||
} href="/docs/llamaindex/setup/typescript.mdx" />
|
||||
} href="/docs/llamaindex/setup/typescript" />
|
||||
<Card title={
|
||||
<>
|
||||
<SiVite className='inline' color='#646CFF' /> Vite
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
<Card
|
||||
title={
|
||||
<>
|
||||
<SiNextdotjs className='inline' color='#000000' /> Next.js (React Server Component)
|
||||
<SiNextdotjs className='inline' /> Next.js (React Server Component)
|
||||
</>
|
||||
}
|
||||
href="/docs/llamaindex/setup/next"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export type {
|
||||
HandlerContext,
|
||||
Workflow,
|
||||
WorkflowContext,
|
||||
} from "@llamaindex/workflow";
|
||||
@@ -1,2 +1,2 @@
|
||||
// when we are ready, change to /docs/llamaindex
|
||||
export const DOCUMENT_URL = 'https://legacy.ts.llamaindex.ai/'
|
||||
export const LEGACY_DOCUMENT_URL = 'https://legacy.ts.llamaindex.ai/'
|
||||
|
||||
@@ -12,6 +12,7 @@ export default {
|
||||
"./node_modules/fumadocs-openapi/dist/**/*.js",
|
||||
],
|
||||
presets: [createPreset()],
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
theme: {
|
||||
extend: {
|
||||
|
||||
@@ -24,6 +24,12 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
"**/*.mts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<svg fill="none" height="50" viewBox="0 0 512 512" width="50" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect fill="#3178c6" height="512" rx="50" width="512" />
|
||||
<rect fill="#3178c6" height="512" rx="50" width="512" />
|
||||
<path clip-rule="evenodd"
|
||||
d="m316.939 407.424v50.061c8.138 4.172 17.763 7.3 28.875 9.386s22.823 3.129 35.135 3.129c11.999 0 23.397-1.147 34.196-3.442 10.799-2.294 20.268-6.075 28.406-11.342 8.138-5.266 14.581-12.15 19.328-20.65s7.121-19.007 7.121-31.522c0-9.074-1.356-17.026-4.069-23.857s-6.625-12.906-11.738-18.225c-5.112-5.319-11.242-10.091-18.389-14.315s-15.207-8.213-24.18-11.967c-6.573-2.712-12.468-5.345-17.685-7.9-5.217-2.556-9.651-5.163-13.303-7.822-3.652-2.66-6.469-5.476-8.451-8.448-1.982-2.973-2.974-6.336-2.974-10.091 0-3.441.887-6.544 2.661-9.308s4.278-5.136 7.512-7.118c3.235-1.981 7.199-3.52 11.894-4.615 4.696-1.095 9.912-1.642 15.651-1.642 4.173 0 8.581.313 13.224.938 4.643.626 9.312 1.591 14.008 2.894 4.695 1.304 9.259 2.947 13.694 4.928 4.434 1.982 8.529 4.276 12.285 6.884v-46.776c-7.616-2.92-15.937-5.084-24.962-6.492s-19.381-2.112-31.066-2.112c-11.895 0-23.163 1.278-33.805 3.833s-20.006 6.544-28.093 11.967c-8.086 5.424-14.476 12.333-19.171 20.729-4.695 8.395-7.043 18.433-7.043 30.114 0 14.914 4.304 27.638 12.912 38.172 8.607 10.533 21.675 19.45 39.204 26.751 6.886 2.816 13.303 5.579 19.25 8.291s11.086 5.528 15.415 8.448c4.33 2.92 7.747 6.101 10.252 9.543 2.504 3.441 3.756 7.352 3.756 11.733 0 3.233-.783 6.231-2.348 8.995s-3.939 5.162-7.121 7.196-7.147 3.624-11.894 4.771c-4.748 1.148-10.303 1.721-16.668 1.721-10.851 0-21.597-1.903-32.24-5.71-10.642-3.806-20.502-9.516-29.579-17.13zm-84.159-123.342h64.22v-41.082h-179v41.082h63.906v182.918h50.874z"
|
||||
fill="#fff" fill-rule="evenodd" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,62 @@
|
||||
// @ts-check
|
||||
|
||||
import eslint from "@eslint/js";
|
||||
import eslintConfigPrettier from "eslint-config-prettier";
|
||||
import turboPlugin from "eslint-plugin-turbo";
|
||||
import globals from "globals";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
eslintConfigPrettier,
|
||||
{
|
||||
languageOptions: {
|
||||
ecmaVersion: 2022,
|
||||
sourceType: "module",
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eslint-config-turbo (recreated flat)",
|
||||
plugins: {
|
||||
turbo: { rules: turboPlugin.rules },
|
||||
},
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
"no-irregular-whitespace": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/no-explicit-any": [
|
||||
"error",
|
||||
{
|
||||
ignoreRestArgs: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["packages/wasm-tools/**"],
|
||||
rules: {
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: [
|
||||
"**/dist/**",
|
||||
"**/lib/*",
|
||||
"**/deps/**",
|
||||
"**/.next/**",
|
||||
"**/node_modules/**",
|
||||
"**/build/**",
|
||||
"**/.docusaurus/**",
|
||||
// third party deps
|
||||
"packages/env/src/fs/memfs/index.js",
|
||||
"packages/core/src/prompts/format.ts",
|
||||
"packages/core/src/node-parser/sentence_tokenizer.js",
|
||||
],
|
||||
},
|
||||
);
|
||||
@@ -1,5 +1,12 @@
|
||||
# examples
|
||||
|
||||
## 0.0.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [0765742]
|
||||
- @llamaindex/workflow@0.0.2
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -22,13 +22,14 @@ const extractWikipediaTitle = async (title: string) => {
|
||||
const url = `https://en.wikipedia.org/w/api.php?${queryParams}`;
|
||||
|
||||
const response = await fetch(url);
|
||||
const data: any = await response.json();
|
||||
const data = await response.json();
|
||||
|
||||
const pages = data.query.pages;
|
||||
const page = pages[Object.keys(pages)[0]];
|
||||
const wikiText = page.extract;
|
||||
|
||||
await new Promise((resolve) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
fs.writeFile(path.join(dataPath, `${title}.txt`), wikiText, (err: any) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
|
||||
@@ -37,7 +37,9 @@ async function main() {
|
||||
});
|
||||
|
||||
// TODO: fix any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const documentAgents: any = {};
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const queryEngines: any = {};
|
||||
|
||||
for (const title of wikiTitles) {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { CosmosClient } from "@azure/cosmos";
|
||||
import { DefaultAzureCredential } from "@azure/identity";
|
||||
import * as dotenv from "dotenv";
|
||||
import * as fs from "fs";
|
||||
// Load environment variables from local .env file
|
||||
dotenv.config();
|
||||
|
||||
const jsonFile = "./data/shortStories.json";
|
||||
const cosmosEndpoint = process.env.AZURE_COSMOSDB_NOSQL_ENDPOINT!;
|
||||
const cosmosConnectionString =
|
||||
process.env.AZURE_COSMOSDB_NOSQL_CONNECTION_STRING!;
|
||||
const databaseName =
|
||||
process.env.AZURE_COSMOSDB_DATABASE_NAME || "shortStoriesDatabase";
|
||||
const containerName =
|
||||
process.env.AZURE_COSMOSDB_CONTAINER_NAME || "shortStoriesContainer";
|
||||
|
||||
async function addDocumentsToCosmosDB() {
|
||||
if (!cosmosConnectionString && !cosmosEndpoint) {
|
||||
throw new Error(
|
||||
"Azure CosmosDB connection string or endpoint must be set.",
|
||||
);
|
||||
}
|
||||
|
||||
let cosmosClient: CosmosClient;
|
||||
|
||||
const stories = JSON.parse(fs.readFileSync(jsonFile, "utf-8"));
|
||||
|
||||
// initialize the cosmos client
|
||||
if (cosmosConnectionString) {
|
||||
cosmosClient = new CosmosClient(cosmosConnectionString);
|
||||
} else {
|
||||
cosmosClient = new CosmosClient({
|
||||
endpoint: cosmosEndpoint,
|
||||
aadCredentials: new DefaultAzureCredential(),
|
||||
});
|
||||
}
|
||||
|
||||
// Create a new database and container if they don't exist
|
||||
const { database } = await cosmosClient.databases.createIfNotExists({
|
||||
id: databaseName,
|
||||
});
|
||||
const { container } = await database.containers.createIfNotExists({
|
||||
id: containerName,
|
||||
partitionKey: "/id",
|
||||
});
|
||||
|
||||
console.log(
|
||||
`Data import started to the CosmosDB container ${containerName}.`,
|
||||
);
|
||||
// Insert the short stories into the CosmosDB container
|
||||
for (const story of stories) {
|
||||
await container.items.create(story);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Successfully imported data to the CosmosDB container ${containerName}.`,
|
||||
);
|
||||
}
|
||||
|
||||
addDocumentsToCosmosDB().catch(console.error);
|
||||
@@ -0,0 +1,95 @@
|
||||
import { CosmosClient } from "@azure/cosmos";
|
||||
import { DefaultAzureCredential } from "@azure/identity";
|
||||
import {
|
||||
SimpleCosmosDBReader,
|
||||
SimpleCosmosDBReaderLoaderConfig,
|
||||
} from "@llamaindex/readers/cosmosdb";
|
||||
import * as dotenv from "dotenv";
|
||||
import {
|
||||
AzureCosmosDBNoSqlVectorStore,
|
||||
OpenAI,
|
||||
OpenAIEmbedding,
|
||||
Settings,
|
||||
storageContextFromDefaults,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
// Load environment variables from local .env file
|
||||
dotenv.config();
|
||||
|
||||
const cosmosEndpoint = process.env.AZURE_COSMOSDB_NOSQL_ENDPOINT!;
|
||||
const cosmosConnectionString =
|
||||
process.env.AZURE_COSMOSDB_NOSQL_CONNECTION_STRING!;
|
||||
const databaseName =
|
||||
process.env.AZURE_COSMOSDB_DATABASE_NAME || "shortStoriesDatabase";
|
||||
const collectionName =
|
||||
process.env.AZURE_COSMOSDB_CONTAINER_NAME || "shortStoriesContainer";
|
||||
const vectorCollectionName =
|
||||
process.env.AZURE_COSMOSDB_VECTOR_CONTAINER_NAME || "vectorContainer";
|
||||
|
||||
// This exampple uses Azure OpenAI llm and embedding models
|
||||
const llmInit = {
|
||||
azure: {
|
||||
apiVersion: process.env.AZURE_OPENAI_LLM_API_VERSION,
|
||||
endpoint: process.env.AZURE_OPENAI_LLM_ENDPOINT,
|
||||
apiKey: process.env.AZURE_OPENAI_LLM_API_KEY,
|
||||
},
|
||||
};
|
||||
|
||||
const embedModelInit = {
|
||||
azure: {
|
||||
apiVersion: process.env.AZURE_OPENAI_EMBEDDING_API_VERSION,
|
||||
endpoint: process.env.AZURE_OPENAI_EMBEDDING_ENDPOINT,
|
||||
apiKey: process.env.AZURE_OPENAI_EMBEDDING_API_KEY,
|
||||
},
|
||||
};
|
||||
|
||||
Settings.llm = new OpenAI(llmInit);
|
||||
Settings.embedModel = new OpenAIEmbedding(embedModelInit);
|
||||
|
||||
async function loadVectorData() {
|
||||
if (!cosmosConnectionString && !cosmosEndpoint) {
|
||||
throw new Error(
|
||||
"Azure CosmosDB connection string or endpoint must be set.",
|
||||
);
|
||||
}
|
||||
|
||||
let cosmosClient: CosmosClient;
|
||||
// initialize the cosmos client
|
||||
if (cosmosConnectionString) {
|
||||
cosmosClient = new CosmosClient(cosmosConnectionString);
|
||||
} else {
|
||||
cosmosClient = new CosmosClient({
|
||||
endpoint: cosmosEndpoint,
|
||||
aadCredentials: new DefaultAzureCredential(),
|
||||
});
|
||||
}
|
||||
|
||||
const reader = new SimpleCosmosDBReader(cosmosClient);
|
||||
// create a configuration object for the reader
|
||||
const simpleCosmosReaderConfig: SimpleCosmosDBReaderLoaderConfig = {
|
||||
databaseName,
|
||||
containerName: collectionName,
|
||||
fields: ["text"],
|
||||
query: "SELECT c.id, c.text as text, c.metadata as metadata FROM c",
|
||||
metadataFields: ["metadata"],
|
||||
};
|
||||
|
||||
// load objects from cosmos and convert them into LlamaIndex Document objects
|
||||
const documents = await reader.loadData(simpleCosmosReaderConfig);
|
||||
// create Azure CosmosDB as a vector store
|
||||
const vectorStore = new AzureCosmosDBNoSqlVectorStore({
|
||||
client: cosmosClient,
|
||||
databaseName,
|
||||
containerName: vectorCollectionName,
|
||||
flatMetadata: false,
|
||||
});
|
||||
|
||||
// Store the embeddings in the CosmosDB container
|
||||
const storageContext = await storageContextFromDefaults({ vectorStore });
|
||||
await VectorStoreIndex.fromDocuments(documents, { storageContext });
|
||||
console.log(
|
||||
`Successfully created embeddings in the CosmosDB container ${vectorCollectionName}.`,
|
||||
);
|
||||
}
|
||||
|
||||
loadVectorData().catch(console.error);
|
||||
@@ -0,0 +1,83 @@
|
||||
import { CosmosClient } from "@azure/cosmos";
|
||||
import { DefaultAzureCredential } from "@azure/identity";
|
||||
import * as dotenv from "dotenv";
|
||||
import {
|
||||
AzureCosmosDBNoSQLConfig,
|
||||
AzureCosmosDBNoSqlVectorStore,
|
||||
OpenAI,
|
||||
OpenAIEmbedding,
|
||||
Settings,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
|
||||
// Load environment variables from local .env file
|
||||
dotenv.config();
|
||||
|
||||
const cosmosEndpoint = process.env.AZURE_COSMOSDB_NOSQL_ENDPOINT!;
|
||||
const cosmosConnectionString =
|
||||
process.env.AZURE_COSMOSDB_NOSQL_CONNECTION_STRING!;
|
||||
const databaseName =
|
||||
process.env.AZURE_COSMOSDB_DATABASE_NAME || "shortStoriesDatabase";
|
||||
const containerName =
|
||||
process.env.AZURE_COSMOSDB_VECTOR_CONTAINER_NAME || "vectorContainer";
|
||||
|
||||
const llmInit = {
|
||||
azure: {
|
||||
apiVersion: process.env.AZURE_OPENAI_LLM_API_VERSION,
|
||||
endpoint: process.env.AZURE_OPENAI_LLM_ENDPOINT,
|
||||
apiKey: process.env.AZURE_OPENAI_LLM_API_KEY,
|
||||
},
|
||||
};
|
||||
|
||||
const embedModelInit = {
|
||||
azure: {
|
||||
apiVersion: process.env.AZURE_OPENAI_EMBEDDING_API_VERSION,
|
||||
endpoint: process.env.AZURE_OPENAI_EMBEDDING_ENDPOINT,
|
||||
apiKey: process.env.AZURE_OPENAI_EMBEDDING_API_KEY,
|
||||
},
|
||||
};
|
||||
|
||||
Settings.llm = new OpenAI(llmInit);
|
||||
Settings.embedModel = new OpenAIEmbedding(embedModelInit);
|
||||
|
||||
async function query() {
|
||||
if (!cosmosConnectionString && !cosmosEndpoint) {
|
||||
throw new Error(
|
||||
"Azure CosmosDB connection string or endpoint must be set.",
|
||||
);
|
||||
}
|
||||
|
||||
let cosmosClient: CosmosClient;
|
||||
// initialize the cosmos client
|
||||
if (cosmosConnectionString) {
|
||||
cosmosClient = new CosmosClient(cosmosConnectionString);
|
||||
} else {
|
||||
cosmosClient = new CosmosClient({
|
||||
endpoint: cosmosEndpoint,
|
||||
aadCredentials: new DefaultAzureCredential(),
|
||||
});
|
||||
}
|
||||
|
||||
// configure the Azure CosmosDB NoSQL Vector Store
|
||||
const dbConfig: AzureCosmosDBNoSQLConfig = {
|
||||
client: cosmosClient,
|
||||
databaseName,
|
||||
containerName,
|
||||
flatMetadata: false,
|
||||
};
|
||||
const store = new AzureCosmosDBNoSqlVectorStore(dbConfig);
|
||||
|
||||
// create an index from the Azure CosmosDB NoSQL Vector Store
|
||||
const index = await VectorStoreIndex.fromVectorStore(store);
|
||||
|
||||
// create a retriever and a query engine from the index
|
||||
const retriever = index.asRetriever({ similarityTopK: 20 });
|
||||
const queryEngine = index.asQueryEngine({ retriever });
|
||||
|
||||
const result = await queryEngine.query({
|
||||
query: "Who all jog?", // Cosmo, Ludo, Maud, Hale, Constance, Garrison, Fergus, Rafe, Waverly, Rex, Loveday
|
||||
});
|
||||
console.log(result.message);
|
||||
}
|
||||
|
||||
void query();
|
||||
@@ -0,0 +1,702 @@
|
||||
[
|
||||
{
|
||||
"text": "Araminta found herself elbow deep in her garden, planting an array of flowers, when she uncovered a tiny, ornate box. Curious, she opened it to reveal a glittering, ancient amulet that promised the bearer the gift of understanding animals. She wore it and spent jubilant afternoons conversing with garden birds and her old cat, Whiskers.",
|
||||
"metadata": {
|
||||
"category": "Category: Fantasy/Adventure",
|
||||
"subCategory": "Gardening Discoveries"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Arden spent the afternoon testing his new invention in the park—a device that could translate dog barks into human language. Each curious bark from nearby dogs resulted in cheers and laughter from the gathering crowd as the device spat out humorous and sassy translations.",
|
||||
"metadata": {
|
||||
"category": "Category: Innovation and Entertainment",
|
||||
"subCategory": "Pet Communication Gadgets"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Azalea rushed through the rainy streets, juggling her groceries as she dodged puddles. Today was her turn to cook the family dinner, and she was determined to make her grandmother's famous lasagna. As she hurried into her apartment, she almost crashed into her neighbor, who laughed and helped her pick up a stray tomato. Despite the chaos, Azalea knew that the warm smiles at dinner would make the rush worthwhile.",
|
||||
"metadata": {
|
||||
"category": "Category: Daily Activities",
|
||||
"subCategory": "Urban Life Challenges"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Birdie hopped off the train in a bustling city, her camera slung over her shoulder. With each snapshot, she captured fleeting moments: a child's laughter, a couple's quarrel, an old man's wisdom-filled eyes. As dusk fell, her photos told the story of a bustling day, weaving a tapestry of urban life that she’d later exhibit at her downtown gallery.",
|
||||
"metadata": {
|
||||
"category": "Urban Photography Exploration",
|
||||
"subCategory": "Urban Photography"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Blythe woke up early to catch the stunning sunrise from her rooftop. Later that morning, she decided to bake blueberry muffins to share with her new neighbors, turning a casual hello into a sweet gesture of friendship. As the day wound down, Blythe hosted a small board games night, filling her home with laughter and strategic whispers only gameplay can inspire.",
|
||||
"metadata": {
|
||||
"category": "Category: Daily Activities",
|
||||
"subCategory": "Urban Lifestyle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Clover dashed through the bustling streets, late for her meeting. In her haste, she bumped into a mime, accidentally becoming part of his performance. The crowd roared with laughter as Clover, red-faced but amused, played along, juggling imaginary balls. Her unintended detour not only entertained a crowd but also landed her a minor role in a local comedy troupe.",
|
||||
"metadata": {
|
||||
"category": "Category: Urban Adventures",
|
||||
"subCategory": "Street Performance Mishaps"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Lilac hurried through the bustling market to pick the freshest vegetables for her impromptu dinner party. As she rushed back home, she bumped into an old friend she hadn't seen in years, leading to an evening filled with laughter and reminiscing, making her dinner party an unexpected reunion.",
|
||||
"metadata": {
|
||||
"category": "Category: Friendship & Reunions",
|
||||
"subCategory": "Impromptu Reunions"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Lavender rushed through her early morning tasks, finding her lost cat, and eventually made it to the bus stop just in time. During her bus ride, she sketched random passengers and struck a conversation with an elderly man who shared fascinating stories about the town's history. Unbeknownst to her, she had left her sketchbook behind, and it embarked on an adventure of its own as various people added their own drawings to it before it finally made its way back to her.",
|
||||
"metadata": {
|
||||
"category": "Category: Daily Adventures",
|
||||
"subCategory": "Urban Adventures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Posey decided it was the perfect day to test her grandmother's vintage typewriter. She set it up in the park, her fingers dancing over the keys as curious onlookers occasionally stopped by. Each click and clack echoed her heart's rhythm, telling a silent story of her love for forgotten treasures. As the sun began to set, Posey realized she had filled pages with whimsical thoughts and tales. Feeling accomplished, she packed up, promising the typewriter another adventure soon.",
|
||||
"metadata": {
|
||||
"category": "Category: Lifestyle and Hobbies",
|
||||
"subCategory": "Vintage Escapades"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Waverly sprinted through the crowded farmer's market, dodging between stalls in a desperate bid to catch the runaway puppy that was weaving through people's legs. Just as it seemed doomed to disappear in the throng, an old lady with lightening reflexes snagged its leash, saving the day with a smile. Waverly thanked her profusely, catching her breath, as the little escape artist barked happily, oblivious to the chaos it had caused.",
|
||||
"metadata": {
|
||||
"category": "Category: Adventure",
|
||||
"subCategory": "Urban Chase"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Birch woke up early for his Saturday morning ritual: hiking through the tranquil forests. Today, he stumbled upon a hidden waterfall he'd never seen before. Mesmerized, he spent hours sketching the scene in his notebook, capturing the beauty in pencil strokes. What started as a typical day, ended with a newfound inspiration for his art.",
|
||||
"metadata": {
|
||||
"category": "Outdoor Adventure & Artistic Inspiration",
|
||||
"subCategory": "Outdoor Exploration"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Booker, a skilled carpenter, spent the quiet Sunday afternoon crafting a unique wooden chessboard. As he intricately carved each piece, he reminisced about the games he played with his grandfather. By sunset, Booker finished the chessboard, feeling a warm sense of accomplishment and connection to his cherished memories.",
|
||||
"metadata": {
|
||||
"category": "Category: Crafts and Hobbies",
|
||||
"subCategory": "Craftsmanship and Memories"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Dane woke up excited, it was finally the day of the city's annual kite festival. He grabbed his handmade kite, its colors vibrant under the sun, and headed to the park. Upon arriving, he found a spot on the grassy hill, feeling the breeze which was perfect for flying. As Dane launched his kite into the sky, a crowd gathered, impressed by its agility and beauty. Hours flew by like seconds, and as the festival ended, Dane felt a sense of pride watching his",
|
||||
"metadata": {
|
||||
"category": "Category: Outdoor Activities",
|
||||
"subCategory": "kite fly so well."
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Garrison missed his bus again, so he decided to jog to work. Along the way, he found a lost dog with no collar. Determined to find the owner, he took a small detour to the local vet, only to discover that the dog was from the next town over. Instead of going to work, Garrison spent his day reuniting the dog with its family, making new friends, and unexpectedly enjoying the best day off.",
|
||||
"metadata": {
|
||||
"category": "Category: Unexpected Adventures",
|
||||
"subCategory": "Unexpected Adventures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Hale, tired after a long work day, decided to unwind with a jog through the bustling city park. Amidst his stride, he spotted a lost puppy with a collar tag inscribed \"Buddy\". Determined, Hale spent the next hour dodging puzzled pedestrians, clumsy cyclists, and precariously perched pigeons to return Buddy to the address on the tag. The grateful owner rewarded Hale with a fresh apple pie, making his unexpected adventure even sweeter.",
|
||||
"metadata": {
|
||||
"category": "Category: Urban Adventure",
|
||||
"subCategory": "Urban Adventure"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Kit dashed through the subway station, barely catching the last train home. He sighed in relief, finally settling into a seat. Across from him, a curious old lady with a large, mysterious hat watched. She pulled a flute from her bag and played a haunting melody that seemed to make the train travel faster. Kit was intrigued by the magic of the moment but knew his stop was next, so he prepared to leave this brief magical encounter behind.",
|
||||
"metadata": {
|
||||
"category": "Category: Urban Fantasy Adventure",
|
||||
"subCategory": "Public Transit Encounters"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Oberon decided to indulge in a rare day off by visiting the local art museum. He wandered through galleries filled with vibrant paintings and ancient sculptures, losing track of time as he immersed himself in stories depicted on canvas and in stone. Each artwork inspired him to sketch ideas for his next graphic novel—a mix of myth and modern struggles. By closing time, his mind buzzed with creativity, eager to transfer his sketches into vivid scenes.",
|
||||
"metadata": {
|
||||
"category": "Category: Creativity and Inspiration",
|
||||
"subCategory": "Art and Creativity"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "While walking his dog in the park, Shaw discovered a hidden, ancient-looking map stuck behind a loose brick near the old fountain. Curious and excited, he followed the map's winding trail, which led him to a buried chest filled with turn-of-the-century coins in a secluded part of the woods.",
|
||||
"metadata": {
|
||||
"category": "Adventure and Discovery",
|
||||
"subCategory": "Adventure_Discovery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Tobin decided to challenge himself with a culinary adventure, aiming to cook dishes from different countries for an entire week. His tiny apartment was soon filled with the aromas of Indian spices, Italian herbs, and Japanese seasonings. The week’s pinnacle was his successful attempt at a complex French dish which he shared with his food-loving friends over laughter and good wine.",
|
||||
"metadata": {
|
||||
"category": "Category: Lifestyle & Cooking",
|
||||
"subCategory": "International Cuisine Challenge"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Winston decided to try his luck at gardening. After weeks of nurturing, his backyard transformed into a splendid display of colorful blooms. Inspired by his success, he entered a local gardening contest and, to his delight, won first prize for his vibrant tulips. His neighbors, impressed by his skills, started seeking his advice, turning Winston into the local gardening guru.",
|
||||
"metadata": {
|
||||
"category": "Category: Hobby and Community Engagement",
|
||||
"subCategory": "Backyard Transformation"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Antigone spent her morning organizing a community clean-up, rallying her neighbors with her infectious enthusiasm. By afternoon, the park was spotless, and everyone celebrated with a picnic under the newly visible sun, sharing stories and homemade lemonade. Antigone felt a deep satisfaction, knowing she had not only cleaned the environment but also strengthened community bonds.",
|
||||
"metadata": {
|
||||
"category": "Category: Community Engagement & Environmentalism",
|
||||
"subCategory": "Community Service"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Antonia raced through the crowded streets, her heart pounding as she clutched the last golden ticket to the midnight art gala. As the city lights blurred past, she dodged a cyclist and leaped over a sleeping dog, determined not to miss the showcase that could launch her hidden photography talent into the limelight. The grand old clock tower struck 11:45; she was almost there, the lights of the gallery flickering like stars just ahead. With her hopes high, she pushed forward",
|
||||
"metadata": {
|
||||
"category": "Category: Urban Adventure",
|
||||
"subCategory": "Urban Adventure"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Aurelia spent the afternoon organizing a community garden clean-up. Under the warm sun, neighbors of all ages gathered, pulling weeds and planting flowers. Their laughter and chatter filled the air, creating a tapestry of camaraderie. As the day ended, Aurelia looked around at the vibrant blooms and the smiling faces, feeling a deep sense of accomplishment and connection.",
|
||||
"metadata": {
|
||||
"category": "Community Service",
|
||||
"subCategory": "Community Volunteering"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Beatrix spent her morning in a bustling café, tirelessly sketching the passersby from her quiet corner. Each person unwittingly contributed to her grand mural envisioned for the local gallery. Her afternoon was a whirlwind of colors and brushes, as she transferred her morning inspirations onto a vast canvas, her vision slowly coming to life.",
|
||||
"metadata": {
|
||||
"category": "Art and Creativity",
|
||||
"subCategory": "Urban Artistry"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Bluebell woke up to a quiet house with a note on the fridge: \"Meet us at the pier.\" Puzzled, she grabbed her bike and headed to the seaside. Arriving, she found her friends with a seaside picnic ready, celebrating her surprise job promotion that she hadn’t told anyone about yet.",
|
||||
"metadata": {
|
||||
"category": "Category: Friendship and Celebration",
|
||||
"subCategory": "Surprise Celebration"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Cecily rushed through the bustling market, her basket brimming with fresh produce. She was preparing a grand feast to celebrate her promotion at work. As she haggled with vendors and gathered ingredients, her excitement grew. With every vegetable and spice, she could almost taste the success of the evening that awaited.",
|
||||
"metadata": {
|
||||
"category": "Category: Celebration Preparation",
|
||||
"subCategory": "Market Adventures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Clementine hurried through her morning routine, grabbing her reusable coffee cup and messenger bag as she dashed out the door. Today was the grand opening of her dream project, a community garden designed to reconnect city dwellers with nature. As she arrived, volunteers from around the neighborhood were already digging and planting under the early morning sun, their laughter blending with the chirps of waking birds. Clementine's heart swelled with pride and excitement, knowing her efforts would blossom into a green oasis amidst the concrete",
|
||||
"metadata": {
|
||||
"category": "Category: Community and Sustainability",
|
||||
"subCategory": "Urban Greening Initiatives"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Coco spent her Sunday mastering the art of homemade pizza. In her tiny kitchen, surrounded by flour clouds and tomato sauce splatters, she discovered that adding a sprinkle of basil from her windowsill garden gave the pizzas an unexpected, delightful twist. The magic truly happened when she shared the steaming slices with her neighbors, turning a quiet day into an impromptu pizza party that lasted into the night.",
|
||||
"metadata": {
|
||||
"category": "Category: Culinary Adventures",
|
||||
"subCategory": "Gourmet Home Cooking"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Constance decided to turn her routine jog into a scavenger hunt around the city. Each park she visited, she collected a unique leaf. By sunset, she had 20 different leaves pinned in her scrapbook, each representing a mile conquered and a new discovery made.",
|
||||
"metadata": {
|
||||
"category": "Outdoor Adventure",
|
||||
"subCategory": "Urban Adventure"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Cosima raced through the bustling streets of the city, dodging pedestrians and street vendors as she tried to make it to the old bookstore before it closed. Inside the cramped, dusty shop, a treasure awaited her—a rare, ancient manuscript that supposedly contained the secrets of forgotten magic. As she finally grasped the leather-bound tome in her hands, she felt a surge of excitement, knowing that her life was about to change forever.",
|
||||
"metadata": {
|
||||
"category": "Category: Adventure",
|
||||
"subCategory": "Urban Adventure"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Dorothy spent the afternoon perfecting her homemade pizza recipe. She kneaded the dough, spun it in the air, and topped it with fresh basil and mozzarella. As the aroma filled her apartment, neighbors knocked, drawn by the scent. Together, they enjoyed slices on her balcony, laughing under the twinkling city lights.",
|
||||
"metadata": {
|
||||
"category": "Category: Culinary Delights",
|
||||
"subCategory": "\"Urban Culinary Delights\""
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Flora spent her morning sifting through vintage records at the local flea market. By sunset, she found herself at a cozy beachside café, sipping tea and sketching the vibrant horizon. An old man nearby shared tales of his youthful adventures at sea, and Flora listened, inspired and sketching his portrait on a napkin, capturing the intricate lines of his life-worn face. A day of simple yet fulfilling connections.",
|
||||
"metadata": {
|
||||
"category": "Category: Daily Activities",
|
||||
"subCategory": "Flea Market Finds & Beachside Inspirations"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Henrietta decided to repurpose her old, dusty attic into a cozy reading nook. She spent the morning clearing out boxes and found a forgotten collection of classic novels. With a fresh coat of paint, some string lights, and a comfy chair, she transformed the space. By evening, Henrietta settled into her new nook, lost in a book as rain pattered softly on the window.",
|
||||
"metadata": {
|
||||
"category": "Home Improvement",
|
||||
"subCategory": "Home Renovation"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Hester rushed through the crowded market, her basket brimming with fresh fruits. Amidst the chaos, she unexpectedly bumped into an old friend she hadn't seen in years, leading to a spontaneous coffee date where they reminisced and planned a future reunion trip to Greece.",
|
||||
"metadata": {
|
||||
"category": "Category: Reunion",
|
||||
"subCategory": "Market Encounter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Honor, renowned for her green thumb, found an unusual seed nestled in her mailbox. Intrigued, she planted it in her garden. The next morning, she woke to find a shimmering tree dripping with golden apples, each bite revealing visions of far-off lands and forgotten tales.",
|
||||
"metadata": {
|
||||
"category": "Category: Fantasy Gardening",
|
||||
"subCategory": "Mystical Gardening"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Ida spent her morning biking through the winding trails of her local park, enjoying the fresh air and the sounds of nature. As she reached the top of a particularly steep hill, she paused to catch her breath and looked out over the city below, feeling a sense of accomplishment wash over her. After her descent, she treated herself to a homemade smoothie at a nearby cafe, savoring the sweet blend of berries and yogurt.",
|
||||
"metadata": {
|
||||
"category": "Outdoor Activities",
|
||||
"subCategory": "Outdoor Activities"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Jemima forgot her umbrella during a sudden downpour and had to take shelter in a quirky little bookshop. As she browsed the shelves, her fingers brushed against a peculiar, ancient-looking tome. When she opened it, a map fell out, leading to a hidden room right there in the shop. Curiosity piqued, she followed it, finding a trove of old, mystical artifacts that hinted at adventures yet to come.",
|
||||
"metadata": {
|
||||
"category": "Category: Adventure/Mystery",
|
||||
"subCategory": "Urban Exploration"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Kitty decided to reorganize her entire wardrobe today. As she sorted through piles of clothes, she discovered an old, forgotten letter tucked inside a jacket. Curiosity piqued, she sat on the floor, unfolding the letter. It turned out to be a heartfelt note from an old friend that brought back a flood of warm memories and a smile to her face. Inspired, Kitty finished her task with a newfound sense of nostalgia, planning to reconnect with her old friend soon.",
|
||||
"metadata": {
|
||||
"category": "Category: Lifestyle & Relationships",
|
||||
"subCategory": "Rediscovery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Loveday forgot her phone at home, but as she reached the park, the serendipity of leaving technology behind felt refreshing. She saw an old man struggling with his shoelaces, bent down to help, and they ended up sharing a bench and stories of their world travels for hours.",
|
||||
"metadata": {
|
||||
"category": "Category: Serendipitous Encounters",
|
||||
"subCategory": "Unplanned Connections"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Marina spent her afternoon at a bustling flea market, searching for vintage vinyl records. Amidst the chaos, she stumbled upon a rare 1960s Beatles album. Thrilled, she bought it and headed to the nearby park, where she played it on a portable record player, attracting a small crowd who shared her appreciation for classic tunes.",
|
||||
"metadata": {
|
||||
"category": "Category: Vintage Shopping and Music Enjoyment",
|
||||
"subCategory": "Vintage Hunting"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Maud briskly tied her sneakers and stepped out into the crisp morning air. Today was her attempt at breaking her personal record for the park's 5K loop. As she ran, her breath made little clouds. Determined, she pushed past the point of fatigue, cheered on by the local squirrels. As she crossed her imaginary finish line, her watch beeped—she did it, a new record! Maud punched the air, a victory against her own limits.",
|
||||
"metadata": {
|
||||
"category": "Exercise Achievement",
|
||||
"subCategory": "Outdoor Running Achievement"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Olympia rushed through her morning routine, spilling coffee as she balanced her laptop bag and keys. At work, she expertly handled a tricky client call that won her praise from her boss. Back home, she soaked in the tub, proud of navigating her hectic yet successful day.",
|
||||
"metadata": {
|
||||
"category": "Category: Daily Work-Life Balance",
|
||||
"subCategory": "Work-Life Balance"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Ottilie decided to make her famous lemon cupcakes for the neighborhood bake sale. As she prepped the ingredients, she realized she was out of sugar. Frantically, she dashed to her neighbor, Mr. Thompson. To her delight, not only did he have sugar, but he also shared his secret recipe for the fluffiest frosting. The cupcakes were a hit, and Ottilie returned home with a smile, her basket empty but her heart full.",
|
||||
"metadata": {
|
||||
"category": "Category: Community Interaction",
|
||||
"subCategory": "Neighborhood Collaboration"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Rosanna, a pastry chef, woke up early to prepare her signature chocolate eclairs. Today was special; she was invited to compete in the local baking contest. As she added the final touches to her eclairs, her oven malfunctioned. Thinking quickly, Rosanna used her neighbor's oven. She rushed to the contest, eclairs in hand, just in time. The judges were impressed with her skills and her quick thinking, awarding her first place.",
|
||||
"metadata": {
|
||||
"category": "Category: Culinary Triumph",
|
||||
"subCategory": "Culinary Challenge"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Sybil hurried through the crowded market, her basket heavy with fresh produce. As she navigated the narrow alleys, she caught a glimpse of a fluttering blue scarf. Curious, she followed it to a small, secluded booth selling handmade jewelry. There, she found an old friend she hadn’t seen in years. They spent the afternoon catching up, surrounded by the vibrant sights and sounds of the bustling market.",
|
||||
"metadata": {
|
||||
"category": "Category: Friendship and Markets",
|
||||
"subCategory": "Market Adventure"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Tabitha woke up to the soft chirping of birds outside her window. Inspired to start gardening, she spent her morning planting vibrant tulips and roses. Little did she know, under the calm soil, she unearthed a time capsule left by the previous homeowner filled with trinkets and old letters, sparking a day filled with mystery and nostalgia.",
|
||||
"metadata": {
|
||||
"category": "Gardening and Discovery",
|
||||
"subCategory": "Backyard Discoveries"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Xenia sprinted towards the bus stop, her mind racing as fast as her legs. She had overslept and couldn't afford to be late for her job interview. As she rounded the corner, she saw the bus starting to pull away. Desperate, she shouted and waved her arms wildly. The bus driver noticed her in the rearview mirror and stopped. Breathing a sigh of relief, Xenia thanked the driver profusely as she boarded. Little did she know that the kindness",
|
||||
"metadata": {
|
||||
"category": "Category: Urban Commute Drama",
|
||||
"subCategory": "Urban Commute Drama"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Balthazar, a retired clockmaker, spent his afternoons in his quiet workshop tinkering with the mysterious, ancient lockbox he found in his attic. One late evening, a series of soft clicks echoed through the room, and the lock sprung open, revealing a dusty set of handwritten notes about hidden mechanics in the town's old clock tower that, if solved, could display the lunar eclipse every timelapse. Eagerly, he set out to unravel a secret older than himself.",
|
||||
"metadata": {
|
||||
"category": "Category: Mystery & Adventure",
|
||||
"subCategory": "Mystery Discovery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Barnaby decided to create a homemade kite using old newspapers and sticks. In the local park, with a slight breeze teasing the leaves, he launched his creation. To his delight and the cheers of nearby children, the kite danced gracefully above the treetops, a testament to simple joys crafted by hand.",
|
||||
"metadata": {
|
||||
"category": "Category: Outdoor Activities",
|
||||
"subCategory": "DIY Crafts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Bertie, always a culinary enthusiast, decided to create her own fusion dish. She combined flavors from Italy and Japan to make sushi pasta. At her dinner party, guests were amazed by the unique blend as chopsticks twirled spaghetti topped with spicy tuna. Bertie smiled, proud of her kitchen adventure.",
|
||||
"metadata": {
|
||||
"category": "Category: Culinary Exploration",
|
||||
"subCategory": "Culinary Fusion"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Cosmo woke up to his alarm blaring at 6 a.m., and groggily got ready for his daily jog. As he hit the park, he noticed more joggers than usual, all training for the upcoming city marathon. Inspired, he pushed his limits and managed his best time yet. After catching his breath, he struck up a conversation with a fellow runner, planning to join the marathon group training sessions starting next week.",
|
||||
"metadata": {
|
||||
"category": "Category: Fitness and Social Interaction",
|
||||
"subCategory": "Fitness Motivation"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Digby woke up to a strange silence in his usually bustling city neighborhood. Curious, he stepped outside and found the streets empty, the usual morning chaos paused. Deciding to investigate, he grabbed his bike and pedaled towards the park. As he arrived, he discovered everyone gathered around a giant, mysterious book that had appeared overnight. Fascinated, Digby joined in, reading alongside neighbors, as the book unveiled untold secrets of their city, making that day an unforgettable adventure in unity and",
|
||||
"metadata": {
|
||||
"category": "Category: Urban Mystery Adventure",
|
||||
"subCategory": "\"Mystery Discovery in the City\""
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Edmund spent his afternoon trying to teach his old dog, Buster, a new trick: playing fetch with a frisbee instead of a ball. Despite Buster's confusion and several failed attempts, Edmund's patience paid off. The park echoed with laughter as Buster finally soared, catching the frisbee mid-air for the first time.",
|
||||
"metadata": {
|
||||
"category": "Category: Pet Training",
|
||||
"subCategory": "Pet Training Success"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Ernest found an old map tucked in a library book about secret city tunnels. Curious, he spent his day off exploring these hidden paths, discovering forgotten underground art and bits of history that even locals were unaware of. By sunset, he had a camera full of incredible images and a heart full of adventure.",
|
||||
"metadata": {
|
||||
"category": "Urban Exploration",
|
||||
"subCategory": "Urban Exploration"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Fergus, after waking up unusually early, decided to take a rare jog in the park. Mid-run, he stumbled upon a lost parrot that could spout hilarious jokes. Amused and curious, he spent hours with the bird, finally helping it find its way back home to a local comedian who had been worried sick. The day left him with sore muscles but a happy heart.",
|
||||
"metadata": {
|
||||
"category": "Category: Unexpected Encounters",
|
||||
"subCategory": "Unexpected Encounters"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Fraser spent the afternoon attempting to teach his cat, Whiskers, to fetch. After countless treats and failed attempts, Whiskers finally chased after the small, crumpled paper ball, returning it triumphantly. Fraser couldn't help but laugh, proud of their small, silly victory.",
|
||||
"metadata": {
|
||||
"category": "Pet Training Achievements",
|
||||
"subCategory": "Pet Training Triumph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Guy, a keen bird watcher, woke up early and ventured into the dense forest with his binoculars. As he navigated through the woods, he stumbled upon a hidden pond where a rare species of owl bathed in the morning sun. Excited, he quietly set up his camera and captured stunning shots, immortalizing his unexpected discovery.",
|
||||
"metadata": {
|
||||
"category": "Wildlife Photography Adventure",
|
||||
"subCategory": "Nature Photography"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Horatio decided to venture into the uncharted forest behind his house. As he delved deeper, he stumbled upon a glowing stone. Without hesitation, he pocketed it, unknowingly releasing a cascade of luck. The following week, Horatio found random money on the streets, aced a job interview, and even won a small lottery.",
|
||||
"metadata": {
|
||||
"category": "Adventure & Supernatural",
|
||||
"subCategory": "Adventure and Fortune"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Hugh discovered an old, dusty keyboard in his attic. Each key he pressed played a unique sound, not just musical notes but also whispers of past conversations. Determined to decode these snippets, he spent his evenings piecing together tales of long-lost love, secret deals, and forgotten friendships, immersing himself in a melodic narrative of histories never recorded.",
|
||||
"metadata": {
|
||||
"category": "Category: Mystery and Discoveries",
|
||||
"subCategory": "Mystery Sounds Exploration"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Laurence spent his Sunday morning at the bustling farmers' market, browsing through stands of fresh vegetables and homemade jams. After selecting a jar of strawberry jam, he shared a laugh with the vendor about a mischievous squirrel stealing tomatoes. Feeling content with his purchases, he pedaled home on his vintage bike, the basket full of vibrant produce.",
|
||||
"metadata": {
|
||||
"category": "Category: Lifestyle & Leisure",
|
||||
"subCategory": "Farmers' Market Adventures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Leopold decided to walk his cat, Mr. Whiskers, through the bustling Sunday market. As they meandered past antique stalls and street-food vendors, the cat spotted a glistening fake jewel. Assuming it was a real gem, Mr. Whiskers pounced, knocking over displays and causing a delightful chaos that ended with Leopold and several amused vendors chasing a very proud cat through the market.",
|
||||
"metadata": {
|
||||
"category": "Category: Daily Life and Pets",
|
||||
"subCategory": "Pet Adventures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Ludo decided to experiment with his usual morning jog by taking a different route through the city. He zigzagged through bustling markets, quiet alleys, and even stumbled upon a hidden garden full of vibrant flowers. Each turn brought new sights and sounds, enriching his morning exercise with unexpected adventures. As he paused to catch his breath, Ludo realized that sometimes, a little change in routine can lead to extraordinary discoveries.",
|
||||
"metadata": {
|
||||
"category": "Category: Urban Exploration",
|
||||
"subCategory": "Urban Exploration"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Lysander woke up at dawn to prepare for his big presentation. After double-checking his slides, he grabbed his lucky pen and cycled to work. Midway, a sudden rain shower forced him to take shelter under a tree, where he met an old friend he hadn't seen in years. They shared coffee at a nearby cafe, reminiscing and laughing over past adventures. Energized by the reunion, Lysander reached his office with minutes to spare, delivered a stellar presentation, and",
|
||||
"metadata": {
|
||||
"category": "Category: Daily Activities",
|
||||
"subCategory": "received applause from his colleagues."
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Maximilian decided to break his routine, swapping his office chair for a mountain bike. As dawn broke, he tackled the steep trails of Shadow Peak, navigating through foggy turns and narrowly missing mischievous squirrels. At the summit, breathless, he watched the sunrise, vowing to make adventure a new part of his daily life.",
|
||||
"metadata": {
|
||||
"category": "Outdoor Adventure",
|
||||
"subCategory": "Outdoor Adventure"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "One rainy afternoon, Otis decided to try his luck at the new artisanal bakery that had opened around the corner. While sampling a delectable raspberry tart, he bumped into a long-lost friend from college. Over cups of steaming hot chocolate, they reminisced about old times and planned a summer reunion trip.",
|
||||
"metadata": {
|
||||
"category": "Category: Chance Encounters",
|
||||
"subCategory": "Unexpected Reunions"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Percival, a librarian, discovered a mysterious, ancient book hidden behind other dusty tomes on medieval literature. As he flipped through it, the characters started leaping off the pages, pulling him into an adventure where he had to solve riddles based on the works of Chaucer to return to the real world. Every solved riddle brought him closer to his own time, weaving through historical events as a silent observer. Finally, after the last riddle, Percival emerged, forever changed",
|
||||
"metadata": {
|
||||
"category": "Category: Fantasy Adventure",
|
||||
"subCategory": "Mystical Adventures in Literature"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Percy forgot his glasses at a cafe. Realizing only at home, he dashed back. There, he found a toddler amusingly trying them on, guided by laughs from surrounding patrons. With a smile, Percy exchanged his glasses for a balloon from his pocket, earning cheer from the crowd.",
|
||||
"metadata": {
|
||||
"category": "Lost and Found",
|
||||
"subCategory": "Lost and Found"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Rafe usually took his morning jog by the lake, but today he decided on the bustling city streets instead. As he rounded a corner, he bumped into an old lady who smiled and handed him a crumpled map, whispering, \"Find the red door, and you shall gain your heart's deepest desire.\" With a mixture of curiosity and excitement, Rafe spent the afternoon tracing the map's clues, which led him through hidden alleys and quaint bookshops. By evening, he stood",
|
||||
"metadata": {
|
||||
"category": "Urban Adventure",
|
||||
"subCategory": "Urban Adventure"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Rafferty always preferred cycling over driving. Every morning, he'd pedal through city streets, weaving swiftly between cars. Today was different; he stumbled upon a curious maze of vintage shops and quirky cafes tucked away in a hidden alley. Deciding to explore, he parked his bike and spent hours lost among antiques, old books, and the rich aroma of freshly brewed coffee. A simple detour turned into an unexpected adventure, sparking his new weekend ritual.",
|
||||
"metadata": {
|
||||
"category": "Urban Exploration",
|
||||
"subCategory": "Urban Exploration"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Rex woke up late and realized he had missed his morning jog. Instead, he quickly dressed and headed to the local bakery to grab his favorite blueberry muffin. As he enjoyed his breakfast on a park bench, a friendly squirrel hopped up beside him, seemingly interested in his meal. Chuckling, Rex tore off a small piece and shared his treat, making a tiny new friend before rushing off to work.",
|
||||
"metadata": {
|
||||
"category": "Category: Daily Life & Animal Encounters",
|
||||
"subCategory": "Morning Routine Twist"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Roland decided to challenge himself to a day without technology. From sunrise, he read books by the window, wrote letters on old stationery, and took long walks in the nearby woods. By sunset, disconnected from the digital world, he felt a serene connection to everything around him.",
|
||||
"metadata": {
|
||||
"category": "Category: Mindfulness and Well-being",
|
||||
"subCategory": "Digital Detox Experience"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Rupert decided to try his hand at baking for the first time. Despite the kitchen chaos, with flour everywhere and eggs on the floor, his homemade cookies came out surprisingly delicious, earning him rave reviews from his skeptical family.",
|
||||
"metadata": {
|
||||
"category": "Category: Baking_Success",
|
||||
"subCategory": "Hobby Baking Success"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Wilfred decided to try yoga for the first time today. Surprisingly flexible, he managed a perfect downward dog pose in his first session, impressing the instructor and making new friends in the class. Feeling invigorated, he promised to make it a part of his daily routine.",
|
||||
"metadata": {
|
||||
"category": "Category: Health & Wellness",
|
||||
"subCategory": "Health and Wellness"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Ziggy, an enthusiastic birdwatcher, ventured into the dense forests early one morning. With his camera and binoculars, he hoped to spot the elusive emerald-feathered parakeet. As daylight broke, Ziggy, perched quietly near an old oak, finally caught a glimpse and snapped the perfect shot, his heart swelling with triumph.",
|
||||
"metadata": {
|
||||
"category": "Outdoor Adventure",
|
||||
"subCategory": "Birdwatching Adventures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Allegra spent her Saturday morning searching for the perfect hat to wear to the outdoor jazz festival. After visiting three boutiques, she found a wide-brimmed, floral sunhat that matched her flowery sundress. As she strolled through the festival, several admirers complimented her style, making her smile brighter than the sunny day.",
|
||||
"metadata": {
|
||||
"category": "Category: Fashion and Events",
|
||||
"subCategory": "Fashion Adventures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Elettra spent her afternoon exploring a secret garden hidden behind her bustling city street. Surrounded by ancient oaks and whispers of forgotten lore, she stumbled upon an intricately carved stone well that promised to grant a wish to those who truly believed. With a hopeful heart, she tossed in a coin, wishing for a glimpse of magical creatures. To her delight, shadows danced, revealing playful pixies who twirled around her in joyous revelry until dusk.",
|
||||
"metadata": {
|
||||
"category": "Urban Fantasy Exploration",
|
||||
"subCategory": "Urban Fantasy Exploration"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Leonora misplaced her keys in the busy marketplace. She retraced her steps, searching every stall she had visited, until a child waved her keychain from atop a nearby fountain. Grateful, Leonora bought the child an ice cream cone, and they laughed about the adventure.",
|
||||
"metadata": {
|
||||
"category": "Category: Lost and Found",
|
||||
"subCategory": "Lost and Found"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Nephele spent her afternoon visiting a local animal shelter. While there, she met an elderly dog named Max who was often overlooked by potential adopters. Touched by his gentle eyes, she decided to adopt him, promising him a loving home and a future filled with cuddles and treats. As they walked home together, Max wagged his tail, knowing he had found his forever friend.",
|
||||
"metadata": {
|
||||
"category": "Category: Heartwarming Acts",
|
||||
"subCategory": "Animal Adoption"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Christabel decided to bake 50 cupcakes for her neighborhood block party. Each cupcake was a masterpiece, adorned with a tiny edible version of their town's famous statue. The party turned into a sweet success, and everyone praised Christabel's creativity and baking skills.",
|
||||
"metadata": {
|
||||
"category": "Category: Community Events",
|
||||
"subCategory": "Baking Mastery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Georgiana spent her afternoon perfecting her grandmother's old recipe for blueberry scones. In the midst of flour clouds and buttery fingers, she discovered the joy of baking, which transformed her gloomy Sunday into a delightful feast, capped off by an unexpected visit from her best friend who was lured by the irresistible aroma.",
|
||||
"metadata": {
|
||||
"category": "Category: Culinary Adventures",
|
||||
"subCategory": "Baking and Friendship"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "In a small coastal town, Prudence stumbled upon an ancient map hidden inside a library book about local legends. Enthralled by the promise of undiscovered treasure, she embarked on a quest that led her through whispering caves, past cunning traps, and across moonlit beaches. Finally, in the hollow of an age-old oak tree, she unearthed a chest brimming with golden doubloons, proving the legends true.",
|
||||
"metadata": {
|
||||
"category": "Adventure",
|
||||
"subCategory": "Adventure and Discovery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Winifred spent her entire Saturday afternoon meticulously organizing her vast collection of vintage vinyl records. Each one had its own special memory and she enjoyed reminiscing as she wiped them down and carefully placed them back into their sleeves. The highlight of her day was discovering an old Beatles album she thought she had lost years ago.",
|
||||
"metadata": {
|
||||
"category": "Category: Leisure and Hobbies",
|
||||
"subCategory": "Hobby Organization"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Milou, a curious dog with a nose for adventure, accidentally hopped on a city bus during his morning stroll through the park. As skyscrapers rammed past him, he spent his afternoon navigating through bustling sidewalks, dodging pedestrians, and stopping by every friendly face for a quick pet before finally boarding the right bus home, a hero in his own epic city tale.",
|
||||
"metadata": {
|
||||
"category": "Category: Animal Adventures",
|
||||
"subCategory": "Urban Animal Adventure"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Posy sprinted through the bustling farmers' market, eyes set on the last bouquet of sunflowers. As she reached for them, so did another hand. A friendly face smiled back at her, sparking conversation over coffee, bonding them over shared love for blooms and lazy Sundays.",
|
||||
"metadata": {
|
||||
"category": "Category: Romance",
|
||||
"subCategory": "Unexpected Encounters"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Suki hurried through the bustling market, her basket brimming with fresh ingredients. Today, she planned to surprise her grandmother with a special dish from her homeland, a delicious meal that carried the aroma of nostalgia and the warmth of family love. As the sun dipped below the horizon, Suki added the final touches, her heart swelling with anticipation and joy.",
|
||||
"metadata": {
|
||||
"category": "Category: Family Traditions",
|
||||
"subCategory": "Market Adventures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Tiggy grabbed her vibrant umbrella as rain splashed the city streets. Despite the weather, her spirits were high; she was on a mission to find the most delectable cupcake in town. Shop after shop, taste after taste, until finally, at a quaint corner bakery, she discovered a chocolate cherry delight that danced on her taste buds, making the rainy day adventure entirely worth it.",
|
||||
"metadata": {
|
||||
"category": "Category: Urban Adventure",
|
||||
"subCategory": "Urban Culinary Quest"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "After his morning run, Carew discovered a curious old map tucked inside a library book on local history. Deciding to follow its trail, he embarked on a spontaneous adventure across town, uncovering hidden art murals and secret gardens that even longtime residents knew nothing about. His day ended with a sunset viewed from the city's highest hill, a spot he would never have found without the mysterious map guiding his steps.",
|
||||
"metadata": {
|
||||
"category": "Adventure, Exploration, Discovery",
|
||||
"subCategory": "Urban Exploration"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Hamish decided to dedicate his morning to baking sourdough bread from scratch. After hours of kneading and waiting, he proudly pulled a golden loaf from the oven. Just as he was about to slice it, his cat, Whiskers, jumped on the counter and swatted the bread onto the floor, making it a game of soccer instead.",
|
||||
"metadata": {
|
||||
"category": "Category: Daily Life Disruptions",
|
||||
"subCategory": "Domestic Adventures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Kenelm decided to turn his mundane evening into an adventure by exploring the labyrinthine alleys of the local flea market. Amidst the clutter of ancient artifacts and eclectic goods, he stumbled upon an old, dusty lamp. With a curious rub, the lamp released a cloud of smoke and a mischievous genie who granted Kenelm three unpredictable wishes that turned his life into an uproarious sequence of events.",
|
||||
"metadata": {
|
||||
"category": "Category: Fantasy Adventure",
|
||||
"subCategory": "Urban Exploration"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Jolyon, an amateur astronomer, had been eagerly awaiting the clearest night to observe a predicted meteor shower. With his trusted telescope perched on the hill behind his house, he marveled as streaks of light danced across the sky, noting each one in his observation log. Suddenly, a much brighter comet not mentioned in any guidebook graced the heavens. Excited, Jolyon recorded its path, realizing he might have discovered a new celestial body.",
|
||||
"metadata": {
|
||||
"category": "Category: Astronomy and Discovery",
|
||||
"subCategory": "Stargazing Discoveries"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Peregrine decided to try a new hobby, birdwatching in the marshes. Equipped with only a pair of old binoculars and a guidebook, he stumbled upon a rare azure-winged magpie. Captivated by its beauty, he spent the whole afternoon tracking its movements, forgetting about the time, until the sunset painted the sky in hues of orange and pink.",
|
||||
"metadata": {
|
||||
"category": "Nature and Adventure",
|
||||
"subCategory": "Outdoor Adventures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Zebedee decided to bring vibrancy to his monotonous routine. Every morning, he now takes a different route to work, each path leading him to unexpected cafés and charming little bookshops. His favorite discovery has been a vintage record store where he’s started a modest collection of jazz vinyls that play every evening as he relaxes. This small change brought a new rhythm to his life, making every day uniquely delightful.",
|
||||
"metadata": {
|
||||
"category": "Category: Lifestyle Change",
|
||||
"subCategory": "Urban Explorations"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Rizal missed his bus to work and decided to walk the distance instead. Along the way, he found a stray puppy shivering under a park bench. Without a second thought, he scooped it up and spent the day caring for it, only to discover that the little dog belonged to a nearby shelter that offered him a job as a caretaker. Rizal never made it to his original job, but he found his calling in unexpected circumstances.",
|
||||
"metadata": {
|
||||
"category": "Category: Unexpected Encounters & Life Changes",
|
||||
"subCategory": "Commuting Challenges and Heartwarming Encounters"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Mastani hurried through the bustling market, weaving between stalls to find the perfect spice blend for her grandmother’s 90th birthday feast. As she picked up a packet, the aroma teased stories of past family gatherings, filling her with warmth and a dash of nostalgia. She rushed home, eager to create a meal that would add another beautiful chapter to their family history.",
|
||||
"metadata": {
|
||||
"category": "Category: Family Traditions",
|
||||
"subCategory": "\"Family Traditions\""
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Loveth spent the morning perfecting her banana bread recipe, hoping to impress her brunch guests. As the delicious aroma filled her kitchen, her cat, Mr. Whiskers, leaped onto the counter, causing a flour explosion. Laughter echoed through the apartment as Loveth chased the mischievous cat, forgetting the oven timer. Her friends arrived, greeted by a slightly charred loaf, but the warm, hearty laughs made the brunch unforgettable.",
|
||||
"metadata": {
|
||||
"category": "Category: Daily Life & Cooking Misadventures",
|
||||
"subCategory": "Kitchen Mishaps"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Hauwa spent her afternoon in a lively pottery class, carefully molding a delicate vase. As the wheel spun, her focus was unmatched, fingers dancing with the clay. The vase slowly took shape, each curve a testament to her patience and creativity. At the end of the day, not only did she leave with a beautiful piece of art, but also a newfound appreciation for the craft.",
|
||||
"metadata": {
|
||||
"category": "Category: Arts and Crafts",
|
||||
"subCategory": "Art and Craft Experience"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Jotaro, a seasoned detective, trudges through the murky streets of the city with his trusty sidekick, a clever corgi named Max. They are hot on the trail of a mysterious jewel thief who has been evading capture for months. Under the dim streetlights, they uncover a clue concealed within an abandoned glove, setting the stage for a thrilling chase across the rooftops, ending with Jotaro cleverly outsmarting the thief, securing the jewels, and earning",
|
||||
"metadata": {
|
||||
"category": "Category: Crime Mystery",
|
||||
"subCategory": "Urban Detective Adventures"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Zarlish, always zealous about her garden, decided to plant a mysterious seed she found nestled in an antique silk pouch at the local market. Weeks later, to her astonishment, the plant sprouted sparkles every sunset, enchanting the whole neighborhood with glimmers of twilight magic.",
|
||||
"metadata": {
|
||||
"category": "Category: Urban Fantasy Gardening",
|
||||
"subCategory": "Mystical Gardening"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Ayzin, a retired opera singer, found unexpected joy teaching stray cats in his neighborhood to respond to classical music. Each morning, as the sun rose, he played different arias from his balcony and delighted in watching the cats gather, their tails swaying in rhythmic appreciation.",
|
||||
"metadata": {
|
||||
"category": "Category: Lifestyle and Animals",
|
||||
"subCategory": "Pet Music Therapy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "Nivetha spent her morning at the farmers market, feeling a buzz of excitement for fresh herbs and sun-ripened tomatoes. With a basket full of vibrant produce, she decided on a whim to host a spontaneous garden dinner for her friends. Under fairy lights and stars, they savored homemade pasta and laughed late into the evening, celebrating simple joys and impromptu gatherings.",
|
||||
"metadata": {
|
||||
"category": "Category: Lifestyle and Entertainment",
|
||||
"subCategory": "\"Market Visit and Garden Dinner\""
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -3,7 +3,7 @@ import { SimpleDirectoryReader } from "llamaindex";
|
||||
function callback(
|
||||
category: string,
|
||||
name: string,
|
||||
status: any,
|
||||
status: unknown,
|
||||
message?: string,
|
||||
): boolean {
|
||||
console.log(category, name, status, message);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
import * as dotenv from "dotenv";
|
||||
import * as fs from "fs";
|
||||
import { MongoClient } from "mongodb";
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
import { SimpleMongoReader } from "@llamaindex/readers/mongo";
|
||||
import * as dotenv from "dotenv";
|
||||
import {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
import * as dotenv from "dotenv";
|
||||
import { MongoDBAtlasVectorSearch, VectorStoreIndex } from "llamaindex";
|
||||
import { MongoClient } from "mongodb";
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getStorageContext } from "./storage";
|
||||
Settings.chunkSize = 512;
|
||||
Settings.chunkOverlap = 20;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
async function getRuntime(func: any) {
|
||||
const start = Date.now();
|
||||
await func();
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { StartEvent, StopEvent, Workflow } from "@llamaindex/workflow";
|
||||
|
||||
type ContextData = {
|
||||
counter: number;
|
||||
};
|
||||
|
||||
const contextData: ContextData = { counter: 0 };
|
||||
|
||||
const workflow = new Workflow<ContextData, string, string>();
|
||||
|
||||
workflow.addStep(
|
||||
{
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [StopEvent<string>],
|
||||
},
|
||||
async (context, startEvent) => {
|
||||
const input = startEvent.data;
|
||||
context.data.counter++;
|
||||
return new StopEvent(`Hello, ${input}!`);
|
||||
},
|
||||
);
|
||||
|
||||
{
|
||||
const ret = await workflow.run("Alex", contextData);
|
||||
console.log(ret.data); // Hello, Alex!
|
||||
}
|
||||
|
||||
{
|
||||
const ret = await workflow.run("World", contextData);
|
||||
console.log(ret.data); // Hello, World!
|
||||
}
|
||||
|
||||
console.log(contextData.counter); // 2
|
||||
@@ -1,13 +1,15 @@
|
||||
{
|
||||
"name": "@llamaindex/examples",
|
||||
"private": true,
|
||||
"version": "0.0.11",
|
||||
"version": "0.0.12",
|
||||
"dependencies": {
|
||||
"@aws-crypto/sha256-js": "^5.2.0",
|
||||
"@azure/cosmos": "^4.1.1",
|
||||
"@azure/identity": "^4.4.1",
|
||||
"@datastax/astra-db-ts": "^1.4.1",
|
||||
"@llamaindex/core": "^0.4.0",
|
||||
"@llamaindex/readers": "^1.0.0",
|
||||
"@llamaindex/workflow": "^0.0.2",
|
||||
"@notionhq/client": "^2.2.15",
|
||||
"@pinecone-database/pinecone": "^3.0.2",
|
||||
"@vercel/postgres": "^0.10.0",
|
||||
@@ -22,7 +24,7 @@
|
||||
"postgres": "^3.4.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.5.1",
|
||||
"@types/node": "^22.8.4",
|
||||
"tsx": "^4.19.0",
|
||||
"typescript": "^5.6.2"
|
||||
},
|
||||
|
||||
@@ -16,13 +16,14 @@ async function getSourceFilenames(sourceDir: string) {
|
||||
function callback(
|
||||
category: string,
|
||||
name: string,
|
||||
status: any,
|
||||
status: unknown,
|
||||
message: string = "",
|
||||
): boolean {
|
||||
console.log(category, name, status, message);
|
||||
return true;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
async function main(args: any) {
|
||||
const sourceDir: string = args.length > 2 ? args[2] : "../data";
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { PineconeVectorStore, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const readline = require("readline").createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
@@ -44,6 +45,7 @@ function isQuit(question: string) {
|
||||
}
|
||||
|
||||
// Function to get user input as a promise
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function getUserInput(readline: any): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
readline.question(
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"llamaindex": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.5.1",
|
||||
"@types/node": "^22.8.4",
|
||||
"tsx": "^4.19.0",
|
||||
"typescript": "^5.6.2"
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ function getTextDocs(jsonList: { text: string; page: number }[]): Document[] {
|
||||
}
|
||||
// Download all images from jsonObjs, send them to OpenAI API to get alt text, return an array of Document objects
|
||||
async function getImageTextDocs(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
jsonObjs: Record<string, any>[],
|
||||
): Promise<Document[]> {
|
||||
const llm = new OpenAI({
|
||||
|
||||
@@ -16,13 +16,14 @@ async function getSourceFilenames(sourceDir: string) {
|
||||
function callback(
|
||||
category: string,
|
||||
name: string,
|
||||
status: any,
|
||||
status: unknown,
|
||||
message: string = "",
|
||||
): boolean {
|
||||
console.log(category, name, status, message);
|
||||
return true;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
async function main(args: any) {
|
||||
const sourceDir: string = args.length > 2 ? args[2] : "../data";
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
import dotenv from "dotenv";
|
||||
import { Document, PGVectorStore, VectorStoreQueryMode } from "llamaindex";
|
||||
import postgres from "postgres";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { PGVectorStore, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const readline = require("readline").createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
@@ -50,6 +51,7 @@ function isQuit(question: string) {
|
||||
}
|
||||
|
||||
// Function to get user input as a promise
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function getUserInput(readline: any): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
readline.question(
|
||||
|
||||
@@ -46,6 +46,7 @@ class PineconeVectorStore<T extends RecordMetadata = RecordMetadata>
|
||||
|
||||
async query(
|
||||
query: VectorStoreQuery,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
kwargs?: any,
|
||||
): Promise<VectorStoreQueryResult> {
|
||||
let queryEmbedding: number[] = [];
|
||||
|
||||
+11
-10
@@ -19,19 +19,20 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.27.5",
|
||||
"@typescript-eslint/eslint-plugin": "^8.3.0",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-next": "^14.2.7",
|
||||
"eslint": "9.13.0",
|
||||
"eslint-config-next": "^15.0.2",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-turbo": "^2.1.0",
|
||||
"eslint-plugin-react": "7.35.0",
|
||||
"husky": "^9.1.5",
|
||||
"lint-staged": "^15.2.9",
|
||||
"eslint-config-turbo": "^2.2.3",
|
||||
"eslint-plugin-react": "7.37.2",
|
||||
"globals": "^15.11.0",
|
||||
"husky": "^9.1.6",
|
||||
"lint-staged": "^15.2.10",
|
||||
"madge": "^8.0.0",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-organize-imports": "^4.0.0",
|
||||
"turbo": "^2.1.2",
|
||||
"typescript": "^5.6.2"
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"turbo": "^2.2.3",
|
||||
"typescript": "^5.6.2",
|
||||
"typescript-eslint": "^8.12.2"
|
||||
},
|
||||
"packageManager": "pnpm@9.5.0",
|
||||
"pnpm": {
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
# @llamaindex/autotool
|
||||
|
||||
## 5.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [35430d3]
|
||||
- llamaindex@0.8.4
|
||||
|
||||
## 5.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.8.3
|
||||
|
||||
## 5.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c7a918c]
|
||||
- llamaindex@0.8.2
|
||||
|
||||
## 5.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.8.1
|
||||
|
||||
## 5.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
# @llamaindex/autotool-01-node-example
|
||||
|
||||
## 0.0.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [35430d3]
|
||||
- llamaindex@0.8.4
|
||||
- @llamaindex/autotool@5.0.4
|
||||
|
||||
## 0.0.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.8.3
|
||||
- @llamaindex/autotool@5.0.3
|
||||
|
||||
## 0.0.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c7a918c]
|
||||
- llamaindex@0.8.2
|
||||
- @llamaindex/autotool@5.0.2
|
||||
|
||||
## 0.0.44
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.8.1
|
||||
- @llamaindex/autotool@5.0.1
|
||||
|
||||
## 0.0.43
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
"scripts": {
|
||||
"start": "node --import tsx --import @llamaindex/autotool/node ./src/index.ts"
|
||||
},
|
||||
"version": "0.0.43"
|
||||
"version": "0.0.47"
|
||||
}
|
||||
|
||||
@@ -18,6 +18,6 @@ const openai = new OpenAI();
|
||||
|
||||
const toolCalls = response.choices[0]!.message.tool_calls ?? [];
|
||||
for (const toolCall of toolCalls) {
|
||||
toolCall.function.name;
|
||||
console.log(toolCall);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
# @llamaindex/autotool-02-next-example
|
||||
|
||||
## 0.1.91
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [35430d3]
|
||||
- llamaindex@0.8.4
|
||||
- @llamaindex/autotool@5.0.4
|
||||
|
||||
## 0.1.90
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.8.3
|
||||
- @llamaindex/autotool@5.0.3
|
||||
|
||||
## 0.1.89
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c7a918c]
|
||||
- llamaindex@0.8.2
|
||||
- @llamaindex/autotool@5.0.2
|
||||
|
||||
## 0.1.88
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.8.1
|
||||
- @llamaindex/autotool@5.0.1
|
||||
|
||||
## 0.1.87
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/autotool-02-next-example",
|
||||
"private": true,
|
||||
"version": "0.1.87",
|
||||
"version": "0.1.91",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
@@ -24,7 +24,7 @@
|
||||
"tailwind-merge": "^2.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.5.1",
|
||||
"@types/node": "^22.8.4",
|
||||
"@types/react": "^18.3.12",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@types/react-syntax-highlighter": "^15.5.11",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/autotool",
|
||||
"type": "module",
|
||||
"version": "5.0.0",
|
||||
"version": "5.0.4",
|
||||
"description": "auto transpile your JS function to LLM Agent compatible",
|
||||
"files": [
|
||||
"dist",
|
||||
@@ -69,7 +69,7 @@
|
||||
"devDependencies": {
|
||||
"@swc/types": "^0.1.12",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/node": "^22.5.1",
|
||||
"@types/node": "^22.8.4",
|
||||
"bunchee": "5.5.1",
|
||||
"llamaindex": "workspace:*",
|
||||
"next": "14.2.11",
|
||||
|
||||
@@ -2,6 +2,7 @@ import { atom, createStore } from "jotai/vanilla";
|
||||
import type { ToolMetadata } from "llamaindex";
|
||||
|
||||
export type Info = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
originalFunction?: (...args: any[]) => any;
|
||||
/**
|
||||
* In current LLM, it doesn't support non-object parameter, so we mock arguments as object, and use this mapping to convert it back.
|
||||
@@ -23,4 +24,5 @@ export type InfoString = {
|
||||
|
||||
export const store = createStore();
|
||||
export const toolMetadataAtom = atom<[ToolMetadata, Info][]>([]);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const toolsAtom = atom<Record<string, (...args: any[]) => any>>({});
|
||||
|
||||
@@ -4,6 +4,7 @@ import webpackPlugin from "./webpack";
|
||||
export function withNext(config: NextConfig) {
|
||||
return {
|
||||
...config,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
webpack: (webpackConfig: any, context: any) => {
|
||||
webpackConfig = config.webpack?.(webpackConfig, context) ?? webpackConfig;
|
||||
webpackConfig.plugins.push(webpackPlugin());
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { ExpressionStatement } from "@swc/types";
|
||||
import { createUnplugin, type UnpluginFactory } from "unplugin";
|
||||
import { isJSorTS, isToolFile, transformAutoTool } from "./compiler";
|
||||
|
||||
export interface Options {}
|
||||
export type Options = object;
|
||||
|
||||
const name = "llama-index-tool";
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @llamaindex/cloud
|
||||
|
||||
## 2.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [9c73f0a]
|
||||
- @llamaindex/core@0.4.1
|
||||
|
||||
## 2.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/cloud",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -18,7 +18,7 @@ type WriteStream = {
|
||||
};
|
||||
|
||||
// Do not modify this variable or cause type errors
|
||||
// eslint-disable-next-line no-var
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, no-var
|
||||
var process: any;
|
||||
|
||||
/**
|
||||
@@ -215,6 +215,7 @@ export class LlamaParseReader extends FileReader {
|
||||
private async getJobResult(
|
||||
jobId: string,
|
||||
resultType: "text" | "json" | "markdown",
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
): Promise<any> {
|
||||
const signal = AbortSignal.timeout(this.maxTimeout * 1000);
|
||||
let tries = 0;
|
||||
@@ -354,6 +355,7 @@ export class LlamaParseReader extends FileReader {
|
||||
*/
|
||||
async loadJson(
|
||||
filePathOrContent: string | Uint8Array,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
): Promise<Record<string, any>[]> {
|
||||
let jobId;
|
||||
const isFilePath = typeof filePathOrContent === "string";
|
||||
@@ -394,8 +396,10 @@ export class LlamaParseReader extends FileReader {
|
||||
* @return {Promise<Record<string, any>[]>} A Promise that resolves to an array of image objects.
|
||||
*/
|
||||
async getImages(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
jsonResult: Record<string, any>[],
|
||||
downloadPath: string,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
): Promise<Record<string, any>[]> {
|
||||
try {
|
||||
// Create download directory if it doesn't exist (Actually check for write access, not existence, since fsPromises does not have a `existsSync` method)
|
||||
@@ -405,6 +409,7 @@ export class LlamaParseReader extends FileReader {
|
||||
await fs.mkdir(downloadPath, { recursive: true });
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const images: Record<string, any>[] = [];
|
||||
for (const result of jsonResult) {
|
||||
const jobId = result.job_id;
|
||||
@@ -473,9 +478,12 @@ export class LlamaParseReader extends FileReader {
|
||||
|
||||
// Filters out invalid values (null, undefined, empty string) of specific params.
|
||||
private filterSpecificParams(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
params: Record<string, any>,
|
||||
keysToCheck: string[],
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
): Record<string, any> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const filteredParams: Record<string, any> = {};
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
if (keysToCheck.includes(key)) {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @llamaindex/community
|
||||
|
||||
## 0.0.58
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [9c73f0a]
|
||||
- @llamaindex/core@0.4.1
|
||||
|
||||
## 0.0.57
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/community",
|
||||
"description": "Community package for LlamaIndexTS",
|
||||
"version": "0.0.57",
|
||||
"version": "0.0.58",
|
||||
"type": "module",
|
||||
"types": "dist/type/index.d.ts",
|
||||
"main": "dist/cjs/index.js",
|
||||
@@ -42,7 +42,7 @@
|
||||
"dev": "bunchee --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.5.1",
|
||||
"@types/node": "^22.8.4",
|
||||
"bunchee": "5.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -31,12 +31,14 @@ import {
|
||||
|
||||
export class AnthropicProvider extends Provider<AnthropicStreamEvent> {
|
||||
getResultFromResponse(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
response: Record<string, any>,
|
||||
): AnthropicNoneStreamingResponse {
|
||||
return JSON.parse(toUtf8(response.body));
|
||||
}
|
||||
|
||||
getToolsFromResponse<AnthropicToolContent>(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
response: Record<string, any>,
|
||||
): AnthropicToolContent[] {
|
||||
const result = this.getResultFromResponse(response);
|
||||
@@ -45,6 +47,7 @@ export class AnthropicProvider extends Provider<AnthropicStreamEvent> {
|
||||
.map((item) => item as AnthropicToolContent);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getTextFromResponse(response: Record<string, any>): string {
|
||||
const result = this.getResultFromResponse(response);
|
||||
return result.content
|
||||
@@ -53,6 +56,7 @@ export class AnthropicProvider extends Provider<AnthropicStreamEvent> {
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getTextFromStreamResponse(response: Record<string, any>): string {
|
||||
const event = this.getStreamingEventResponse(response);
|
||||
if (event?.type === "content_block_delta") {
|
||||
|
||||
@@ -23,12 +23,14 @@ import {
|
||||
|
||||
export class MetaProvider extends Provider<MetaStreamEvent> {
|
||||
getResultFromResponse(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
response: Record<string, any>,
|
||||
): MetaNoneStreamingResponse {
|
||||
return JSON.parse(toUtf8(response.body));
|
||||
}
|
||||
|
||||
getToolsFromResponse<ToolContent>(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
response: Record<string, any>,
|
||||
): ToolContent[] {
|
||||
const result = this.getResultFromResponse(response);
|
||||
@@ -45,12 +47,14 @@ export class MetaProvider extends Provider<MetaStreamEvent> {
|
||||
];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getTextFromResponse(response: Record<string, any>): string {
|
||||
const result = this.getResultFromResponse(response);
|
||||
if (result.generation.trim().startsWith(TOKENS.TOOL_CALL)) return "";
|
||||
return result.generation;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getTextFromStreamResponse(response: Record<string, any>): string {
|
||||
const event = this.getStreamingEventResponse(response);
|
||||
if (event?.generation) {
|
||||
|
||||
@@ -20,15 +20,18 @@ export type BedrockChatStreamResponse = AsyncIterable<
|
||||
ChatResponseChunk<ToolCallLLMMessageOptions>
|
||||
>;
|
||||
|
||||
export abstract class Provider<ProviderStreamEvent extends {} = {}> {
|
||||
export abstract class Provider<ProviderStreamEvent extends object = object> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
abstract getTextFromResponse(response: Record<string, any>): string;
|
||||
|
||||
// Return tool calls from none streaming calls
|
||||
abstract getToolsFromResponse<T extends {} = {}>(
|
||||
abstract getToolsFromResponse<T extends object = object>(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
response: Record<string, any>,
|
||||
): T[];
|
||||
|
||||
getStreamingEventResponse(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
response: Record<string, any>,
|
||||
): ProviderStreamEvent | undefined {
|
||||
return response.chunk?.bytes
|
||||
@@ -47,6 +50,7 @@ export abstract class Provider<ProviderStreamEvent extends {} = {}> {
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getTextFromStreamResponse(response: Record<string, any>): string {
|
||||
return this.getTextFromResponse(response);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @llamaindex/core
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9c73f0a: fix: async local storage in `Setting.with` API
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/core",
|
||||
"type": "module",
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.1",
|
||||
"description": "LlamaIndex Core Module",
|
||||
"exports": {
|
||||
"./agent": {
|
||||
@@ -355,7 +355,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@llamaindex/env": "workspace:*",
|
||||
"@types/node": "^22.5.1",
|
||||
"@types/node": "^22.8.4",
|
||||
"magic-bytes.js": "^1.10.0",
|
||||
"zod": "^3.23.8",
|
||||
"zod-to-json-schema": "^3.23.3"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": "./dist/index.js",
|
||||
"private": true
|
||||
}
|
||||
@@ -28,7 +28,7 @@ export const MAX_TOOL_CALLS = 10;
|
||||
|
||||
export function createTaskOutputStream<
|
||||
Model extends LLM,
|
||||
Store extends object = {},
|
||||
Store extends object = object,
|
||||
AdditionalMessageOptions extends object = Model extends LLM<
|
||||
object,
|
||||
infer AdditionalMessageOptions
|
||||
@@ -99,7 +99,7 @@ export function createTaskOutputStream<
|
||||
|
||||
export type AgentRunnerParams<
|
||||
AI extends LLM,
|
||||
Store extends object = {},
|
||||
Store extends object = object,
|
||||
AdditionalMessageOptions extends object = AI extends LLM<
|
||||
object,
|
||||
infer AdditionalMessageOptions
|
||||
@@ -146,7 +146,7 @@ export type AgentParamsBase<
|
||||
*/
|
||||
export abstract class AgentWorker<
|
||||
AI extends LLM,
|
||||
Store extends object = {},
|
||||
Store extends object = object,
|
||||
AdditionalMessageOptions extends object = AI extends LLM<
|
||||
object,
|
||||
infer AdditionalMessageOptions
|
||||
@@ -198,7 +198,7 @@ export abstract class AgentWorker<
|
||||
*/
|
||||
export abstract class AgentRunner<
|
||||
AI extends LLM,
|
||||
Store extends object = {},
|
||||
Store extends object = object,
|
||||
AdditionalMessageOptions extends object = AI extends LLM<
|
||||
object,
|
||||
infer AdditionalMessageOptions
|
||||
@@ -292,7 +292,7 @@ export abstract class AgentRunner<
|
||||
|
||||
static shouldContinue<
|
||||
AI extends LLM,
|
||||
Store extends object = {},
|
||||
Store extends object = object,
|
||||
AdditionalMessageOptions extends object = AI extends LLM<
|
||||
object,
|
||||
infer AdditionalMessageOptions
|
||||
|
||||
@@ -12,7 +12,7 @@ import type {
|
||||
|
||||
export type AgentTaskContext<
|
||||
Model extends LLM,
|
||||
Store extends object = {},
|
||||
Store extends object = object,
|
||||
AdditionalMessageOptions extends object = Model extends LLM<
|
||||
object,
|
||||
infer AdditionalMessageOptions
|
||||
@@ -38,7 +38,7 @@ export type AgentTaskContext<
|
||||
|
||||
export type TaskStep<
|
||||
Model extends LLM = LLM,
|
||||
Store extends object = {},
|
||||
Store extends object = object,
|
||||
AdditionalMessageOptions extends object = Model extends LLM<
|
||||
object,
|
||||
infer AdditionalMessageOptions
|
||||
@@ -56,7 +56,7 @@ export type TaskStep<
|
||||
|
||||
export type TaskStepOutput<
|
||||
Model extends LLM,
|
||||
Store extends object = {},
|
||||
Store extends object = object,
|
||||
AdditionalMessageOptions extends object = Model extends LLM<
|
||||
object,
|
||||
infer AdditionalMessageOptions
|
||||
@@ -74,7 +74,7 @@ export type TaskStepOutput<
|
||||
|
||||
export type TaskHandler<
|
||||
Model extends LLM,
|
||||
Store extends object = {},
|
||||
Store extends object = object,
|
||||
AdditionalMessageOptions extends object = Model extends LLM<
|
||||
object,
|
||||
infer AdditionalMessageOptions
|
||||
|
||||
@@ -25,9 +25,9 @@ import type { TaskHandler } from "./types.js";
|
||||
type StepToolsResponseParams<Model extends LLM> = {
|
||||
response: ChatResponse<ToolCallLLMMessageOptions>;
|
||||
tools: BaseTool[];
|
||||
step: Parameters<TaskHandler<Model, {}, ToolCallLLMMessageOptions>>[0];
|
||||
step: Parameters<TaskHandler<Model, object, ToolCallLLMMessageOptions>>[0];
|
||||
enqueueOutput: Parameters<
|
||||
TaskHandler<Model, {}, ToolCallLLMMessageOptions>
|
||||
TaskHandler<Model, object, ToolCallLLMMessageOptions>
|
||||
>[1];
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user