@retrivora-ai/rag-engine 0.1.0
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/.env.example +77 -0
- package/README.md +149 -0
- package/dist/DocumentChunker-BUrIrcPk.d.mts +43 -0
- package/dist/DocumentChunker-BUrIrcPk.d.ts +43 -0
- package/dist/RAGPipeline-BmkIv1HD.d.mts +298 -0
- package/dist/RAGPipeline-BmkIv1HD.d.ts +298 -0
- package/dist/chunk-NCG2JKXB.mjs +1254 -0
- package/dist/chunk-ZPXLQR5Q.mjs +67 -0
- package/dist/handlers/index.d.mts +68 -0
- package/dist/handlers/index.d.ts +68 -0
- package/dist/handlers/index.js +1319 -0
- package/dist/handlers/index.mjs +13 -0
- package/dist/index.d.mts +93 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +612 -0
- package/dist/index.mjs +551 -0
- package/dist/server.d.mts +211 -0
- package/dist/server.d.ts +211 -0
- package/dist/server.js +1457 -0
- package/dist/server.mjs +148 -0
- package/package.json +90 -0
- package/src/app/api/chat/route.ts +4 -0
- package/src/app/api/health/route.ts +4 -0
- package/src/app/api/ingest/route.ts +26 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +163 -0
- package/src/app/layout.tsx +35 -0
- package/src/app/page.tsx +506 -0
- package/src/components/ChatWidget.tsx +91 -0
- package/src/components/ChatWindow.tsx +248 -0
- package/src/components/ConfigProvider.tsx +56 -0
- package/src/components/MessageBubble.tsx +99 -0
- package/src/components/SourceCard.tsx +66 -0
- package/src/components/ThemeProvider.tsx +8 -0
- package/src/components/ThemeToggle.tsx +29 -0
- package/src/config/RagConfig.ts +159 -0
- package/src/config/UniversalProfiles.ts +83 -0
- package/src/config/serverConfig.ts +142 -0
- package/src/handlers/index.ts +202 -0
- package/src/hooks/useHydrated.ts +13 -0
- package/src/hooks/useRagChat.ts +167 -0
- package/src/hooks/useStoredMessages.ts +53 -0
- package/src/index.ts +27 -0
- package/src/llm/ILLMProvider.ts +60 -0
- package/src/llm/LLMFactory.ts +54 -0
- package/src/llm/providers/AnthropicProvider.ts +87 -0
- package/src/llm/providers/OllamaProvider.ts +102 -0
- package/src/llm/providers/OpenAIProvider.ts +92 -0
- package/src/llm/providers/UniversalLLMAdapter.ts +154 -0
- package/src/rag/DocumentChunker.ts +105 -0
- package/src/rag/RAGPipeline.ts +196 -0
- package/src/server.ts +30 -0
- package/src/types/pdf-parse.d.ts +13 -0
- package/src/utils/DocumentParser.ts +75 -0
- package/src/utils/templateUtils.ts +78 -0
- package/src/vectordb/IVectorDB.ts +75 -0
- package/src/vectordb/VectorDBFactory.ts +41 -0
- package/src/vectordb/adapters/MongoDbAdapter.ts +175 -0
- package/src/vectordb/adapters/PgVectorAdapter.ts +159 -0
- package/src/vectordb/adapters/PineconeAdapter.ts +115 -0
- package/src/vectordb/adapters/UniversalVectorDBAdapter.ts +177 -0
package/dist/server.mjs
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AnthropicProvider,
|
|
3
|
+
DocumentChunker,
|
|
4
|
+
LLMFactory,
|
|
5
|
+
MongoDbAdapter,
|
|
6
|
+
OllamaProvider,
|
|
7
|
+
OpenAIProvider,
|
|
8
|
+
PgVectorAdapter,
|
|
9
|
+
PineconeAdapter,
|
|
10
|
+
RAGPipeline,
|
|
11
|
+
VectorDBFactory,
|
|
12
|
+
createChatHandler,
|
|
13
|
+
createHealthHandler,
|
|
14
|
+
createIngestHandler,
|
|
15
|
+
createUploadHandler
|
|
16
|
+
} from "./chunk-NCG2JKXB.mjs";
|
|
17
|
+
import "./chunk-ZPXLQR5Q.mjs";
|
|
18
|
+
|
|
19
|
+
// src/config/serverConfig.ts
|
|
20
|
+
var VECTOR_DB_PROVIDERS = ["pinecone", "pgvector", "mongodb", "rest", "universal_rest", "custom"];
|
|
21
|
+
var LLM_PROVIDERS = ["openai", "anthropic", "ollama", "rest", "universal_rest", "custom"];
|
|
22
|
+
var EMBEDDING_PROVIDERS = ["openai", "ollama", "rest", "universal_rest", "custom"];
|
|
23
|
+
function readString(env, name) {
|
|
24
|
+
var _a;
|
|
25
|
+
const value = (_a = env[name]) == null ? void 0 : _a.trim();
|
|
26
|
+
return value ? value : void 0;
|
|
27
|
+
}
|
|
28
|
+
function readNumber(env, name, fallback) {
|
|
29
|
+
const value = env[name];
|
|
30
|
+
if (!value) return fallback;
|
|
31
|
+
const parsed = Number(value);
|
|
32
|
+
if (!Number.isFinite(parsed)) {
|
|
33
|
+
throw new Error(`[getRagConfig] ${name} must be a valid number`);
|
|
34
|
+
}
|
|
35
|
+
return parsed;
|
|
36
|
+
}
|
|
37
|
+
function readEnum(env, name, fallback, allowed) {
|
|
38
|
+
var _a;
|
|
39
|
+
const value = (_a = readString(env, name)) != null ? _a : fallback;
|
|
40
|
+
if (allowed.includes(value)) {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
|
|
44
|
+
}
|
|
45
|
+
function getRagConfig(env = process.env) {
|
|
46
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;
|
|
47
|
+
const projectId = (_b = (_a = readString(env, "RAG_PROJECT_ID")) != null ? _a : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : "default";
|
|
48
|
+
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
49
|
+
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
50
|
+
const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
|
|
51
|
+
const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
|
|
52
|
+
const vectorDbOptions = {};
|
|
53
|
+
if (vectorProvider === "pinecone") {
|
|
54
|
+
vectorDbOptions.apiKey = (_c = readString(env, "PINECONE_API_KEY")) != null ? _c : "";
|
|
55
|
+
vectorDbOptions.environment = (_d = readString(env, "PINECONE_ENVIRONMENT")) != null ? _d : "";
|
|
56
|
+
} else if (vectorProvider === "pgvector") {
|
|
57
|
+
vectorDbOptions.connectionString = (_e = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _e : "";
|
|
58
|
+
vectorDbOptions.dimensions = embeddingDimensions;
|
|
59
|
+
} else if (vectorProvider === "rest") {
|
|
60
|
+
vectorDbOptions.baseUrl = (_f = readString(env, "VECTOR_DB_REST_URL")) != null ? _f : "";
|
|
61
|
+
vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { "api-key": readString(env, "VECTOR_DB_REST_API_KEY") } : {};
|
|
62
|
+
} else if (vectorProvider === "universal_rest") {
|
|
63
|
+
vectorDbOptions.baseUrl = (_h = (_g = readString(env, "VECTOR_BASE_URL")) != null ? _g : readString(env, "VECTOR_DB_REST_URL")) != null ? _h : "";
|
|
64
|
+
vectorDbOptions.profile = readString(env, "VECTOR_UNIVERSAL_PROFILE");
|
|
65
|
+
vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { Authorization: `Bearer ${readString(env, "VECTOR_DB_REST_API_KEY")}` } : {};
|
|
66
|
+
} else if (vectorProvider === "mongodb") {
|
|
67
|
+
vectorDbOptions.uri = (_i = readString(env, "MONGODB_URI")) != null ? _i : "";
|
|
68
|
+
vectorDbOptions.database = (_j = readString(env, "MONGODB_DB")) != null ? _j : "";
|
|
69
|
+
vectorDbOptions.collection = (_k = readString(env, "MONGODB_COLLECTION")) != null ? _k : "";
|
|
70
|
+
vectorDbOptions.indexName = (_l = readString(env, "MONGODB_INDEX_NAME")) != null ? _l : "vector_index";
|
|
71
|
+
}
|
|
72
|
+
const llmApiKeyByProvider = {
|
|
73
|
+
openai: readString(env, "OPENAI_API_KEY"),
|
|
74
|
+
anthropic: readString(env, "ANTHROPIC_API_KEY"),
|
|
75
|
+
ollama: void 0,
|
|
76
|
+
universal_rest: readString(env, "LLM_API_KEY")
|
|
77
|
+
};
|
|
78
|
+
const embeddingApiKeyByProvider = {
|
|
79
|
+
openai: readString(env, "OPENAI_API_KEY"),
|
|
80
|
+
ollama: void 0,
|
|
81
|
+
custom: (_m = readString(env, "EMBEDDING_API_KEY")) != null ? _m : readString(env, "OPENAI_API_KEY")
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
projectId,
|
|
85
|
+
vectorDb: {
|
|
86
|
+
provider: vectorProvider,
|
|
87
|
+
indexName: (_n = readString(env, "VECTOR_DB_INDEX")) != null ? _n : "rag-index",
|
|
88
|
+
options: vectorDbOptions
|
|
89
|
+
},
|
|
90
|
+
llm: {
|
|
91
|
+
provider: llmProvider,
|
|
92
|
+
model: (_o = readString(env, "LLM_MODEL")) != null ? _o : "gpt-4o",
|
|
93
|
+
apiKey: (_p = llmApiKeyByProvider[llmProvider]) != null ? _p : "",
|
|
94
|
+
baseUrl: readString(env, "LLM_BASE_URL"),
|
|
95
|
+
systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
|
|
96
|
+
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 1024),
|
|
97
|
+
temperature: readNumber(env, "LLM_TEMPERATURE", 0.7),
|
|
98
|
+
options: {
|
|
99
|
+
profile: readString(env, "LLM_UNIVERSAL_PROFILE")
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
embedding: {
|
|
103
|
+
provider: embeddingProvider,
|
|
104
|
+
model: (_q = readString(env, "EMBEDDING_MODEL")) != null ? _q : "text-embedding-3-small",
|
|
105
|
+
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
106
|
+
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
107
|
+
dimensions: embeddingDimensions,
|
|
108
|
+
options: {
|
|
109
|
+
profile: readString(env, "EMBEDDING_UNIVERSAL_PROFILE")
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
ui: {
|
|
113
|
+
title: (_s = (_r = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _r : readString(env, "UI_TITLE")) != null ? _s : "AI Assistant",
|
|
114
|
+
subtitle: (_u = (_t = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _t : readString(env, "UI_SUBTITLE")) != null ? _u : "Powered by RAG",
|
|
115
|
+
primaryColor: (_w = (_v = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _v : readString(env, "UI_PRIMARY_COLOR")) != null ? _w : "#10b981",
|
|
116
|
+
accentColor: (_y = (_x = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _x : readString(env, "UI_ACCENT_COLOR")) != null ? _y : "#3b82f6",
|
|
117
|
+
logoUrl: (_z = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _z : readString(env, "UI_LOGO_URL"),
|
|
118
|
+
placeholder: (_B = (_A = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _A : readString(env, "UI_PLACEHOLDER")) != null ? _B : "Ask me anything\u2026",
|
|
119
|
+
showSources: ((_D = (_C = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _C : readString(env, "UI_SHOW_SOURCES")) != null ? _D : "true") !== "false",
|
|
120
|
+
welcomeMessage: (_F = (_E = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _E : readString(env, "UI_WELCOME_MESSAGE")) != null ? _F : "Hello! I'm your AI assistant. Ask me anything about your documents.",
|
|
121
|
+
visualStyle: (_H = (_G = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _G : readString(env, "UI_VISUAL_STYLE")) != null ? _H : "glass",
|
|
122
|
+
borderRadius: (_J = (_I = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _I : readString(env, "UI_BORDER_RADIUS")) != null ? _J : "xl"
|
|
123
|
+
},
|
|
124
|
+
rag: {
|
|
125
|
+
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
126
|
+
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
127
|
+
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
128
|
+
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200)
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
AnthropicProvider,
|
|
134
|
+
DocumentChunker,
|
|
135
|
+
LLMFactory,
|
|
136
|
+
MongoDbAdapter,
|
|
137
|
+
OllamaProvider,
|
|
138
|
+
OpenAIProvider,
|
|
139
|
+
PgVectorAdapter,
|
|
140
|
+
PineconeAdapter,
|
|
141
|
+
RAGPipeline,
|
|
142
|
+
VectorDBFactory,
|
|
143
|
+
createChatHandler,
|
|
144
|
+
createHealthHandler,
|
|
145
|
+
createIngestHandler,
|
|
146
|
+
createUploadHandler,
|
|
147
|
+
getRagConfig
|
|
148
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@retrivora-ai/rag-engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
|
|
5
|
+
"author": "Abhinav Alkuchi",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"rag",
|
|
9
|
+
"chatbot",
|
|
10
|
+
"vector-database",
|
|
11
|
+
"pinecone",
|
|
12
|
+
"pgvector",
|
|
13
|
+
"openai",
|
|
14
|
+
"anthropic",
|
|
15
|
+
"ollama",
|
|
16
|
+
"nextjs",
|
|
17
|
+
"react",
|
|
18
|
+
"ai",
|
|
19
|
+
"llm"
|
|
20
|
+
],
|
|
21
|
+
"main": "dist/index.js",
|
|
22
|
+
"module": "dist/index.mjs",
|
|
23
|
+
"types": "dist/index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"require": "./dist/index.js",
|
|
28
|
+
"import": "./dist/index.mjs"
|
|
29
|
+
},
|
|
30
|
+
"./handlers": {
|
|
31
|
+
"types": "./dist/handlers/index.d.ts",
|
|
32
|
+
"require": "./dist/handlers/index.js",
|
|
33
|
+
"import": "./dist/handlers/index.mjs"
|
|
34
|
+
},
|
|
35
|
+
"./server": {
|
|
36
|
+
"types": "./dist/server.d.ts",
|
|
37
|
+
"require": "./dist/server.js",
|
|
38
|
+
"import": "./dist/server.mjs"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"src",
|
|
44
|
+
".env.example",
|
|
45
|
+
"README.md"
|
|
46
|
+
],
|
|
47
|
+
"scripts": {
|
|
48
|
+
"dev": "next dev",
|
|
49
|
+
"build": "next build",
|
|
50
|
+
"build:pkg": "tsup src/index.ts src/handlers/index.ts src/server.ts --format cjs,esm --dts --clean --tsconfig tsconfig.build.json --external react,react-dom,next",
|
|
51
|
+
"start": "next start",
|
|
52
|
+
"lint": "eslint",
|
|
53
|
+
"prepublishOnly": "npm run build:pkg"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"next": ">=14.0.0",
|
|
57
|
+
"react": ">=18.0.0",
|
|
58
|
+
"react-dom": ">=18.0.0"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@anthropic-ai/sdk": "^0.90.0",
|
|
62
|
+
"@pinecone-database/pinecone": "^7.2.0",
|
|
63
|
+
"axios": "^1.15.0",
|
|
64
|
+
"lucide-react": "^1.8.0",
|
|
65
|
+
"mammoth": "^1.8.0",
|
|
66
|
+
"mongodb": "^7.1.1",
|
|
67
|
+
"next": ">=14.0.0",
|
|
68
|
+
"next-themes": "^0.4.6",
|
|
69
|
+
"openai": "^6.34.0",
|
|
70
|
+
"pdf-parse": "^1.1.1",
|
|
71
|
+
"pg": "^8.20.0",
|
|
72
|
+
"react": ">=18.0.0",
|
|
73
|
+
"react-dom": ">=18.0.0",
|
|
74
|
+
"react-markdown": "^10.1.0",
|
|
75
|
+
"remark-gfm": "^4.0.1"
|
|
76
|
+
},
|
|
77
|
+
"devDependencies": {
|
|
78
|
+
"@tailwindcss/postcss": "^4",
|
|
79
|
+
"@types/node": "^20",
|
|
80
|
+
"@types/pdf-parse": "^1.1.5",
|
|
81
|
+
"@types/pg": "^8.20.0",
|
|
82
|
+
"@types/react": "^19.2.14",
|
|
83
|
+
"@types/react-dom": "^19.2.3",
|
|
84
|
+
"eslint": "^9",
|
|
85
|
+
"eslint-config-next": "16.2.4",
|
|
86
|
+
"tailwindcss": "^4",
|
|
87
|
+
"tsup": "^8.5.1",
|
|
88
|
+
"typescript": "^5"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/ingest
|
|
3
|
+
*
|
|
4
|
+
* Ingests one or more documents into the vector DB for a project.
|
|
5
|
+
*
|
|
6
|
+
* Request body:
|
|
7
|
+
* {
|
|
8
|
+
* documents: Array<{
|
|
9
|
+
* docId: string
|
|
10
|
+
* content: string
|
|
11
|
+
* metadata?: Record<string, unknown>
|
|
12
|
+
* }>
|
|
13
|
+
* namespace?: string – optional project namespace override
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* Response:
|
|
17
|
+
* {
|
|
18
|
+
* results: Array<{ docId: string; chunksIngested: number }>
|
|
19
|
+
* totalChunks: number
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { createIngestHandler } from '@/handlers';
|
|
24
|
+
import { getRagConfig } from '@/config/serverConfig';
|
|
25
|
+
|
|
26
|
+
export const POST = createIngestHandler(getRagConfig());
|
|
Binary file
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/* ─── Design Tokens ─────────────────────────────────────────── */
|
|
8
|
+
:root {
|
|
9
|
+
--font-inter: 'Inter', sans-serif;
|
|
10
|
+
|
|
11
|
+
/* Light Mode (Default) */
|
|
12
|
+
--bg-base: #f8fafc; /* slate-50 */
|
|
13
|
+
--bg-surface: #ffffff;
|
|
14
|
+
--bg-elevated: #f1f5f9; /* slate-100 */
|
|
15
|
+
--border: rgba(0, 0, 0, 0.08);
|
|
16
|
+
--text-primary: #0f172a; /* slate-900 */
|
|
17
|
+
--text-secondary: #475569; /* slate-600 */
|
|
18
|
+
--text-muted: #94a3b8; /* slate-400 */
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.dark {
|
|
22
|
+
/* Dark Mode */
|
|
23
|
+
--bg-base: #080811;
|
|
24
|
+
--bg-surface: #0f0f1a;
|
|
25
|
+
--bg-elevated: #161625;
|
|
26
|
+
--border: rgba(255, 255, 255, 0.08);
|
|
27
|
+
--text-primary: rgba(255, 255, 255, 0.92);
|
|
28
|
+
--text-secondary: rgba(255, 255, 255, 0.55);
|
|
29
|
+
--text-muted: rgba(255, 255, 255, 0.25);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* ─── Base Reset ────────────────────────────────────────────── */
|
|
33
|
+
*,
|
|
34
|
+
*::before,
|
|
35
|
+
*::after {
|
|
36
|
+
box-sizing: border-box;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
html {
|
|
40
|
+
font-family: var(--font-inter), system-ui, sans-serif;
|
|
41
|
+
-webkit-font-smoothing: antialiased;
|
|
42
|
+
-moz-osx-font-smoothing: grayscale;
|
|
43
|
+
scroll-behavior: smooth;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
body {
|
|
47
|
+
background-color: var(--bg-base);
|
|
48
|
+
color: var(--text-primary);
|
|
49
|
+
margin: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* ─── Scrollbar ─────────────────────────────────────────────── */
|
|
53
|
+
::-webkit-scrollbar {
|
|
54
|
+
width: 4px;
|
|
55
|
+
height: 4px;
|
|
56
|
+
}
|
|
57
|
+
::-webkit-scrollbar-track {
|
|
58
|
+
background: transparent;
|
|
59
|
+
}
|
|
60
|
+
::-webkit-scrollbar-thumb {
|
|
61
|
+
background: rgba(255, 255, 255, 0.12);
|
|
62
|
+
border-radius: 999px;
|
|
63
|
+
}
|
|
64
|
+
::-webkit-scrollbar-thumb:hover {
|
|
65
|
+
background: rgba(255, 255, 255, 0.2);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* ─── Prose Overrides (markdown in chat) ───────────────────── */
|
|
69
|
+
.prose-invert {
|
|
70
|
+
color: inherit;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.prose-invert p {
|
|
74
|
+
margin: 0.25em 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.prose-invert pre {
|
|
78
|
+
background: rgba(0, 0, 0, 0.4);
|
|
79
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
80
|
+
border-radius: 0.5rem;
|
|
81
|
+
padding: 0.75rem 1rem;
|
|
82
|
+
overflow-x: auto;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.prose-invert code:not(pre code) {
|
|
86
|
+
background: rgba(255, 255, 255, 0.08);
|
|
87
|
+
border-radius: 0.25rem;
|
|
88
|
+
padding: 0.1em 0.35em;
|
|
89
|
+
font-size: 0.85em;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.prose-invert a {
|
|
93
|
+
color: #818cf8;
|
|
94
|
+
text-decoration: underline;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.prose-invert ul,
|
|
98
|
+
.prose-invert ol {
|
|
99
|
+
padding-left: 1.25em;
|
|
100
|
+
margin: 0.35em 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.prose-invert li {
|
|
104
|
+
margin: 0.15em 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.prose-invert blockquote {
|
|
108
|
+
border-left: 3px solid rgba(99, 102, 241, 0.5);
|
|
109
|
+
padding-left: 0.75em;
|
|
110
|
+
color: rgba(255, 255, 255, 0.6);
|
|
111
|
+
margin: 0.5em 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* ─── Animations ────────────────────────────────────────────── */
|
|
115
|
+
@keyframes fadeInUp {
|
|
116
|
+
from {
|
|
117
|
+
opacity: 0;
|
|
118
|
+
transform: translateY(8px);
|
|
119
|
+
}
|
|
120
|
+
to {
|
|
121
|
+
opacity: 1;
|
|
122
|
+
transform: translateY(0);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@keyframes slideUp {
|
|
127
|
+
from {
|
|
128
|
+
opacity: 0;
|
|
129
|
+
transform: translateY(16px) scale(0.98);
|
|
130
|
+
}
|
|
131
|
+
to {
|
|
132
|
+
opacity: 1;
|
|
133
|
+
transform: translateY(0) scale(1);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@keyframes shimmer {
|
|
138
|
+
0% { background-position: -200% 0; }
|
|
139
|
+
100% { background-position: 200% 0; }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.animate-fade-in-up {
|
|
143
|
+
animation: fadeInUp 0.3s ease-out both;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.animate-slide-up {
|
|
147
|
+
animation: slideUp 0.35s cubic-bezier(0.34, 1.56, 0.64, 1) both;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* ─── Glass Surface ─────────────────────────────────────────── */
|
|
151
|
+
.glass {
|
|
152
|
+
background: rgba(255, 255, 255, 0.04);
|
|
153
|
+
backdrop-filter: blur(16px);
|
|
154
|
+
border: 1px solid var(--border);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* ─── Gradient Text Utility ─────────────────────────────────── */
|
|
158
|
+
.gradient-text {
|
|
159
|
+
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
|
160
|
+
-webkit-background-clip: text;
|
|
161
|
+
-webkit-text-fill-color: transparent;
|
|
162
|
+
background-clip: text;
|
|
163
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Metadata } from 'next';
|
|
2
|
+
import { Inter } from 'next/font/google';
|
|
3
|
+
import './globals.css';
|
|
4
|
+
import { ConfigProvider } from '@/components/ConfigProvider';
|
|
5
|
+
import { ThemeProvider } from '@/components/ThemeProvider';
|
|
6
|
+
import { getRagConfig } from '@/config/serverConfig';
|
|
7
|
+
|
|
8
|
+
const inter = Inter({ subsets: ['latin'], variable: '--font-inter' });
|
|
9
|
+
|
|
10
|
+
export const metadata: Metadata = {
|
|
11
|
+
title: 'Retrivora AI',
|
|
12
|
+
description:
|
|
13
|
+
'A configurable Retrieval-Augmented Generation chatbot — generic across any vector database and LLM provider.',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
17
|
+
const clientConfig = getRagConfig();
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<html lang="en" className={inter.variable} suppressHydrationWarning>
|
|
21
|
+
<body className="bg-slate-50 dark:bg-[#080811] text-slate-900 dark:text-white antialiased transition-colors duration-300">
|
|
22
|
+
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem disableTransitionOnChange>
|
|
23
|
+
<ConfigProvider
|
|
24
|
+
config={{
|
|
25
|
+
projectId: clientConfig.projectId,
|
|
26
|
+
ui: clientConfig.ui,
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
{children}
|
|
30
|
+
</ConfigProvider>
|
|
31
|
+
</ThemeProvider>
|
|
32
|
+
</body>
|
|
33
|
+
</html>
|
|
34
|
+
);
|
|
35
|
+
}
|