create-rag-app 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1,49 +1,53 @@
1
- # Create RAG App
2
-
3
- Scaffold a production-ready RAG (Retrieval Augmented Generation) application in seconds.
4
-
5
- ## Features
6
-
7
- - šŸš€ **Next.js & React**: Modern frontend with Tailwind setup.
8
- - 🦜 **LangChain**: Best-in-class RAG pipeline.
9
- - šŸ—„ļø **ChromaDB**: Built-in local vector database.
10
- - šŸ¤– **Multi-LLM Support**: Switch between OpenAI, Groq, and Ollama.
11
- - šŸ“„ **Document Ingestion**: Simple script to index PDFs and Text files.
12
-
13
- ## Usage
14
-
15
- ```bash
16
- # Run directly with npx
17
- npx create-rag-app my-ai-project
18
-
19
- # Or install globally
20
- npm install -g create-rag-app
21
- create-rag-app my-ai-project
22
- ```
23
-
24
- ## Structure Result
25
-
26
- The created app will have:
27
-
28
- - `src/app`: User Interface (Chat)
29
- - `src/lib`: RAG Utilities
30
- - `scripts/ingest.js`: Document processor
31
- - `documents/`: Folder to drop your knowledge base
32
-
33
- ## Development
34
-
35
- ```bash
36
- # Clone the repo
37
- git clone https://github.com/your-username/create-rag-app.git
38
-
39
- # Install dependencies
40
- npm install
41
-
42
- # Test locally
43
- npm link
44
- create-rag-app test-project
45
- ```
46
-
47
- ## License
48
-
49
- MIT
1
+ # Create RAG App
2
+
3
+ Scaffold a production-ready RAG (Retrieval Augmented Generation) application in seconds.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/create-rag-app.svg)](https://www.npmjs.com/package/create-rag-app)
6
+ [![npm downloads](https://img.shields.io/npm/dt/create-rag-app.svg)](https://www.npmjs.com/package/create-rag-app)
7
+
8
+
9
+ ## Features
10
+
11
+ - šŸš€ **Next.js & React**: Modern frontend with Tailwind setup.
12
+ - 🦜 **LangChain**: Best-in-class RAG pipeline.
13
+ - šŸ—„ļø **ChromaDB**: Built-in local vector database.
14
+ - šŸ¤– **Multi-LLM Support**: Switch between OpenAI, Groq, and Ollama.
15
+ - šŸ“„ **Document Ingestion**: Simple script to index PDFs and Text files.
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ # Run directly with npx
21
+ npx create-rag-app my-ai-project
22
+
23
+ # Or install globally
24
+ npm install -g create-rag-app
25
+ create-rag-app my-ai-project
26
+ ```
27
+
28
+ ## Structure Result
29
+
30
+ The created app will have:
31
+
32
+ - `src/app`: User Interface (Chat)
33
+ - `src/lib`: RAG Utilities
34
+ - `scripts/ingest.js`: Document processor
35
+ - `documents/`: Folder to drop your knowledge base
36
+
37
+ ## Development
38
+
39
+ ```bash
40
+ # Clone the repo
41
+ git clone https://github.com/your-username/create-rag-app.git
42
+
43
+ # Install dependencies
44
+ npm install
45
+
46
+ # Test locally
47
+ npm link
48
+ create-rag-app test-project
49
+ ```
50
+
51
+ ## License
52
+
53
+ MIT
package/bin/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
-
3
- import { main } from "../src/index.js";
4
-
5
- main().catch((err) => {
6
- console.error(err);
7
- process.exit(1);
8
- });
2
+
3
+ import { main } from "../src/index.js";
4
+
5
+ main().catch((err) => {
6
+ console.error(err);
7
+ process.exit(1);
8
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-rag-app",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Scaffold a new RAG application",
5
5
  "type": "module",
6
6
  "bin": {
@@ -24,6 +24,14 @@
24
24
  "chroma",
25
25
  "ai"
26
26
  ],
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/itwaasyou/create-rag-app.git"
30
+ },
31
+ "homepage": "https://github.com/itwaasyou/create-rag-app",
32
+ "bugs": {
33
+ "url": "https://github.com/itwaasyou/create-rag-app/issues"
34
+ },
27
35
  "license": "MIT",
28
36
  "dependencies": {
29
37
  "chalk": "^5.6.2",
package/src/index.js CHANGED
@@ -1,65 +1,65 @@
1
- import path from "path";
2
- import fs from "fs-extra";
3
- import chalk from "chalk";
4
- import { Command } from "commander";
5
- import { getOptions } from "./prompts.js";
6
- import { checkDir, copyTemplate, installDependencies } from "./utils.js";
7
-
8
- const packageJson = JSON.parse(
9
- await fs.readFile(new URL("../package.json", import.meta.url))
10
- );
11
-
12
- export async function main() {
13
- console.log(chalk.bold.cyan("\nšŸš€ Welcome to Create RAG App!\n"));
14
-
15
- let projectName;
16
-
17
- const program = new Command(packageJson.name)
18
- .version(packageJson.version)
19
- .arguments('[project-directory]')
20
- .usage(`${chalk.green('[project-directory]')} [options]`)
21
- .action((name) => {
22
- projectName = name;
23
- })
24
- .parse(process.argv);
25
-
26
- const options = await getOptions(projectName);
27
- const projectPath = path.resolve(process.cwd(), options.projectName);
28
-
29
- console.log(`\nCreating a new RAG app in: ${chalk.green(projectPath)}\n`);
30
-
31
- // Ensure directory doesn't exist
32
- checkDir(projectPath);
33
-
34
- // Copy template
35
- // We need to map the template option to a folder name
36
- // The 'value' in prompts.js choices is 'nextjs-rag', so ensure that folder exists in templates/
37
- const templateName = options.template;
38
- await copyTemplate(templateName, projectPath);
39
-
40
- // Configure Environment Variables
41
- const envExamplePath = path.join(projectPath, ".env.example");
42
- const envPath = path.join(projectPath, ".env");
43
-
44
- if (await fs.pathExists(envExamplePath)) {
45
- await fs.copy(envExamplePath, envPath);
46
- console.log(chalk.green("āœ” Created .env file from example"));
47
-
48
- // Inject selected provider config
49
- let envContent = await fs.readFile(envPath, "utf-8");
50
- envContent += `\n# Auto-generated config\n`;
51
- envContent += `LLM_PROVIDER=${options.provider}\n`;
52
- envContent += `VECTOR_DB=${options.vectorDb}\n`;
53
- await fs.writeFile(envPath, envContent);
54
- }
55
-
56
- // Install Dependencies (user requested automatic installation)
57
- await installDependencies(projectPath);
58
-
59
- // Final Success Message
60
- console.log(chalk.bold.green("\nšŸŽ‰ Success! Your RAG app is ready."));
61
- console.log(chalk.yellow("\nNext steps:"));
62
- console.log(chalk.cyan(` cd ${options.projectName}`));
63
- console.log(chalk.cyan(` npm run dev`));
64
- console.log("");
65
- }
1
+ import path from "path";
2
+ import fs from "fs-extra";
3
+ import chalk from "chalk";
4
+ import { Command } from "commander";
5
+ import { getOptions } from "./prompts.js";
6
+ import { checkDir, copyTemplate, installDependencies } from "./utils.js";
7
+
8
+ const packageJson = JSON.parse(
9
+ await fs.readFile(new URL("../package.json", import.meta.url))
10
+ );
11
+
12
+ export async function main() {
13
+ console.log(chalk.bold.cyan("\nšŸš€ Welcome to Create RAG App!\n"));
14
+
15
+ let projectName;
16
+
17
+ const program = new Command(packageJson.name)
18
+ .version(packageJson.version)
19
+ .arguments('[project-directory]')
20
+ .usage(`${chalk.green('[project-directory]')} [options]`)
21
+ .action((name) => {
22
+ projectName = name;
23
+ })
24
+ .parse(process.argv);
25
+
26
+ const options = await getOptions(projectName);
27
+ const projectPath = path.resolve(process.cwd(), options.projectName);
28
+
29
+ console.log(`\nCreating a new RAG app in: ${chalk.green(projectPath)}\n`);
30
+
31
+ // Ensure directory doesn't exist
32
+ checkDir(projectPath);
33
+
34
+ // Copy template
35
+ // We need to map the template option to a folder name
36
+ // The 'value' in prompts.js choices is 'nextjs-rag', so ensure that folder exists in templates/
37
+ const templateName = options.template;
38
+ await copyTemplate(templateName, projectPath);
39
+
40
+ // Configure Environment Variables
41
+ const envExamplePath = path.join(projectPath, ".env.example");
42
+ const envPath = path.join(projectPath, ".env");
43
+
44
+ if (await fs.pathExists(envExamplePath)) {
45
+ await fs.copy(envExamplePath, envPath);
46
+ console.log(chalk.green("āœ” Created .env file from example"));
47
+
48
+ // Inject selected provider config
49
+ let envContent = await fs.readFile(envPath, "utf-8");
50
+ envContent += `\n# Auto-generated config\n`;
51
+ envContent += `LLM_PROVIDER=${options.provider}\n`;
52
+ envContent += `VECTOR_DB=${options.vectorDb}\n`;
53
+ await fs.writeFile(envPath, envContent);
54
+ }
55
+
56
+ // Install Dependencies (user requested automatic installation)
57
+ await installDependencies(projectPath);
58
+
59
+ // Final Success Message
60
+ console.log(chalk.bold.green("\nšŸŽ‰ Success! Your RAG app is ready."));
61
+ console.log(chalk.yellow("\nNext steps:"));
62
+ console.log(chalk.cyan(` cd ${options.projectName}`));
63
+ console.log(chalk.cyan(` npm run dev`));
64
+ console.log("");
65
+ }
package/src/prompts.js CHANGED
@@ -1,66 +1,66 @@
1
-
2
- import inquirer from "inquirer";
3
-
4
- export async function getOptions(initialProjectName) {
5
- let questions = [
6
- {
7
- type: "input",
8
- name: "projectName",
9
- message: "What is your project named?",
10
- default: "my-rag-app",
11
- validate: (input) => {
12
- if (/^([a-z0-9\-\_\.]+)$/.test(input)) return true;
13
- return "Project name may only include letters, numbers, dashes, and underscores.";
14
- },
15
- },
16
- {
17
- type: "list",
18
- name: "template",
19
- message: "Which template would you like to use?",
20
- choices: [
21
- { name: "Next.js + LangChain + ChromaDB (Recommended)", value: "nextjs-rag" },
22
- { name: "Express API + PDF Processor (Backend Only)", value: "express-rag" }, // Future scope
23
- ],
24
- default: "nextjs-rag",
25
- },
26
- {
27
- type: "list",
28
- name: "provider",
29
- message: "Which LLM provider do you want configured?",
30
- 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" },
35
- ],
36
- default: "openai",
37
- },
38
- {
39
- type: "list",
40
- name: "vectorDb",
41
- message: "Which Vector Database do you want to use?",
42
- choices: [
43
- { name: "ChromaDB (Local)", value: "chroma" },
44
- { name: "Supabase pgvector (Cloud)", value: "supabase" },
45
- ],
46
- 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
- }
58
- }
59
-
60
- const answers = await inquirer.prompt(questions);
61
-
62
- return {
63
- projectName: initialProjectName || answers.projectName,
64
- ...answers
65
- };
66
- }
1
+
2
+ import inquirer from "inquirer";
3
+
4
+ export async function getOptions(initialProjectName) {
5
+ let questions = [
6
+ {
7
+ type: "input",
8
+ name: "projectName",
9
+ message: "What is your project named?",
10
+ default: "my-rag-app",
11
+ validate: (input) => {
12
+ if (/^([a-z0-9\-\_\.]+)$/.test(input)) return true;
13
+ return "Project name may only include letters, numbers, dashes, and underscores.";
14
+ },
15
+ },
16
+ {
17
+ type: "list",
18
+ name: "template",
19
+ message: "Which template would you like to use?",
20
+ choices: [
21
+ { name: "Next.js + LangChain + ChromaDB (Recommended)", value: "nextjs-rag" },
22
+ { name: "Express API + PDF Processor (Backend Only)", value: "express-rag" }, // Future scope
23
+ ],
24
+ default: "nextjs-rag",
25
+ },
26
+ {
27
+ type: "list",
28
+ name: "provider",
29
+ message: "Which LLM provider do you want configured?",
30
+ 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" },
35
+ ],
36
+ default: "openai",
37
+ },
38
+ {
39
+ type: "list",
40
+ name: "vectorDb",
41
+ message: "Which Vector Database do you want to use?",
42
+ choices: [
43
+ { name: "ChromaDB (Local)", value: "chroma" },
44
+ { name: "Supabase pgvector (Cloud)", value: "supabase" },
45
+ ],
46
+ 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
+ }
58
+ }
59
+
60
+ const answers = await inquirer.prompt(questions);
61
+
62
+ return {
63
+ projectName: initialProjectName || answers.projectName,
64
+ ...answers
65
+ };
66
+ }
package/src/utils.js CHANGED
@@ -1,62 +1,62 @@
1
-
2
- import fs from "fs-extra";
3
- import path from "path";
4
- import chalk from "chalk";
5
- import { exec } from "child_process";
6
- import util from "util";
7
- import ora from "ora";
8
- import { fileURLToPath } from 'url';
9
-
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = path.dirname(__filename);
12
- const execAsync = util.promisify(exec);
13
-
14
- export function checkDir(targetPath) {
15
- if (fs.existsSync(targetPath)) {
16
- console.error(chalk.red(`\nāŒ Error: Directory ${path.basename(targetPath)} already exists.`));
17
- process.exit(1);
18
- }
19
- }
20
-
21
- export async function copyTemplate(templateName, targetPath) {
22
- const spinner = ora("Copying project files...").start();
23
-
24
- // Assuming templates live in ../templates relative to this file
25
- const templateDir = path.resolve(__dirname, "../templates", templateName);
26
-
27
- if (!fs.existsSync(templateDir)) {
28
- spinner.fail(chalk.red(`Template ${templateName} not found at ${templateDir}`));
29
- process.exit(1);
30
- }
31
-
32
- try {
33
- await fs.copy(templateDir, targetPath);
34
- spinner.succeed(chalk.green("Project files created successfully."));
35
- } catch (err) {
36
- spinner.fail(chalk.red("Failed to copy files."));
37
- console.error(err);
38
- process.exit(1);
39
- }
40
- }
41
-
42
- export async function installDependencies(targetPath) {
43
- const spinner = ora("Installing dependencies... This might take a moment.").start();
44
-
45
- try {
46
- // Run npm install in the new directory
47
- await execAsync("npm install", { cwd: targetPath });
48
- spinner.succeed(chalk.green("Dependencies installed via npm."));
49
- } catch (err) {
50
- // Fallback for peer dependency conflicts common in AI libraries
51
- try {
52
- spinner.text = "Retrying with --legacy-peer-deps...";
53
- await execAsync("npm install --legacy-peer-deps", { cwd: targetPath });
54
- spinner.succeed(chalk.green("Dependencies installed with legacy peer deps."));
55
- } catch (retryErr) {
56
- spinner.fail(chalk.red("Failed to install dependencies."));
57
- console.log(chalk.yellow("You can try installing manually:"));
58
- console.log(chalk.cyan(` cd ${path.basename(targetPath)}`));
59
- console.log(chalk.cyan(" npm install --legacy-peer-deps"));
60
- }
61
- }
62
- }
1
+
2
+ import fs from "fs-extra";
3
+ import path from "path";
4
+ import chalk from "chalk";
5
+ import { exec } from "child_process";
6
+ import util from "util";
7
+ import ora from "ora";
8
+ import { fileURLToPath } from 'url';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+ const execAsync = util.promisify(exec);
13
+
14
+ export function checkDir(targetPath) {
15
+ if (fs.existsSync(targetPath)) {
16
+ console.error(chalk.red(`\nāŒ Error: Directory ${path.basename(targetPath)} already exists.`));
17
+ process.exit(1);
18
+ }
19
+ }
20
+
21
+ export async function copyTemplate(templateName, targetPath) {
22
+ const spinner = ora("Copying project files...").start();
23
+
24
+ // Assuming templates live in ../templates relative to this file
25
+ const templateDir = path.resolve(__dirname, "../templates", templateName);
26
+
27
+ if (!fs.existsSync(templateDir)) {
28
+ spinner.fail(chalk.red(`Template ${templateName} not found at ${templateDir}`));
29
+ process.exit(1);
30
+ }
31
+
32
+ try {
33
+ await fs.copy(templateDir, targetPath);
34
+ spinner.succeed(chalk.green("Project files created successfully."));
35
+ } catch (err) {
36
+ spinner.fail(chalk.red("Failed to copy files."));
37
+ console.error(err);
38
+ process.exit(1);
39
+ }
40
+ }
41
+
42
+ export async function installDependencies(targetPath) {
43
+ const spinner = ora("Installing dependencies... This might take a moment.").start();
44
+
45
+ try {
46
+ // Run npm install in the new directory
47
+ await execAsync("npm install", { cwd: targetPath });
48
+ spinner.succeed(chalk.green("Dependencies installed via npm."));
49
+ } catch (err) {
50
+ // Fallback for peer dependency conflicts common in AI libraries
51
+ try {
52
+ spinner.text = "Retrying with --legacy-peer-deps...";
53
+ await execAsync("npm install --legacy-peer-deps", { cwd: targetPath });
54
+ spinner.succeed(chalk.green("Dependencies installed with legacy peer deps."));
55
+ } catch (retryErr) {
56
+ spinner.fail(chalk.red("Failed to install dependencies."));
57
+ console.log(chalk.yellow("You can try installing manually:"));
58
+ console.log(chalk.cyan(` cd ${path.basename(targetPath)}`));
59
+ console.log(chalk.cyan(" npm install --legacy-peer-deps"));
60
+ }
61
+ }
62
+ }
@@ -1,13 +1,13 @@
1
-
2
- # AI Provider Keys
3
- OPENAI_API_KEY=sk-your-key-here
4
- GROQ_API_KEY=your-groq-key
5
- GOOGLE_API_KEY=your-gemini-key-here
6
-
7
- # Vector DB
8
- # Default to local persistent client
9
- CHROMA_URL=http://localhost:8000
10
- COLLECTION_NAME=rag-docs
11
-
12
- # App Config
13
- NEXT_PUBLIC_APP_NAME="My RAG App"
1
+
2
+ # AI Provider Keys
3
+ OPENAI_API_KEY=sk-your-key-here
4
+ GROQ_API_KEY=your-groq-key
5
+ GOOGLE_API_KEY=your-gemini-key-here
6
+
7
+ # Vector DB
8
+ # Default to local persistent client
9
+ CHROMA_URL=http://localhost:8000
10
+ COLLECTION_NAME=rag-docs
11
+
12
+ # App Config
13
+ NEXT_PUBLIC_APP_NAME="My RAG App"
@@ -1,2 +1,2 @@
1
- Put your PDF or .txt files here to be ingested by the RAG pipeline.
1
+ Put your PDF or .txt files here to be ingested by the RAG pipeline.
2
2
  Then run `npm run ingest` to build the vector index.
@@ -1,15 +1,15 @@
1
- {
2
- "compilerOptions": {
3
- "baseUrl": ".",
4
- "paths": {
5
- "@/*": ["./src/*"]
6
- },
7
- // Useful for Next.js strict mode and modern JS features
8
- "target": "ESNext",
9
- "module": "ESNext",
10
- "jsx": "preserve",
11
- "strict": false
12
- },
13
- "include": ["next-env.d.ts", "**/*.js", "**/*.jsx", ".next/types/**/*.ts"],
14
- "exclude": ["node_modules"]
15
- }
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": ".",
4
+ "paths": {
5
+ "@/*": ["./src/*"]
6
+ },
7
+ // Useful for Next.js strict mode and modern JS features
8
+ "target": "ESNext",
9
+ "module": "ESNext",
10
+ "jsx": "preserve",
11
+ "strict": false
12
+ },
13
+ "include": ["next-env.d.ts", "**/*.js", "**/*.jsx", ".next/types/**/*.ts"],
14
+ "exclude": ["node_modules"]
15
+ }
@@ -1,7 +1,7 @@
1
- /** @type {import('next').NextConfig} */
2
- const nextConfig = {
3
- reactStrictMode: true,
4
- serverExternalPackages: ["chromadb"],
5
- };
6
-
7
- export default nextConfig;
1
+ /** @type {import('next').NextConfig} */
2
+ const nextConfig = {
3
+ reactStrictMode: true,
4
+ serverExternalPackages: ["chromadb"],
5
+ };
6
+
7
+ export default nextConfig;