AnesKAM commited on
Commit
f7fafa4
·
verified ·
1 Parent(s): e4fd902

Create routes/image.js

Browse files
Files changed (1) hide show
  1. routes/image.js +76 -0
routes/image.js ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from "express";
2
+ import fetch from "node-fetch";
3
+ import { checkUserQuota, recordUserHit, enqueue } from "../lib/rateLimiter.js";
4
+
5
+ const router = express.Router();
6
+ const INVOKE_URL = "https://ai.api.nvidia.com/v1/genai/black-forest-labs/flux.1-dev";
7
+
8
+ // POST /api/image { prompt, clientId }
9
+ router.post("/image", async (req, res) => {
10
+ try {
11
+ const { prompt, clientId = "anon" } = req.body;
12
+ if (!prompt || !prompt.trim()) {
13
+ return res.status(400).json({ error: "missing_prompt" });
14
+ }
15
+
16
+ // حد المستخدم: 3 صور / 3 ساعات
17
+ const quota = checkUserQuota(clientId);
18
+ if (!quota.allowed) {
19
+ const mins = Math.ceil(quota.retryMs / 60000);
20
+ return res.status(429).json({
21
+ error: "rate_limited",
22
+ message: `وصلت إلى حد 3 صور كل 3 ساعات. حاول مجدداً بعد ${mins} دقيقة.`,
23
+ retryMs: quota.retryMs,
24
+ });
25
+ }
26
+
27
+ // إعدادات واقعية ودقيقة جداً
28
+ const payload = {
29
+ prompt: `${prompt}, ultra realistic, highly detailed, photorealistic, 8k, sharp focus, natural lighting, professional photography`,
30
+ mode: "base",
31
+ cfg_scale: 3.5,
32
+ width: 1024,
33
+ height: 1024,
34
+ seed: Math.floor(Math.random() * 1_000_000),
35
+ steps: 50,
36
+ };
37
+
38
+ // عبر الطابور العالمي (<= 40/دقيقة)
39
+ const data = await enqueue(async () => {
40
+ const r = await fetch(INVOKE_URL, {
41
+ method: "POST",
42
+ headers: {
43
+ Authorization: `Bearer ${process.env.NVIDIA_API_KEY}`,
44
+ Accept: "application/json",
45
+ "Content-Type": "application/json",
46
+ },
47
+ body: JSON.stringify(payload),
48
+ });
49
+ if (r.status !== 200) {
50
+ const errBody = await r.text();
51
+ throw new Error(`NVIDIA ${r.status}: ${errBody}`);
52
+ }
53
+ return r.json();
54
+ });
55
+
56
+ recordUserHit(clientId);
57
+
58
+ // FLUX يرجع base64 في artifacts[0].base64 (أو image)
59
+ const b64 =
60
+ data?.artifacts?.[0]?.base64 ||
61
+ data?.image ||
62
+ data?.data?.[0]?.b64_json ||
63
+ null;
64
+
65
+ if (!b64) {
66
+ return res.status(502).json({ error: "no_image", raw: data });
67
+ }
68
+
69
+ res.json({ image: `data:image/png;base64,${b64}`, remaining: quota.remaining - 1 });
70
+ } catch (err) {
71
+ console.error("image error:", err);
72
+ res.status(500).json({ error: "image_failed", message: String(err?.message || err) });
73
+ }
74
+ });
75
+
76
+ export default router;