caiosilva1221 commited on
Commit
d5cae2f
·
verified ·
1 Parent(s): c66b282

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +126 -66
server.js CHANGED
@@ -4,106 +4,166 @@ import { fileURLToPath } from "url";
4
  import dotenv from "dotenv";
5
  import bodyParser from "body-parser";
6
 
 
 
 
7
  dotenv.config();
8
 
9
  const app = express();
 
10
  const __filename = fileURLToPath(import.meta.url);
11
  const __dirname = path.dirname(__filename);
12
- const PORT = process.env.APP_PORT || 7860;
13
- const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY;
14
 
15
  app.use(bodyParser.json());
16
  app.use(express.static(path.join(__dirname, "dist")));
17
 
18
  app.post("/api/ask-ai", async (req, res) => {
19
- const { prompt, html, previousPrompt } = req.body;
20
  if (!prompt) {
21
- return res.status(400).send({ ok: false, message: "Missing prompt" });
22
- }
23
-
24
- if (!OPENROUTER_API_KEY) {
25
- return res.status(500).send({
26
  ok: false,
27
- message: "Missing OpenRouter API Key",
28
  });
29
  }
30
 
 
31
  res.setHeader("Content-Type", "text/plain");
32
  res.setHeader("Cache-Control", "no-cache");
33
  res.setHeader("Connection", "keep-alive");
34
 
35
- const messages = [
36
- {
37
- role: "system",
38
- content:
39
- "Você é um especialista em landing pages. Gere um HTML bonito e persuasivo para a copy enviada. Responda apenas com código HTML válido e completo.",
40
- },
41
- ...(previousPrompt ? [{ role: "user", content: previousPrompt }] : []),
42
- ...(html ? [{ role: "assistant", content: `The current code is: ${html}` }] : []),
43
- { role: "user", content: prompt },
44
- ];
45
-
46
- try {
47
- const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
48
- method: "POST",
49
- headers: {
50
- Authorization: `Bearer ${OPENROUTER_API_KEY}`,
51
- "Content-Type": "application/json",
52
- "HTTP-Referer": "https://raypages.com", // personalize aqui
53
- "X-Title": "RayPages AI",
54
- },
55
- body: JSON.stringify({
56
- model: "deepseek-chat-v3.0",
57
- stream: true,
58
- messages,
59
- }),
60
  });
 
61
 
62
- if (!response.ok || !response.body) {
63
- return res.status(500).send({
64
- ok: false,
65
- message: "Failed to fetch OpenRouter response",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  });
67
- }
 
 
 
68
 
69
- const reader = response.body.getReader();
70
- const decoder = new TextDecoder("utf-8");
71
- let completeResponse = "";
72
 
73
- const stream = async () => {
74
  while (true) {
75
  const { done, value } = await reader.read();
76
  if (done) break;
77
 
78
- const chunk = decoder.decode(value, { stream: true });
79
- const matches = chunk.match(/"content":"([^"]*)"/g);
80
 
81
- if (matches) {
82
- for (const match of matches) {
83
- const text = match
84
- .replace(/"content":"|"/g, "")
85
- .replace(/\\n/g, "\n")
86
- .replace(/\\t/g, "\t");
87
 
88
- completeResponse += text;
89
- res.write(text);
 
 
 
 
 
 
 
90
 
91
- if (completeResponse.includes("</html>")) {
92
- res.end();
93
- return;
94
  }
 
 
 
 
 
 
 
 
 
 
 
95
  }
96
  }
 
97
  }
98
  res.end();
99
- };
100
-
101
- stream();
102
- } catch (err) {
103
- res.status(500).send({
104
- ok: false,
105
- message: err.message || "AI request failed",
106
- });
 
 
 
 
 
 
 
 
 
 
107
  }
108
  });
109
 
@@ -112,5 +172,5 @@ app.get("*", (_req, res) => {
112
  });
113
 
114
  app.listen(PORT, () => {
115
- console.log(`✅ Server running on port ${PORT}`);
116
- });
 
4
  import dotenv from "dotenv";
5
  import bodyParser from "body-parser";
6
 
7
+ import { PROVIDERS } from "./utils/providers.js";
8
+
9
+ // Load environment variables from .env file
10
  dotenv.config();
11
 
12
  const app = express();
13
+
14
  const __filename = fileURLToPath(import.meta.url);
15
  const __dirname = path.dirname(__filename);
16
+
17
+ const PORT = process.env.APP_PORT || 3000;
18
 
19
  app.use(bodyParser.json());
20
  app.use(express.static(path.join(__dirname, "dist")));
21
 
22
  app.post("/api/ask-ai", async (req, res) => {
23
+ const { prompt, html, previousPrompt, provider } = req.body;
24
  if (!prompt) {
25
+ return res.status(400).send({
 
 
 
 
26
  ok: false,
27
+ message: "Missing required fields",
28
  });
29
  }
30
 
31
+ // Set up response headers for streaming
32
  res.setHeader("Content-Type", "text/plain");
33
  res.setHeader("Cache-Control", "no-cache");
34
  res.setHeader("Connection", "keep-alive");
35
 
36
+ let systemPrompt = `ONLY USE HTML, CSS AND JAVASCRIPT. No explanations, ONLY CODE. If you want to use ICON make sure to import the library first. Try to create the best UI possible by using only HTML, CSS and JAVASCRIPT. Use as much as you can TailwindCSS for the CSS, if you can't do something with TailwindCSS, then use custom CSS (make sure to import <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script> in the head). Also, try to ellaborate as much as you can, to create something unique. ALWAYS GIVE THE RESPONSE INTO A SINGLE HTML FILE`;
37
+
38
+ let TOKENS_USED = prompt?.length;
39
+ if (previousPrompt) TOKENS_USED += previousPrompt.length;
40
+ if (html) TOKENS_USED += html.length;
41
+
42
+ const DEFAULT_PROVIDER = PROVIDERS.openrouter;
43
+ const selectedProvider =
44
+ provider === "auto"
45
+ ? DEFAULT_PROVIDER
46
+ : PROVIDERS[provider] ?? DEFAULT_PROVIDER;
47
+
48
+ if (provider !== "auto" && TOKENS_USED >= selectedProvider.max_tokens) {
49
+ return res.status(400).send({
50
+ ok: false,
51
+ openSelectProvider: true,
52
+ message: `Context is too long. ${selectedProvider.name} allow ${selectedProvider.max_tokens} max tokens.`,
 
 
 
 
 
 
 
 
53
  });
54
+ }
55
 
56
+ if (["local", "openrouter"].includes(selectedProvider.id)) {
57
+ try {
58
+ const { ApiKey, ApiUrl, Model } = req.body;
59
+ if (!ApiUrl || !Model) {
60
+ return res.status(400).send({
61
+ ok: false,
62
+ message: "Missing required fields for provider, set API KEY, BASE URL, and MODEL.",
63
+ });
64
+ }
65
+ const response = await fetch(`${ApiUrl}/chat/completions`, {
66
+ method: "POST",
67
+ headers: {
68
+ "Content-Type": "application/json",
69
+ Authorization: `Bearer ${ApiKey}`,
70
+ },
71
+ body: JSON.stringify({
72
+ model: Model,
73
+ messages: [
74
+ {
75
+ role: "system",
76
+ content: systemPrompt,
77
+ },
78
+ ...(previousPrompt
79
+ ? [
80
+ {
81
+ role: "user",
82
+ content: previousPrompt,
83
+ },
84
+ ]
85
+ : []),
86
+ ...(html
87
+ ? [
88
+ {
89
+ role: "assistant",
90
+ content: `The current code is: ${html}.`,
91
+ },
92
+ ]
93
+ : []),
94
+ {
95
+ role: "user",
96
+ content: prompt,
97
+ },
98
+ ],
99
+ stream: true
100
+ })
101
  });
102
+ if (!response.ok) {
103
+ const errorBody = await response.text();
104
+ throw new Error(`API Error: ${response.status} - ${errorBody}`);
105
+ }
106
 
107
+ const reader = response.body.getReader();
108
+ const decoder = new TextDecoder();
 
109
 
 
110
  while (true) {
111
  const { done, value } = await reader.read();
112
  if (done) break;
113
 
114
+ const chunk = decoder.decode(value);
115
+ const lines = chunk.split('\n').filter(line => line.trim());
116
 
117
+ for (const line of lines) {
118
+ if (!line || !line.startsWith('data: ') || line.includes('[DONE]')) continue;
 
 
 
 
119
 
120
+ try {
121
+ if (line.includes('exceeded')) {
122
+ return res.status(402).send({
123
+ ok: false,
124
+ message: line,
125
+ });
126
+ }
127
+
128
+ const json = line.slice(6).trim();
129
 
130
+ if (!json.startsWith('{')) {
131
+ continue;
 
132
  }
133
+
134
+ const message = JSON.parse(json);
135
+ const content = message?.choices?.[0]?.delta?.content;
136
+
137
+ if (content) {
138
+ res.write(content);
139
+ }
140
+ } catch (e) {
141
+ console.error('Error on line stream:', e.message);
142
+ // continue ao invés de throw, pra não matar tudo por causa de uma linha podre
143
+ continue;
144
  }
145
  }
146
+
147
  }
148
  res.end();
149
+ } catch (error) {
150
+ if (error.message.includes("exceeded")) {
151
+ return res.status(402).send({
152
+ ok: false,
153
+ message: error.message,
154
+ });
155
+ }
156
+ if (!res.headersSent) {
157
+ res.status(500).send({
158
+ ok: false,
159
+ message:
160
+ error.message || "An error occurred while processing your request.",
161
+ });
162
+ } else {
163
+ // Otherwise end the stream
164
+ res.end();
165
+ }
166
+ }
167
  }
168
  });
169
 
 
172
  });
173
 
174
  app.listen(PORT, () => {
175
+ console.log(`Server is running on port ${PORT}`);
176
+ });