@hyperbytes/wappler-all-in-one-ai-v2 1.0.3 → 1.0.4
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/CHANGELOG.md +5 -1
- package/README.md +4 -1
- package/package.json +6 -6
- package/server_connect/modules/multiaiv2.js +22 -5
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
Details here.
|
|
2
|
+
|
|
3
|
+
https://community.wappler.io/t/wappler-all-in-one-ai-node-js-version-2-custom-server-extension/65956
|
|
4
|
+
|
|
2
5
|
<a href="https://www.buymeacoffee.com/JVKdouk" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="max-width: 50%;" ></a>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperbytes/wappler-all-in-one-ai-v2",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Versitile interface to chatGPT, Gemini Claude with file analysis cababilities",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -10,17 +10,17 @@
|
|
|
10
10
|
"postinstall": "node scripts/copyFiles.js"
|
|
11
11
|
},
|
|
12
12
|
"keywords": [
|
|
13
|
-
"wappler-extension
|
|
13
|
+
"wappler-extension",
|
|
14
14
|
"multifunction-ai-connector"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@anthropic-ai/sdk": "^0.71.2",
|
|
18
18
|
"@google/generative-ai": "^0.24.1",
|
|
19
|
+
"fs": "^0.0.1-security",
|
|
19
20
|
"openai": "^6.15.0",
|
|
20
|
-
"sharp": "^0.34.5",
|
|
21
|
-
"xlsx": "^0.18.5",
|
|
22
|
-
"pdf-parse": "^2.4.5",
|
|
23
21
|
"path": "^0.12.7",
|
|
24
|
-
"
|
|
22
|
+
"pdf-parse": "^2.4.5",
|
|
23
|
+
"sharp": "^0.34.5",
|
|
24
|
+
"xlsx": "^0.18.5"
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -14,7 +14,10 @@ const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
|
|
|
14
14
|
*/
|
|
15
15
|
async function getCompressedImageBase64(filePath) {
|
|
16
16
|
try {
|
|
17
|
-
|
|
17
|
+
// Remove leading slash if present to avoid path joining issues
|
|
18
|
+
const cleanPath = filePath.startsWith('/') ? filePath.substring(1) : filePath;
|
|
19
|
+
const fullPath = path.join(process.cwd(), cleanPath);
|
|
20
|
+
|
|
18
21
|
console.log("Checking for image at:", fullPath);
|
|
19
22
|
|
|
20
23
|
if (!fs.existsSync(fullPath)) {
|
|
@@ -23,6 +26,7 @@ async function getCompressedImageBase64(filePath) {
|
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
const buffer = await sharp(fullPath)
|
|
29
|
+
.rotate() // <--- CRITICAL: Fixes portrait/landscape flip
|
|
26
30
|
.resize(1500, 1500, { fit: 'inside', withoutEnlargement: true })
|
|
27
31
|
.jpeg({ quality: 80 })
|
|
28
32
|
.toBuffer();
|
|
@@ -58,13 +62,20 @@ async function getFileContent(filePath) {
|
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
exports.multiaiv2 = async function (options) {
|
|
65
|
+
|
|
66
|
+
// 1. Ensure we grab the question correctly
|
|
61
67
|
let question = this.parseRequired(options.question, "*", 'No Question passed');
|
|
68
|
+
|
|
69
|
+
// 2. Fix the file input assignment
|
|
70
|
+
// Use the exact key from your console log
|
|
71
|
+
const fileInput = options.image_url;
|
|
72
|
+
|
|
62
73
|
const engine = this.parse(options.engine) || 'gpt-4o-mini';
|
|
63
74
|
const maxTokens = parseInt(this.parseOptional(options.maxtokens, "*", 2000));
|
|
64
75
|
const temp = parseFloat(this.parseOptional(options.temperature, "*", 0.7));
|
|
65
|
-
const fileInput = this.parse(options.image_url);
|
|
66
76
|
|
|
67
77
|
const modelName = engine.toLowerCase();
|
|
78
|
+
|
|
68
79
|
const isReasoningModel = modelName.includes('gpt-5') || modelName.startsWith('o1') || modelName.startsWith('o3');
|
|
69
80
|
|
|
70
81
|
console.log(`Starting Request - Model: ${engine}, File: ${fileInput}`);
|
|
@@ -80,14 +91,15 @@ exports.multiaiv2 = async function (options) {
|
|
|
80
91
|
|
|
81
92
|
try {
|
|
82
93
|
// --- OpenAI (GPT-4o, GPT-5, o1) ---
|
|
94
|
+
|
|
83
95
|
if (modelName.includes('gpt') || modelName.includes('o1') || modelName.includes('o3')) {
|
|
84
96
|
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
97
|
+
let userContent = [];
|
|
85
98
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (fileInput && /\.(jpg|jpeg|png|webp)$/i.test(fileInput) && !isReasoningModel) {
|
|
99
|
+
if (fileInput && /\.(jpg|jpeg|png|webp)$/i.test(fileInput)) {
|
|
89
100
|
const b64 = await getCompressedImageBase64(fileInput);
|
|
90
101
|
if (b64) {
|
|
102
|
+
// Push image first
|
|
91
103
|
userContent.push({
|
|
92
104
|
type: "image_url",
|
|
93
105
|
image_url: { url: b64, detail: "high" }
|
|
@@ -96,11 +108,16 @@ exports.multiaiv2 = async function (options) {
|
|
|
96
108
|
}
|
|
97
109
|
}
|
|
98
110
|
|
|
111
|
+
// Add text instructions after the image
|
|
112
|
+
userContent.push({ type: "text", text: question });
|
|
113
|
+
|
|
99
114
|
const payload = {
|
|
100
115
|
model: engine,
|
|
101
116
|
messages: [{ role: 'user', content: userContent }]
|
|
102
117
|
};
|
|
103
118
|
|
|
119
|
+
|
|
120
|
+
|
|
104
121
|
if (isReasoningModel) {
|
|
105
122
|
payload.max_completion_tokens = Math.max(maxTokens, 5000);
|
|
106
123
|
} else {
|