api2img 0.1.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 +56 -0
- package/SKILL.md +122 -0
- package/agents/openai.yaml +4 -0
- package/bin/install.js +46 -0
- package/package.json +16 -0
- package/scripts/configure-api2img.ps1 +150 -0
- package/scripts/invoke-api2img.ps1 +12 -0
- package/scripts/load-api2img-env.ps1 +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Api2img Skill
|
|
2
|
+
|
|
3
|
+
## 功能
|
|
4
|
+
为了 **解决通过中转 API 使用 Codex的用户无法生图的问题**。
|
|
5
|
+
|
|
6
|
+
api2img 专门面向通过中转 API 使用 Codex,同时又有图片生成&编辑需求的人。
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## 优势
|
|
10
|
+
|
|
11
|
+
- **简单**:一条指令安装。
|
|
12
|
+
- **安全**:API Key 使用 Windows DPAPI 保存到当前用户本机,不要求把密钥贴到聊天里。
|
|
13
|
+
- **不污染环境**:不会覆盖你原来的 `OPENAI_API_KEY`、`OPENAI_BASE_URL` 等变量,只在子进程里临时映射。
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## 安装
|
|
17
|
+
|
|
18
|
+
方式1(小白推荐):直接告诉你的 Agent:
|
|
19
|
+
```powershell
|
|
20
|
+
帮我安装这个 codex 技能:npx api2img
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
方式2:命令行输入:
|
|
24
|
+
|
|
25
|
+
```powershell
|
|
26
|
+
npx api2img
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 支持功能
|
|
30
|
+
|
|
31
|
+
会在必要时自动被 codex 调用,正常生图用也可以使用,比如:
|
|
32
|
+
|
|
33
|
+
- 【生成】生成一张xxx图
|
|
34
|
+
- 【修改】替换图片里的某个部分
|
|
35
|
+
- 【上传】修改我上传图片里的xxx
|
|
36
|
+
|
|
37
|
+
### 使用流程
|
|
38
|
+
|
|
39
|
+
```powershell
|
|
40
|
+
1、第一次使用时,Codex 会自动引导你填写第三方生图 API 地址,并打开安全输入流程保存 API Key,不需要把密钥粘贴到聊天里。
|
|
41
|
+
```
|
|
42
|
+
其他功能(用自然语言跟 Codex 说):
|
|
43
|
+
```powershell
|
|
44
|
+
2、我要修改 api2img 技能的 url 与 apikey
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```powershell
|
|
48
|
+
3、我要删除 api2img 技能的 url 与 apikey
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
## 注意
|
|
54
|
+
|
|
55
|
+
- 生成图片会把提示词、上传的图片发送到你配置的三方中转商。
|
|
56
|
+
- 请不要用不可信接口处理身份证件、人脸、工作机密等各类私人敏感内容。
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api2img
|
|
3
|
+
description: Use first whenever the user asks to generate, edit, or modify an image.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# api2img
|
|
7
|
+
|
|
8
|
+
## Priority
|
|
9
|
+
|
|
10
|
+
Use this skill before other image generation paths when the user asks to create, edit, or modify bitmap images, unless they explicitly request another provider.
|
|
11
|
+
|
|
12
|
+
This skill wraps the bundled image generation CLI:
|
|
13
|
+
|
|
14
|
+
`$env:USERPROFILE\.codex\skills\.system\imagegen\scripts\image_gen.py`
|
|
15
|
+
|
|
16
|
+
## Configuration
|
|
17
|
+
|
|
18
|
+
Before the first generation call, check that both dedicated variables exist:
|
|
19
|
+
|
|
20
|
+
- DPAPI-encrypted API key file at `scripts/api2img-api-key.dpapi.txt`
|
|
21
|
+
- `CODEX_API2IMG_BASE_URL`
|
|
22
|
+
|
|
23
|
+
Do not use or overwrite the user's existing `OPENAI_API_KEY`, `OPENAI_BASE_URL`, or other provider variables. The wrapper decrypts the api2img key and maps it to the `OPENAI_*` names only inside the child PowerShell process that runs the CLI.
|
|
24
|
+
|
|
25
|
+
If the base URL is missing, ask the user for it. Once the user provides the base URL, run the configuration command immediately. Pass `-Language zh` when the current conversation with the user is in Chinese, `-Language en` when it is in English, or omit it only when the language is unclear. If the API key is missing or being rotated and the command is running in a redirected/non-interactive Codex shell, it automatically opens a visible PowerShell window for hidden key entry and returns instead of silently waiting in the background. Tell the user to enter the key in that window. The key is saved using Windows DPAPI for the current Windows user; the URL is saved only to `CODEX_API2IMG_BASE_URL`.
|
|
26
|
+
|
|
27
|
+
```powershell
|
|
28
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File "$env:USERPROFILE\.codex\skills\api2img\scripts\configure-api2img.ps1" -BaseUrl "<url>" -Language zh
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
To rotate an existing saved key, pass `-UpdateKey`:
|
|
32
|
+
|
|
33
|
+
```powershell
|
|
34
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File "$env:USERPROFILE\.codex\skills\api2img\scripts\configure-api2img.ps1" -UpdateKey -Language zh
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
To clear the saved api2img API key and base URL, pass `-Clear`:
|
|
38
|
+
|
|
39
|
+
```powershell
|
|
40
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File "$env:USERPROFILE\.codex\skills\api2img\scripts\configure-api2img.ps1" -Clear -Language zh
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`-Clear` only removes api2img's DPAPI key file, `CODEX_API2IMG_BASE_URL`, and the legacy `CODEX_API2IMG_API_KEY` user variable if present. It must not be combined with `-BaseUrl` or `-UpdateKey`, and it must not modify `OPENAI_API_KEY`, `OPENAI_BASE_URL`, or other provider variables.
|
|
44
|
+
|
|
45
|
+
Do not ask the user to paste keys into chat. Do not pass keys on the command line. Do not print the key after storing it.
|
|
46
|
+
|
|
47
|
+
If the command prints `Opened a visible PowerShell window for hidden key entry`, do not rerun it or wait on the background command. Ask the user to finish the prompt in the spawned window, then verify configuration before generation.
|
|
48
|
+
|
|
49
|
+
## Privacy
|
|
50
|
+
|
|
51
|
+
- Image generation sends the prompt to `CODEX_API2IMG_BASE_URL`.
|
|
52
|
+
- Image editing sends the prompt plus the input image files, and mask files when present, to `CODEX_API2IMG_BASE_URL`.
|
|
53
|
+
- Before the first edit or modification that uploads a user-provided image, pause and ask the user to confirm. In Chinese conversations, say: `提示:你上传的图片可能会被第三方 API 获取,请注意自己的信息安全。请回复确认继续,我再上传图片进行修改。`
|
|
54
|
+
- After the user confirms, continue the image-editing workflow and do not repeat this upload warning in later turns for the same conversation/task unless the user asks about privacy again.
|
|
55
|
+
- Do not use api2img for sensitive images or prompts unless the user explicitly confirms the configured API is trusted for that content.
|
|
56
|
+
- Do not create extra local logs containing prompts, image paths, decrypted keys, or API responses.
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
|
|
60
|
+
Run the wrapper with normal imagegen CLI arguments:
|
|
61
|
+
|
|
62
|
+
```powershell
|
|
63
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File "$env:USERPROFILE\.codex\skills\api2img\scripts\invoke-api2img.ps1" generate --prompt "Primary request: a clean product mockup of a ceramic coffee mug" --size 1024x1024 --out "output\imagegen\mug.png"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Edit or modify an existing image with `edit` and one or more `--image` inputs:
|
|
67
|
+
|
|
68
|
+
```powershell
|
|
69
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File "$env:USERPROFILE\.codex\skills\api2img\scripts\invoke-api2img.ps1" edit --image "input.png" --prompt "Primary request: change the background to a quiet studio setting while preserving the subject." --size 1024x1024 --out "output\imagegen/input-edited.png"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Use `--mask` when the user provides a mask or asks for a localized edit:
|
|
73
|
+
|
|
74
|
+
```powershell
|
|
75
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File "$env:USERPROFILE\.codex\skills\api2img\scripts\invoke-api2img.ps1" edit --image "input.png" --mask "mask.png" --prompt "Primary request: replace only the masked area with fresh flowers." --size 1024x1024 --out "output\imagegen/input-masked-edit.png"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Use `--dry-run` to validate payloads without making an image request:
|
|
79
|
+
|
|
80
|
+
```powershell
|
|
81
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File "$env:USERPROFILE\.codex\skills\api2img\scripts\invoke-api2img.ps1" generate --prompt "Primary request: test configuration" --size 1024x1024 --dry-run
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Workflow
|
|
85
|
+
|
|
86
|
+
1. Check configuration before the first generation attempt.
|
|
87
|
+
2. For image edits or modifications, complete the one-time upload confirmation gate in `Privacy` before calling `edit`.
|
|
88
|
+
3. Shape a concise structured prompt while preserving the user's intent.
|
|
89
|
+
4. Run `scripts/invoke-api2img.ps1` with `generate`, `edit`, or `generate-batch`.
|
|
90
|
+
5. Use `edit --image <path>` when the user provides an existing image and asks to revise, transform, restyle, remove, replace, or otherwise modify it. Use `--mask <path>` for mask-constrained edits.
|
|
91
|
+
6. Save assets in the workspace, normally under `output/imagegen/` unless the user names another path.
|
|
92
|
+
7. Inspect the generated or edited file when visual quality matters.
|
|
93
|
+
8. Report the saved path and mention that `api2img` was used.
|
|
94
|
+
|
|
95
|
+
## Reliability
|
|
96
|
+
|
|
97
|
+
- Image generation can take several minutes. Use 300000-600000 ms timeouts for a single 1024x1024 image, and longer for edits, batches, or large outputs.
|
|
98
|
+
- Do not treat a shell timeout as proof that generation failed. First check the expected output path and `output/imagegen/` for new files.
|
|
99
|
+
- If the command times out, check whether a Python/imagegen process is still running before retrying.
|
|
100
|
+
- If an output file appears after a timeout, inspect it and continue from it instead of rerunning the same prompt.
|
|
101
|
+
- For long prompts on Windows, store the prompt in a here-string variable and invoke the script with `& $script generate --prompt $prompt ...`.
|
|
102
|
+
|
|
103
|
+
## Prompt Shape
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
Use case: <photorealistic-natural | product-mockup | ui-mockup | illustration-story | stylized-concept | logo-brand | precise-object-edit>
|
|
107
|
+
Asset type: <where it will be used>
|
|
108
|
+
Primary request: <user request>
|
|
109
|
+
Style/medium: <photo, illustration, 3D, etc.>
|
|
110
|
+
Composition/framing: <wide, close-up, centered, etc.>
|
|
111
|
+
Lighting/mood: <if relevant>
|
|
112
|
+
Text (verbatim): "<exact text, if any>"
|
|
113
|
+
Constraints: <must keep / must avoid>
|
|
114
|
+
Avoid: no watermark, no unintended text
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Output Notes
|
|
118
|
+
|
|
119
|
+
- The bundled CLI default output is `output/imagegen/output.png`.
|
|
120
|
+
- Use `--out` or `--out-dir` when the user names a destination.
|
|
121
|
+
- Do not overwrite existing assets unless the user explicitly requested replacement.
|
|
122
|
+
- For multiple distinct assets, run one prompt per asset or use `generate-batch`; do not use `--n` as a substitute for different prompts.
|
package/bin/install.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
const packageRoot = path.resolve(__dirname, "..");
|
|
7
|
+
const home = process.env.USERPROFILE || process.env.HOME;
|
|
8
|
+
|
|
9
|
+
if (!home) {
|
|
10
|
+
console.error("Cannot find USERPROFILE or HOME. Please install manually into .codex/skills/api2img.");
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const target = path.join(home, ".codex", "skills", "api2img");
|
|
15
|
+
const entries = ["SKILL.md", "README.md", "agents", "scripts"];
|
|
16
|
+
const excludedNames = new Set([
|
|
17
|
+
"api2img-api-key.dpapi.txt",
|
|
18
|
+
"node_modules",
|
|
19
|
+
"output",
|
|
20
|
+
".git"
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
function copyRecursive(source, destination) {
|
|
24
|
+
const stat = fs.statSync(source);
|
|
25
|
+
|
|
26
|
+
if (stat.isDirectory()) {
|
|
27
|
+
fs.mkdirSync(destination, { recursive: true });
|
|
28
|
+
for (const child of fs.readdirSync(source)) {
|
|
29
|
+
if (excludedNames.has(child)) continue;
|
|
30
|
+
copyRecursive(path.join(source, child), path.join(destination, child));
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
36
|
+
fs.copyFileSync(source, destination);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fs.mkdirSync(target, { recursive: true });
|
|
40
|
+
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
copyRecursive(path.join(packageRoot, entry), path.join(target, entry));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log(`api2img Codex skill installed to: ${target}`);
|
|
46
|
+
console.log("Restart Codex if it does not pick up the skill immediately.");
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "api2img",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Install the api2img Codex skill for image generation and editing through a relay API.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"api2img": "bin/install.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"SKILL.md",
|
|
10
|
+
"README.md",
|
|
11
|
+
"agents",
|
|
12
|
+
"scripts",
|
|
13
|
+
"bin"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT"
|
|
16
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[string] $BaseUrl,
|
|
3
|
+
|
|
4
|
+
[switch] $UpdateKey,
|
|
5
|
+
|
|
6
|
+
[switch] $Clear,
|
|
7
|
+
|
|
8
|
+
[switch] $NoRelaunch,
|
|
9
|
+
|
|
10
|
+
[ValidateSet("auto", "zh", "en")]
|
|
11
|
+
[string] $Language = "auto"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
$ErrorActionPreference = "Stop"
|
|
15
|
+
|
|
16
|
+
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
17
|
+
$keyFile = Join-Path $scriptDir "api2img-api-key.dpapi.txt"
|
|
18
|
+
|
|
19
|
+
$keyExists = Test-Path -LiteralPath $keyFile
|
|
20
|
+
$shouldPromptKey = $UpdateKey -or -not $keyExists
|
|
21
|
+
|
|
22
|
+
function Resolve-Language {
|
|
23
|
+
param([string] $RequestedLanguage)
|
|
24
|
+
|
|
25
|
+
if ($RequestedLanguage -in @("zh", "en")) {
|
|
26
|
+
return $RequestedLanguage
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if ([System.Globalization.CultureInfo]::CurrentUICulture.Name -like "zh*") {
|
|
30
|
+
return "zh"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return "en"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function Decode-Text {
|
|
37
|
+
param([string] $Base64Text)
|
|
38
|
+
[System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($Base64Text))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
$resolvedLanguage = Resolve-Language -RequestedLanguage $Language
|
|
42
|
+
|
|
43
|
+
$messages = @{
|
|
44
|
+
en = @{
|
|
45
|
+
NoChanges = "No changes requested. Provide -BaseUrl, pass -UpdateKey to replace the saved API key, or pass -Clear to remove api2img configuration."
|
|
46
|
+
ClearCannotCombine = "-Clear cannot be combined with -BaseUrl or -UpdateKey."
|
|
47
|
+
Cleared = "api2img configuration cleared:"
|
|
48
|
+
KeyCleared = "API key=<DPAPI key file removed>"
|
|
49
|
+
UrlCleared = "CODEX_API2IMG_BASE_URL=<removed>"
|
|
50
|
+
LegacyKeyCleared = "CODEX_API2IMG_API_KEY=<legacy user variable removed if present>"
|
|
51
|
+
OpenedWindow = "api2img needs an API key. Opened a visible PowerShell window for hidden key entry."
|
|
52
|
+
EnterKey = "Enter the api2img API key. Input is hidden and will be saved with Windows DPAPI for this user."
|
|
53
|
+
Prompt = "API key"
|
|
54
|
+
Saved = "api2img configuration saved:"
|
|
55
|
+
KeySaved = "API key=<DPAPI encrypted for current Windows user>"
|
|
56
|
+
KeyPreserved = "API key=<existing DPAPI key preserved>"
|
|
57
|
+
}
|
|
58
|
+
zh = @{
|
|
59
|
+
NoChanges = (Decode-Text "5rKh5pyJ6ZyA6KaB5L+u5pS555qE6YWN572u44CC6K+35o+Q5L6bIC1CYXNlVXJs77yM5oiW5L2/55SoIC1VcGRhdGVLZXkg5pu/5o2i5bey5L+d5a2Y55qEIEFQSSBrZXnvvIzkuZ/lj6/ku6Xkvb/nlKggLUNsZWFyIOa4heepuiBhcGkyaW1nIOmFjee9ruOAgg==")
|
|
60
|
+
ClearCannotCombine = (Decode-Text "LUNsZWFyIOS4jeiDveWSjCAtQmFzZVVybCDmiJYgLVVwZGF0ZUtleSDlkIzml7bkvb/nlKjjgII=")
|
|
61
|
+
Cleared = (Decode-Text "YXBpMmltZyDphY3nva7lt7LmuIXnqbrvvJo=")
|
|
62
|
+
KeyCleared = (Decode-Text "QVBJIGtleT085bey5Yig6ZmkIERQQVBJIGtleSDmlofku7Y+")
|
|
63
|
+
UrlCleared = (Decode-Text "Q09ERVhfQVBJMklNR19CQVNFX1VSTD085bey56e76ZmkPg==")
|
|
64
|
+
LegacyKeyCleared = (Decode-Text "Q09ERVhfQVBJMklNR19BUElfS0VZPTzlt7Lnp7vpmaTml6fniYjnlKjmiLflj5jph4/vvIzlpoLlrZjlnKg+")
|
|
65
|
+
OpenedWindow = (Decode-Text "YXBpMmltZyDpnIDopoEgQVBJIGtleeOAguW3suaJk+W8gOS4gOS4quWPr+ingeeahCBQb3dlclNoZWxsIOeql+WPo++8jOivt+WcqOWFtuS4rei+k+WFpemakOiXj+eahCBrZXnjgII=")
|
|
66
|
+
EnterKey = (Decode-Text "6K+36L6T5YWlIGFwaTJpbWcgQVBJIGtleeOAgui+k+WFpeWGheWuueS8mumakOiXj++8jOW5tuS8muS9v+eUqOW9k+WJjSBXaW5kb3dzIOeUqOaIt+eahCBEUEFQSSDliqDlr4bkv53lrZjjgII=")
|
|
67
|
+
Prompt = "API key"
|
|
68
|
+
Saved = (Decode-Text "YXBpMmltZyDphY3nva7lt7Lkv53lrZjvvJo=")
|
|
69
|
+
KeySaved = (Decode-Text "QVBJIGtleT085bey5L2/55So5b2T5YmNIFdpbmRvd3Mg55So5oi355qEIERQQVBJIOWKoOWvhuS/neWtmD4=")
|
|
70
|
+
KeyPreserved = (Decode-Text "QVBJIGtleT085L+d55WZ546w5pyJIERQQVBJIOWKoOWvhiBrZXk+")
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if ($Clear -and (-not [string]::IsNullOrWhiteSpace($BaseUrl) -or $UpdateKey)) {
|
|
75
|
+
throw $messages[$resolvedLanguage].ClearCannotCombine
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if ($Clear) {
|
|
79
|
+
if (Test-Path -LiteralPath $keyFile) {
|
|
80
|
+
Remove-Item -LiteralPath $keyFile -Force
|
|
81
|
+
}
|
|
82
|
+
[Environment]::SetEnvironmentVariable("CODEX_API2IMG_BASE_URL", $null, "User")
|
|
83
|
+
[Environment]::SetEnvironmentVariable("CODEX_API2IMG_API_KEY", $null, "User")
|
|
84
|
+
Remove-Item Env:\CODEX_API2IMG_BASE_URL -ErrorAction SilentlyContinue
|
|
85
|
+
Remove-Item Env:\CODEX_API2IMG_API_KEY -ErrorAction SilentlyContinue
|
|
86
|
+
|
|
87
|
+
Write-Host $messages[$resolvedLanguage].Cleared
|
|
88
|
+
Write-Host $messages[$resolvedLanguage].KeyCleared
|
|
89
|
+
Write-Host $messages[$resolvedLanguage].UrlCleared
|
|
90
|
+
Write-Host $messages[$resolvedLanguage].LegacyKeyCleared
|
|
91
|
+
exit 0
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if ([string]::IsNullOrWhiteSpace($BaseUrl) -and -not $shouldPromptKey) {
|
|
95
|
+
throw $messages[$resolvedLanguage].NoChanges
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function Quote-Argument {
|
|
99
|
+
param([string] $Value)
|
|
100
|
+
'"' + ($Value -replace '"', '\"') + '"'
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if ($shouldPromptKey -and -not $NoRelaunch -and ([Console]::IsInputRedirected -or [Console]::IsOutputRedirected)) {
|
|
104
|
+
$arguments = @(
|
|
105
|
+
"-NoProfile",
|
|
106
|
+
"-ExecutionPolicy", "Bypass",
|
|
107
|
+
"-NoExit",
|
|
108
|
+
"-File", (Quote-Argument $PSCommandPath),
|
|
109
|
+
"-NoRelaunch",
|
|
110
|
+
"-Language", $resolvedLanguage
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if (-not [string]::IsNullOrWhiteSpace($BaseUrl)) {
|
|
114
|
+
$arguments += @("-BaseUrl", (Quote-Argument $BaseUrl))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if ($UpdateKey) {
|
|
118
|
+
$arguments += "-UpdateKey"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
Start-Process powershell -ArgumentList ($arguments -join " ")
|
|
122
|
+
Write-Host $messages[$resolvedLanguage].OpenedWindow
|
|
123
|
+
exit 0
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if ($shouldPromptKey) {
|
|
127
|
+
Write-Host $messages[$resolvedLanguage].EnterKey
|
|
128
|
+
$secureKey = Read-Host -Prompt $messages[$resolvedLanguage].Prompt -AsSecureString
|
|
129
|
+
$encryptedKey = ConvertFrom-SecureString -SecureString $secureKey
|
|
130
|
+
Set-Content -LiteralPath $keyFile -Value $encryptedKey -Encoding ASCII
|
|
131
|
+
|
|
132
|
+
# Remove the legacy plaintext user variable if it exists from an older api2img setup.
|
|
133
|
+
if (-not [string]::IsNullOrWhiteSpace([Environment]::GetEnvironmentVariable("CODEX_API2IMG_API_KEY", "User"))) {
|
|
134
|
+
[Environment]::SetEnvironmentVariable("CODEX_API2IMG_API_KEY", $null, "User")
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (-not [string]::IsNullOrWhiteSpace($BaseUrl)) {
|
|
139
|
+
[Environment]::SetEnvironmentVariable("CODEX_API2IMG_BASE_URL", $BaseUrl.TrimEnd("/"), "User")
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
Write-Host $messages[$resolvedLanguage].Saved
|
|
143
|
+
if ($shouldPromptKey) {
|
|
144
|
+
Write-Host $messages[$resolvedLanguage].KeySaved
|
|
145
|
+
} else {
|
|
146
|
+
Write-Host $messages[$resolvedLanguage].KeyPreserved
|
|
147
|
+
}
|
|
148
|
+
if (-not [string]::IsNullOrWhiteSpace($BaseUrl)) {
|
|
149
|
+
Write-Host "CODEX_API2IMG_BASE_URL=$($BaseUrl.TrimEnd('/'))"
|
|
150
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
|
2
|
+
|
|
3
|
+
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
4
|
+
. (Join-Path $scriptDir "load-api2img-env.ps1")
|
|
5
|
+
|
|
6
|
+
$imageGenScript = Join-Path $env:USERPROFILE ".codex\skills\.system\imagegen\scripts\image_gen.py"
|
|
7
|
+
|
|
8
|
+
if (-not (Test-Path -LiteralPath $imageGenScript)) {
|
|
9
|
+
throw "Missing image generation CLI script: $imageGenScript"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
python $imageGenScript @args
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Loads api2img credentials for this PowerShell process only.
|
|
2
|
+
# The API key is stored as a DPAPI-encrypted file for the current Windows user.
|
|
3
|
+
# The base URL is stored in the dedicated CODEX_API2IMG_BASE_URL variable.
|
|
4
|
+
|
|
5
|
+
$ErrorActionPreference = "Stop"
|
|
6
|
+
|
|
7
|
+
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
8
|
+
$keyFile = Join-Path $scriptDir "api2img-api-key.dpapi.txt"
|
|
9
|
+
|
|
10
|
+
$apiKey = $null
|
|
11
|
+
if (Test-Path -LiteralPath $keyFile) {
|
|
12
|
+
$encryptedKey = (Get-Content -Raw -LiteralPath $keyFile).Trim()
|
|
13
|
+
$secureKey = ConvertTo-SecureString -String $encryptedKey
|
|
14
|
+
$credential = [System.Management.Automation.PSCredential]::new("api2img", $secureKey)
|
|
15
|
+
$apiKey = $credential.GetNetworkCredential().Password
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
$baseUrl = [Environment]::GetEnvironmentVariable("CODEX_API2IMG_BASE_URL", "Process")
|
|
19
|
+
if ([string]::IsNullOrWhiteSpace($baseUrl)) {
|
|
20
|
+
$baseUrl = [Environment]::GetEnvironmentVariable("CODEX_API2IMG_BASE_URL", "User")
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
$missing = @()
|
|
24
|
+
if ([string]::IsNullOrWhiteSpace($apiKey)) { $missing += "DPAPI encrypted API key" }
|
|
25
|
+
if ([string]::IsNullOrWhiteSpace($baseUrl)) { $missing += "CODEX_API2IMG_BASE_URL" }
|
|
26
|
+
|
|
27
|
+
if ($missing.Count -gt 0) {
|
|
28
|
+
$configure = Join-Path $scriptDir "configure-api2img.ps1"
|
|
29
|
+
throw @"
|
|
30
|
+
api2img is not configured. Missing: $($missing -join ', ')
|
|
31
|
+
|
|
32
|
+
Ask the user for the base URL, then have them enter the image API key only through the hidden terminal prompt:
|
|
33
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File "$configure" -BaseUrl "<url>"
|
|
34
|
+
|
|
35
|
+
The key is entered interactively and saved with Windows DPAPI for the current user. The URL is saved only to CODEX_API2IMG_BASE_URL. This does not modify OPENAI_API_KEY or OPENAI_BASE_URL.
|
|
36
|
+
"@
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
$env:OPENAI_API_KEY = $apiKey
|
|
40
|
+
$env:OPENAI_BASE_URL = $baseUrl.TrimEnd("/")
|
|
41
|
+
|
|
42
|
+
Write-Host "api2img environment loaded for this PowerShell process only."
|
|
43
|
+
Write-Host "CODEX_API2IMG_BASE_URL=$env:OPENAI_BASE_URL"
|