Multiai / src /app.js
Bfjandak's picture
Update src/app.js
997674f verified
Raw
History Blame Contribute Delete
22.8 kB
import './input.css';
import { oauthLoginUrl, oauthHandleRedirectIfPresent } from "@huggingface/hub";
import { InferenceClient } from "@huggingface/inference";
import { Client } from "@gradio/client";
let activeInMemoryUserToken = null;
let internalBlobURL = null;
let targetDownloadBlobURL = null;
let cachedRawText = "";
let activeGradioJobHandle = null;
let currentAbortController = null;
let globalInferenceTimeoutId = null;
let studioRegistryData = null;
const MAX_FILE_SIZE_MB = 25;
const COMPUTATION_TIMEOUT_MS = 300000;
const embeddedFallbackRegistry = {
registryVersion: "local-fallback-v1",
models: {
text: [{ id: "meta-llama/Meta-Llama-3-8B-Instruct:fastest", name: "Llama 3 8B Instruct (Fallback)", transport: "serverless", apiStrategy: "chatStream", inputType: "text", mimeConstraints: [], capabilities: { stream: true, copy: true } }],
image: [{ id: "black-forest-labs/FLUX.1-schnell", name: "FLUX.1 Schnell (Fallback)", transport: "serverless", apiStrategy: "textToImage", inputType: "text", mimeConstraints: [], capabilities: { download: true } }],
video: [], audio: [], vision: []
}
};
window.addEventListener('DOMContentLoaded', async () => {
document.getElementById('loginButton').addEventListener('click', () => oauthLoginUrl().then(url => window.location.href = url));
document.getElementById('logoutBtn').addEventListener('click', purgeLifetimeSessionState);
document.getElementById('generateBtn').addEventListener('click', triggerInferenceEngineLifecycle);
document.getElementById('copyBtn').addEventListener('click', writeTextToClipboardSecurely);
document.getElementById('cancelBtn').addEventListener('click', killActiveInferencePipelines);
document.getElementById('modelSelector').addEventListener('change', runDynamicInputMIMEChecks);
['text', 'image', 'video', 'audio', 'vision'].forEach(domain => {
document.getElementById(`btn-tab-${domain}`).addEventListener('click', () => switchTab(domain));
});
await bootstrapApplicationStudio();
});
function validateRegistrySchema(data) {
if (!data || typeof data !== 'object') return false;
if (typeof data.registryVersion !== 'string') return false;
if (!data.models || typeof data.models !== 'object') return false;
return ['text', 'image', 'video', 'audio', 'vision'].every(key => Array.isArray(data.models[key] || []));
}
async function bootstrapApplicationStudio() {
try {
const networkFetch = await fetch('/registry.json');
if (!networkFetch.ok) throw new Error("Server metadata returned irregular structural states.");
const parsedConfig = await networkFetch.json();
if (validateRegistrySchema(parsedConfig)) {
studioRegistryData = parsedConfig;
console.log("Registry Version Loaded:", studioRegistryData.registryVersion);
} else {
throw new Error("Registry data structurally violated schema blueprints.");
}
} catch (fallbackError) {
console.warn("External registry verification failed. Injecting embedded fallback maps...", fallbackError);
studioRegistryData = embeddedFallbackRegistry;
}
try {
const parsedOAuth = await oauthHandleRedirectIfPresent();
let activeToken = sessionStorage.getItem("hf_transient_token");
if (parsedOAuth?.accessToken) {
activeToken = parsedOAuth.accessToken;
sessionStorage.setItem("hf_transient_token", activeToken);
window.history.replaceState({}, document.title, window.location.pathname);
}
if (activeToken) {
activeInMemoryUserToken = activeToken;
document.getElementById('authOverlay').classList.add('hidden');
document.getElementById('appContainer').classList.remove('hidden');
switchTab('text');
}
} catch (err) { console.error("Identity validation sequence crashed:", err); }
}
function purgeLifetimeSessionState() {
sessionStorage.removeItem("hf_transient_token");
activeInMemoryUserToken = null;
clearActiveBlobAllocations();
window.location.href = window.location.origin + window.location.pathname;
}
function clearActiveBlobAllocations() {
document.getElementById('imageOutput').removeAttribute('src');
document.getElementById('audioOutput').removeAttribute('src');
document.getElementById('videoOutput').removeAttribute('src');
if (internalBlobURL) { URL.revokeObjectURL(internalBlobURL); internalBlobURL = null; }
if (targetDownloadBlobURL) { URL.revokeObjectURL(targetDownloadBlobURL); targetDownloadBlobURL = null; }
}
function switchTab(domain) {
if (!studioRegistryData) return;
document.getElementById('activeDomainContext').value = domain;
['text', 'image', 'video', 'audio', 'vision'].forEach(d => {
const node = document.getElementById(`btn-tab-${d}`);
node.className = (d === domain)
? "w-full flex items-center gap-3 px-3 py-2.5 rounded-xl bg-indigo-600 text-white text-sm font-medium transition cursor-pointer"
: "w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-gray-400 hover:bg-gray-800 hover:text-gray-200 text-sm font-medium transition cursor-pointer";
});
const picker = document.getElementById('modelSelector');
picker.innerHTML = '';
const categoryModels = studioRegistryData.models[domain] || [];
if (!categoryModels.length) {
runDynamicInputMIMEChecks();
resetViewportStateDisplays();
renderViewTagId('stateEmptyCategory');
return;
}
categoryModels.forEach((model, index) => {
const item = document.createElement('option');
item.value = model.id;
item.innerText = model.name;
item.setAttribute('data-index', index);
picker.appendChild(item);
});
runDynamicInputMIMEChecks();
resetViewportStateDisplays();
}
function getActiveModelMetadata() {
if (!studioRegistryData) return null;
const domain = document.getElementById('activeDomainContext').value;
const picker = document.getElementById('modelSelector');
const selection = picker.options[picker.selectedIndex];
if (!selection) return null;
return studioRegistryData.models[domain][selection.getAttribute('data-index')];
}
function runDynamicInputMIMEChecks() {
const meta = getActiveModelMetadata();
const targetGrid = document.getElementById('mediaUploadContainer');
const targetLabel = document.getElementById('uploadInputLabel');
const fileField = document.getElementById('mediaFileInput');
fileField.value = "";
if (meta && meta.inputType.endsWith("File")) {
targetGrid.classList.remove('hidden');
fileField.accept = meta.inputType.startsWith("audio") ? "audio/*" : "image/*";
targetLabel.innerText = `Select Target Input Resource File (${meta.mimeConstraints.join(', ') || '*/*'}):`;
} else {
targetGrid.classList.add('hidden');
}
}
function resetViewportStateDisplays() {
document.getElementById('copyBtn').classList.add('hidden');
document.getElementById('downloadBtn').classList.add('hidden');
document.getElementById('cancelBtn').classList.add('hidden');
renderViewTagId('statePlaceholder');
}
function renderViewTagId(viewId) {
['statePlaceholder', 'stateLoading', 'stateEmptyCategory', 'textOutput', 'imageOutput', 'audioOutput', 'videoOutput'].forEach(id => {
const node = document.getElementById(id);
if (id === viewId) node.classList.remove('hidden');
else node.classList.add('hidden');
});
}
function killActiveInferencePipelines() {
if (globalInferenceTimeoutId) { clearTimeout(globalInferenceTimeoutId); globalInferenceTimeoutId = null; }
if (activeGradioJobHandle) {
try { activeGradioJobHandle.cancel(); } catch(e) { console.error("Remote cancellation error logs:", e); }
activeGradioJobHandle = null;
}
if (currentAbortController) currentAbortController.abort();
}
function extractDeepNestedValue(obj, dotPathString) {
if (!dotPathString) return obj;
return dotPathString.split('.').reduce((acc, currentCursor) => {
const indexMatch = currentCursor.match(/^(\w+)\[(\d+)\]$/);
if (indexMatch) {
const [, prop, idx] = indexMatch;
return acc?.[prop]?.[parseInt(idx, 10)];
}
return acc?.[currentCursor];
}, obj);
}
function normalizeError(err) {
const report = { title: "Execution Fault", message: "An unhandled error has halted processing.", retryable: true };
if (err.name === 'AbortError' || err.message === 'TIMEOUT_TRIGGERED') {
report.title = "Pipeline Terminated";
report.message = err.message === 'TIMEOUT_TRIGGERED'
? "Inference execution ceiling hit. Remote cluster computation dropped automatically after 5 minutes."
: "The active request was canceled via explicit control commands.";
return report;
}
const dataStr = (err.message || String(err)).toLowerCase();
if (err.status === 429 || dataStr.includes("429") || dataStr.includes("limit")) {
report.title = "Quota Limit Reached";
report.message = "Your account has depleted its available serverless execution allocations.";
return report;
}
report.message = err.message || JSON.stringify(err);
return report;
}
function constructDynamicPayload(templateStructure, textPrompt, binaryFile) {
const recurseAndTransform = (element) => {
if (element === "$file") return binaryFile;
if (element === "$text") return textPrompt;
if (Array.isArray(element)) return element.map(recurseAndTransform);
if (element !== null && typeof element === "object") {
const clonedOutputMap = {};
for (const key in element) { clonedOutputMap[key] = recurseAndTransform(element[key]); }
return clonedOutputMap;
}
return element;
};
return recurseAndTransform(templateStructure);
}
function routeMediaByContentType(contentTypeString, fallbackUrl) {
const type = contentTypeString.toLowerCase();
if (type.includes('video/')) {
document.getElementById('videoOutput').src = fallbackUrl;
renderViewTagId('videoOutput');
} else if (type.includes('audio/')) {
document.getElementById('audioOutput').src = fallbackUrl;
renderViewTagId('audioOutput');
} else {
document.getElementById('imageOutput').src = fallbackUrl;
renderViewTagId('imageOutput');
}
}
function sniffTypeFromUrlExtensions(urlString) {
const clearUrl = urlString.split('?')[0].toLowerCase();
if (clearUrl.endsWith('.mp4') || clearUrl.endsWith('.webm')) return "video/mp4";
if (clearUrl.endsWith('.mp3') || clearUrl.endsWith('.wav')) return "audio/mpeg";
return "image/png";
}
const runStrategies = {
chatStream: async (hf, meta, prompt, file, signal) => {
const node = document.getElementById('textOutput');
node.innerText = ""; cachedRawText = "";
renderViewTagId('textOutput');
try {
const stream = await hf.chatCompletionStream({ model: meta.id, messages: [{ role: "user", content: prompt }], max_tokens: 1000 }, { signal });
for await (const chunk of stream) {
cachedRawText += chunk.choices[0]?.delta?.content || "";
node.innerText = cachedRawText;
}
} catch (err) {
if (err.name === 'AbortError') throw err;
const fallbackCompletion = await hf.chatCompletion({ model: meta.id, messages: [{ role: "user", content: prompt }], max_tokens: 1000 }, { signal });
cachedRawText = fallbackCompletion.choices[0].message.content;
node.innerText = cachedRawText;
}
if (meta.capabilities.copy) document.getElementById('copyBtn').classList.remove('hidden');
},
textToImage: async (hf, meta, prompt, file, signal) => {
const blob = await hf.textToImage({ model: meta.id, inputs: prompt, parameters: { guidance_scale: 7.5 } }, { signal });
if (internalBlobURL) URL.revokeObjectURL(internalBlobURL);
internalBlobURL = URL.createObjectURL(blob);
document.getElementById('imageOutput').src = internalBlobURL;
renderViewTagId('imageOutput');
if (meta.capabilities.download) setupSecureDownloadLink(internalBlobURL, "image/png");
},
textToAudio: async (hf, meta, prompt, file, signal) => {
const blob = await hf.textToSpeech({ model: meta.id, inputs: prompt }, { signal });
if (internalBlobURL) URL.revokeObjectURL(internalBlobURL);
internalBlobURL = URL.createObjectURL(blob);
document.getElementById('audioOutput').src = internalBlobURL;
renderViewTagId('audioOutput');
if (meta.capabilities.download) setupSecureDownloadLink(internalBlobURL, "audio/mpeg");
},
audioToText: async (hf, meta, prompt, file, signal) => {
const res = await hf.automaticSpeechRecognition({ model: meta.id, data: file }, { signal });
cachedRawText = res.text || "No text structures resolved.";
document.getElementById('textOutput').innerText = cachedRawText;
renderViewTagId('textOutput');
if (meta.capabilities.copy) document.getElementById('copyBtn').classList.remove('hidden');
},
imageToText: async (hf, meta, prompt, file, signal) => {
const res = await hf.imageToText({ model: meta.id, data: file }, { signal });
cachedRawText = res.generated_text || "Zero descriptions extracted.";
document.getElementById('textOutput').innerText = cachedRawText;
renderViewTagId('textOutput');
if (meta.capabilities.copy) document.getElementById('copyBtn').classList.remove('hidden');
},
imageChat: async (hf, meta, prompt, file, signal) => {
if (file && file.size > 10 * 1024 * 1024) throw new Error("Target upload matrix breaches supported 10MB parameters.");
document.getElementById('textOutput').innerText = "Encoding file layers...";
renderViewTagId('textOutput');
const base64Str = await executeBase64FileConversion(file);
const res = await hf.chatCompletion({
model: meta.id,
messages: [{ role: "user", content: [{ type: "text", text: prompt || "Analyze image metrics." }, { type: "image_url", image_url: { url: base64Str } }] }],
max_tokens: 600
}, { signal });
cachedRawText = res.choices[0].message.content;
document.getElementById('textOutput').innerText = cachedRawText;
if (meta.capabilities.copy) document.getElementById('copyBtn').classList.remove('hidden');
},
gradioBridge: async (hf, meta, prompt, file, signal) => {
document.getElementById('loadingStatusText').innerText = "Acquiring ZeroGPU compute nodes...";
const clientInstance = await Client.connect(meta.id);
const executionTarget = meta.endpoint ?? meta.fnIndex;
const payloadArray = constructDynamicPayload(meta.inputsStructure, prompt, file);
const operationalArguments = Array.isArray(payloadArray) ? payloadArray : [payloadArray];
await new Promise((resolve, reject) => {
activeGradioJobHandle = clientInstance.submit(executionTarget, [...operationalArguments]);
signal.addEventListener('abort', () => {
if (activeGradioJobHandle) activeGradioJobHandle.cancel();
reject(new DOMException("Aborted", "AbortError"));
}, { once: true });
activeGradioJobHandle.on("success", async (dataOutput) => {
try {
const directMediaUrl = extractDeepNestedValue(dataOutput, meta.outputSelector);
if (!directMediaUrl) throw new Error("Output path extraction parameters mismatch structural properties returned.");
let detectedMimeType = null;
try {
const probe = await fetch(directMediaUrl, { method: 'HEAD', signal });
if (!probe.ok) throw new Error("HEAD query rejected.");
detectedMimeType = probe.headers.get("content-type");
} catch (_) {
console.warn("HEAD check blocked. Using fallback matching standard rules...");
}
if (!detectedMimeType) detectedMimeType = sniffTypeFromUrlExtensions(directMediaUrl);
routeMediaByContentType(detectedMimeType, directMediaUrl);
if (meta.capabilities.download) setupSecureDownloadLink(directMediaUrl, detectedMimeType);
resolve();
} catch(e) { reject(e); }
});
activeGradioJobHandle.on("error", (errContext) => reject(new Error(errContext?.message || "Remote ZeroGPU cluster crash detected.")));
});
}
};
async function triggerInferenceEngineLifecycle() {
if (!activeInMemoryUserToken) return alert("System Rejection: Active identity parameters missing.");
const prompt = document.getElementById('promptInput').value.trim();
const file = document.getElementById('mediaFileInput').files[0];
const meta = getActiveModelMetadata();
if (!meta) return;
if (meta.inputType.endsWith("File")) {
if (!file) return alert("Validation Failed: This target parameter requires an attached media context file.");
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > MAX_FILE_SIZE_MB) return alert(`Validation Failed: Capped limit max bounds are ${MAX_FILE_SIZE_MB}MB.`);
if (meta.mimeConstraints.length > 0 && !meta.mimeConstraints.includes(file.type)) {
return alert(`Validation Failed: Invalid format. Expected parameters: ${meta.mimeConstraints.join(', ')}`);
}
} else {
if (meta.inputType === "text" && !prompt) return alert("Validation Failed: Workstation prompts are currently un-assigned.");
}
clearActiveBlobAllocations();
resetViewportStateDisplays();
currentAbortController = new AbortController();
document.getElementById('cancelBtn').classList.remove('hidden');
renderViewTagId('stateLoading');
document.getElementById('loadingStatusText').innerText = "Streaming operational variables...";
globalInferenceTimeoutId = setTimeout(() => {
if (currentAbortController) {
killActiveInferencePipelines();
alert("[Studio Timeout] Computation exceeded the global 5-minute allocation window.");
resetViewportStateDisplays();
}
}, COMPUTATION_TIMEOUT_MS);
try {
const clientWrapper = new InferenceClient(activeInMemoryUserToken);
const targetedRunner = runStrategies[meta.apiStrategy || "gradioBridge"];
await targetedRunner(clientWrapper, meta, prompt, file, currentAbortController.signal);
} catch (err) {
console.error("Execution loop dropped:", err);
const profile = normalizeError(err);
alert(`[${profile.title}] ${profile.message}`);
resetViewportStateDisplays();
} finally {
if (globalInferenceTimeoutId) { clearTimeout(globalInferenceTimeoutId); globalInferenceTimeoutId = null; }
currentAbortController = null;
activeGradioJobHandle = null;
document.getElementById('cancelBtn').classList.add('hidden');
}
}
function setupSecureDownloadLink(targetUrl, incomingMimeType) {
const anchorNode = document.getElementById('downloadBtn');
anchorNode.classList.remove('hidden');
const mimeMap = { "audio/mpeg": "mp3", "audio/mp3": "mp3", "image/png": "png", "image/jpeg": "jpg", "image/webp": "webp", "video/mp4": "mp4", "audio/wav": "wav" };
const cleanExtension = mimeMap[incomingMimeType] || incomingMimeType.split('/')[1]?.split(';')[0] || "bin";
const generatedFilename = `generation.${cleanExtension}`;
anchorNode.onclick = async (e) => {
e.preventDefault();
const originalText = anchorNode.innerText;
try {
anchorNode.innerText = "⏳ Preparing Byte Streams...";
anchorNode.style.pointerEvents = "none";
const fetchStream = await fetch(targetUrl);
if (!fetchStream.ok) throw new Error("CORS origin restrictions blocked asset retrieval operations.");
const blobData = await fetchStream.blob();
if (targetDownloadBlobURL) URL.revokeObjectURL(targetDownloadBlobURL);
targetDownloadBlobURL = URL.createObjectURL(blobData);
anchorNode.href = targetDownloadBlobURL;
anchorNode.setAttribute("download", generatedFilename);
const transientAnchor = document.createElement('a');
transientAnchor.href = targetDownloadBlobURL;
transientAnchor.download = generatedFilename;
document.body.appendChild(transientAnchor);
transientAnchor.click();
document.body.removeChild(transientAnchor);
} catch (e) {
console.error("Download fallback sequence routing triggered...", e);
window.open(targetUrl, '_blank', 'noopener,noreferrer');
} finally {
anchorNode.innerText = originalText;
anchorNode.style.pointerEvents = "auto";
}
};
}
async function writeTextToClipboardSecurely() {
if (!cachedRawText) return;
try {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(cachedRawText);
confirmSuccessTextStyles();
return;
}
} catch (e) { console.warn("Clipboard mapping context fallbacks initialized..."); }
const area = document.createElement("textarea");
area.value = cachedRawText; area.style.position = "fixed"; area.style.left = "-9999px";
document.body.appendChild(area); area.select(); area.setSelectionRange(0, 99999);
try {
if (document.execCommand("copy")) confirmSuccessTextStyles();
} catch (err) { alert("Clipboard actions blocked on this browser context configuration."); }
document.body.removeChild(area);
}
function confirmSuccessTextStyles() {
const btn = document.getElementById('copyBtn'); btn.innerText = "💥 Copied!";
setTimeout(() => { btn.innerText = "📋 Copy Text"; }, 2000);
}
function executeBase64FileConversion(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader(); reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result); reader.onerror = e => reject(e);
});
}