From e564445a045a13f1f6eb957e6d5b508ae942c089 Mon Sep 17 00:00:00 2001 From: mickceb Date: Thu, 25 Apr 2024 16:21:11 +0200 Subject: [PATCH 1/5] init --- .github/workflows/deploy.yml | 17 ++ .gitignore | 183 +----------------- README.md | 20 +- bun.lockb | Bin 75184 -> 73487 bytes image.png | Bin 36043 -> 0 bytes index.ts | 1 - package.json | 26 +-- packages/api/package.json | 25 --- packages/api/src/llm/index.ts | 27 --- packages/front/package.json | 18 -- packages/front/src/index.html | 34 ---- packages/front/src/index.js | 47 ----- packages/front/src/logo-64px.png | Bin 3495 -> 0 bytes .../front/src/logo-64px.png:Zone.Identifier | 0 packages/front/src/style.css | 116 ----------- src/index.ts | 20 ++ src/llm/index.ts | 67 +++++++ {packages/api/src => src}/llm/model.ts | 2 +- {packages/api/src => src}/llm/prompt.ts | 0 {packages/api/src => src}/llm/supabase.ts | 8 +- {packages/api/src => src}/llm/utils.ts | 0 {packages/api/src => src}/server.ts | 0 {packages/api/src => src}/tests.rest | 2 +- {packages/api/src => src}/types/documents.ts | 0 .../api/src => src}/types/requestBody.ts | 0 tests.rest | 6 + tsconfig.json | 28 ++- wrangler.toml | 32 +++ 28 files changed, 185 insertions(+), 494 deletions(-) create mode 100644 .github/workflows/deploy.yml delete mode 100644 image.png delete mode 100644 index.ts delete mode 100644 packages/api/package.json delete mode 100644 packages/api/src/llm/index.ts delete mode 100644 packages/front/package.json delete mode 100644 packages/front/src/index.html delete mode 100644 packages/front/src/index.js delete mode 100644 packages/front/src/logo-64px.png delete mode 100644 packages/front/src/logo-64px.png:Zone.Identifier delete mode 100644 packages/front/src/style.css create mode 100644 src/index.ts create mode 100644 src/llm/index.ts rename {packages/api/src => src}/llm/model.ts (85%) rename {packages/api/src => src}/llm/prompt.ts (100%) rename {packages/api/src => src}/llm/supabase.ts (87%) rename {packages/api/src => src}/llm/utils.ts (100%) rename {packages/api/src => src}/server.ts (100%) rename {packages/api/src => src}/tests.rest (82%) rename {packages/api/src => src}/types/documents.ts (100%) rename {packages/api/src => src}/types/requestBody.ts (100%) create mode 100644 tests.rest create mode 100644 wrangler.toml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..44037b2 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,17 @@ +name: Deploy + +on: + push: + branches: + - main + +jobs: + deploy: + runs-on: ubuntu-latest + name: Deploy + steps: + - uses: actions/checkout@v4 + - name: Deploy + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9b1ee42..3c0be6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,175 +1,10 @@ -# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore - -# Logs - -logs -_.log -npm-debug.log_ -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Caches - -.cache - -# Diagnostic reports (https://nodejs.org/api/report.html) - -report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json - -# Runtime data - -pids -_.pid -_.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover - -lib-cov - -# Coverage directory used by tools like istanbul - -coverage -*.lcov - -# nyc test coverage - -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) - -.grunt - -# Bower dependency directory (https://bower.io/) - -bower_components - -# node-waf configuration - -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) - -build/Release - -# Dependency directories - -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) - -web_modules/ - -# TypeScript cache - -*.tsbuildinfo - -# Optional npm cache directory - -.npm - -# Optional eslint cache - -.eslintcache - -# Optional stylelint cache - -.stylelintcache - -# Microbundle cache - -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history - -.node_repl_history - -# Output of 'npm pack' - -*.tgz - -# Yarn Integrity file - -.yarn-integrity - -# dotenv environment variable files - -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) - -.parcel-cache - -# Next.js build output - -.next -out - -# Nuxt.js build / generate output - -.nuxt +node_modules dist - -# Gatsby files - -# Comment in the public line in if your project uses Gatsby and not Next.js - -# https://nextjs.org/blog/next-9-1#public-directory-support - -# public - -# vuepress build output - -.vuepress/dist - -# vuepress v2.x temp and cache directory - -.temp - -# Docusaurus cache and generated files - -.docusaurus - -# Serverless directories - -.serverless/ - -# FuseBox cache - -.fusebox/ - -# DynamoDB Local files - -.dynamodb/ - -# TernJS port file - -.tern-port - -# Stores VSCode versions used for testing VSCode extensions - -.vscode-test - -# yarn v2 - -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -# IntelliJ based IDEs -.idea - -# Finder (MacOS) folder config -.DS_Store +.wrangler +.dev.vars + +# Change them to your taste: +package-lock.json +yarn.lock +pnpm-lock.yaml +bun.lockb \ No newline at end of file diff --git a/README.md b/README.md index f11eb7b..cc58e96 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,8 @@ -# Node.js AI Assistant +``` +npm install +npm run dev +``` -This project is an example of how to implements a RAG Architecture with LangChain.js and GPT-3.5-turbo to answer any question about the book "Node.js Design Patterns" - -![alt text](image.png) - -### This project was created with: -
-   -   -   -   -   -
\ No newline at end of file +``` +npm run deploy +``` diff --git a/bun.lockb b/bun.lockb index c4911e75f891c190f69747935269da446fdc6b1d..1abaf661e78052b68c86ca7542c07ff9fd83ea24 100755 GIT binary patch literal 73487 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 literal 75184 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 Pp7Rc__BCH#{pbGzl%RJy diff --git a/index.ts b/index.ts deleted file mode 100644 index f67b2c6..0000000 --- a/index.ts +++ /dev/null @@ -1 +0,0 @@ -console.log("Hello via Bun!"); \ No newline at end of file diff --git a/package.json b/package.json index 0553977..bc79d11 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,15 @@ { - "name": "nodejs-ai-assistant", - "module": "index.ts", - "type": "module", "scripts": { - "start": "concurrently \"cd packages/api && bun run server\" \"cd packages/front && bun run start\"" - }, - "workspaces": [ - "packages/api", - "packages/front" - ], - "devDependencies": { - "@types/bun": "latest" - }, - "peerDependencies": { - "typescript": "^5.0.0" + "dev": "wrangler dev src/index.ts", + "deploy": "wrangler deploy --minify src/index.ts" }, "dependencies": { - "concurrently": "^8.2.2" + "@supabase/supabase-js": "^2.42.6", + "hono": "^4.2.7", + "langchain": "^0.1.36" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20240423.0", + "wrangler": "^3.47.0" } -} \ No newline at end of file +} diff --git a/packages/api/package.json b/packages/api/package.json deleted file mode 100644 index 7617112..0000000 --- a/packages/api/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "nodejs-ai-assistant/api", - "module": "server.ts", - "type": "module", - "scripts": { - "server": "bun src/server.ts --watch" - }, - "devDependencies": { - "@types/bun": "latest", - "@types/multer": "^1.4.11", - "@types/express": "^4.17.21", - "@types/cors": "2.8.17" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "dependencies": { - "@supabase/supabase-js": "^2.42.4", - "cors": "^2.8.5", - "express": "^4.19.2", - "langchain": "^0.1.33", - "multer": "^1.4.5-lts.1", - "pdf-parse": "^1.1.1" - } -} \ No newline at end of file diff --git a/packages/api/src/llm/index.ts b/packages/api/src/llm/index.ts deleted file mode 100644 index 119a03f..0000000 --- a/packages/api/src/llm/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { model } from './model' -import { prompt } from './prompt' -import { StringOutputParser } from "@langchain/core/output_parsers"; -import { RunnableSequence, RunnablePassthrough } from "@langchain/core/runnables"; -import { retriever } from './supabase' -import { formatDocumentsAsString } from './utils'; - -export async function main(question: string): Promise { - try { - const chain = RunnableSequence.from([ - { - context: retriever.pipe(formatDocumentsAsString), - question: new RunnablePassthrough() - }, - prompt, - model, - new StringOutputParser() - ]) - const result = await chain.invoke(question) - - return result - - } catch (error: any|unknown) { - console.error("Error: ", error); - return "" - } -} \ No newline at end of file diff --git a/packages/front/package.json b/packages/front/package.json deleted file mode 100644 index 9a35b88..0000000 --- a/packages/front/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "nodejs-ai-assistant/front", - "source": "src/index.html", - "type": "module", - "scripts": { - "start": "parcel", - "build": "parcel build" - }, - "devDependencies": { - "@types/bun": "latest" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "dependencies": { - "parcel": "^2.12.0" - } -} \ No newline at end of file diff --git a/packages/front/src/index.html b/packages/front/src/index.html deleted file mode 100644 index 7d309cd..0000000 --- a/packages/front/src/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - Node.js AI Assistant - RAG created with LangChain.js - - - - -
-
-
- -

Node.js AI Assistant

-

Posez n'importe quelle question, en français, à propos du livre "Node.js Design Patterns".

-

Cette IA, construite avec LangChain.js, est basée sur GPT-3.5-turbo.

-
- -
-
- - -
-
-
-
-
-
-
-
-
- - \ No newline at end of file diff --git a/packages/front/src/index.js b/packages/front/src/index.js deleted file mode 100644 index ed0ed86..0000000 --- a/packages/front/src/index.js +++ /dev/null @@ -1,47 +0,0 @@ -const form = document.querySelector("#form") -// const question = document.querySelector("#question") - -const questionAsked = document.querySelector('#response-question') -const responseDiv = document.querySelector('#response-text') -const reqExecution = document.querySelector("#req-execution") - -form.addEventListener("submit", submitForm) -question.addEventListener("change", () => { - questionAsked.innerHTML = '' - responseDiv.innerHTML = '' - reqExecution.innerHTML = '' -}) - -async function submitForm(e) { - e.preventDefault() - - // const question = e.target.question.value - const question = e.target.question.value - - // Time execution Start - const start = Date.now() - - const response = await fetch("http://localhost:3000/api", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ question }), - }) - // Time execution End - const end = Date.now() - - form.reset() - - questionAsked.innerHTML = ` -

Votre question était

-

${question}"

- ` - responseDiv.innerHTML = ` -

Réponse

-

${await response.text()}

- ` - reqExecution.innerHTML = ` -

Réponse en ${(end - start)/1000} secondes

- ` -} \ No newline at end of file diff --git a/packages/front/src/logo-64px.png b/packages/front/src/logo-64px.png deleted file mode 100644 index 229c1888fedbe9c926f060cd128fb25dfd16e9e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3495 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 VEbIIk^4I_X002ovPDHLkV1heb(sTd- diff --git a/packages/front/src/logo-64px.png:Zone.Identifier b/packages/front/src/logo-64px.png:Zone.Identifier deleted file mode 100644 index e69de29..0000000 diff --git a/packages/front/src/style.css b/packages/front/src/style.css deleted file mode 100644 index 7a75151..0000000 --- a/packages/front/src/style.css +++ /dev/null @@ -1,116 +0,0 @@ -*{ - margin: 0; - padding: 0; - box-sizing: border-box; - font-family: 'Poppins', sans-serif; -} -body, html { - height: 100%; - margin: 0; - display: flex; - justify-content: center; - align-items: center; -} - -.box { - min-height: 400px; - width: 800px; - border: 1px solid #ccc; - padding: 20px 20px; - display: flex; - justify-content: center; - align-items: center; -} - -.container { - width: 100%; -} - -h1 { - margin: 0; - font-size: 3em; - font-weight: 600; - color: #000000; - text-align: center; - padding-bottom: 10px; -} - -h2 { - margin: 0; - font-size: 1.5em; - font-weight: 600; - color: #000000; - text-align: center; - padding-bottom: 1.2rem; -} - -h3 { - margin: 0; - font-size: 2em; - font-weight: 600; - color: #000000; - text-align: center; - padding-bottom: 1.2rem; -} - -p { - margin-bottom: 1.2rem; - color: #000000; - text-align: center; -} - -form{ - width: 50%; -} - -form label{ - font-size: 1rem; -} - -input, textarea, button { - width: 100%; - font-size: 1.2rem; - padding: 0.5em; - border: none; -} -input[type="text"], input[type="email"], textarea { - margin: 0 0 1em; - border: 1px solid #cccccc; - outline: none; -} - -textarea { - height: 6em; -} - -form { - width: 100%; -} - -.form-button{ - background: #000000; - color: #fff; - cursor: pointer; -} -input[type= "submit"]:hover, button:hover { - background: 'black'; -} - -.file-input { - border: 1px solid #000000 ; - margin-bottom: 1.2em; -} - -.box-form { - margin-top: 2em; -} - -.box-response { - margin-top: 2em; -} - -.center { - display: block; - margin-left: auto; - margin-right: auto; -} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..2676ac3 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,20 @@ +import { Hono } from 'hono' +import { getResponseFromLLM } from './llm' + +export type ENV = { + OPENAI_API_KEY: string, + SUPABASE_API_KEY: string, + SUPABASE_URL: string +} + +const app = new Hono<{ Bindings: ENV }>() + +app.post('/api', async (c) => { + const body = await c.req.json() + const question = body.question + const response = await getResponseFromLLM(c, question) + + return c.text(response) +}) + +export default app diff --git a/src/llm/index.ts b/src/llm/index.ts new file mode 100644 index 0000000..90297af --- /dev/null +++ b/src/llm/index.ts @@ -0,0 +1,67 @@ +import { prompt } from "./prompt"; +import { StringOutputParser } from "@langchain/core/output_parsers"; +import { + RunnableSequence, + RunnablePassthrough, +} from "@langchain/core/runnables"; +import { formatDocumentsAsString } from "./utils"; +import { Context } from "hono"; +import { ChatOpenAI } from "langchain/chat_models/openai"; +import { createClient } from "@supabase/supabase-js"; +import { SupabaseVectorStore } from "langchain/vectorstores/supabase"; +import { MultiQueryRetriever } from "langchain/retrievers/multi_query"; +import { OpenAIEmbeddings } from "langchain/embeddings/openai"; + + +export async function getResponseFromLLM( + c: Context, + question: string +): Promise { + try { + // Model + const model = new ChatOpenAI({ + openAIApiKey: c.env.OPENAI_API_KEY, + modelName: "gpt-3.5-turbo", + // temperature: 1, + // topP: 1, + // maxTokens: 1000, + // frequencyPenalty: 0, + // presencePenalty: 0, + // stop: [] + }); + + // Retriever + const supabaseKey = c.env.SUPABASE_API_KEY; + const url = c.env.SUPABASE_URL; + const client = createClient(url, supabaseKey); + + const vectorStore = new SupabaseVectorStore(new OpenAIEmbeddings(), { + client, + tableName: "documents", + queryName: "match_documents", + }); + + const retriever = MultiQueryRetriever.fromLLM({ + llm: model, + retriever: vectorStore.asRetriever(), + verbose: true, + }); + + // Chain + const chain = RunnableSequence.from([ + { + context: retriever.pipe(formatDocumentsAsString), + question: new RunnablePassthrough(), + }, + prompt, + model, + new StringOutputParser(), + ]); + + const result = await chain.invoke(question); + + return result; + } catch (error: any | unknown) { + return ""; + } +} diff --git a/packages/api/src/llm/model.ts b/src/llm/model.ts similarity index 85% rename from packages/api/src/llm/model.ts rename to src/llm/model.ts index f9ada6b..d2ec790 100644 --- a/packages/api/src/llm/model.ts +++ b/src/llm/model.ts @@ -1,7 +1,7 @@ import { ChatOpenAI } from "langchain/chat_models/openai"; export const model = new ChatOpenAI({ - openAIApiKey: process.env.OPENAI_API_KEY, + openAIApiKey: c.env.OPENAI_API_KEY, modelName: "gpt-3.5-turbo", // temperature: 1, // topP: 1, diff --git a/packages/api/src/llm/prompt.ts b/src/llm/prompt.ts similarity index 100% rename from packages/api/src/llm/prompt.ts rename to src/llm/prompt.ts diff --git a/packages/api/src/llm/supabase.ts b/src/llm/supabase.ts similarity index 87% rename from packages/api/src/llm/supabase.ts rename to src/llm/supabase.ts index 45c460a..f5fe76a 100644 --- a/packages/api/src/llm/supabase.ts +++ b/src/llm/supabase.ts @@ -7,11 +7,11 @@ import type { Document } from "langchain/document"; import { MultiQueryRetriever } from "langchain/retrievers/multi_query"; import { model } from "./model"; -if (!process.env.SUPABASE_API_KEY) throw new Error(`Expected SUPABASE_API_KEY`); -const supabaseKey = process.env.SUPABASE_API_KEY; +if (!SUPABASE_API_KEY) throw new Error(`Expected SUPABASE_API_KEY`); +const supabaseKey = SUPABASE_API_KEY; -if (!process.env.SUPABASE_URL) throw new Error(`Expected env var SUPABASE_URL`); -const url = process.env.SUPABASE_URL; +if (!SUPABASE_URL) throw new Error(`Expected env var SUPABASE_URL`); +const url = SUPABASE_URL; const client = createClient(url, supabaseKey); diff --git a/packages/api/src/llm/utils.ts b/src/llm/utils.ts similarity index 100% rename from packages/api/src/llm/utils.ts rename to src/llm/utils.ts diff --git a/packages/api/src/server.ts b/src/server.ts similarity index 100% rename from packages/api/src/server.ts rename to src/server.ts diff --git a/packages/api/src/tests.rest b/src/tests.rest similarity index 82% rename from packages/api/src/tests.rest rename to src/tests.rest index 748dae3..3892307 100644 --- a/packages/api/src/tests.rest +++ b/src/tests.rest @@ -2,7 +2,7 @@ GET http://localhost:3000 ### -POST http://localhost:3000/api +POST http://localhost:8787/api Content-Type: application/json { diff --git a/packages/api/src/types/documents.ts b/src/types/documents.ts similarity index 100% rename from packages/api/src/types/documents.ts rename to src/types/documents.ts diff --git a/packages/api/src/types/requestBody.ts b/src/types/requestBody.ts similarity index 100% rename from packages/api/src/types/requestBody.ts rename to src/types/requestBody.ts diff --git a/tests.rest b/tests.rest new file mode 100644 index 0000000..0ec1917 --- /dev/null +++ b/tests.rest @@ -0,0 +1,6 @@ +POST http://localhost:8787/api +Content-Type: "application/json" + +{ + "question": "How are you?" +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index dcd8fc5..33a96fd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,22 +1,16 @@ { "compilerOptions": { - "lib": ["ESNext"], "target": "ESNext", "module": "ESNext", - "moduleDetection": "force", - "jsx": "react-jsx", - "allowJs": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "noEmit": true, - - /* Linting */ - "skipLibCheck": true, + "moduleResolution": "Bundler", "strict": true, - "noFallthroughCasesInSwitch": true, - "forceConsistentCasingInFileNames": true - } -} + "lib": [ + "ESNext" + ], + "types": [ + "@cloudflare/workers-types" + ], + "jsx": "react-jsx", + "jsxImportSource": "hono/jsx" + }, +} \ No newline at end of file diff --git a/wrangler.toml b/wrangler.toml new file mode 100644 index 0000000..85b7fcc --- /dev/null +++ b/wrangler.toml @@ -0,0 +1,32 @@ +name = "hono-workers" +compatibility_date = "2023-12-01" +main = "src/index.ts" +minify = true + +[vars] +# MY_VAR = "my-variable" +OPENAI_API_KEY="sk-proj-AwzEREEFXPFxx5l1QBmWT3BlbkFJ0caAJJ3aoASGUyFz1re4" +LANGCHAIN_API_KEY="ls__7e3e00493a964889989ed2345f284752" +LANGCHAIN_TRACING_V2=true +SUPABASE_API_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imlvemp0eGJmZnV6YWJ6ZW5yaGJlIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTMyODI4MzMsImV4cCI6MjAyODg1ODgzM30.V6U4L1GC-bm6078ALN1DEfASWrYooU8tnAGzAMo1pKc" +SUPABASE_URL="https://iozjtxbffuzabzenrhbe.supabase.co" + +# [[kv_namespaces]] +# binding = "MY_KV_NAMESPACE" +# id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +# [[r2_buckets]] +# binding = "MY_BUCKET" +# bucket_name = "my-bucket" + +# [[d1_databases]] +# binding = "DB" +# database_name = "my-database" +# database_id = "" + +# [ai] +# binding = "AI" + +# [env.staging.vars] + +# [env.production.vars] \ No newline at end of file From 2e3c8f3d2208ebfa425f6a78e3147f13cd12ee69 Mon Sep 17 00:00:00 2001 From: mickceb Date: Fri, 26 Apr 2024 09:45:30 +0200 Subject: [PATCH 2/5] remove secrets --- wrangler.toml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/wrangler.toml b/wrangler.toml index 85b7fcc..f6c838e 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -5,11 +5,6 @@ minify = true [vars] # MY_VAR = "my-variable" -OPENAI_API_KEY="sk-proj-AwzEREEFXPFxx5l1QBmWT3BlbkFJ0caAJJ3aoASGUyFz1re4" -LANGCHAIN_API_KEY="ls__7e3e00493a964889989ed2345f284752" -LANGCHAIN_TRACING_V2=true -SUPABASE_API_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imlvemp0eGJmZnV6YWJ6ZW5yaGJlIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTMyODI4MzMsImV4cCI6MjAyODg1ODgzM30.V6U4L1GC-bm6078ALN1DEfASWrYooU8tnAGzAMo1pKc" -SUPABASE_URL="https://iozjtxbffuzabzenrhbe.supabase.co" # [[kv_namespaces]] # binding = "MY_KV_NAMESPACE" From 743c1d2b07ec5344958620a339d31acca934786b Mon Sep 17 00:00:00 2001 From: mickceb Date: Fri, 26 Apr 2024 15:14:31 +0200 Subject: [PATCH 3/5] init chatbot --- bun.lockb | Bin 73487 -> 73845 bytes package.json | 5 +- src/index.ts | 84 +++++++++++++--- src/llm/index.ts | 67 ------------- src/llm/model.ts | 12 --- src/llm/prompt.ts | 7 -- src/llm/supabase.ts | 60 ----------- src/server.ts | 36 ------- src/tests.rest | 13 --- src/types/documents.ts | 4 - src/types/requestBody.ts | 3 - src/ui/index.html | 143 +++++++++++++++++++++++++++ src/ui/script.js | 22 +++++ src/ui/style.css | 64 ++++++++++++ src/{llm/utils.ts => utils/index.ts} | 2 +- tests.rest | 6 -- wrangler.toml | 12 +-- 17 files changed, 306 insertions(+), 234 deletions(-) delete mode 100644 src/llm/index.ts delete mode 100644 src/llm/model.ts delete mode 100644 src/llm/prompt.ts delete mode 100644 src/llm/supabase.ts delete mode 100644 src/server.ts delete mode 100644 src/tests.rest delete mode 100644 src/types/documents.ts delete mode 100644 src/types/requestBody.ts create mode 100644 src/ui/index.html create mode 100644 src/ui/script.js create mode 100644 src/ui/style.css rename src/{llm/utils.ts => utils/index.ts} (99%) delete mode 100644 tests.rest diff --git a/bun.lockb b/bun.lockb index 1abaf661e78052b68c86ca7542c07ff9fd83ea24..5026de28d9a484ace832532eeb60dcd1fc3cd9b4 100755 GIT binary patch delta 13432 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 YB~&^?Sz6OX45aGc{cFE|+_}wv0Kb#D-2eap delta 13423 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 f-049N@9OA{M+SOuw+`*O_q`bSNe@x%() +app.get('/', (c) => { + return c.html(ui) +}) + +app.get('/query', async (c) => { + const question = c.req.query("text") + + // Model + const model = new ChatOpenAI({ + openAIApiKey: c.env.OPENAI_API_KEY + }) + // Prompt + const prompt = ChatPromptTemplate.fromTemplate(` + Répond à la question suivante uniquement d'après le context donné: {context} + Donne des exemples de code quand c'est nécessaire. + La réponse doit être formatée en HTML, le texte dans une balise

et les exemples de code dans une balise . + Dans les balises respecte la mise en forme, comme les sauts de ligne. + Question : {question}`) + // Retriever + const supabaseKey = c.env.SUPABASE_API_KEY + const url = c.env.SUPABASE_URL + const client = createClient(url, supabaseKey); + +const vectorStore = new SupabaseVectorStore(new OpenAIEmbeddings({ apiKey: c.env.OPENAI_API_KEY}), { + client, + tableName: "documents", + queryName: "match_documents", +}); + +const retriever = MultiQueryRetriever.fromLLM({ + llm: model, + retriever: vectorStore.asRetriever(), + verbose: true +}) + // Chain + try { + const chain = RunnableSequence.from([ + { + context: retriever.pipe(formatDocumentsAsString), + question: new RunnablePassthrough() + }, + prompt, + model, + new StringOutputParser() + ]) + const result = await chain.invoke(question) + + return c.html(`

${result}
`) -app.post('/api', async (c) => { - const body = await c.req.json() - const question = body.question - const response = await getResponseFromLLM(c, question) + } catch (error: any|unknown) { + console.error("Error: ", error); + return c.html(`
${error.message}
`) + } - return c.text(response) }) -export default app +app.get('/notfound', (c) => { + return c.notFound() +}) + + +export default app \ No newline at end of file diff --git a/src/llm/index.ts b/src/llm/index.ts deleted file mode 100644 index 90297af..0000000 --- a/src/llm/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { prompt } from "./prompt"; -import { StringOutputParser } from "@langchain/core/output_parsers"; -import { - RunnableSequence, - RunnablePassthrough, -} from "@langchain/core/runnables"; -import { formatDocumentsAsString } from "./utils"; -import { Context } from "hono"; -import { ChatOpenAI } from "langchain/chat_models/openai"; -import { createClient } from "@supabase/supabase-js"; -import { SupabaseVectorStore } from "langchain/vectorstores/supabase"; -import { MultiQueryRetriever } from "langchain/retrievers/multi_query"; -import { OpenAIEmbeddings } from "langchain/embeddings/openai"; - - -export async function getResponseFromLLM( - c: Context, - question: string -): Promise { - try { - // Model - const model = new ChatOpenAI({ - openAIApiKey: c.env.OPENAI_API_KEY, - modelName: "gpt-3.5-turbo", - // temperature: 1, - // topP: 1, - // maxTokens: 1000, - // frequencyPenalty: 0, - // presencePenalty: 0, - // stop: [] - }); - - // Retriever - const supabaseKey = c.env.SUPABASE_API_KEY; - const url = c.env.SUPABASE_URL; - const client = createClient(url, supabaseKey); - - const vectorStore = new SupabaseVectorStore(new OpenAIEmbeddings(), { - client, - tableName: "documents", - queryName: "match_documents", - }); - - const retriever = MultiQueryRetriever.fromLLM({ - llm: model, - retriever: vectorStore.asRetriever(), - verbose: true, - }); - - // Chain - const chain = RunnableSequence.from([ - { - context: retriever.pipe(formatDocumentsAsString), - question: new RunnablePassthrough(), - }, - prompt, - model, - new StringOutputParser(), - ]); - - const result = await chain.invoke(question); - - return result; - } catch (error: any | unknown) { - return ""; - } -} diff --git a/src/llm/model.ts b/src/llm/model.ts deleted file mode 100644 index d2ec790..0000000 --- a/src/llm/model.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ChatOpenAI } from "langchain/chat_models/openai"; - -export const model = new ChatOpenAI({ - openAIApiKey: c.env.OPENAI_API_KEY, - modelName: "gpt-3.5-turbo", - // temperature: 1, - // topP: 1, - // maxTokens: 1000, - // frequencyPenalty: 0, - // presencePenalty: 0, - // stop: [] -}) \ No newline at end of file diff --git a/src/llm/prompt.ts b/src/llm/prompt.ts deleted file mode 100644 index c32324e..0000000 --- a/src/llm/prompt.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ChatPromptTemplate } from "@langchain/core/prompts"; - -export const prompt = ChatPromptTemplate.fromTemplate(` - Répond à la question suivante uniquement d'après le context donné: {context} - Donne des exemples de code quand c'est nécessaire. - Question : {question}` -) \ No newline at end of file diff --git a/src/llm/supabase.ts b/src/llm/supabase.ts deleted file mode 100644 index f5fe76a..0000000 --- a/src/llm/supabase.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { SupabaseVectorStore } from "langchain/vectorstores/supabase"; -import { OpenAIEmbeddings } from "langchain/embeddings/openai"; -import { createClient } from "@supabase/supabase-js"; -import { PDFLoader } from "langchain/document_loaders/fs/pdf"; -import { RecursiveCharacterTextSplitter } from "langchain/text_splitter"; -import type { Document } from "langchain/document"; -import { MultiQueryRetriever } from "langchain/retrievers/multi_query"; -import { model } from "./model"; - -if (!SUPABASE_API_KEY) throw new Error(`Expected SUPABASE_API_KEY`); -const supabaseKey = SUPABASE_API_KEY; - -if (!SUPABASE_URL) throw new Error(`Expected env var SUPABASE_URL`); -const url = SUPABASE_URL; - -const client = createClient(url, supabaseKey); - -const vectorStore = new SupabaseVectorStore(new OpenAIEmbeddings(), { - client, - tableName: "documents", - queryName: "match_documents", -}); - -export const retriever = MultiQueryRetriever.fromLLM({ - llm: model, - retriever: vectorStore.asRetriever(), - verbose: true -}) - -/** - * Adding docs to a Supabase Vector store from a PDF file - * - * @export - * @param file - The file to add to the vector store - */ -export async function createAndStoreEmbeddings(file: File) { - try { - // Get chunks - const docs = await loadingAndSplittingDocuments(file) - // Adding chunks to vector store - vectorStore.addDocuments(docs); - } catch (error: any | unknown) { - console.error("ERROR: ", error.message); - } -} - -/** - * Loading and splitting data from a PDF file - * - * @param file - The file to load and split - * @return Returns chunks of the PDF file - */ -async function loadingAndSplittingDocuments(file: File): Promise { - // Loading - const loader = new PDFLoader(file); - const docs = await loader.load(); - // Splitting - const textSplitters = new RecursiveCharacterTextSplitter(); - return await textSplitters.splitDocuments(docs); -} diff --git a/src/server.ts b/src/server.ts deleted file mode 100644 index dff5283..0000000 --- a/src/server.ts +++ /dev/null @@ -1,36 +0,0 @@ - -import express, { type Request, type Response, type NextFunction } from "express" -import cors from "cors" -import { main } from "./llm" - -const app = express() -app.use(express.json()) -app.use(cors()) - -const port = process.env.PORT || 3000 - - -app.get("/", (req: Request, res: Response) => { - res.send("Hello from Node.js AI Assistant!") -}) - -app.post("/api", async (req: Request, res: Response) => { - const { question } = req.body - - const result = await main(question) - res.status(200).send(result) -}) - -app.put('/upload', async (req: Request, res: Response) => { - // TO DO: adding the handle function - res.status(200).send("OK !!!") -}) - -app.use((err: Error, req: Request, res: Response, next: NextFunction) => { - console.error(err.stack); - res.status(500).send('Something went wrong'); -}) - -app.listen(port, () => { - console.log(`Server running at http://localhost:${port}`); -}) \ No newline at end of file diff --git a/src/tests.rest b/src/tests.rest deleted file mode 100644 index 3892307..0000000 --- a/src/tests.rest +++ /dev/null @@ -1,13 +0,0 @@ -GET http://localhost:3000 - - -### -POST http://localhost:8787/api -Content-Type: application/json - -{ - "question": "comment implémenter un proxy" -} - -### -PUT http://localhost:3000/upload \ No newline at end of file diff --git a/src/types/documents.ts b/src/types/documents.ts deleted file mode 100644 index 008d840..0000000 --- a/src/types/documents.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type DocumentToVectorStore = { - pageContent: string, - metadata: object -} \ No newline at end of file diff --git a/src/types/requestBody.ts b/src/types/requestBody.ts deleted file mode 100644 index 41313e2..0000000 --- a/src/types/requestBody.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type requestBody = { - question: string -} \ No newline at end of file diff --git a/src/ui/index.html b/src/ui/index.html new file mode 100644 index 0000000..cc7037a --- /dev/null +++ b/src/ui/index.html @@ -0,0 +1,143 @@ + + + + + + +Node.js Chatbot + + + + +
+
+
Node.js - Your AI Assistant
+
+
+ +
+ + +
+ + + + + diff --git a/src/ui/script.js b/src/ui/script.js new file mode 100644 index 0000000..d2b6a49 --- /dev/null +++ b/src/ui/script.js @@ -0,0 +1,22 @@ +function sendMessage() { + var userInput = document.getElementById("user-input").value; + if (userInput.trim() === "") return; + + var chatMessages = document.getElementById("chat-messages"); + var userMessage = document.createElement("div"); + userMessage.className = "message user-message"; + userMessage.innerHTML = userInput; + chatMessages.appendChild(userMessage); + + // Simulate bot response (replace with actual response from server) + setTimeout(function() { + var botMessage = document.createElement("div"); + botMessage.className = "message bot-message"; + botMessage.innerHTML = "I'm just a demo, but I'm glad you asked!"; + chatMessages.appendChild(botMessage); + chatMessages.scrollTop = chatMessages.scrollHeight; + }, 500); + + document.getElementById("user-input").value = ""; + chatMessages.scrollTop = chatMessages.scrollHeight; +} \ No newline at end of file diff --git a/src/ui/style.css b/src/ui/style.css new file mode 100644 index 0000000..1a2b6ef --- /dev/null +++ b/src/ui/style.css @@ -0,0 +1,64 @@ +body { + font-family: Arial, sans-serif; + background-color: #f4f4f4; + margin: 0; + padding: 0; + box-sizing: border-box; +} + +.chat-container { + width: 300px; + margin: 50px auto; + border: 1px solid #ccc; + border-radius: 5px; + overflow: hidden; +} + +.chat-messages { + padding: 10px; + height: 300px; + overflow-y: scroll; +} + +.message { + margin-bottom: 10px; +} + +.user-message { + background-color: #3b5998; + color: white; + padding: 8px 10px; + border-radius: 5px; + float: right; +} + +.bot-message { + background-color: #eceff1; + color: #333; + padding: 8px 10px; + border-radius: 5px; + float: left; +} + +.chat-input { + width: calc(100% - 20px); + padding: 10px; + border: 1px solid #ccc; + border-radius: 5px; + margin: 10px; +} + +.send-btn { + padding: 10px 20px; + background-color: #3b5998; + color: white; + border: none; + border-radius: 5px; + cursor: pointer; + float: right; + margin-right: 10px; +} + +.send-btn:hover { + background-color: #2a3f7f; +} \ No newline at end of file diff --git a/src/llm/utils.ts b/src/utils/index.ts similarity index 99% rename from src/llm/utils.ts rename to src/utils/index.ts index c01cc07..b0a28f0 100644 --- a/src/llm/utils.ts +++ b/src/utils/index.ts @@ -9,4 +9,4 @@ import type { Document } from "langchain/document"; */ export async function formatDocumentsAsString(documents: Document[]): Promise { return documents.map(doc => doc.pageContent).join("\n") -} +} \ No newline at end of file diff --git a/tests.rest b/tests.rest deleted file mode 100644 index 0ec1917..0000000 --- a/tests.rest +++ /dev/null @@ -1,6 +0,0 @@ -POST http://localhost:8787/api -Content-Type: "application/json" - -{ - "question": "How are you?" -} \ No newline at end of file diff --git a/wrangler.toml b/wrangler.toml index f6c838e..9003070 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -1,9 +1,7 @@ -name = "hono-workers" +name = "nodejs-chatbot" compatibility_date = "2023-12-01" -main = "src/index.ts" -minify = true -[vars] +# [vars] # MY_VAR = "my-variable" # [[kv_namespaces]] @@ -20,8 +18,4 @@ minify = true # database_id = "" # [ai] -# binding = "AI" - -# [env.staging.vars] - -# [env.production.vars] \ No newline at end of file +# binding = "AI" \ No newline at end of file From f9927d0a5eb482ee33f3978c527da1e99c62ff8f Mon Sep 17 00:00:00 2001 From: mickceb Date: Fri, 26 Apr 2024 15:23:02 +0200 Subject: [PATCH 4/5] add readme --- README.md | 21 ++++++++++++++------- image.png | Bin 0 -> 19551 bytes 2 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 image.png diff --git a/README.md b/README.md index cc58e96..afff710 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,15 @@ -``` -npm install -npm run dev -``` +# Node.js AI Assistant -``` -npm run deploy -``` +This project is an example of how to implements a RAG Architecture with LangChain.js and GPT-3.5-turbo to answer any question about the book "Node.js Design Patterns" + +![alt text](image.png) + +### This project was created with: +
+   +   +   +   +   +   +
\ No newline at end of file diff --git a/image.png b/image.png new file mode 100644 index 0000000000000000000000000000000000000000..8c236b2cfd0634977507dea3a8529b85ab061efe GIT binary patch literal 19551 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 Date: Fri, 26 Apr 2024 15:27:00 +0200 Subject: [PATCH 5/5] update --- .gitignore | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 174 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 3c0be6e..e55124c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,176 @@ -node_modules -dist -.wrangler +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local .dev.vars -# Change them to your taste: -package-lock.json -yarn.lock -pnpm-lock.yaml -bun.lockb \ No newline at end of file +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store \ No newline at end of file