create-rag-app 0.1.2 → 0.2.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kundan Kumar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
- # Create RAG App
1
+ # Create RAG App (Beta)
2
2
 
3
- Scaffold a production-ready RAG (Retrieval Augmented Generation) application in seconds.
3
+ > **Note:** This project is currently in beta. Features and APIs are subject to change.
4
+
5
+ Scaffold a RAG (Retrieval Augmented Generation) application in seconds.
4
6
 
5
7
  [![npm version](https://img.shields.io/npm/v/create-rag-app.svg)](https://www.npmjs.com/package/create-rag-app)
6
8
  [![npm downloads](https://img.shields.io/npm/dt/create-rag-app.svg)](https://www.npmjs.com/package/create-rag-app)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-rag-app",
3
- "version": "0.1.2",
3
+ "version": "0.2.1-beta.1",
4
4
  "description": "Scaffold a new RAG application",
5
5
  "type": "module",
6
6
  "bin": {
@@ -34,10 +34,10 @@
34
34
  },
35
35
  "license": "MIT",
36
36
  "dependencies": {
37
+ "@inquirer/prompts": "^8.3.0",
37
38
  "chalk": "^5.6.2",
38
39
  "commander": "^14.0.3",
39
40
  "fs-extra": "^11.3.3",
40
- "inquirer": "^13.2.2",
41
41
  "ora": "^9.3.0"
42
42
  }
43
43
  }
package/src/index.js CHANGED
@@ -3,7 +3,7 @@ import fs from "fs-extra";
3
3
  import chalk from "chalk";
4
4
  import { Command } from "commander";
5
5
  import { getOptions } from "./prompts.js";
6
- import { checkDir, copyTemplate, installDependencies } from "./utils.js";
6
+ import { checkDir, copyTemplate, installDependencies, initGit } from "./utils.js";
7
7
 
8
8
  const packageJson = JSON.parse(
9
9
  await fs.readFile(new URL("../package.json", import.meta.url))
@@ -18,12 +18,18 @@ export async function main() {
18
18
  .version(packageJson.version)
19
19
  .arguments('[project-directory]')
20
20
  .usage(`${chalk.green('[project-directory]')} [options]`)
21
+ .option('-t, --template <template>', 'Specify the template (nextjs-rag, express-rag, fastapi-rag)')
22
+ .option('-p, --provider <provider>', 'Specify the LLM provider (openai, ollama, gemini)')
23
+ .option('-v, --vector-db <vectorDb>', 'Specify the Vector Database (chroma, pinecone, weaviate)')
24
+ .option('--skip-install', 'Skip dependency installation')
25
+ .option('--no-git', 'Skip git initialization')
21
26
  .action((name) => {
22
27
  projectName = name;
23
28
  })
24
29
  .parse(process.argv);
25
30
 
26
- const options = await getOptions(projectName);
31
+ const cliOptions = program.opts();
32
+ const options = await getOptions(projectName, cliOptions);
27
33
  const projectPath = path.resolve(process.cwd(), options.projectName);
28
34
 
29
35
  console.log(`\nCreating a new RAG app in: ${chalk.green(projectPath)}\n`);
@@ -53,11 +59,58 @@ export async function main() {
53
59
  await fs.writeFile(envPath, envContent);
54
60
  }
55
61
 
62
+ // Update package.json based on selections
63
+ const pkgPath = path.join(projectPath, "package.json");
64
+ if (await fs.pathExists(pkgPath)) {
65
+ const pkg = await fs.readJson(pkgPath);
66
+
67
+ // Inject Pinecone dependencies if selected
68
+ if (options.vectorDb === "pinecone") {
69
+ pkg.dependencies = {
70
+ ...pkg.dependencies,
71
+ "@pinecone-database/pinecone": "^4.1.0",
72
+ "@langchain/pinecone": "^0.1.3"
73
+ };
74
+ }
75
+
76
+ // Inject Weaviate dependencies if selected
77
+ if (options.vectorDb === "weaviate") {
78
+ pkg.dependencies = {
79
+ ...pkg.dependencies,
80
+ "weaviate-ts-client": "^2.2.0",
81
+ "@langchain/weaviate": "^0.0.3"
82
+ };
83
+ }
84
+
85
+ // Inject Gemini dependencies if selected
86
+ if (options.provider === "gemini") {
87
+ pkg.dependencies["@langchain/google-genai"] = "^0.1.3";
88
+ }
89
+
90
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
91
+ }
92
+
56
93
  // Install Dependencies (user requested automatic installation)
57
- await installDependencies(projectPath);
94
+ let installed = false;
95
+ if (!options.skipInstall) {
96
+ installed = await installDependencies(projectPath);
97
+ } else {
98
+ console.log(chalk.yellow("\n⚠ Skipping dependency installation."));
99
+ }
100
+
101
+ // Initialize Git
102
+ if (options.git) {
103
+ await initGit(projectPath);
104
+ }
58
105
 
59
106
  // Final Success Message
60
- console.log(chalk.bold.green("\n🎉 Success! Your RAG app is ready."));
107
+ if (installed) {
108
+ console.log(chalk.bold.green("\n🎉 Success! Your RAG app is ready."));
109
+ } else if (options.skipInstall) {
110
+ console.log(chalk.bold.green("\n🎉 Project created successfully."));
111
+ } else {
112
+ console.log(chalk.bold.yellow("\n⚠️ Project created, but dependencies failed to install."));
113
+ }
61
114
  console.log(chalk.yellow("\nNext steps:"));
62
115
  console.log(chalk.cyan(` cd ${options.projectName}`));
63
116
  console.log(chalk.cyan(` npm run dev`));
package/src/prompts.js CHANGED
@@ -1,66 +1,71 @@
1
1
 
2
- import inquirer from "inquirer";
2
+ import { input, select } from "@inquirer/prompts";
3
3
 
4
- export async function getOptions(initialProjectName) {
5
- let questions = [
6
- {
7
- type: "input",
8
- name: "projectName",
4
+ export async function getOptions(initialProjectName, cliOptions = {}) {
5
+ let projectName = initialProjectName;
6
+
7
+ if (projectName) {
8
+ if (!/^([a-z0-9\-\_\.]+)$/.test(projectName)) {
9
+ console.log("⚠ Invalid project name provided via CLI.");
10
+ projectName = null; // Force prompt
11
+ }
12
+ }
13
+
14
+ if (!projectName) {
15
+ projectName = await input({
9
16
  message: "What is your project named?",
10
17
  default: "my-rag-app",
11
- validate: (input) => {
12
- if (/^([a-z0-9\-\_\.]+)$/.test(input)) return true;
18
+ validate: (value) => {
19
+ if (/^([a-z0-9\-\_\.]+)$/.test(value)) return true;
13
20
  return "Project name may only include letters, numbers, dashes, and underscores.";
14
21
  },
15
- },
16
- {
17
- type: "list",
18
- name: "template",
19
- message: "Which template would you like to use?",
22
+ });
23
+ }
24
+
25
+ let template = cliOptions.template;
26
+ if (!template) {
27
+ template = await select({
28
+ message: "Choose template",
20
29
  choices: [
21
- { name: "Next.js + LangChain + ChromaDB (Recommended)", value: "nextjs-rag" },
22
- { name: "Express API + PDF Processor (Backend Only)", value: "express-rag" }, // Future scope
30
+ { name: "Next.js", value: "nextjs-rag" },
31
+ { name: "Express", value: "express-rag" },
32
+ { name: "FastAPI", value: "fastapi-rag" },
23
33
  ],
24
34
  default: "nextjs-rag",
25
- },
26
- {
27
- type: "list",
28
- name: "provider",
29
- message: "Which LLM provider do you want configured?",
35
+ });
36
+ }
37
+
38
+ let provider = cliOptions.provider;
39
+ if (!provider) {
40
+ provider = await select({
41
+ message: "Choose LLM",
30
42
  choices: [
31
- { name: "OpenAI (GPT-4o, GPT-3.5)", value: "openai" },
32
- { name: "Groq (Llama 3, Mixtral - Fast!)", value: "groq" },
33
- { name: "Ollama (Local Models)", value: "ollama" },
34
- { name: "Gemini (Google DeepMind)", value: "gemini" },
43
+ { name: "OpenAI", value: "openai" },
44
+ { name: "Gemini", value: "gemini" },
45
+ { name: "Ollama", value: "ollama" },
35
46
  ],
36
47
  default: "openai",
37
- },
38
- {
39
- type: "list",
40
- name: "vectorDb",
41
- message: "Which Vector Database do you want to use?",
48
+ });
49
+ }
50
+
51
+ let vectorDb = cliOptions.vectorDb;
52
+ if (!vectorDb) {
53
+ vectorDb = await select({
54
+ message: "Choose Vector DB",
42
55
  choices: [
43
- { name: "ChromaDB (Local)", value: "chroma" },
44
- { name: "Supabase pgvector (Cloud)", value: "supabase" },
56
+ { name: "Chroma", value: "chroma" },
57
+ { name: "Pinecone", value: "pinecone" },
58
+ { name: "Weaviate", value: "weaviate" },
45
59
  ],
46
60
  default: "chroma",
47
- },
48
- ];
49
-
50
- if (initialProjectName) {
51
- if (/^([a-z0-9\-\_\.]+)$/.test(initialProjectName)) {
52
- // Valid project name provided via CLI, skip the prompt
53
- questions = questions.filter(q => q.name !== "projectName");
54
- } else {
55
- console.log("⚠ Invalid project name provided via CLI.");
56
- initialProjectName = null; // Force prompt
57
- }
61
+ });
58
62
  }
59
63
 
60
- const answers = await inquirer.prompt(questions);
61
-
62
64
  return {
63
- projectName: initialProjectName || answers.projectName,
64
- ...answers
65
+ projectName,
66
+ template,
67
+ provider,
68
+ vectorDb,
69
+ ...cliOptions
65
70
  };
66
71
  }
package/src/utils.js CHANGED
@@ -46,17 +46,31 @@ export async function installDependencies(targetPath) {
46
46
  // Run npm install in the new directory
47
47
  await execAsync("npm install", { cwd: targetPath });
48
48
  spinner.succeed(chalk.green("Dependencies installed via npm."));
49
+ return true;
49
50
  } catch (err) {
50
51
  // Fallback for peer dependency conflicts common in AI libraries
51
52
  try {
52
53
  spinner.text = "Retrying with --legacy-peer-deps...";
53
54
  await execAsync("npm install --legacy-peer-deps", { cwd: targetPath });
54
55
  spinner.succeed(chalk.green("Dependencies installed with legacy peer deps."));
56
+ return true;
55
57
  } catch (retryErr) {
56
58
  spinner.fail(chalk.red("Failed to install dependencies."));
59
+ if (retryErr.stderr) console.error(chalk.red(retryErr.stderr));
57
60
  console.log(chalk.yellow("You can try installing manually:"));
58
61
  console.log(chalk.cyan(` cd ${path.basename(targetPath)}`));
59
62
  console.log(chalk.cyan(" npm install --legacy-peer-deps"));
63
+ return false;
60
64
  }
61
65
  }
62
66
  }
67
+
68
+ export async function initGit(targetPath) {
69
+ const spinner = ora("Initializing git repository...").start();
70
+ try {
71
+ await execAsync("git init", { cwd: targetPath });
72
+ spinner.succeed(chalk.green("Git repository initialized."));
73
+ } catch (err) {
74
+ spinner.warn(chalk.yellow("Failed to initialize git repository."));
75
+ }
76
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-rag-app",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "next dev",
@@ -10,24 +10,24 @@
10
10
  "ingest": "node scripts/ingest.js"
11
11
  },
12
12
  "dependencies": {
13
- "next": "15.5.10",
14
- "react": "19.0.0-rc-66855b96-20241106",
15
- "react-dom": "19.0.0-rc-66855b96-20241106",
16
- "langchain": "^0.3.5",
17
- "@langchain/openai": "^0.3.11",
18
- "@langchain/ollama": "^0.1.2",
19
- "@langchain/google-genai": "^0.1.3",
20
13
  "@langchain/community": "^0.3.11",
21
14
  "@langchain/core": "^0.3.15",
15
+ "@langchain/google-genai": "^0.1.3",
16
+ "@langchain/ollama": "^0.1.2",
17
+ "@langchain/openai": "^0.3.11",
22
18
  "@langchain/textsplitters": "^0.1.0",
23
19
  "chromadb": "^1.9.4",
24
- "pdf-parse": "1.1.1",
20
+ "dotenv": "^16.4.5",
21
+ "langchain": "^0.3.5",
22
+ "next": "^16.1.6",
25
23
  "openai": "^4.71.1",
26
- "dotenv": "^16.4.5"
24
+ "pdf-parse": "1.1.1",
25
+ "react": "^19.2.4",
26
+ "react-dom": "^19.2.4"
27
27
  },
28
28
  "devDependencies": {
29
+ "autoprefixer": "^10.4.20",
29
30
  "postcss": "^8.4.47",
30
- "tailwindcss": "^3.4.14",
31
- "autoprefixer": "^10.4.20"
31
+ "tailwindcss": "^3.4.14"
32
32
  }
33
33
  }
@@ -1,6 +1,7 @@
1
1
  import { getLLM, getEmbeddings } from "@/lib/llm";
2
- import { Chroma } from "@langchain/community/vectorstores/chroma";
3
2
  import { PromptTemplate } from "@langchain/core/prompts";
3
+ import { StringOutputParser } from "@langchain/core/output_parsers";
4
+ import { RunnableSequence, RunnablePassthrough } from "@langchain/core/runnables";
4
5
 
5
6
  export async function POST(req) {
6
7
  try {
@@ -14,36 +15,65 @@ export async function POST(req) {
14
15
  );
15
16
  }
16
17
 
17
- const vectorStore = await Chroma.fromExistingCollection(getEmbeddings(), {
18
- collectionName: process.env.COLLECTION_NAME || "rag-docs",
19
- url: process.env.CHROMA_URL || "http://localhost:8000"
20
- });
18
+ let vectorStore;
19
+ const embeddings = getEmbeddings();
21
20
 
22
- const retriever = vectorStore.asRetriever();
23
- const llm = getLLM();
21
+ if (process.env.VECTOR_DB === "supabase") {
22
+ const { SupabaseVectorStore } = await import("@langchain/community/vectorstores/supabase");
23
+ const { createClient } = await import("@supabase/supabase-js");
24
+ const client = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_PRIVATE_KEY);
24
25
 
25
- // 🔥 manually retrieve documents
26
- const docs = await retriever.invoke(message);
26
+ vectorStore = await SupabaseVectorStore.fromExistingIndex(embeddings, {
27
+ client,
28
+ tableName: "documents",
29
+ queryName: "match_documents",
30
+ });
31
+ } else {
32
+ const { Chroma } = await import("@langchain/community/vectorstores/chroma");
33
+ vectorStore = await Chroma.fromExistingCollection(embeddings, {
34
+ collectionName: process.env.COLLECTION_NAME || "rag-docs",
35
+ url: process.env.CHROMA_URL || "http://localhost:8000"
36
+ });
37
+ }
27
38
 
28
- const context = docs.map((doc) => doc.pageContent).join("\n\n");
39
+ const retriever = vectorStore.asRetriever();
40
+ const llm = getLLM();
29
41
 
30
- const prompt = PromptTemplate.fromTemplate(`
42
+ const template = `
31
43
  Answer the question based only on the following context:
32
44
 
33
45
  {context}
34
46
 
35
47
  Question: {question}
36
- `);
48
+ `;
37
49
 
38
- const formattedPrompt = await prompt.format({
39
- context,
40
- question: message
41
- });
50
+ const prompt = PromptTemplate.fromTemplate(template);
51
+
52
+ // Create an LCEL chain: Retriever -> Prompt -> LLM -> OutputParser
53
+ const chain = RunnableSequence.from([
54
+ {
55
+ context: retriever.pipe((docs) => docs.map((d) => d.pageContent).join("\n\n")),
56
+ question: new RunnablePassthrough()
57
+ },
58
+ prompt,
59
+ llm,
60
+ new StringOutputParser()
61
+ ]);
42
62
 
43
- const result = await llm.invoke(formattedPrompt);
63
+ const stream = await chain.stream(message);
64
+
65
+ const textEncoder = new TextEncoder();
66
+ const readable = new ReadableStream({
67
+ async start(controller) {
68
+ for await (const chunk of stream) {
69
+ controller.enqueue(textEncoder.encode(chunk));
70
+ }
71
+ controller.close();
72
+ }
73
+ });
44
74
 
45
- return Response.json({
46
- response: result.content
75
+ return new Response(readable, {
76
+ headers: { "Content-Type": "text/plain" },
47
77
  });
48
78
  } catch (error) {
49
79
  console.error(error);