Spaces:
Runtime error
Runtime error
Update server.js
Browse files
server.js
CHANGED
|
@@ -4,166 +4,101 @@ import { fileURLToPath } from "url";
|
|
| 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 ||
|
|
|
|
|
|
|
|
|
|
| 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
|
|
|
|
| 24 |
if (!prompt) {
|
| 25 |
-
return res.status(400).send({
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
ok: false,
|
| 27 |
-
message: "Missing
|
| 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 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
|
|
|
|
|
|
| 53 |
});
|
| 54 |
-
}
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 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 |
-
|
| 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 |
-
|
| 115 |
-
|
| 116 |
|
| 117 |
-
|
| 118 |
-
|
|
|
|
| 119 |
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
return res.status(402).send({
|
| 123 |
-
ok: false,
|
| 124 |
-
message: line,
|
| 125 |
-
});
|
| 126 |
-
}
|
| 127 |
|
| 128 |
-
|
|
|
|
| 129 |
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
|
| 134 |
-
|
| 135 |
-
|
| 136 |
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 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,5 +107,5 @@ app.get("*", (_req, res) => {
|
|
| 172 |
});
|
| 173 |
|
| 174 |
app.listen(PORT, () => {
|
| 175 |
-
console.log(`Server
|
| 176 |
-
});
|
|
|
|
| 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 |
|
| 13 |
+
const PORT = process.env.APP_PORT || 7860;
|
| 14 |
+
const ApiKey = process.env.OPENROUTER_API_KEY;
|
| 15 |
+
const Model = process.env.OPENROUTER_MODEL;
|
| 16 |
+
const ApiUrl = "https://openrouter.ai/api/v1";
|
| 17 |
|
| 18 |
app.use(bodyParser.json());
|
| 19 |
app.use(express.static(path.join(__dirname, "dist")));
|
| 20 |
|
| 21 |
app.post("/api/ask-ai", async (req, res) => {
|
| 22 |
+
const { prompt, html, previousPrompt } = req.body;
|
| 23 |
+
|
| 24 |
if (!prompt) {
|
| 25 |
+
return res.status(400).send({ ok: false, message: "Missing prompt" });
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
if (!ApiKey || !Model) {
|
| 29 |
+
return res.status(500).send({
|
| 30 |
ok: false,
|
| 31 |
+
message: "Missing API Key or Model in .env file",
|
| 32 |
});
|
| 33 |
}
|
| 34 |
|
|
|
|
| 35 |
res.setHeader("Content-Type", "text/plain");
|
| 36 |
res.setHeader("Cache-Control", "no-cache");
|
| 37 |
res.setHeader("Connection", "keep-alive");
|
| 38 |
|
| 39 |
+
const 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 using TailwindCSS. If not possible, use custom CSS (remember to import <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script> in the head). ALWAYS GIVE THE RESPONSE INTO A SINGLE HTML FILE`;
|
| 40 |
+
|
| 41 |
+
try {
|
| 42 |
+
const response = await fetch(`${ApiUrl}/chat/completions`, {
|
| 43 |
+
method: "POST",
|
| 44 |
+
headers: {
|
| 45 |
+
Authorization: `Bearer ${ApiKey}`,
|
| 46 |
+
"Content-Type": "application/json",
|
| 47 |
+
},
|
| 48 |
+
body: JSON.stringify({
|
| 49 |
+
model: Model,
|
| 50 |
+
stream: true,
|
| 51 |
+
messages: [
|
| 52 |
+
{ role: "system", content: systemPrompt },
|
| 53 |
+
...(previousPrompt ? [{ role: "user", content: previousPrompt }] : []),
|
| 54 |
+
...(html ? [{ role: "assistant", content: `The current code is: ${html}` }] : []),
|
| 55 |
+
{ role: "user", content: prompt },
|
| 56 |
+
],
|
| 57 |
+
}),
|
| 58 |
});
|
|
|
|
| 59 |
|
| 60 |
+
if (!response.ok || !response.body) {
|
| 61 |
+
return res.status(500).send({
|
| 62 |
+
ok: false,
|
| 63 |
+
message: "Failed to fetch OpenRouter response",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
});
|
| 65 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
+
const reader = response.body.getReader();
|
| 68 |
+
const decoder = new TextDecoder();
|
| 69 |
|
| 70 |
+
while (true) {
|
| 71 |
+
const { done, value } = await reader.read();
|
| 72 |
+
if (done) break;
|
| 73 |
|
| 74 |
+
const chunk = decoder.decode(value);
|
| 75 |
+
const lines = chunk.split('\n').filter(line => line.trim());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
+
for (const line of lines) {
|
| 78 |
+
if (!line || !line.startsWith('data: ') || line.includes('[DONE]')) continue;
|
| 79 |
|
| 80 |
+
try {
|
| 81 |
+
const json = line.slice(6).trim();
|
| 82 |
+
if (!json.startsWith('{')) continue;
|
| 83 |
|
| 84 |
+
const message = JSON.parse(json);
|
| 85 |
+
const content = message?.choices?.[0]?.delta?.content;
|
| 86 |
|
| 87 |
+
if (content) res.write(content);
|
| 88 |
+
} catch (err) {
|
| 89 |
+
console.error("Streaming error:", err.message);
|
| 90 |
+
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
}
|
| 93 |
}
|
| 94 |
+
|
| 95 |
+
res.end();
|
| 96 |
+
} catch (error) {
|
| 97 |
+
console.error("Request error:", error.message);
|
| 98 |
+
res.status(500).send({
|
| 99 |
+
ok: false,
|
| 100 |
+
message: error.message || "Unexpected error",
|
| 101 |
+
});
|
| 102 |
}
|
| 103 |
});
|
| 104 |
|
|
|
|
| 107 |
});
|
| 108 |
|
| 109 |
app.listen(PORT, () => {
|
| 110 |
+
console.log(`✅ Server running on port ${PORT}`);
|
| 111 |
+
});
|