ima2-gen 1.0.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/.env.example +2 -0
- package/README.md +77 -0
- package/bin/ima2.js +134 -0
- package/package.json +41 -0
- package/public/index.html +1013 -0
- package/server.js +348 -0
package/.env.example
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# ima2-gen
|
|
2
|
+
|
|
3
|
+
Minimal CLI + web UI for OpenAI `gpt-image-2` image generation.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/lidge-jun/ima2-gen.git
|
|
9
|
+
cd ima2-gen
|
|
10
|
+
npm install
|
|
11
|
+
npm start
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
First run prompts you to choose:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
1) API Key — paste your OpenAI API key (paid)
|
|
18
|
+
2) OAuth — login with ChatGPT account (free)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then opens `http://localhost:3333`.
|
|
22
|
+
|
|
23
|
+
## CLI
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx ima2 serve # start server (auto-setup on first run)
|
|
27
|
+
npx ima2 setup # reconfigure auth
|
|
28
|
+
npx ima2 reset # clear saved config
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Or install globally:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install -g ima2-gen
|
|
35
|
+
ima2 serve
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- **Dual provider** — OAuth (free, ChatGPT account) or API Key (paid)
|
|
41
|
+
- **Text-to-Image** — generate images from text prompts
|
|
42
|
+
- **Image-to-Image** — edit/inpaint with drag-and-drop
|
|
43
|
+
- **Quality** — low / medium / high
|
|
44
|
+
- **Size** — presets (1024 ~ 4K) + custom (any 16px-aligned ratio)
|
|
45
|
+
- **Format** — PNG / JPEG / WebP
|
|
46
|
+
- **Moderation** — auto (standard) / low (less restrictive)
|
|
47
|
+
- **History** — session thumbnail strip
|
|
48
|
+
- **Download / Copy** — save or clipboard
|
|
49
|
+
|
|
50
|
+
## Architecture
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
ima2 serve
|
|
54
|
+
├── Express (:3333) ← web UI + API
|
|
55
|
+
└── openai-oauth (:10531) ← embedded OAuth proxy
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Config
|
|
59
|
+
|
|
60
|
+
Stored in `.ima2/config.json` (auto-created, gitignored).
|
|
61
|
+
|
|
62
|
+
Optional `.env`:
|
|
63
|
+
```
|
|
64
|
+
OPENAI_API_KEY=sk-proj-...
|
|
65
|
+
PORT=3333
|
|
66
|
+
OAUTH_PORT=10531
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Pricing (API Key mode)
|
|
70
|
+
|
|
71
|
+
| Quality | 1024x1024 | 1024x1536 | 1536x1024 |
|
|
72
|
+
|---------|-----------|-----------|-----------|
|
|
73
|
+
| Low | $0.006 | $0.005 | $0.005 |
|
|
74
|
+
| Medium | $0.053 | $0.041 | $0.041 |
|
|
75
|
+
| High | $0.211 | $0.165 | $0.165 |
|
|
76
|
+
|
|
77
|
+
OAuth mode is free (uses your ChatGPT Plus/Pro subscription).
|
package/bin/ima2.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createInterface } from "readline/promises";
|
|
3
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
4
|
+
import { join, dirname } from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import { spawn, execSync } from "child_process";
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const ROOT = join(__dirname, "..");
|
|
10
|
+
const CONFIG_DIR = join(ROOT, ".ima2");
|
|
11
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
12
|
+
|
|
13
|
+
function loadConfig() {
|
|
14
|
+
if (existsSync(CONFIG_FILE)) {
|
|
15
|
+
return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
16
|
+
}
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function saveConfig(config) {
|
|
21
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
22
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function setup() {
|
|
26
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
27
|
+
|
|
28
|
+
console.log("\n ima2-gen — GPT Image 2 Generator\n");
|
|
29
|
+
console.log(" Choose authentication method:\n");
|
|
30
|
+
console.log(" 1) API Key — paste your OpenAI API key (paid)");
|
|
31
|
+
console.log(" 2) OAuth — login with ChatGPT account (free)\n");
|
|
32
|
+
|
|
33
|
+
const choice = await rl.question(" Enter 1 or 2: ");
|
|
34
|
+
const config = loadConfig();
|
|
35
|
+
|
|
36
|
+
if (choice.trim() === "1") {
|
|
37
|
+
const key = await rl.question(" OpenAI API Key: ");
|
|
38
|
+
if (!key.startsWith("sk-")) {
|
|
39
|
+
console.log(" Invalid API key format. Expected sk-...");
|
|
40
|
+
rl.close();
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
config.provider = "api";
|
|
44
|
+
config.apiKey = key.trim();
|
|
45
|
+
saveConfig(config);
|
|
46
|
+
console.log("\n API key saved. Starting server...\n");
|
|
47
|
+
} else {
|
|
48
|
+
config.provider = "oauth";
|
|
49
|
+
delete config.apiKey;
|
|
50
|
+
saveConfig(config);
|
|
51
|
+
console.log("\n Starting OAuth login...\n");
|
|
52
|
+
|
|
53
|
+
// Check if codex auth exists
|
|
54
|
+
const hasAuth =
|
|
55
|
+
existsSync(join(process.env.HOME, ".codex", "auth.json")) ||
|
|
56
|
+
existsSync(join(process.env.HOME, ".chatgpt-local", "auth.json"));
|
|
57
|
+
|
|
58
|
+
if (!hasAuth) {
|
|
59
|
+
console.log(" Running 'codex login' — follow the browser prompt.\n");
|
|
60
|
+
try {
|
|
61
|
+
execSync("npx @openai/codex login", { stdio: "inherit" });
|
|
62
|
+
} catch {
|
|
63
|
+
console.log("\n Login failed or cancelled. You can retry with 'ima2 serve'.\n");
|
|
64
|
+
rl.close();
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
console.log(" Existing OAuth session found.\n");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
saveConfig(config);
|
|
72
|
+
console.log(" OAuth configured. Starting server...\n");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
rl.close();
|
|
76
|
+
return config;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function serve() {
|
|
80
|
+
let config = loadConfig();
|
|
81
|
+
|
|
82
|
+
if (!config.provider) {
|
|
83
|
+
config = await setup();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const env = { ...process.env };
|
|
87
|
+
|
|
88
|
+
if (config.provider === "api" && config.apiKey) {
|
|
89
|
+
env.OPENAI_API_KEY = config.apiKey;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const serverPath = join(ROOT, "server.js");
|
|
93
|
+
const child = spawn("node", [serverPath], {
|
|
94
|
+
stdio: "inherit",
|
|
95
|
+
env,
|
|
96
|
+
cwd: ROOT,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
child.on("exit", (code) => process.exit(code));
|
|
100
|
+
|
|
101
|
+
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
102
|
+
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ── CLI ──
|
|
106
|
+
const args = process.argv.slice(2);
|
|
107
|
+
const command = args[0];
|
|
108
|
+
|
|
109
|
+
switch (command) {
|
|
110
|
+
case "serve":
|
|
111
|
+
serve();
|
|
112
|
+
break;
|
|
113
|
+
case "setup":
|
|
114
|
+
case "login":
|
|
115
|
+
setup().then(() => console.log(" Done. Run 'ima2 serve' to start."));
|
|
116
|
+
break;
|
|
117
|
+
case "reset":
|
|
118
|
+
if (existsSync(CONFIG_FILE)) {
|
|
119
|
+
writeFileSync(CONFIG_FILE, "{}");
|
|
120
|
+
console.log(" Config reset. Run 'ima2 serve' to reconfigure.");
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
default:
|
|
124
|
+
console.log(`
|
|
125
|
+
ima2-gen — GPT Image 2 Generator
|
|
126
|
+
|
|
127
|
+
Usage:
|
|
128
|
+
ima2 serve Start the image generation server
|
|
129
|
+
ima2 setup Configure API key or OAuth (interactive)
|
|
130
|
+
ima2 reset Reset configuration
|
|
131
|
+
|
|
132
|
+
First run of 'ima2 serve' will prompt for setup automatically.
|
|
133
|
+
`);
|
|
134
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ima2-gen",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "GPT Image 2 generator with OAuth & API key support",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ima2": "./bin/ima2.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node bin/ima2.js serve",
|
|
11
|
+
"dev": "node --watch server.js",
|
|
12
|
+
"setup": "node bin/ima2.js setup",
|
|
13
|
+
"prepublishOnly": "npm run lint:pkg",
|
|
14
|
+
"lint:pkg": "node -e \"const p=require('./package.json'); if(!p.name||!p.version||!p.bin) throw new Error('missing fields')\"",
|
|
15
|
+
"release:patch": "npm version patch && npm publish && git push origin main --tags",
|
|
16
|
+
"release:minor": "npm version minor && npm publish && git push origin main --tags",
|
|
17
|
+
"release:major": "npm version major && npm publish && git push origin main --tags"
|
|
18
|
+
},
|
|
19
|
+
"keywords": ["openai", "gpt-image-2", "image-generation", "oauth", "cli"],
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/lidge-jun/ima2-gen.git"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"bin/",
|
|
27
|
+
"public/",
|
|
28
|
+
"server.js",
|
|
29
|
+
".env.example",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"dotenv": "^17.4.2",
|
|
37
|
+
"express": "^5.1.0",
|
|
38
|
+
"openai": "^5.8.2",
|
|
39
|
+
"openai-oauth": "^1.0.2"
|
|
40
|
+
}
|
|
41
|
+
}
|