@nogataka/imgen 0.2.0 → 0.3.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.md +36 -35
- package/dist/{chunk-HQT7ZTCY.js → chunk-UZXMJEHL.js} +55 -269
- package/dist/index.js +22 -440
- package/dist/sdk.d.ts +10 -57
- package/dist/sdk.js +1 -9
- package/package.json +1 -8
package/README.md
CHANGED
|
@@ -10,25 +10,32 @@ npm install -g @nogataka/imgen
|
|
|
10
10
|
|
|
11
11
|
## セットアップ
|
|
12
12
|
|
|
13
|
-
###
|
|
13
|
+
### 環境変数
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com"
|
|
17
17
|
export AZURE_OPENAI_API_KEY="your-api-key"
|
|
18
18
|
export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-5.1"
|
|
19
19
|
export AZURE_OPENAI_DEPLOYMENT_NAME_IMAGE="gpt-image-1.5"
|
|
20
|
-
export AZURE_OPENAI_API_VERSION="2024-02-15-preview"
|
|
21
|
-
export AZURE_OPENAI_IMAGE_API_VERSION="2025-04-01-preview"
|
|
20
|
+
export AZURE_OPENAI_API_VERSION="2024-02-15-preview" # 省略可
|
|
21
|
+
export AZURE_OPENAI_IMAGE_API_VERSION="2025-04-01-preview" # 省略可
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
###
|
|
24
|
+
### .env ファイル
|
|
25
|
+
|
|
26
|
+
環境変数の代わりに `.env` ファイルで設定できます。探索順:
|
|
27
|
+
|
|
28
|
+
1. `cwd/.env`(カレントディレクトリ)
|
|
29
|
+
2. `~/.imgen/.env`
|
|
25
30
|
|
|
26
31
|
```bash
|
|
27
|
-
|
|
32
|
+
# .env
|
|
33
|
+
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
|
|
34
|
+
AZURE_OPENAI_API_KEY=your-api-key
|
|
35
|
+
AZURE_OPENAI_DEPLOYMENT_NAME=gpt-5.1
|
|
36
|
+
AZURE_OPENAI_DEPLOYMENT_NAME_IMAGE=gpt-image-1.5
|
|
28
37
|
```
|
|
29
38
|
|
|
30
|
-
Azure OpenAI の接続情報やデフォルト値を対話的に設定できます。設定は `~/.imgen/config.json` に保存されます。
|
|
31
|
-
|
|
32
39
|
環境変数が設定されている場合、環境変数が優先されます。
|
|
33
40
|
|
|
34
41
|
## 使い方
|
|
@@ -54,7 +61,7 @@ imgen image gen "商品写真" -p builtin:landscape
|
|
|
54
61
|
| `--output <path>` | `-o` | 出力先ファイルまたはディレクトリ | カレントディレクトリ |
|
|
55
62
|
| `--json` | | JSON 形式で出力 | - |
|
|
56
63
|
| `--dry-run` | | API を呼ばずに設定を確認 | - |
|
|
57
|
-
| `--debug` | `-d` |
|
|
64
|
+
| `--debug` | `-d` | デバッグ情報を表示 | - |
|
|
58
65
|
|
|
59
66
|
### 画像編集
|
|
60
67
|
|
|
@@ -95,11 +102,7 @@ imgen image explain chart.png -c "Q4 sales report" -f json -o description.json
|
|
|
95
102
|
|
|
96
103
|
対応言語: `ja`(日本語), `en`(英語), `zh`(中国語), `ko`(韓国語), `es`(スペイン語), `fr`(フランス語), `de`(ドイツ語), `it`(イタリア語), `ru`(ロシア語), `vi`(ベトナム語)
|
|
97
104
|
|
|
98
|
-
##
|
|
99
|
-
|
|
100
|
-
よく使う設定をプリセットとして保存・呼び出しできます。
|
|
101
|
-
|
|
102
|
-
### ビルトインプリセット
|
|
105
|
+
## ビルトインプリセット
|
|
103
106
|
|
|
104
107
|
| 名前 | サイズ | 品質 | 用途 |
|
|
105
108
|
|------|--------|------|------|
|
|
@@ -109,41 +112,39 @@ imgen image explain chart.png -c "Q4 sales report" -f json -o description.json
|
|
|
109
112
|
| `builtin:draft` | 1024x1024 | low | 下書き、プロトタイプ |
|
|
110
113
|
| `builtin:photo` | 1536x1024 | high | 商品写真 |
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
imgen preset save myhd -s 1536x1024 -q high -f png
|
|
116
|
-
imgen preset list
|
|
117
|
-
imgen preset delete myhd
|
|
118
|
-
```
|
|
115
|
+
## 設定の優先順位
|
|
119
116
|
|
|
120
|
-
|
|
117
|
+
1. CLI オプション(最優先)
|
|
118
|
+
2. プリセット値(`-p` 指定時)
|
|
119
|
+
3. デフォルト値
|
|
121
120
|
|
|
122
|
-
##
|
|
121
|
+
## SDK として使う
|
|
123
122
|
|
|
124
|
-
|
|
123
|
+
imgen は CLI だけでなく、Node.js ライブラリとしても利用できます。スライドジェネレーターや LLM ツールなど、他のアプリケーションから画像生成・編集・説明機能を呼び出せます。
|
|
125
124
|
|
|
126
125
|
```bash
|
|
127
|
-
|
|
128
|
-
imgen log -n 50 -l debug # 直近 50 件(DEBUG 以上)
|
|
129
|
-
imgen log -l error # エラーのみ
|
|
126
|
+
npm install @nogataka/imgen
|
|
130
127
|
```
|
|
131
128
|
|
|
132
|
-
|
|
129
|
+
### 認証設定
|
|
133
130
|
|
|
134
|
-
|
|
135
|
-
2. プリセット値(`-p` 指定時)
|
|
136
|
-
3. 設定ファイル(`~/.imgen/config.json`)
|
|
137
|
-
4. デフォルト値
|
|
131
|
+
`getAzureConfig()` は以下の優先順位で設定を解決します:
|
|
138
132
|
|
|
139
|
-
|
|
133
|
+
1. **環境変数**(最優先)
|
|
134
|
+
2. **`.env` ファイル**(`cwd/.env` → `~/.imgen/.env`)
|
|
140
135
|
|
|
141
|
-
|
|
136
|
+
アプリ側で `.env` ファイルを読み込んでいる場合(dotenv, Next.js 等)、そこに追記するだけで動きます:
|
|
142
137
|
|
|
143
138
|
```bash
|
|
144
|
-
|
|
139
|
+
# アプリ側の .env
|
|
140
|
+
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
|
|
141
|
+
AZURE_OPENAI_API_KEY=your-api-key
|
|
142
|
+
AZURE_OPENAI_DEPLOYMENT_NAME=gpt-5.1
|
|
143
|
+
AZURE_OPENAI_DEPLOYMENT_NAME_IMAGE=gpt-image-1.5
|
|
145
144
|
```
|
|
146
145
|
|
|
146
|
+
### 使用例
|
|
147
|
+
|
|
147
148
|
```typescript
|
|
148
149
|
import {
|
|
149
150
|
AzureImageClient,
|
|
@@ -152,7 +153,7 @@ import {
|
|
|
152
153
|
saveFileWithUniqueNameIfExists,
|
|
153
154
|
} from "@nogataka/imgen/sdk";
|
|
154
155
|
|
|
155
|
-
// Azure OpenAI 設定を取得(環境変数 or
|
|
156
|
+
// Azure OpenAI 設定を取得(環境変数 or .envファイル)
|
|
156
157
|
const config = await getAzureConfig();
|
|
157
158
|
|
|
158
159
|
// 画像生成
|
|
@@ -1,58 +1,45 @@
|
|
|
1
|
-
// src/lang.ts
|
|
2
|
-
var LANGUAGE_DESCRIPTIONS = {
|
|
3
|
-
ja: "\u65E5\u672C\u8A9E",
|
|
4
|
-
en: "\u82F1\u8A9E",
|
|
5
|
-
zh: "\u4E2D\u56FD\u8A9E",
|
|
6
|
-
ko: "\u97D3\u56FD\u8A9E",
|
|
7
|
-
es: "\u30B9\u30DA\u30A4\u30F3\u8A9E",
|
|
8
|
-
fr: "\u30D5\u30E9\u30F3\u30B9\u8A9E",
|
|
9
|
-
de: "\u30C9\u30A4\u30C4\u8A9E",
|
|
10
|
-
it: "\u30A4\u30BF\u30EA\u30A2\u8A9E",
|
|
11
|
-
ru: "\u30ED\u30B7\u30A2\u8A9E",
|
|
12
|
-
vi: "\u30D9\u30C8\u30CA\u30E0\u8A9E"
|
|
13
|
-
};
|
|
14
|
-
|
|
15
1
|
// src/utils/config.ts
|
|
16
2
|
import * as fs from "fs/promises";
|
|
17
3
|
import * as os from "os";
|
|
18
4
|
import * as path from "path";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
async function loadConfig() {
|
|
33
|
-
try {
|
|
34
|
-
const text = await fs.readFile(getConfigPath(), "utf-8");
|
|
35
|
-
return JSON.parse(text);
|
|
36
|
-
} catch {
|
|
37
|
-
return null;
|
|
5
|
+
function parseEnvFile(content) {
|
|
6
|
+
const result = {};
|
|
7
|
+
for (const line of content.split("\n")) {
|
|
8
|
+
const trimmed = line.trim();
|
|
9
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
10
|
+
const eqIndex = trimmed.indexOf("=");
|
|
11
|
+
if (eqIndex === -1) continue;
|
|
12
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
13
|
+
let value = trimmed.slice(eqIndex + 1).trim();
|
|
14
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
15
|
+
value = value.slice(1, -1);
|
|
16
|
+
}
|
|
17
|
+
result[key] = value;
|
|
38
18
|
}
|
|
19
|
+
return result;
|
|
39
20
|
}
|
|
40
|
-
async function
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
21
|
+
async function loadEnvVars() {
|
|
22
|
+
const candidates = [path.join(process.cwd(), ".env"), path.join(os.homedir(), ".imgen", ".env")];
|
|
23
|
+
for (const envPath of candidates) {
|
|
24
|
+
try {
|
|
25
|
+
const content = await fs.readFile(envPath, "utf-8");
|
|
26
|
+
return parseEnvFile(content);
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return {};
|
|
44
31
|
}
|
|
45
32
|
async function getAzureConfig() {
|
|
46
|
-
const
|
|
47
|
-
const endpoint = process.env.AZURE_OPENAI_ENDPOINT ||
|
|
48
|
-
const apiKey = process.env.AZURE_OPENAI_API_KEY ||
|
|
49
|
-
const deploymentName = process.env.AZURE_OPENAI_DEPLOYMENT_NAME ||
|
|
50
|
-
const imageDeploymentName = process.env.AZURE_OPENAI_DEPLOYMENT_NAME_IMAGE ||
|
|
51
|
-
const apiVersion = process.env.AZURE_OPENAI_API_VERSION ||
|
|
52
|
-
const imageApiVersion = process.env.AZURE_OPENAI_IMAGE_API_VERSION ||
|
|
33
|
+
const envVars = await loadEnvVars();
|
|
34
|
+
const endpoint = process.env.AZURE_OPENAI_ENDPOINT || envVars.AZURE_OPENAI_ENDPOINT;
|
|
35
|
+
const apiKey = process.env.AZURE_OPENAI_API_KEY || envVars.AZURE_OPENAI_API_KEY;
|
|
36
|
+
const deploymentName = process.env.AZURE_OPENAI_DEPLOYMENT_NAME || envVars.AZURE_OPENAI_DEPLOYMENT_NAME;
|
|
37
|
+
const imageDeploymentName = process.env.AZURE_OPENAI_DEPLOYMENT_NAME_IMAGE || envVars.AZURE_OPENAI_DEPLOYMENT_NAME_IMAGE;
|
|
38
|
+
const apiVersion = process.env.AZURE_OPENAI_API_VERSION || envVars.AZURE_OPENAI_API_VERSION || "2024-02-15-preview";
|
|
39
|
+
const imageApiVersion = process.env.AZURE_OPENAI_IMAGE_API_VERSION || envVars.AZURE_OPENAI_IMAGE_API_VERSION || "2025-04-01-preview";
|
|
53
40
|
if (!endpoint || !apiKey || !deploymentName || !imageDeploymentName) {
|
|
54
41
|
throw new Error(
|
|
55
|
-
"Azure OpenAI \u306E\u8A2D\u5B9A\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002
|
|
42
|
+
"Azure OpenAI \u306E\u8A2D\u5B9A\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002\u74B0\u5883\u5909\u6570\u307E\u305F\u306F .env \u30D5\u30A1\u30A4\u30EB\u3067\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
56
43
|
);
|
|
57
44
|
}
|
|
58
45
|
return { endpoint, apiKey, deploymentName, imageDeploymentName, apiVersion, imageApiVersion };
|
|
@@ -112,157 +99,9 @@ async function fileExists(filePath) {
|
|
|
112
99
|
|
|
113
100
|
// src/utils/azure-chat.ts
|
|
114
101
|
import { AzureOpenAI } from "openai";
|
|
115
|
-
|
|
116
|
-
// src/utils/logger.ts
|
|
117
|
-
import * as fs3 from "fs/promises";
|
|
118
|
-
import * as path2 from "path";
|
|
119
|
-
import * as os2 from "os";
|
|
120
|
-
import { format } from "date-fns";
|
|
121
|
-
var Logger = class _Logger {
|
|
122
|
-
constructor(name) {
|
|
123
|
-
this.name = name;
|
|
124
|
-
const home = os2.homedir();
|
|
125
|
-
this.logDir = path2.join(home, ".imgen", "logs");
|
|
126
|
-
this.currentLogFile = this.generateLogFileName();
|
|
127
|
-
}
|
|
128
|
-
static instances = /* @__PURE__ */ new Map();
|
|
129
|
-
static globalConfig = {
|
|
130
|
-
destination: "CONSOLE" /* CONSOLE */,
|
|
131
|
-
minLevel: "INFO" /* INFO */
|
|
132
|
-
};
|
|
133
|
-
static currentContext = "default";
|
|
134
|
-
logDir;
|
|
135
|
-
currentLogFile;
|
|
136
|
-
static setGlobalConfig(config) {
|
|
137
|
-
_Logger.globalConfig = { ..._Logger.globalConfig, ...config };
|
|
138
|
-
}
|
|
139
|
-
static setContext(name) {
|
|
140
|
-
_Logger.currentContext = name;
|
|
141
|
-
}
|
|
142
|
-
static getInstance(options) {
|
|
143
|
-
const { name } = options;
|
|
144
|
-
if (!_Logger.instances.has(name)) {
|
|
145
|
-
_Logger.instances.set(name, new _Logger(name));
|
|
146
|
-
}
|
|
147
|
-
return _Logger.instances.get(name);
|
|
148
|
-
}
|
|
149
|
-
generateLogFileName() {
|
|
150
|
-
return path2.join(this.logDir, `${this.name}-${format(/* @__PURE__ */ new Date(), "yyyy-MM-dd")}.log`);
|
|
151
|
-
}
|
|
152
|
-
async ensureLogDirectory() {
|
|
153
|
-
await fs3.mkdir(this.logDir, { recursive: true });
|
|
154
|
-
}
|
|
155
|
-
formatLogEntry(level, message, data) {
|
|
156
|
-
return { timestamp: (/* @__PURE__ */ new Date()).toISOString(), level, message, data };
|
|
157
|
-
}
|
|
158
|
-
shouldLog(level) {
|
|
159
|
-
const priority = {
|
|
160
|
-
["DEBUG" /* DEBUG */]: 0,
|
|
161
|
-
["INFO" /* INFO */]: 1,
|
|
162
|
-
["WARN" /* WARN */]: 2,
|
|
163
|
-
["ERROR" /* ERROR */]: 3
|
|
164
|
-
};
|
|
165
|
-
return priority[level] >= priority[_Logger.globalConfig.minLevel];
|
|
166
|
-
}
|
|
167
|
-
async writeLog(entry) {
|
|
168
|
-
if (!this.shouldLog(entry.level)) return;
|
|
169
|
-
const { destination } = _Logger.globalConfig;
|
|
170
|
-
if (destination === "CONSOLE" /* CONSOLE */ || destination === "BOTH" /* BOTH */) {
|
|
171
|
-
this.writeToConsole(entry);
|
|
172
|
-
}
|
|
173
|
-
if (destination === "FILE" /* FILE */ || destination === "BOTH" /* BOTH */) {
|
|
174
|
-
await this.writeToFile(entry);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
writeToConsole(entry) {
|
|
178
|
-
const ts = entry.timestamp.replace("T", " ").replace(/\.\d+Z$/, "");
|
|
179
|
-
const dataStr = entry.data ? ` ${JSON.stringify(entry.data)}` : "";
|
|
180
|
-
const msg = `[${ts}] [${this.name}] [${entry.level}] ${entry.message}${dataStr}`;
|
|
181
|
-
switch (entry.level) {
|
|
182
|
-
case "DEBUG" /* DEBUG */:
|
|
183
|
-
console.debug(msg);
|
|
184
|
-
break;
|
|
185
|
-
case "INFO" /* INFO */:
|
|
186
|
-
console.info(msg);
|
|
187
|
-
break;
|
|
188
|
-
case "WARN" /* WARN */:
|
|
189
|
-
console.warn(msg);
|
|
190
|
-
break;
|
|
191
|
-
case "ERROR" /* ERROR */:
|
|
192
|
-
console.error(msg);
|
|
193
|
-
break;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
async writeToFile(entry) {
|
|
197
|
-
await this.ensureLogDirectory();
|
|
198
|
-
try {
|
|
199
|
-
await fs3.appendFile(this.currentLogFile, JSON.stringify(entry) + "\n");
|
|
200
|
-
} catch (error) {
|
|
201
|
-
console.error(
|
|
202
|
-
`\u30ED\u30B0\u306E\u66F8\u304D\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${error instanceof Error ? error.message : String(error)}`
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
debug(message, data) {
|
|
207
|
-
return this.writeLog(this.formatLogEntry("DEBUG" /* DEBUG */, message, data));
|
|
208
|
-
}
|
|
209
|
-
info(message, data) {
|
|
210
|
-
return this.writeLog(this.formatLogEntry("INFO" /* INFO */, message, data));
|
|
211
|
-
}
|
|
212
|
-
warn(message, data) {
|
|
213
|
-
return this.writeLog(this.formatLogEntry("WARN" /* WARN */, message, data));
|
|
214
|
-
}
|
|
215
|
-
error(message, data) {
|
|
216
|
-
return this.writeLog(this.formatLogEntry("ERROR" /* ERROR */, message, data));
|
|
217
|
-
}
|
|
218
|
-
static debug(message, data) {
|
|
219
|
-
return _Logger.getInstance({ name: _Logger.currentContext }).debug(message, data);
|
|
220
|
-
}
|
|
221
|
-
static info(message, data) {
|
|
222
|
-
return _Logger.getInstance({ name: _Logger.currentContext }).info(message, data);
|
|
223
|
-
}
|
|
224
|
-
static warn(message, data) {
|
|
225
|
-
return _Logger.getInstance({ name: _Logger.currentContext }).warn(message, data);
|
|
226
|
-
}
|
|
227
|
-
static error(message, data) {
|
|
228
|
-
return _Logger.getInstance({ name: _Logger.currentContext }).error(message, data);
|
|
229
|
-
}
|
|
230
|
-
getLatestLogFilePath() {
|
|
231
|
-
return this.currentLogFile;
|
|
232
|
-
}
|
|
233
|
-
async getLogEntries(minLevel = "INFO" /* INFO */, maxEntries = 100) {
|
|
234
|
-
try {
|
|
235
|
-
await this.ensureLogDirectory();
|
|
236
|
-
const content = await fs3.readFile(this.currentLogFile, "utf-8");
|
|
237
|
-
const lines = content.trim().split("\n");
|
|
238
|
-
const priority = {
|
|
239
|
-
["DEBUG" /* DEBUG */]: 0,
|
|
240
|
-
["INFO" /* INFO */]: 1,
|
|
241
|
-
["WARN" /* WARN */]: 2,
|
|
242
|
-
["ERROR" /* ERROR */]: 3
|
|
243
|
-
};
|
|
244
|
-
const entries = [];
|
|
245
|
-
for (let i = lines.length - 1; i >= 0 && entries.length < maxEntries; i--) {
|
|
246
|
-
try {
|
|
247
|
-
const entry = JSON.parse(lines[i]);
|
|
248
|
-
if (priority[entry.level] >= priority[minLevel]) entries.unshift(entry);
|
|
249
|
-
} catch {
|
|
250
|
-
continue;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
return entries;
|
|
254
|
-
} catch (error) {
|
|
255
|
-
if (error.code === "ENOENT") return [];
|
|
256
|
-
throw error;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
// src/utils/azure-chat.ts
|
|
262
102
|
var AzureChatClient = class {
|
|
263
103
|
client;
|
|
264
104
|
deploymentName;
|
|
265
|
-
logger;
|
|
266
105
|
constructor(config) {
|
|
267
106
|
this.client = new AzureOpenAI({
|
|
268
107
|
endpoint: config.endpoint,
|
|
@@ -271,7 +110,6 @@ var AzureChatClient = class {
|
|
|
271
110
|
deployment: config.deploymentName
|
|
272
111
|
});
|
|
273
112
|
this.deploymentName = config.deploymentName;
|
|
274
|
-
this.logger = Logger.getInstance({ name: "azure-chat" });
|
|
275
113
|
}
|
|
276
114
|
/**
|
|
277
115
|
* Generates a detailed image-generation prompt from a short theme description.
|
|
@@ -304,8 +142,7 @@ Prompt:
|
|
|
304
142
|
messages: [{ role: "user", content: prompt }]
|
|
305
143
|
});
|
|
306
144
|
return response.choices[0]?.message?.content ?? "";
|
|
307
|
-
} catch
|
|
308
|
-
this.logger.error("\u30D7\u30ED\u30F3\u30D7\u30C8\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F", { error });
|
|
145
|
+
} catch {
|
|
309
146
|
throw new Error("\u30D7\u30ED\u30F3\u30D7\u30C8\u306E\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F");
|
|
310
147
|
}
|
|
311
148
|
}
|
|
@@ -332,8 +169,7 @@ Prompt:
|
|
|
332
169
|
fileName = fileName.toLowerCase().replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
333
170
|
if (fileName.length > maxLength) fileName = fileName.substring(0, maxLength);
|
|
334
171
|
return fileName || "image";
|
|
335
|
-
} catch
|
|
336
|
-
this.logger.error("\u30D5\u30A1\u30A4\u30EB\u540D\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F", { error });
|
|
172
|
+
} catch {
|
|
337
173
|
throw new Error("\u30D5\u30A1\u30A4\u30EB\u540D\u306E\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F");
|
|
338
174
|
}
|
|
339
175
|
}
|
|
@@ -365,8 +201,7 @@ ${context}` : ""}`
|
|
|
365
201
|
]
|
|
366
202
|
});
|
|
367
203
|
return response.choices[0]?.message?.content ?? "";
|
|
368
|
-
} catch
|
|
369
|
-
this.logger.error("\u753B\u50CF\u8AAC\u660E\u306E\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F", { error });
|
|
204
|
+
} catch {
|
|
370
205
|
throw new Error("\u753B\u50CF\u306E\u8AAC\u660E\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F");
|
|
371
206
|
}
|
|
372
207
|
}
|
|
@@ -377,7 +212,6 @@ import { AzureOpenAI as AzureOpenAI2 } from "openai";
|
|
|
377
212
|
var AzureImageClient = class {
|
|
378
213
|
client;
|
|
379
214
|
config;
|
|
380
|
-
logger;
|
|
381
215
|
constructor(config) {
|
|
382
216
|
this.config = config;
|
|
383
217
|
this.client = new AzureOpenAI2({
|
|
@@ -386,7 +220,6 @@ var AzureImageClient = class {
|
|
|
386
220
|
apiVersion: config.imageApiVersion,
|
|
387
221
|
deployment: config.imageDeploymentName
|
|
388
222
|
});
|
|
389
|
-
this.logger = Logger.getInstance({ name: "azure-image" });
|
|
390
223
|
}
|
|
391
224
|
/**
|
|
392
225
|
* Generates an image from a text prompt using the Azure OpenAI SDK.
|
|
@@ -394,7 +227,6 @@ var AzureImageClient = class {
|
|
|
394
227
|
*/
|
|
395
228
|
async generateImage(prompt, options) {
|
|
396
229
|
const { size = "1024x1024", quality = "high" } = options;
|
|
397
|
-
this.logger.debug("\u753B\u50CF\u751F\u6210\u30EA\u30AF\u30A8\u30B9\u30C8", { prompt: prompt.substring(0, 100), size, quality });
|
|
398
230
|
try {
|
|
399
231
|
const response = await this.client.images.generate({
|
|
400
232
|
model: this.config.imageDeploymentName,
|
|
@@ -416,7 +248,6 @@ var AzureImageClient = class {
|
|
|
416
248
|
return bytes;
|
|
417
249
|
} catch (error) {
|
|
418
250
|
if (error instanceof Error && error.message === "\u753B\u50CF\u30C7\u30FC\u30BF\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093") throw error;
|
|
419
|
-
this.logger.error("\u753B\u50CF\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F", { error });
|
|
420
251
|
throw new Error(
|
|
421
252
|
`\u753B\u50CF\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${error instanceof Error ? error.message : String(error)}`
|
|
422
253
|
);
|
|
@@ -429,7 +260,6 @@ var AzureImageClient = class {
|
|
|
429
260
|
*/
|
|
430
261
|
async editImage(imageBuffer, prompt, options = {}) {
|
|
431
262
|
const { size = "1024x1024" } = options;
|
|
432
|
-
this.logger.debug("\u753B\u50CF\u7DE8\u96C6\u30EA\u30AF\u30A8\u30B9\u30C8 (REST API)", { prompt: prompt.substring(0, 100), size });
|
|
433
263
|
const url = `${this.config.endpoint}/openai/deployments/${this.config.imageDeploymentName}/images/edits?api-version=${this.config.imageApiVersion}`;
|
|
434
264
|
const blob = new Blob([imageBuffer], { type: "image/png" });
|
|
435
265
|
const formData = new FormData();
|
|
@@ -459,7 +289,6 @@ var AzureImageClient = class {
|
|
|
459
289
|
return bytes;
|
|
460
290
|
} catch (error) {
|
|
461
291
|
if (error instanceof Error && error.message === "\u753B\u50CF\u30C7\u30FC\u30BF\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093") throw error;
|
|
462
|
-
this.logger.error("\u753B\u50CF\u7DE8\u96C6\u306B\u5931\u6557\u3057\u307E\u3057\u305F", { error });
|
|
463
292
|
throw new Error(
|
|
464
293
|
`\u753B\u50CF\u7DE8\u96C6\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${error instanceof Error ? error.message : String(error)}`
|
|
465
294
|
);
|
|
@@ -467,11 +296,25 @@ var AzureImageClient = class {
|
|
|
467
296
|
}
|
|
468
297
|
};
|
|
469
298
|
|
|
299
|
+
// src/lang.ts
|
|
300
|
+
var LANGUAGE_DESCRIPTIONS = {
|
|
301
|
+
ja: "\u65E5\u672C\u8A9E",
|
|
302
|
+
en: "\u82F1\u8A9E",
|
|
303
|
+
zh: "\u4E2D\u56FD\u8A9E",
|
|
304
|
+
ko: "\u97D3\u56FD\u8A9E",
|
|
305
|
+
es: "\u30B9\u30DA\u30A4\u30F3\u8A9E",
|
|
306
|
+
fr: "\u30D5\u30E9\u30F3\u30B9\u8A9E",
|
|
307
|
+
de: "\u30C9\u30A4\u30C4\u8A9E",
|
|
308
|
+
it: "\u30A4\u30BF\u30EA\u30A2\u8A9E",
|
|
309
|
+
ru: "\u30ED\u30B7\u30A2\u8A9E",
|
|
310
|
+
vi: "\u30D9\u30C8\u30CA\u30E0\u8A9E"
|
|
311
|
+
};
|
|
312
|
+
|
|
470
313
|
// src/utils/image.ts
|
|
471
|
-
import * as
|
|
314
|
+
import * as fs3 from "fs/promises";
|
|
472
315
|
async function readImageFile(filePath) {
|
|
473
316
|
try {
|
|
474
|
-
const buffer = await
|
|
317
|
+
const buffer = await fs3.readFile(filePath);
|
|
475
318
|
return {
|
|
476
319
|
data: buffer.toString("base64"),
|
|
477
320
|
mimeType: getMimeType(filePath)
|
|
@@ -499,8 +342,6 @@ function getMimeType(filePath) {
|
|
|
499
342
|
}
|
|
500
343
|
|
|
501
344
|
// src/utils/preset.ts
|
|
502
|
-
import * as fs5 from "fs/promises";
|
|
503
|
-
import * as path3 from "path";
|
|
504
345
|
var BUILTIN_PRESETS = {
|
|
505
346
|
"builtin:square": { size: "1024x1024", quality: "high" },
|
|
506
347
|
"builtin:landscape": { size: "1536x1024", quality: "high" },
|
|
@@ -508,78 +349,23 @@ var BUILTIN_PRESETS = {
|
|
|
508
349
|
"builtin:draft": { size: "1024x1024", quality: "low" },
|
|
509
350
|
"builtin:photo": { size: "1536x1024", quality: "high" }
|
|
510
351
|
};
|
|
511
|
-
function
|
|
512
|
-
return path3.join(getConfigDir(), "presets.json");
|
|
513
|
-
}
|
|
514
|
-
async function loadPresets() {
|
|
515
|
-
try {
|
|
516
|
-
const text = await fs5.readFile(getPresetsPath(), "utf-8");
|
|
517
|
-
return JSON.parse(text);
|
|
518
|
-
} catch {
|
|
519
|
-
return {};
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
async function savePresets(presets) {
|
|
523
|
-
const p = getPresetsPath();
|
|
524
|
-
await fs5.mkdir(path3.dirname(p), { recursive: true });
|
|
525
|
-
await fs5.writeFile(p, JSON.stringify(presets, null, 2));
|
|
526
|
-
}
|
|
527
|
-
async function getPreset(name) {
|
|
352
|
+
function getPreset(name) {
|
|
528
353
|
if (name.startsWith("builtin:") && BUILTIN_PRESETS[name]) {
|
|
529
354
|
return BUILTIN_PRESETS[name];
|
|
530
355
|
}
|
|
531
|
-
|
|
532
|
-
return presets[name] || null;
|
|
533
|
-
}
|
|
534
|
-
async function savePreset(name, preset) {
|
|
535
|
-
if (name.startsWith("builtin:")) {
|
|
536
|
-
throw new Error("\u30D3\u30EB\u30C8\u30A4\u30F3\u30D7\u30EA\u30BB\u30C3\u30C8\u306F\u4E0A\u66F8\u304D\u3067\u304D\u307E\u305B\u3093");
|
|
537
|
-
}
|
|
538
|
-
const presets = await loadPresets();
|
|
539
|
-
presets[name] = preset;
|
|
540
|
-
await savePresets(presets);
|
|
541
|
-
}
|
|
542
|
-
async function deletePreset(name) {
|
|
543
|
-
if (name.startsWith("builtin:")) {
|
|
544
|
-
throw new Error("\u30D3\u30EB\u30C8\u30A4\u30F3\u30D7\u30EA\u30BB\u30C3\u30C8\u306F\u524A\u9664\u3067\u304D\u307E\u305B\u3093");
|
|
545
|
-
}
|
|
546
|
-
const presets = await loadPresets();
|
|
547
|
-
if (!presets[name]) return false;
|
|
548
|
-
delete presets[name];
|
|
549
|
-
await savePresets(presets);
|
|
550
|
-
return true;
|
|
551
|
-
}
|
|
552
|
-
async function listAllPresets() {
|
|
553
|
-
const result = [];
|
|
554
|
-
for (const [name, preset] of Object.entries(BUILTIN_PRESETS)) {
|
|
555
|
-
result.push({ name, preset, builtin: true });
|
|
556
|
-
}
|
|
557
|
-
const presets = await loadPresets();
|
|
558
|
-
for (const [name, preset] of Object.entries(presets)) {
|
|
559
|
-
result.push({ name, preset, builtin: false });
|
|
560
|
-
}
|
|
561
|
-
return result;
|
|
356
|
+
return BUILTIN_PRESETS[name] || null;
|
|
562
357
|
}
|
|
563
358
|
|
|
564
359
|
export {
|
|
565
|
-
LANGUAGE_DESCRIPTIONS,
|
|
566
|
-
DEFAULT_CONFIG,
|
|
567
|
-
getConfigPath,
|
|
568
|
-
loadConfig,
|
|
569
|
-
saveConfig,
|
|
570
360
|
getAzureConfig,
|
|
571
361
|
saveFileWithUniqueNameIfExists,
|
|
572
362
|
loadContextFile,
|
|
573
363
|
fileExists,
|
|
574
|
-
Logger,
|
|
575
364
|
AzureChatClient,
|
|
576
365
|
AzureImageClient,
|
|
366
|
+
LANGUAGE_DESCRIPTIONS,
|
|
577
367
|
readImageFile,
|
|
578
368
|
getMimeType,
|
|
579
369
|
BUILTIN_PRESETS,
|
|
580
|
-
|
|
581
|
-
getPreset,
|
|
582
|
-
savePreset,
|
|
583
|
-
deletePreset,
|
|
584
|
-
listAllPresets
|
|
370
|
+
getPreset
|
|
585
371
|
};
|