feat: move base URL, API key, and model to server .env
- BASE_URL, API_KEY, MODEL now read from process.env (Bun auto-loads .env)
- requireEnv() fails fast at startup if any is missing
- request body simplifies to { prompt, size, referenceImages? }
- client drops the three fields from form and localStorage
- add .env.example as the variable-name source of truth
- AGENTS.md notes the 0.0.0.0 bind now exposes the upstream quota to
anyone reachable on the network
This commit is contained in:
@@ -6,14 +6,23 @@ import index from "./index.html";
|
||||
type Size = `${number}x${number}`;
|
||||
|
||||
type GenerateRequest = {
|
||||
baseURL?: string;
|
||||
apiKey?: string;
|
||||
model?: string;
|
||||
prompt?: string;
|
||||
size?: Size;
|
||||
referenceImages?: string[];
|
||||
};
|
||||
|
||||
function requireEnv(name: string): string {
|
||||
const v = process.env[name];
|
||||
if (!v) {
|
||||
throw new Error(`Missing required env: ${name} (see .env.example).`);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
const BASE_URL = requireEnv("BASE_URL");
|
||||
const API_KEY = requireEnv("API_KEY");
|
||||
const MODEL = requireEnv("MODEL");
|
||||
|
||||
function decodeDataUrl(
|
||||
dataUrl: string,
|
||||
): { bytes: Uint8Array<ArrayBuffer>; mime: string } | null {
|
||||
@@ -27,22 +36,19 @@ function decodeDataUrl(
|
||||
}
|
||||
|
||||
async function callUpstream(args: {
|
||||
baseURL: string;
|
||||
apiKey: string;
|
||||
model: string;
|
||||
prompt: string;
|
||||
size: Size;
|
||||
referenceImages: string[];
|
||||
stream: boolean;
|
||||
signal?: AbortSignal;
|
||||
}): Promise<Response> {
|
||||
const { baseURL, apiKey, model, prompt, size, referenceImages, stream, signal } = args;
|
||||
const { prompt, size, referenceImages, stream, signal } = args;
|
||||
const isEdit = referenceImages.length > 0;
|
||||
const url = `${baseURL.replace(/\/+$/, "")}/images/${isEdit ? "edits" : "generations"}`;
|
||||
const url = `${BASE_URL.replace(/\/+$/, "")}/images/${isEdit ? "edits" : "generations"}`;
|
||||
|
||||
if (isEdit) {
|
||||
const form = new FormData();
|
||||
form.append("model", model);
|
||||
form.append("model", MODEL);
|
||||
form.append("prompt", prompt);
|
||||
form.append("size", size);
|
||||
if (stream) {
|
||||
@@ -64,13 +70,13 @@ async function callUpstream(args: {
|
||||
}
|
||||
return fetch(url, {
|
||||
method: "POST",
|
||||
headers: { Authorization: `Bearer ${apiKey}` },
|
||||
headers: { Authorization: `Bearer ${API_KEY}` },
|
||||
body: form,
|
||||
signal,
|
||||
});
|
||||
}
|
||||
|
||||
const body: Record<string, unknown> = { model, prompt, size };
|
||||
const body: Record<string, unknown> = { model: MODEL, prompt, size };
|
||||
if (stream) {
|
||||
body.stream = true;
|
||||
body.partial_images = 2;
|
||||
@@ -78,7 +84,7 @@ async function callUpstream(args: {
|
||||
return fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
Authorization: `Bearer ${API_KEY}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
@@ -180,18 +186,12 @@ const app = new Hono();
|
||||
|
||||
app.post("/api/generate", async (c) => {
|
||||
const body = (await c.req.json()) as GenerateRequest;
|
||||
const { baseURL, apiKey, model, prompt, size, referenceImages } = body;
|
||||
if (!baseURL || !apiKey || !model || !prompt) {
|
||||
return c.json(
|
||||
{ error: "baseURL, apiKey, model, prompt are required" },
|
||||
400,
|
||||
);
|
||||
const { prompt, size, referenceImages } = body;
|
||||
if (!prompt) {
|
||||
return c.json({ error: "prompt is required" }, 400);
|
||||
}
|
||||
const refs = Array.isArray(referenceImages) ? referenceImages : [];
|
||||
const args = {
|
||||
baseURL,
|
||||
apiKey,
|
||||
model,
|
||||
prompt,
|
||||
size: size ?? ("1024x1024" as Size),
|
||||
referenceImages: refs,
|
||||
|
||||
Reference in New Issue
Block a user