@make-u-free/migi 0.3.1 → 0.3.3
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/package.json +3 -1
- package/src/agent.js +7 -2
- package/src/tools.js +68 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@make-u-free/migi",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Your AI right-hand agent. Works anywhere, with any LLM API.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
"start": "node bin/migi.js"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
+
"adm-zip": "^0.5.16",
|
|
13
14
|
"chalk": "^5.3.0",
|
|
14
15
|
"dotenv": "^16.4.0",
|
|
15
16
|
"glob": "^11.0.0",
|
|
16
17
|
"openai": "^4.0.0",
|
|
18
|
+
"pdf-parse": "^2.4.5",
|
|
17
19
|
"xlsx": "^0.18.5"
|
|
18
20
|
},
|
|
19
21
|
"engines": {
|
package/src/agent.js
CHANGED
|
@@ -7,8 +7,9 @@ import { httpsAgent } from './tls.js'
|
|
|
7
7
|
|
|
8
8
|
export class MigiAgent {
|
|
9
9
|
constructor({ context = '', promptFn = null, apiKey = null, model = 'gpt-4.1-2025-04-14', name = 'Migi', userName = '', teamsWebhookUrl = '' } = {}) {
|
|
10
|
+
this.apiKey = apiKey || process.env.OPENAI_API_KEY
|
|
10
11
|
this.client = new OpenAI({
|
|
11
|
-
apiKey: apiKey
|
|
12
|
+
apiKey: this.apiKey,
|
|
12
13
|
...(httpsAgent ? { httpAgent: httpsAgent } : {})
|
|
13
14
|
})
|
|
14
15
|
this.model = model
|
|
@@ -123,7 +124,11 @@ ${userNameLine}
|
|
|
123
124
|
|
|
124
125
|
if (approved) {
|
|
125
126
|
try {
|
|
126
|
-
result = await executeTool(name, args, {
|
|
127
|
+
result = await executeTool(name, args, {
|
|
128
|
+
teamsWebhookUrl: this.teamsWebhookUrl,
|
|
129
|
+
apiKey: this.apiKey,
|
|
130
|
+
model: this.model
|
|
131
|
+
})
|
|
127
132
|
} catch (err) {
|
|
128
133
|
result = `エラー: ${err.message}`
|
|
129
134
|
}
|
package/src/tools.js
CHANGED
|
@@ -4,9 +4,16 @@ import { dirname, extname } from 'path'
|
|
|
4
4
|
import { request } from 'https'
|
|
5
5
|
import { glob } from 'glob'
|
|
6
6
|
import xlsxPkg from 'xlsx'
|
|
7
|
+
import pdfParse from 'pdf-parse'
|
|
8
|
+
import AdmZip from 'adm-zip'
|
|
9
|
+
import OpenAI from 'openai'
|
|
7
10
|
import { httpsAgent } from './tls.js'
|
|
8
11
|
const { readFile: xlsxReadFile, utils: xlsxUtils } = xlsxPkg
|
|
9
12
|
|
|
13
|
+
const IMAGE_EXTS = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp'])
|
|
14
|
+
const OFFICE_EXTS = new Set(['.pdf', '.pptx', '.ppt', '.docx', '.doc', '.odp', '.odt'])
|
|
15
|
+
const MIME = { '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png', '.gif': 'image/gif', '.webp': 'image/webp' }
|
|
16
|
+
|
|
10
17
|
// ---- OpenAI ツールスキーマ定義 ----
|
|
11
18
|
|
|
12
19
|
export const toolSchemas = [
|
|
@@ -14,7 +21,7 @@ export const toolSchemas = [
|
|
|
14
21
|
type: 'function',
|
|
15
22
|
function: {
|
|
16
23
|
name: 'read_file',
|
|
17
|
-
description: '
|
|
24
|
+
description: 'ファイルの内容を読み込む。テキスト・Excel・PDF・Word・PowerPoint・画像に対応',
|
|
18
25
|
parameters: {
|
|
19
26
|
type: 'object',
|
|
20
27
|
properties: {
|
|
@@ -124,6 +131,8 @@ export async function executeTool(name, args, opts = {}) {
|
|
|
124
131
|
case 'read_file': {
|
|
125
132
|
if (!existsSync(args.path)) return `エラー: ファイルが見つかりません: ${args.path}`
|
|
126
133
|
const ext = extname(args.path).toLowerCase()
|
|
134
|
+
|
|
135
|
+
// Excel
|
|
127
136
|
if (ext === '.xlsx' || ext === '.xls') {
|
|
128
137
|
const workbook = xlsxReadFile(args.path)
|
|
129
138
|
const result = []
|
|
@@ -134,6 +143,64 @@ export async function executeTool(name, args, opts = {}) {
|
|
|
134
143
|
}
|
|
135
144
|
return result.join('\n\n')
|
|
136
145
|
}
|
|
146
|
+
|
|
147
|
+
// PDF
|
|
148
|
+
if (ext === '.pdf') {
|
|
149
|
+
try {
|
|
150
|
+
const buf = readFileSync(args.path)
|
|
151
|
+
const data = await pdfParse(buf)
|
|
152
|
+
return data.text?.trim() || '(テキストが抽出できませんでした)'
|
|
153
|
+
} catch (err) {
|
|
154
|
+
return `エラー: PDFの解析に失敗しました: ${err.message}`
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// PowerPoint(PPTX)/ Word(DOCX)→ ZIPを展開してXMLからテキスト抽出
|
|
159
|
+
if (['.pptx', '.ppt', '.docx', '.doc', '.odp', '.odt'].includes(ext)) {
|
|
160
|
+
try {
|
|
161
|
+
const zip = new AdmZip(args.path)
|
|
162
|
+
const entries = zip.getEntries()
|
|
163
|
+
const xmlTexts = []
|
|
164
|
+
for (const entry of entries) {
|
|
165
|
+
const name = entry.entryName
|
|
166
|
+
const isSlide = name.startsWith('ppt/slides/slide') && name.endsWith('.xml')
|
|
167
|
+
const isDoc = name === 'word/document.xml'
|
|
168
|
+
const isOdp = name === 'content.xml'
|
|
169
|
+
if (isSlide || isDoc || isOdp) {
|
|
170
|
+
const xml = entry.getData().toString('utf-8')
|
|
171
|
+
const text = xml.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim()
|
|
172
|
+
if (text) xmlTexts.push(text)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return xmlTexts.join('\n\n') || '(テキストが抽出できませんでした)'
|
|
176
|
+
} catch (err) {
|
|
177
|
+
return `エラー: ファイルの解析に失敗しました: ${err.message}`
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 画像 → Vision API で内容を説明させる
|
|
182
|
+
if (IMAGE_EXTS.has(ext)) {
|
|
183
|
+
if (!opts.apiKey) return 'エラー: 画像読み込みにはAPIキーが必要です'
|
|
184
|
+
const base64 = readFileSync(args.path).toString('base64')
|
|
185
|
+
const mimeType = MIME[ext] || 'image/jpeg'
|
|
186
|
+
const client = new OpenAI({
|
|
187
|
+
apiKey: opts.apiKey,
|
|
188
|
+
...(httpsAgent ? { httpAgent: httpsAgent } : {})
|
|
189
|
+
})
|
|
190
|
+
const res = await client.chat.completions.create({
|
|
191
|
+
model: opts.model || 'gpt-4.1-2025-04-14',
|
|
192
|
+
messages: [{
|
|
193
|
+
role: 'user',
|
|
194
|
+
content: [
|
|
195
|
+
{ type: 'image_url', image_url: { url: `data:${mimeType};base64,${base64}` } },
|
|
196
|
+
{ type: 'text', text: 'この画像の内容を詳しく説明してください。テキストが含まれている場合はすべて書き起こしてください。' }
|
|
197
|
+
]
|
|
198
|
+
}],
|
|
199
|
+
max_tokens: 2000
|
|
200
|
+
})
|
|
201
|
+
return res.choices[0].message.content
|
|
202
|
+
}
|
|
203
|
+
|
|
137
204
|
return readFileSync(args.path, 'utf-8')
|
|
138
205
|
}
|
|
139
206
|
|