CoolFace
Apppublic

facessss/deepsite

sourceHugging Facemitupdated 1y agoView on Hugging Face
0likes
server.js425 linesDownload Raw Back to root
1import express from "express";2import path from "path";3import { fileURLToPath } from "url";4import dotenv from "dotenv";5import cookieParser from "cookie-parser";6import {7  createRepo,8  uploadFiles,9  whoAmI,10  spaceInfo,11  fileExists,12} from "@huggingface/hub";13import { InferenceClient } from "@huggingface/inference";14import bodyParser from "body-parser";15 16import checkUser from "./middlewares/checkUser.js";17import { PROVIDERS } from "./utils/providers.js";18import { COLORS } from "./utils/colors.js";19 20// Load environment variables from .env file21dotenv.config();22 23const app = express();24 25const ipAddresses = new Map();26 27const __filename = fileURLToPath(import.meta.url);28const __dirname = path.dirname(__filename);29 30const PORT = process.env.APP_PORT || 3000;31const REDIRECT_URI =32  process.env.REDIRECT_URI || `http://localhost:${PORT}/auth/login`;33const MODEL_ID = "deepseek-ai/DeepSeek-V3-0324";34const MAX_REQUESTS_PER_IP = 2;35 36app.use(cookieParser());37app.use(bodyParser.json());38app.use(express.static(path.join(__dirname, "dist")));39 40const getPTag = (repoId) => {41  return `<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=${repoId}" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p>`;42};43 44app.get("/api/login", (_req, res) => {45  // res.redirect(46  //   302,47  //   `https://huggingface.co/oauth/authorize?client_id=${process.env.OAUTH_CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=openid%20profile%20write-repos%20manage-repos%20inference-api&prompt=consent&state=1234567890`48  // );49  // redirect in new tab50  const redirectUrl = `https://huggingface.co/oauth/authorize?client_id=${process.env.OAUTH_CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=openid%20profile%20write-repos%20manage-repos%20inference-api&prompt=consent&state=1234567890`;51  res.status(200).send({52    ok: true,53    redirectUrl,54  });55});56app.get("/auth/login", async (req, res) => {57  const { code } = req.query;58 59  if (!code) {60    return res.redirect(302, "/");61  }62  const Authorization = `Basic ${Buffer.from(63    `${process.env.OAUTH_CLIENT_ID}:${process.env.OAUTH_CLIENT_SECRET}`64  ).toString("base64")}`;65 66  const request_auth = await fetch("https://huggingface.co/oauth/token", {67    method: "POST",68    headers: {69      "Content-Type": "application/x-www-form-urlencoded",70      Authorization,71    },72    body: new URLSearchParams({73      grant_type: "authorization_code",74      code: code,75      redirect_uri: REDIRECT_URI,76    }),77  });78 79  const response = await request_auth.json();80 81  if (!response.access_token) {82    return res.redirect(302, "/");83  }84 85  res.cookie("hf_token", response.access_token, {86    httpOnly: false,87    secure: true,88    sameSite: "none",89    maxAge: 30 * 24 * 60 * 60 * 1000,90  });91 92  return res.redirect(302, "/");93});94app.get("/auth/logout", (req, res) => {95  res.clearCookie("hf_token", {96    httpOnly: false,97    secure: true,98    sameSite: "none",99  });100  return res.redirect(302, "/");101});102 103app.get("/api/@me", checkUser, async (req, res) => {104  const { hf_token } = req.cookies;105  try {106    const request_user = await fetch("https://huggingface.co/oauth/userinfo", {107      headers: {108        Authorization: `Bearer ${hf_token}`,109      },110    });111 112    const user = await request_user.json();113    res.send(user);114  } catch (err) {115    res.clearCookie("hf_token", {116      httpOnly: false,117      secure: true,118      sameSite: "none",119    });120    res.status(401).send({121      ok: false,122      message: err.message,123    });124  }125});126 127app.post("/api/deploy", checkUser, async (req, res) => {128  const { html, title, path } = req.body;129  if (!html || (!path && !title)) {130    return res.status(400).send({131      ok: false,132      message: "Missing required fields",133    });134  }135 136  const { hf_token } = req.cookies;137  try {138    const repo = {139      type: "space",140      name: path ?? "",141    };142 143    let readme;144    let newHtml = html;145 146    if (!path || path === "") {147      const { name: username } = await whoAmI({ accessToken: hf_token });148      const newTitle = title149        .toLowerCase()150        .replace(/[^a-z0-9]+/g, "-")151        .split("-")152        .filter(Boolean)153        .join("-")154        .slice(0, 96);155 156      const repoId = `${username}/${newTitle}`;157      repo.name = repoId;158 159      await createRepo({160        repo,161        accessToken: hf_token,162      });163      const colorFrom = COLORS[Math.floor(Math.random() * COLORS.length)];164      const colorTo = COLORS[Math.floor(Math.random() * COLORS.length)];165      readme = `---166title: ${newTitle}167emoji: 🐳168colorFrom: ${colorFrom}169colorTo: ${colorTo}170sdk: static171pinned: false172tags:173  - deepsite174---175 176Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference`;177    }178 179    newHtml = html.replace(/<\/body>/, `${getPTag(repo.name)}</body>`);180    const file = new Blob([newHtml], { type: "text/html" });181    file.name = "index.html"; // Add name property to the Blob182 183    const files = [file];184    if (readme) {185      const readmeFile = new Blob([readme], { type: "text/markdown" });186      readmeFile.name = "README.md"; // Add name property to the Blob187      files.push(readmeFile);188    }189    await uploadFiles({190      repo,191      files,192      accessToken: hf_token,193    });194    return res.status(200).send({ ok: true, path: repo.name });195  } catch (err) {196    return res.status(500).send({197      ok: false,198      message: err.message,199    });200  }201});202 203app.post("/api/ask-ai", async (req, res) => {204  const { prompt, html, previousPrompt, provider } = req.body;205  if (!prompt) {206    return res.status(400).send({207      ok: false,208      message: "Missing required fields",209    });210  }211 212  const { hf_token } = req.cookies;213  let token = hf_token;214  const ip =215    req.headers["x-forwarded-for"]?.split(",")[0].trim() ||216    req.headers["x-real-ip"] ||217    req.socket.remoteAddress ||218    req.ip ||219    "0.0.0.0";220 221  if (!hf_token) {222    ipAddresses.set(ip, (ipAddresses.get(ip) || 0) + 1);223    if (ipAddresses.get(ip) > MAX_REQUESTS_PER_IP) {224      return res.status(429).send({225        ok: false,226        openLogin: true,227        message: "Log In to continue using the service",228      });229    }230 231    token = process.env.DEFAULT_HF_TOKEN;232  }233 234  // Set up response headers for streaming235  res.setHeader("Content-Type", "text/plain");236  res.setHeader("Cache-Control", "no-cache");237  res.setHeader("Connection", "keep-alive");238 239  const client = new InferenceClient(token);240  let completeResponse = "";241 242  let TOKENS_USED = prompt?.length;243  if (previousPrompt) TOKENS_USED += previousPrompt.length;244  if (html) TOKENS_USED += html.length;245 246  const DEFAULT_PROVIDER = PROVIDERS.novita;247  // const selectedProvider =248  //   provider === "auto"249  //     ? TOKENS_USED < PROVIDERS.sambanova.max_tokens250  //       ? PROVIDERS.sambanova251  //       : DEFAULT_PROVIDER252  //     : PROVIDERS[provider] ?? DEFAULT_PROVIDER;253  const selectedProvider =254    provider === "auto"255      ? DEFAULT_PROVIDER256      : PROVIDERS[provider] ?? DEFAULT_PROVIDER;257 258  if (provider !== "auto" && TOKENS_USED >= selectedProvider.max_tokens) {259    return res.status(400).send({260      ok: false,261      openSelectProvider: true,262      message: `Context is too long. ${selectedProvider.name} allow ${selectedProvider.max_tokens} max tokens.`,263    });264  }265 266  try {267    const chatCompletion = client.chatCompletionStream({268      model: MODEL_ID,269      provider: selectedProvider.id,270      messages: [271        {272          role: "system",273          content: `ONLY USE HTML, CSS AND JAVASCRIPT. 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.tailwindcss.com"></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`,274        },275        ...(previousPrompt276          ? [277              {278                role: "user",279                content: previousPrompt,280              },281            ]282          : []),283        ...(html284          ? [285              {286                role: "assistant",287                content: `The current code is: ${html}.`,288              },289            ]290          : []),291        {292          role: "user",293          content: prompt,294        },295      ],296      ...(selectedProvider.id !== "sambanova"297        ? {298            max_tokens: selectedProvider.max_tokens,299          }300        : {}),301    });302 303    while (true) {304      const { done, value } = await chatCompletion.next();305      if (done) {306        break;307      }308      const chunk = value.choices[0]?.delta?.content;309      if (chunk) {310        if (provider !== "sambanova") {311          res.write(chunk);312          completeResponse += chunk;313 314          if (completeResponse.includes("</html>")) {315            break;316          }317        } else {318          let newChunk = chunk;319          if (chunk.includes("</html>")) {320            // Replace everything after the last </html> tag with an empty string321            newChunk = newChunk.replace(/<\/html>[\s\S]*/, "</html>");322          }323          completeResponse += newChunk;324          res.write(newChunk);325          if (newChunk.includes("</html>")) {326            break;327          }328        }329      }330    }331    // End the response stream332    res.end();333  } catch (error) {334    if (error.message.includes("exceeded your monthly included credits")) {335      return res.status(402).send({336        ok: false,337        openProModal: true,338        message: error.message,339      });340    }341    if (!res.headersSent) {342      res.status(500).send({343        ok: false,344        message:345          error.message || "An error occurred while processing your request.",346      });347    } else {348      // Otherwise end the stream349      res.end();350    }351  }352});353 354app.get("/api/remix/:username/:repo", async (req, res) => {355  const { username, repo } = req.params;356  const { hf_token } = req.cookies;357 358  const token = hf_token || process.env.DEFAULT_HF_TOKEN;359 360  const repoId = `${username}/${repo}`;361 362  const url = `https://huggingface.co/spaces/${repoId}/raw/main/index.html`;363  try {364    const space = await spaceInfo({365      name: repoId,366      accessToken: token,367      additionalFields: ["author"],368    });369 370    if (!space || space.sdk !== "static" || space.private) {371      return res.status(404).send({372        ok: false,373        message: "Space not found",374      });375    }376 377    const response = await fetch(url);378    if (!response.ok) {379      return res.status(404).send({380        ok: false,381        message: "Space not found",382      });383    }384    let html = await response.text();385    // remove the last p tag including this url https://enzostvs-deepsite.hf.space386    html = html.replace(getPTag(repoId), "");387 388    let user = null;389 390    if (token) {391      const request_user = await fetch(392        "https://huggingface.co/oauth/userinfo",393        {394          headers: {395            Authorization: `Bearer ${hf_token}`,396          },397        }398      )399        .then((res) => res.json())400        .catch(() => null);401 402      user = request_user;403    }404 405    res.status(200).send({406      ok: true,407      html,408      isOwner: space.author === user?.preferred_username,409      path: repoId,410    });411  } catch (error) {412    return res.status(500).send({413      ok: false,414      message: error.message,415    });416  }417});418app.get("*", (_req, res) => {419  res.sendFile(path.join(__dirname, "dist", "index.html"));420});421 422app.listen(PORT, () => {423  console.log(`Server is running on port ${PORT}`);424});425