trace.ai-cli 1.1.8 → 1.2.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/README.markdown +150 -150
- package/cli/traceAI.js +32 -7
- package/index.js +8 -4
- package/package.json +46 -45
- package/services/aiService.js +36 -9
- package/services/fileAnalyzer.js +80 -5
- package/services/folderAnalyzer.js +163 -163
- package/services/imageService.js +16 -2
- package/services/systemInfoService.js +956 -956
- package/utils/encryption.js +41 -41
- package/utils/fileUtils.js +7 -2
- package/utils/markdown.js +168 -0
package/services/fileAnalyzer.js
CHANGED
|
@@ -1,16 +1,91 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
+
const fs = require('fs').promises;
|
|
3
|
+
const pdfParse = require('pdf-parse');
|
|
2
4
|
const { getFileType, readFileContent } = require('../utils/fileUtils');
|
|
3
5
|
const { processWithAI } = require('./aiService');
|
|
4
6
|
const { extractTextFromImage } = require('./imageService');
|
|
5
7
|
|
|
6
|
-
async function analyzeFile(filePath, query = '') {
|
|
8
|
+
async function analyzeFile(filePath, query = '', mode = 2) {
|
|
7
9
|
try {
|
|
8
10
|
const fileType = getFileType(filePath);
|
|
9
11
|
|
|
12
|
+
// Handle images - use vision API only for images
|
|
10
13
|
if (fileType === 'image') {
|
|
11
|
-
|
|
14
|
+
const result = await extractTextFromImage(filePath, query, mode);
|
|
15
|
+
return { text: result };
|
|
12
16
|
}
|
|
13
17
|
|
|
18
|
+
// Handle documents (PDFs, Word, etc.)
|
|
19
|
+
if (fileType === 'document') {
|
|
20
|
+
const fileName = path.basename(filePath);
|
|
21
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
22
|
+
|
|
23
|
+
// Extract text from PDF
|
|
24
|
+
if (ext === '.pdf') {
|
|
25
|
+
try {
|
|
26
|
+
const dataBuffer = await fs.readFile(filePath);
|
|
27
|
+
const pdfData = await pdfParse(dataBuffer);
|
|
28
|
+
const content = pdfData.text;
|
|
29
|
+
|
|
30
|
+
if (!content || content.trim().length === 0) {
|
|
31
|
+
return {
|
|
32
|
+
text: `❌ **Unable to Extract Text from PDF**\n\n` +
|
|
33
|
+
`The PDF "${fileName}" appears to be empty or contains only images/scanned content.\n\n` +
|
|
34
|
+
`**Try using the /image command for scanned PDFs:**\n` +
|
|
35
|
+
`\`/image "${filePath}" ${query || 'analyze this document'}\``
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Build prompt for AI analysis
|
|
40
|
+
let prompt;
|
|
41
|
+
if (query) {
|
|
42
|
+
prompt = `PDF Document: ${fileName}
|
|
43
|
+
Content:
|
|
44
|
+
\`\`\`
|
|
45
|
+
${content}
|
|
46
|
+
\`\`\`
|
|
47
|
+
|
|
48
|
+
User Question: ${query}`;
|
|
49
|
+
} else {
|
|
50
|
+
prompt = `Analyze this PDF document (${fileName}):
|
|
51
|
+
|
|
52
|
+
\`\`\`
|
|
53
|
+
${content}
|
|
54
|
+
\`\`\`
|
|
55
|
+
|
|
56
|
+
Please provide a comprehensive summary and analysis of the document.`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const result = await processWithAI(prompt, '', mode);
|
|
60
|
+
return { text: result || 'No response generated' };
|
|
61
|
+
|
|
62
|
+
} catch (pdfError) {
|
|
63
|
+
return {
|
|
64
|
+
text: `❌ **Error Reading PDF**\n\n` +
|
|
65
|
+
`Failed to extract text from "${fileName}": ${pdfError.message}\n\n` +
|
|
66
|
+
`**Possible reasons:**\n` +
|
|
67
|
+
`- The PDF is corrupted or password-protected\n` +
|
|
68
|
+
`- The PDF contains only images (scanned document)\n\n` +
|
|
69
|
+
`**Try using /image command for scanned PDFs:**\n` +
|
|
70
|
+
`\`/image "${filePath}" ${query || 'analyze this document'}\``
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// For other document types (Word, Excel, etc.)
|
|
76
|
+
return {
|
|
77
|
+
text: `❌ **Document Type Not Supported**\n\n` +
|
|
78
|
+
`The file "${fileName}" is a ${ext.toUpperCase()} document.\n\n` +
|
|
79
|
+
`**Supported formats:**\n` +
|
|
80
|
+
`- PDF files (.pdf) - Text extraction supported\n` +
|
|
81
|
+
`- Text files (.txt, .md, etc.)\n` +
|
|
82
|
+
`- Code files (.js, .py, .java, etc.)\n\n` +
|
|
83
|
+
`**For ${ext.toUpperCase()} files:**\n` +
|
|
84
|
+
`Please convert to PDF or text format first.`
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Handle text-based files
|
|
14
89
|
const content = await readFileContent(filePath);
|
|
15
90
|
const fileName = path.basename(filePath);
|
|
16
91
|
|
|
@@ -48,8 +123,8 @@ Please provide a summary and analysis of the content.`;
|
|
|
48
123
|
}
|
|
49
124
|
}
|
|
50
125
|
|
|
51
|
-
const result = await processWithAI(prompt);
|
|
52
|
-
return { text: result || 'No response generated' };
|
|
126
|
+
const result = await processWithAI(prompt, '', mode);
|
|
127
|
+
return { text: result || 'No response generated' };
|
|
53
128
|
} catch (error) {
|
|
54
129
|
throw error;
|
|
55
130
|
}
|
|
@@ -57,4 +132,4 @@ Please provide a summary and analysis of the content.`;
|
|
|
57
132
|
|
|
58
133
|
module.exports = {
|
|
59
134
|
analyzeFile
|
|
60
|
-
};
|
|
135
|
+
};
|
|
@@ -1,164 +1,164 @@
|
|
|
1
|
-
const fs = require('fs').promises;
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { getFileType } = require('../utils/fileUtils');
|
|
4
|
-
const { processWithAI } = require('./aiService');
|
|
5
|
-
|
|
6
|
-
function buildSimpleFileTree(folderPath, items, statsCache, depth = 0) {
|
|
7
|
-
let tree = '';
|
|
8
|
-
const indent = ' '.repeat(depth);
|
|
9
|
-
|
|
10
|
-
for (const item of items) {
|
|
11
|
-
const itemPath = path.join(folderPath, item);
|
|
12
|
-
const stats = statsCache.get(itemPath);
|
|
13
|
-
tree += `${indent}${item}${stats.isDirectory() ? '/' : ''}\n`;
|
|
14
|
-
|
|
15
|
-
if (stats.isDirectory()) {
|
|
16
|
-
try {
|
|
17
|
-
const subItems = fs.readdirSync(itemPath);
|
|
18
|
-
const subStatsCache = new Map();
|
|
19
|
-
for (const subItem of subItems) {
|
|
20
|
-
const subItemPath = path.join(itemPath, subItem);
|
|
21
|
-
subStatsCache.set(subItemPath, fs.statSync(subItemPath));
|
|
22
|
-
}
|
|
23
|
-
tree += buildSimpleFileTree(itemPath, subItems, subStatsCache, depth + 1);
|
|
24
|
-
} catch (error) {
|
|
25
|
-
tree += `${indent} (error accessing directory)\n`;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return tree;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function analyzeFolder(folderPath, maxDepth = 2, currentDepth = 0) {
|
|
34
|
-
try {
|
|
35
|
-
const stats = await fs.stat(folderPath);
|
|
36
|
-
if (!stats.isDirectory()) {
|
|
37
|
-
throw new Error('Path is not a directory');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const analysis = {
|
|
41
|
-
path: folderPath,
|
|
42
|
-
files: [],
|
|
43
|
-
folders: [],
|
|
44
|
-
fileTree: '', // Store simple file tree
|
|
45
|
-
summary: {
|
|
46
|
-
totalFiles: 0,
|
|
47
|
-
totalFolders: 0,
|
|
48
|
-
fileTypes: {},
|
|
49
|
-
languages: {},
|
|
50
|
-
size: 0
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const items = await fs.readdir(folderPath);
|
|
55
|
-
const statsCache = new Map();
|
|
56
|
-
|
|
57
|
-
// Cache stats for all items
|
|
58
|
-
for (const item of items) {
|
|
59
|
-
const itemPath = path.join(folderPath, item);
|
|
60
|
-
statsCache.set(itemPath, await fs.stat(itemPath));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Build simple file tree
|
|
64
|
-
analysis.fileTree = buildSimpleFileTree(folderPath, items, statsCache);
|
|
65
|
-
|
|
66
|
-
for (const item of items) {
|
|
67
|
-
const itemPath = path.join(folderPath, item);
|
|
68
|
-
const itemStats = statsCache.get(itemPath);
|
|
69
|
-
|
|
70
|
-
if (itemStats.isDirectory()) {
|
|
71
|
-
analysis.folders.push(item);
|
|
72
|
-
analysis.summary.totalFolders++;
|
|
73
|
-
|
|
74
|
-
if (currentDepth < maxDepth) {
|
|
75
|
-
try {
|
|
76
|
-
const subAnalysis = await analyzeFolder(itemPath, maxDepth, currentDepth + 1);
|
|
77
|
-
analysis.summary.totalFiles += subAnalysis.summary.totalFiles;
|
|
78
|
-
analysis.summary.totalFolders += subAnalysis.summary.totalFolders;
|
|
79
|
-
analysis.summary.size += subAnalysis.summary.size;
|
|
80
|
-
|
|
81
|
-
Object.keys(subAnalysis.summary.fileTypes).forEach(type => {
|
|
82
|
-
analysis.summary.fileTypes[type] = (analysis.summary.fileTypes[type] || 0) + subAnalysis.summary.fileTypes[type];
|
|
83
|
-
});
|
|
84
|
-
Object.keys(subAnalysis.summary.languages).forEach(lang => {
|
|
85
|
-
analysis.summary.languages[lang] = (analysis.summary.languages[lang] || 0) + subAnalysis.summary.languages[lang];
|
|
86
|
-
});
|
|
87
|
-
} catch (error) {
|
|
88
|
-
console.warn(`Warning: Cannot access folder ${itemPath}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
} else {
|
|
92
|
-
const fileType = getFileType(itemPath);
|
|
93
|
-
analysis.files.push({
|
|
94
|
-
name: item,
|
|
95
|
-
type: fileType,
|
|
96
|
-
size: itemStats.size,
|
|
97
|
-
modified: itemStats.mtime
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
analysis.summary.totalFiles++;
|
|
101
|
-
analysis.summary.size += itemStats.size;
|
|
102
|
-
analysis.summary.fileTypes[fileType] = (analysis.summary.fileTypes[fileType] || 0) + 1;
|
|
103
|
-
|
|
104
|
-
if (fileType !== 'image' && fileType !== 'Unknown') {
|
|
105
|
-
analysis.summary.languages[fileType] = (analysis.summary.languages[fileType] || 0) + 1;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return analysis;
|
|
111
|
-
} catch (error) {
|
|
112
|
-
if (error.code === 'ENOENT') {
|
|
113
|
-
throw new Error(`Folder not found: ${folderPath}`);
|
|
114
|
-
}
|
|
115
|
-
if (error.code === 'EACCES') {
|
|
116
|
-
throw new Error(`Access denied: ${folderPath}`);
|
|
117
|
-
}
|
|
118
|
-
throw error;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async function analyzeFolderStructure(folderPath, query = '') {
|
|
123
|
-
try {
|
|
124
|
-
const analysis = await analyzeFolder(folderPath);
|
|
125
|
-
|
|
126
|
-
const structureText = `
|
|
127
|
-
Folder: ${analysis.path}
|
|
128
|
-
Files: ${analysis.summary.totalFiles}
|
|
129
|
-
Folders: ${analysis.summary.totalFolders}
|
|
130
|
-
Total Size: ${(analysis.summary.size / 1024).toFixed(2)} KB
|
|
131
|
-
|
|
132
|
-
Files and Directories:
|
|
133
|
-
${analysis.fileTree}
|
|
134
|
-
|
|
135
|
-
File Types:
|
|
136
|
-
${Object.entries(analysis.summary.fileTypes).map(([type, count]) => `- ${type}: ${count}`).join('\n')}
|
|
137
|
-
|
|
138
|
-
Languages/Technologies:
|
|
139
|
-
${Object.entries(analysis.summary.languages).map(([lang, count]) => `- ${lang}: ${count} files`).join('\n')}
|
|
140
|
-
`;
|
|
141
|
-
|
|
142
|
-
let prompt;
|
|
143
|
-
if (query) {
|
|
144
|
-
prompt = `Project Structure:
|
|
145
|
-
${structureText}
|
|
146
|
-
|
|
147
|
-
User Question: ${query}`;
|
|
148
|
-
} else {
|
|
149
|
-
prompt = `Analyze this project structure:
|
|
150
|
-
${structureText}
|
|
151
|
-
|
|
152
|
-
Provide a brief overview of the project based on its file structure.`;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const result = await processWithAI(prompt);
|
|
156
|
-
return { text: result || 'No response generated' }; // Ensure text property is always defined
|
|
157
|
-
} catch (error) {
|
|
158
|
-
throw error;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
module.exports = {
|
|
163
|
-
analyzeFolderStructure
|
|
1
|
+
const fs = require('fs').promises;
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { getFileType } = require('../utils/fileUtils');
|
|
4
|
+
const { processWithAI } = require('./aiService');
|
|
5
|
+
|
|
6
|
+
function buildSimpleFileTree(folderPath, items, statsCache, depth = 0) {
|
|
7
|
+
let tree = '';
|
|
8
|
+
const indent = ' '.repeat(depth);
|
|
9
|
+
|
|
10
|
+
for (const item of items) {
|
|
11
|
+
const itemPath = path.join(folderPath, item);
|
|
12
|
+
const stats = statsCache.get(itemPath);
|
|
13
|
+
tree += `${indent}${item}${stats.isDirectory() ? '/' : ''}\n`;
|
|
14
|
+
|
|
15
|
+
if (stats.isDirectory()) {
|
|
16
|
+
try {
|
|
17
|
+
const subItems = fs.readdirSync(itemPath);
|
|
18
|
+
const subStatsCache = new Map();
|
|
19
|
+
for (const subItem of subItems) {
|
|
20
|
+
const subItemPath = path.join(itemPath, subItem);
|
|
21
|
+
subStatsCache.set(subItemPath, fs.statSync(subItemPath));
|
|
22
|
+
}
|
|
23
|
+
tree += buildSimpleFileTree(itemPath, subItems, subStatsCache, depth + 1);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
tree += `${indent} (error accessing directory)\n`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return tree;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function analyzeFolder(folderPath, maxDepth = 2, currentDepth = 0) {
|
|
34
|
+
try {
|
|
35
|
+
const stats = await fs.stat(folderPath);
|
|
36
|
+
if (!stats.isDirectory()) {
|
|
37
|
+
throw new Error('Path is not a directory');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const analysis = {
|
|
41
|
+
path: folderPath,
|
|
42
|
+
files: [],
|
|
43
|
+
folders: [],
|
|
44
|
+
fileTree: '', // Store simple file tree
|
|
45
|
+
summary: {
|
|
46
|
+
totalFiles: 0,
|
|
47
|
+
totalFolders: 0,
|
|
48
|
+
fileTypes: {},
|
|
49
|
+
languages: {},
|
|
50
|
+
size: 0
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const items = await fs.readdir(folderPath);
|
|
55
|
+
const statsCache = new Map();
|
|
56
|
+
|
|
57
|
+
// Cache stats for all items
|
|
58
|
+
for (const item of items) {
|
|
59
|
+
const itemPath = path.join(folderPath, item);
|
|
60
|
+
statsCache.set(itemPath, await fs.stat(itemPath));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Build simple file tree
|
|
64
|
+
analysis.fileTree = buildSimpleFileTree(folderPath, items, statsCache);
|
|
65
|
+
|
|
66
|
+
for (const item of items) {
|
|
67
|
+
const itemPath = path.join(folderPath, item);
|
|
68
|
+
const itemStats = statsCache.get(itemPath);
|
|
69
|
+
|
|
70
|
+
if (itemStats.isDirectory()) {
|
|
71
|
+
analysis.folders.push(item);
|
|
72
|
+
analysis.summary.totalFolders++;
|
|
73
|
+
|
|
74
|
+
if (currentDepth < maxDepth) {
|
|
75
|
+
try {
|
|
76
|
+
const subAnalysis = await analyzeFolder(itemPath, maxDepth, currentDepth + 1);
|
|
77
|
+
analysis.summary.totalFiles += subAnalysis.summary.totalFiles;
|
|
78
|
+
analysis.summary.totalFolders += subAnalysis.summary.totalFolders;
|
|
79
|
+
analysis.summary.size += subAnalysis.summary.size;
|
|
80
|
+
|
|
81
|
+
Object.keys(subAnalysis.summary.fileTypes).forEach(type => {
|
|
82
|
+
analysis.summary.fileTypes[type] = (analysis.summary.fileTypes[type] || 0) + subAnalysis.summary.fileTypes[type];
|
|
83
|
+
});
|
|
84
|
+
Object.keys(subAnalysis.summary.languages).forEach(lang => {
|
|
85
|
+
analysis.summary.languages[lang] = (analysis.summary.languages[lang] || 0) + subAnalysis.summary.languages[lang];
|
|
86
|
+
});
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.warn(`Warning: Cannot access folder ${itemPath}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
const fileType = getFileType(itemPath);
|
|
93
|
+
analysis.files.push({
|
|
94
|
+
name: item,
|
|
95
|
+
type: fileType,
|
|
96
|
+
size: itemStats.size,
|
|
97
|
+
modified: itemStats.mtime
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
analysis.summary.totalFiles++;
|
|
101
|
+
analysis.summary.size += itemStats.size;
|
|
102
|
+
analysis.summary.fileTypes[fileType] = (analysis.summary.fileTypes[fileType] || 0) + 1;
|
|
103
|
+
|
|
104
|
+
if (fileType !== 'image' && fileType !== 'Unknown') {
|
|
105
|
+
analysis.summary.languages[fileType] = (analysis.summary.languages[fileType] || 0) + 1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return analysis;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (error.code === 'ENOENT') {
|
|
113
|
+
throw new Error(`Folder not found: ${folderPath}`);
|
|
114
|
+
}
|
|
115
|
+
if (error.code === 'EACCES') {
|
|
116
|
+
throw new Error(`Access denied: ${folderPath}`);
|
|
117
|
+
}
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function analyzeFolderStructure(folderPath, query = '') {
|
|
123
|
+
try {
|
|
124
|
+
const analysis = await analyzeFolder(folderPath);
|
|
125
|
+
|
|
126
|
+
const structureText = `
|
|
127
|
+
Folder: ${analysis.path}
|
|
128
|
+
Files: ${analysis.summary.totalFiles}
|
|
129
|
+
Folders: ${analysis.summary.totalFolders}
|
|
130
|
+
Total Size: ${(analysis.summary.size / 1024).toFixed(2)} KB
|
|
131
|
+
|
|
132
|
+
Files and Directories:
|
|
133
|
+
${analysis.fileTree}
|
|
134
|
+
|
|
135
|
+
File Types:
|
|
136
|
+
${Object.entries(analysis.summary.fileTypes).map(([type, count]) => `- ${type}: ${count}`).join('\n')}
|
|
137
|
+
|
|
138
|
+
Languages/Technologies:
|
|
139
|
+
${Object.entries(analysis.summary.languages).map(([lang, count]) => `- ${lang}: ${count} files`).join('\n')}
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
let prompt;
|
|
143
|
+
if (query) {
|
|
144
|
+
prompt = `Project Structure:
|
|
145
|
+
${structureText}
|
|
146
|
+
|
|
147
|
+
User Question: ${query}`;
|
|
148
|
+
} else {
|
|
149
|
+
prompt = `Analyze this project structure:
|
|
150
|
+
${structureText}
|
|
151
|
+
|
|
152
|
+
Provide a brief overview of the project based on its file structure.`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const result = await processWithAI(prompt);
|
|
156
|
+
return { text: result || 'No response generated' }; // Ensure text property is always defined
|
|
157
|
+
} catch (error) {
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
module.exports = {
|
|
163
|
+
analyzeFolderStructure
|
|
164
164
|
};
|
package/services/imageService.js
CHANGED
|
@@ -3,6 +3,20 @@ const fetch = require('node-fetch');
|
|
|
3
3
|
const { encryptData, decryptData } = require('../utils/encryption');
|
|
4
4
|
const { getMimeType } = require('../utils/fileUtils');
|
|
5
5
|
|
|
6
|
+
// Model selection helper for vision models
|
|
7
|
+
function getVisionModels(mode) {
|
|
8
|
+
switch (Number(mode)) {
|
|
9
|
+
case 1: // Fast
|
|
10
|
+
return ['g1'];
|
|
11
|
+
case 2: // Balanced
|
|
12
|
+
return ['qvl72', 'mvrk'];
|
|
13
|
+
case 3: // Think
|
|
14
|
+
return ['g1', 'mvrk', 'gma3', 'qvl72', 'sct'];
|
|
15
|
+
default:
|
|
16
|
+
return ['qvl72', 'mvrk'];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
6
20
|
async function convertImageToBase64(imagePath) {
|
|
7
21
|
try {
|
|
8
22
|
const imageBuffer = await fs.readFile(imagePath);
|
|
@@ -14,10 +28,10 @@ async function convertImageToBase64(imagePath) {
|
|
|
14
28
|
}
|
|
15
29
|
}
|
|
16
30
|
|
|
17
|
-
async function extractTextFromImage(imagePath, question = '') {
|
|
31
|
+
async function extractTextFromImage(imagePath, question = '', mode = 2) {
|
|
18
32
|
try {
|
|
19
33
|
const { base64, mimeType } = await convertImageToBase64(imagePath);
|
|
20
|
-
const visionModels =
|
|
34
|
+
const visionModels = getVisionModels(mode); // Use selected mode
|
|
21
35
|
|
|
22
36
|
const modelRequests = visionModels.map(model =>
|
|
23
37
|
fetch('https://traceai.dukeindustries7.workers.dev/', {
|