@hyperbytes/wappler-all-in-one-ai-v2 1.0.2 → 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 CHANGED
@@ -1 +1,5 @@
1
- Pre release beta for testing
1
+ Release version.
2
+
3
+ Details here.
4
+
5
+ https://community.wappler.io/t/wappler-all-in-one-ai-node-js-version-2-custom-server-extension/65956
package/README.md CHANGED
@@ -1,2 +1,5 @@
1
- Pre release beta for testing
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.2",
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,16 +10,17 @@
10
10
  "postinstall": "node scripts/copyFiles.js"
11
11
  },
12
12
  "keywords": [
13
- "wappler-extension-beta",
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",
21
+ "path": "^0.12.7",
22
22
  "pdf-parse": "^2.4.5",
23
- "path": "^0.12.7"
23
+ "sharp": "^0.34.5",
24
+ "xlsx": "^0.18.5"
24
25
  }
25
26
  }
@@ -19,7 +19,8 @@
19
19
  'sharp': '^0.34.5',
20
20
  'xlsx': '^0.18.5',
21
21
  'pdf-parse':'^2.4.5',
22
- 'path':'^0.12.7'
22
+ 'path':'^0.12.7',
23
+ 'fs':'^0.0.0'
23
24
 
24
25
  }
25
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
- const fullPath = path.join(process.cwd(), filePath);
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
- let userContent = [{ type: "text", text: question }];
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 {