opencode-avatar 0.1.0 → 0.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.md +7 -5
- package/dist/electron.js +26 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,12 +42,14 @@ Then add to your OpenCode config:
|
|
|
42
42
|
|
|
43
43
|
## Configuration
|
|
44
44
|
|
|
45
|
-
###
|
|
45
|
+
### API Key Configuration
|
|
46
46
|
|
|
47
|
-
Create a
|
|
47
|
+
Create a config file at `~/.config/opencode/opencode-avatar.json`:
|
|
48
48
|
|
|
49
|
-
```
|
|
50
|
-
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"falKey": "your_fal_ai_api_key_here"
|
|
52
|
+
}
|
|
51
53
|
```
|
|
52
54
|
|
|
53
55
|
Get your FAL.ai API key from [fal.ai](https://fal.ai).
|
|
@@ -168,7 +170,7 @@ The output shows:
|
|
|
168
170
|
### Avatar Not Showing
|
|
169
171
|
|
|
170
172
|
1. Check console output for errors
|
|
171
|
-
2. Verify FAL.ai API key in
|
|
173
|
+
2. Verify FAL.ai API key in `~/.config/opencode/opencode-avatar.json`
|
|
172
174
|
3. Ensure port 47291 is available
|
|
173
175
|
4. Try restarting OpenCode
|
|
174
176
|
|
package/dist/electron.js
CHANGED
|
@@ -402,8 +402,23 @@ import { app, BrowserWindow, screen, Tray, Menu, nativeImage } from "electron";
|
|
|
402
402
|
import * as path from "path";
|
|
403
403
|
import * as http from "http";
|
|
404
404
|
import * as fs from "fs";
|
|
405
|
+
import * as os from "os";
|
|
405
406
|
import { fileURLToPath } from "url";
|
|
406
407
|
require_main().config();
|
|
408
|
+
function getFalKey() {
|
|
409
|
+
try {
|
|
410
|
+
const configPath = path.join(os.homedir(), ".config", "opencode", "opencode-avatar.json");
|
|
411
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
412
|
+
if (!config.falKey) {
|
|
413
|
+
console.warn("Warning: falKey not found in config file. Avatar generation will not work. Please set falKey in ~/.config/opencode/opencode-avatar.json");
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
return config.falKey;
|
|
417
|
+
} catch (error) {
|
|
418
|
+
console.warn(`Warning: Failed to read config file: ${error.message}. Avatar generation will not work. Please ensure ~/.config/opencode/opencode-avatar.json exists and contains falKey.`);
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
407
422
|
var FAL_CDN_URL = "https://v3.fal.media";
|
|
408
423
|
var FAL_REST_URL = "https://rest.alpha.fal.ai";
|
|
409
424
|
var FAL_NANO_BANANA_URL = "https://fal.run/fal-ai/nano-banana-pro/edit";
|
|
@@ -551,13 +566,13 @@ function getAvatarPath() {
|
|
|
551
566
|
}
|
|
552
567
|
return path.join(AVATAR_DIR, "avatar.png");
|
|
553
568
|
}
|
|
554
|
-
async function uploadFile(filePath) {
|
|
569
|
+
async function uploadFile(filePath, falKey) {
|
|
555
570
|
const fileBuffer = fs.readFileSync(filePath);
|
|
556
571
|
const fileName = path.basename(filePath);
|
|
557
572
|
const tokenResponse = await fetch(`${FAL_REST_URL}/storage/auth/token?storage_type=fal-cdn-v3`, {
|
|
558
573
|
method: "POST",
|
|
559
574
|
headers: {
|
|
560
|
-
Authorization: `Key ${
|
|
575
|
+
Authorization: `Key ${falKey}`,
|
|
561
576
|
Accept: "application/json",
|
|
562
577
|
"Content-Type": "application/json"
|
|
563
578
|
},
|
|
@@ -585,11 +600,11 @@ async function uploadFile(filePath) {
|
|
|
585
600
|
const result = await response.json();
|
|
586
601
|
return result.access_url || result.url || "";
|
|
587
602
|
}
|
|
588
|
-
async function generateAvatarImage(imageUrl, prompt) {
|
|
603
|
+
async function generateAvatarImage(imageUrl, prompt, falKey) {
|
|
589
604
|
const response = await fetch(FAL_NANO_BANANA_URL, {
|
|
590
605
|
method: "POST",
|
|
591
606
|
headers: {
|
|
592
|
-
Authorization: `Key ${
|
|
607
|
+
Authorization: `Key ${falKey}`,
|
|
593
608
|
"Content-Type": "application/json"
|
|
594
609
|
},
|
|
595
610
|
body: JSON.stringify({
|
|
@@ -612,6 +627,11 @@ async function downloadImage(url, outputPath) {
|
|
|
612
627
|
fs.writeFileSync(outputPath, buffer);
|
|
613
628
|
}
|
|
614
629
|
async function generateAvatarForPrompt(prompt) {
|
|
630
|
+
const falKey = getFalKey();
|
|
631
|
+
if (!falKey) {
|
|
632
|
+
console.warn("falKey is not set. Cannot generate avatar. Using default avatar.");
|
|
633
|
+
return path.join(AVATAR_DIR, "avatar.png");
|
|
634
|
+
}
|
|
615
635
|
const cachedFilename = promptToFilename(prompt);
|
|
616
636
|
const cachedPath = path.join(AVATAR_DIR, cachedFilename);
|
|
617
637
|
if (fs.existsSync(cachedPath)) {
|
|
@@ -627,9 +647,9 @@ async function generateAvatarForPrompt(prompt) {
|
|
|
627
647
|
return;
|
|
628
648
|
}
|
|
629
649
|
const sourceAvatar = path.join(AVATAR_DIR, "avatar.png");
|
|
630
|
-
const uploadedUrl = await uploadFile(sourceAvatar);
|
|
650
|
+
const uploadedUrl = await uploadFile(sourceAvatar, falKey);
|
|
631
651
|
const fullPrompt = `make a character variant: ${prompt}. Keep the background as a solid green screen color. Do not let the green screen color appear in reflections or on the subject.`;
|
|
632
|
-
const result = await generateAvatarImage(uploadedUrl, fullPrompt);
|
|
652
|
+
const result = await generateAvatarImage(uploadedUrl, fullPrompt, falKey);
|
|
633
653
|
const outputUrl = result.images?.[0]?.url || result.image?.url || result.url;
|
|
634
654
|
if (!outputUrl) {
|
|
635
655
|
throw new Error("No output image URL in response: " + JSON.stringify(result, null, 2));
|