enzostvs/deepsite
17k
1import { clsx, type ClassValue } from "clsx";2import { twMerge } from "tailwind-merge";3import { File } from "./type";4 5export function cn(...inputs: ClassValue[]) {6 return twMerge(clsx(inputs));7}8 9export const ALLOWED_DOMAINS = [10 "huggingface.co",11 "deepsite.hf.co",12 "localhost",13 "enzostvs-deepsite-v4-demo.hf.space",14];15 16export const COLORS = [17 "red",18 "blue",19 "green",20 "yellow",21 "purple",22 "pink",23 "gray",24];25export const EMOJIS_FOR_SPACE = [26 "๐",27 "๐ฅ",28 "โจ",29 "๐ก",30 "๐ค",31 "๐",32 "๐",33 "๐",34 "โก",35 "๐จ",36 "๐ง ",37 "๐ฆ",38 "๐ ๏ธ",39 "๐ง",40 "๐",41 "๐",42 "๐งฉ",43 "๐ง",44 "๐ฅ๏ธ",45 "๐ฑ",46];47 48export const getMentionsFromPrompt = async (prompt: string) => {49 const mentions = prompt.match(/[a-zA-Z0-9-]+\/[a-zA-Z0-9-]+/g);50 const validMentions = await Promise.all(51 mentions?.map(async (mention) => {52 let type = "model";53 let response = await fetch(54 `https://huggingface.co/api/models/${mention}`55 );56 if (!response.ok) {57 type = "dataset";58 response = await fetch(59 `https://huggingface.co/api/datasets/${mention}`60 );61 if (!response.ok) {62 return null;63 }64 }65 const readme = await fetch(66 `https://huggingface.co/${67 type === "model" ? "" : "datasets/"68 }${mention}/raw/main/README.md`69 );70 const readmeContent = await readme.text();71 72 const data = await response.json();73 return {74 library_name: data?.library_name ?? data?.cardData?.library_name,75 pipeline_tag: data?.pipeline_tag ?? data?.cardData?.pipeline_tag,76 model_id: data.id,77 readme: readmeContent ?? "",78 };79 }) ?? []80 );81 return validMentions?.filter((mention) => mention !== null) ?? [];82};83export const getContextFilesFromPrompt = async (84 prompt: string,85 currentFiles: File[]86) => {87 const mentions = prompt.match(/file:\/[a-zA-Z0-9-_.\/]+/g);88 const filesToUseAsContext: File[] = [];89 if (currentFiles.length === 0) return currentFiles;90 if (!mentions || mentions.length === 0) return currentFiles;91 mentions?.forEach((mention) => {92 const filePath = mention.replace("file:/", "");93 const matchedFile = currentFiles.find((file) => file.path === filePath);94 if (matchedFile) {95 filesToUseAsContext.push(matchedFile);96 }97 });98 return filesToUseAsContext;99};100 101export const defaultHTML = `<!DOCTYPE html>102<html>103 <head>104 <title>My app</title>105 <meta name="viewport" content="width=device-width, initial-scale=1.0" />106 <meta charset="utf-8">107 <script src="https://cdn.tailwindcss.com"></script>108 </head>109 <body class="flex justify-center items-center h-screen overflow-hidden bg-white dark:bg-neutral-950 font-sans text-center px-6">110 <div class="w-full">111 <span class="text-xs rounded-full mb-4 inline-block px-2 py-1 border border-indigo-500/15 bg-indigo-500/15 text-indigo-500">112 ๐ฅ DeepSite v4: New version dropped!113 </span>114 <h1 class="text-4xl lg:text-6xl font-bold font-sans dark:text-white">115 <span class="text-2xl lg:text-4xl text-gray-400 dark:text-neutral-500 block font-medium">116 I'm ready to develop,117 </span>118 Ask me anything.119 </h1>120 </div>121 <img src="https://deepsite.hf.co/arrow.svg" class="absolute bottom-8 left-0 w-[100px] transform rotate-30 dark:invert dark:brightness-0" />122 <script></script>123 </body>124</html>125`;126 127export function injectDeepSiteBadge(html: string): string {128 const badgeScript =129 '<script src="https://deepsite.hf.co/deepsite-badge.js"></script>';130 131 // Remove any existing badge script to avoid duplicates132 const cleanedHtml = html.replace(133 /<script\s+src=["']https:\/\/deepsite\.hf\.co\/deepsite-badge\.js["']\s*><\/script>\s*/gi,134 ""135 );136 137 // Check if there's a closing body tag138 const bodyCloseIndex = cleanedHtml.lastIndexOf("</body>");139 140 if (bodyCloseIndex !== -1) {141 // Inject the script before the closing </body> tag142 return (143 cleanedHtml.slice(0, bodyCloseIndex) +144 badgeScript +145 "\n" +146 cleanedHtml.slice(bodyCloseIndex)147 );148 }149 150 // If no closing body tag, append the script at the end151 return cleanedHtml + "\n" + badgeScript;152}153 154export function isIndexPage(path: string): boolean {155 const normalizedPath = path.toLowerCase();156 return (157 normalizedPath === "/" ||158 normalizedPath === "index" ||159 normalizedPath === "/index" ||160 normalizedPath === "index.html" ||161 normalizedPath === "/index.html"162 );163}164 165export const humanizeNumber = (num: number): string => {166 if (num >= 1_000_000) {167 return (num / 1_000_000).toFixed(1).replace(/\.0$/, "") + "M+";168 }169 if (num >= 1_000) {170 return (num / 1_000).toFixed(1).replace(/\.0$/, "") + "K+";171 }172 return num.toString();173};174 175export const getFileType = (url: string) => {176 if (typeof url !== "string") {177 return "unknown";178 }179 const extension = url.split(".").pop()?.toLowerCase();180 if (["jpg", "jpeg", "png", "gif", "webp", "svg"].includes(extension || "")) {181 return "image";182 } else if (["mp4", "webm", "ogg", "avi", "mov"].includes(extension || "")) {183 return "video";184 } else if (["mp3", "wav", "ogg", "aac", "m4a"].includes(extension || "")) {185 return "audio";186 }187 return "unknown";188};189export const DISCORD_URL = "https://discord.gg/KpanwM3vXa";190 