@mongoosejs/studio 0.1.11 → 0.1.12
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 +10 -4
- package/backend/integrations/callLLM.js +30 -8
- package/backend/integrations/streamLLM.js +39 -10
- package/frontend/public/app.js +5 -3
- package/frontend/src/api.js +2 -2
- package/frontend/src/chat/chat.js +2 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -34,8 +34,10 @@ If you have a Mongoose Studio Pro API key, you can set it as follows:
|
|
|
34
34
|
const opts = process.env.MONGOOSE_STUDIO_API_KEY ? { apiKey: process.env.MONGOOSE_STUDIO_API_KEY } : {};
|
|
35
35
|
// Optionally specify which ChatGPT model to use for chat messages
|
|
36
36
|
opts.model = 'gpt-4o-mini';
|
|
37
|
-
// Provide your own OpenAI API key to run chat completions locally
|
|
37
|
+
// Provide your own OpenAI, Anthropic, or Google Gemini API key to run chat completions locally
|
|
38
38
|
opts.openAIAPIKey = process.env.OPENAI_API_KEY;
|
|
39
|
+
opts.anthropicAPIKey = process.env.ANTHROPIC_API_KEY;
|
|
40
|
+
opts.googleGeminiAPIKey = process.env.GOOGLE_GEMINI_API_KEY;
|
|
39
41
|
|
|
40
42
|
// Mount Mongoose Studio on '/studio'
|
|
41
43
|
app.use('/studio', await studio('/studio/api', mongoose, opts));
|
|
@@ -88,8 +90,10 @@ const opts = {
|
|
|
88
90
|
apiKey: process.env.MONGOOSE_STUDIO_API_KEY,
|
|
89
91
|
// Optionally specify which ChatGPT model to use for chat messages
|
|
90
92
|
model: 'gpt-4o-mini',
|
|
91
|
-
// Provide your own OpenAI API key to run chat completions locally
|
|
92
|
-
openAIAPIKey: process.env.OPENAI_API_KEY
|
|
93
|
+
// Provide your own OpenAI, Anthropic, or Google Gemini API key to run chat completions locally
|
|
94
|
+
openAIAPIKey: process.env.OPENAI_API_KEY,
|
|
95
|
+
anthropicAPIKey: process.env.ANTHROPIC_API_KEY,
|
|
96
|
+
googleGeminiAPIKey: process.env.GOOGLE_GEMINI_API_KEY
|
|
93
97
|
};
|
|
94
98
|
console.log('Creating Mongoose studio', opts);
|
|
95
99
|
require('@mongoosejs/studio/frontend')(`/.netlify/functions/studio`, true, opts).then(() => {
|
|
@@ -108,7 +112,9 @@ const mongoose = require('mongoose');
|
|
|
108
112
|
const handler = require('@mongoosejs/studio/backend/netlify')({
|
|
109
113
|
apiKey: process.env.MONGOOSE_STUDIO_API_KEY,
|
|
110
114
|
model: 'gpt-4o-mini',
|
|
111
|
-
openAIAPIKey: process.env.OPENAI_API_KEY
|
|
115
|
+
openAIAPIKey: process.env.OPENAI_API_KEY,
|
|
116
|
+
anthropicAPIKey: process.env.ANTHROPIC_API_KEY,
|
|
117
|
+
googleGeminiAPIKey: process.env.GOOGLE_GEMINI_API_KEY
|
|
112
118
|
}).handler;
|
|
113
119
|
|
|
114
120
|
let conn = null;
|
|
@@ -1,22 +1,44 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { createAnthropic } = require('@ai-sdk/anthropic');
|
|
4
|
+
const { createGoogleGenerativeAI } = require('@ai-sdk/google');
|
|
4
5
|
const { createOpenAI } = require('@ai-sdk/openai');
|
|
5
6
|
const { generateText } = require('ai');
|
|
6
7
|
|
|
7
8
|
module.exports = async function callLLM(messages, system, options) {
|
|
8
9
|
let provider = null;
|
|
9
10
|
let model = null;
|
|
10
|
-
|
|
11
|
-
throw new Error('Cannot set both OpenAI and Anthropic API keys');
|
|
12
|
-
}
|
|
11
|
+
const providers = [];
|
|
13
12
|
|
|
14
13
|
if (options?.openAIAPIKey) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
providers.push({
|
|
15
|
+
provider: createOpenAI({ apiKey: options.openAIAPIKey }),
|
|
16
|
+
model: options?.model ?? 'gpt-4o-mini'
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (options?.anthropicAPIKey) {
|
|
21
|
+
providers.push({
|
|
22
|
+
provider: createAnthropic({ apiKey: options.anthropicAPIKey }),
|
|
23
|
+
model: options?.model ?? 'claude-haiku-4-5-20251001'
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (options?.googleGeminiAPIKey) {
|
|
28
|
+
providers.push({
|
|
29
|
+
provider: createGoogleGenerativeAI({ apiKey: options.googleGeminiAPIKey }),
|
|
30
|
+
model: options?.model ?? 'gemini-2.5-flash'
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (providers.length > 1) {
|
|
35
|
+
throw new Error('Cannot set multiple LLM API keys');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (providers.length > 0) {
|
|
39
|
+
const selected = providers[0];
|
|
40
|
+
provider = selected.provider;
|
|
41
|
+
model = selected.model;
|
|
20
42
|
}
|
|
21
43
|
|
|
22
44
|
if (provider) {
|
|
@@ -1,37 +1,66 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { createAnthropic } = require('@ai-sdk/anthropic');
|
|
4
|
+
const { createGoogleGenerativeAI } = require('@ai-sdk/google');
|
|
4
5
|
const { createOpenAI } = require('@ai-sdk/openai');
|
|
5
6
|
const { streamText } = require('ai');
|
|
6
7
|
|
|
7
8
|
module.exports = async function* streamLLM(messages, system, options) {
|
|
8
9
|
let provider = null;
|
|
9
10
|
let model = null;
|
|
10
|
-
|
|
11
|
-
throw new Error('Cannot set both OpenAI and Anthropic API keys');
|
|
12
|
-
}
|
|
11
|
+
const providers = [];
|
|
13
12
|
|
|
14
13
|
if (options?.openAIAPIKey) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
providers.push({
|
|
15
|
+
provider: createOpenAI({ apiKey: options.openAIAPIKey }),
|
|
16
|
+
model: options?.model ?? 'gpt-4o-mini'
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (options?.anthropicAPIKey) {
|
|
21
|
+
providers.push({
|
|
22
|
+
provider: createAnthropic({ apiKey: options.anthropicAPIKey }),
|
|
23
|
+
model: options?.model ?? 'claude-haiku-4-5-20251001'
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (options?.googleGeminiAPIKey) {
|
|
28
|
+
providers.push({
|
|
29
|
+
provider: createGoogleGenerativeAI({ apiKey: options.googleGeminiAPIKey }),
|
|
30
|
+
model: options?.model ?? 'gemini-2.5-flash'
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (providers.length > 1) {
|
|
35
|
+
throw new Error('Cannot set multiple LLM API keys');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (providers.length > 0) {
|
|
39
|
+
const selected = providers[0];
|
|
40
|
+
provider = selected.provider;
|
|
41
|
+
model = selected.model;
|
|
20
42
|
}
|
|
21
43
|
|
|
22
44
|
if (provider) {
|
|
45
|
+
let error = null;
|
|
23
46
|
const { textStream } = streamText({
|
|
24
47
|
model: provider(model),
|
|
25
48
|
system,
|
|
26
|
-
messages
|
|
49
|
+
messages,
|
|
50
|
+
onError(err) {
|
|
51
|
+
error = err.error;
|
|
52
|
+
}
|
|
27
53
|
});
|
|
28
54
|
for await (const chunk of textStream) {
|
|
29
55
|
yield chunk;
|
|
30
56
|
}
|
|
57
|
+
if (error) {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
31
60
|
return;
|
|
32
61
|
}
|
|
33
62
|
|
|
34
|
-
// If not using OpenAI or
|
|
63
|
+
// If not using OpenAI, Anthropic, or Google Gemini, fallback to Mongoose (no streaming)
|
|
35
64
|
const headers = { 'Content-Type': 'application/json' };
|
|
36
65
|
const response = await fetch('https://mongoose-js.netlify.app/.netlify/functions/getChatCompletion', {
|
|
37
66
|
method: 'POST',
|
package/frontend/public/app.js
CHANGED
|
@@ -436,9 +436,9 @@ if (window.MONGOOSE_STUDIO_CONFIG.isLambda) {
|
|
|
436
436
|
}
|
|
437
437
|
if (data) {
|
|
438
438
|
try {
|
|
439
|
-
|
|
439
|
+
const res = JSON.parse(data);
|
|
440
|
+
yield res;
|
|
440
441
|
} catch (err) {
|
|
441
|
-
// If not JSON, yield as string
|
|
442
442
|
yield data;
|
|
443
443
|
}
|
|
444
444
|
}
|
|
@@ -1105,6 +1105,8 @@ module.exports = app => app.component('chat', {
|
|
|
1105
1105
|
}
|
|
1106
1106
|
});
|
|
1107
1107
|
}
|
|
1108
|
+
} else if (event.message) {
|
|
1109
|
+
throw new Error(event.message);
|
|
1108
1110
|
}
|
|
1109
1111
|
}
|
|
1110
1112
|
|
|
@@ -16937,7 +16939,7 @@ module.exports = function stringToParts(str) {
|
|
|
16937
16939
|
/***/ ((module) => {
|
|
16938
16940
|
|
|
16939
16941
|
"use strict";
|
|
16940
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.1.
|
|
16942
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.1.12","description":"A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.","homepage":"https://studio.mongoosejs.io/","repository":{"type":"git","url":"https://github.com/mongoosejs/studio"},"license":"Apache-2.0","dependencies":{"@ai-sdk/google":"2.x","@ai-sdk/openai":"2.x","@ai-sdk/anthropic":"2.x","ai":"5.x","archetype":"0.13.1","csv-stringify":"6.3.0","ejson":"^2.2.3","extrovert":"^0.2.0","marked":"15.0.12","node-inspect-extracted":"3.x","tailwindcss":"3.4.0","vanillatoasts":"^1.6.0","vue":"3.x","webpack":"5.x"},"peerDependencies":{"mongoose":"7.x || 8.x || ^9.0.0"},"devDependencies":{"@masteringjs/eslint-config":"0.1.1","axios":"1.2.2","dedent":"^1.6.0","eslint":"9.30.0","express":"4.x","mocha":"10.2.0","mongoose":"9.x"},"scripts":{"lint":"eslint .","tailwind":"tailwindcss -o ./frontend/public/tw.css","tailwind:watch":"tailwindcss -o ./frontend/public/tw.css --watch","test":"mocha test/*.test.js"}}');
|
|
16941
16943
|
|
|
16942
16944
|
/***/ })
|
|
16943
16945
|
|
package/frontend/src/api.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mongoosejs/studio",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "A sleek, powerful MongoDB UI with built-in dashboarding and auth, seamlessly integrated with your Express, Vercel, or Netlify app.",
|
|
5
5
|
"homepage": "https://studio.mongoosejs.io/",
|
|
6
6
|
"repository": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
|
+
"@ai-sdk/google": "2.x",
|
|
12
13
|
"@ai-sdk/openai": "2.x",
|
|
13
14
|
"@ai-sdk/anthropic": "2.x",
|
|
14
15
|
"ai": "5.x",
|