Files

329 lines
12 KiB
JavaScript

import { api } from "../../../scripts/api.js";
export function get_position_style(ctx, widget_width, y, node_height) {
const MARGIN = 4;
const elRect = ctx.canvas.getBoundingClientRect();
const transform = new DOMMatrix()
.scaleSelf(elRect.width / ctx.canvas.width, elRect.height / ctx.canvas.height)
.multiplySelf(ctx.getTransform())
.translateSelf(MARGIN, MARGIN + y);
return {
transformOrigin: '0 0',
transform: transform,
left: `0px`,
top: `0px`,
position: "absolute",
maxWidth: `${widget_width - MARGIN*2}px`,
maxHeight: `${node_height - MARGIN*2}px`,
width: `auto`,
height: `auto`,
}
}
export function formatAndDisplayJSON(text) {
console.log("Input text:", text); // Debug: Log the input
if (typeof text !== 'string') {
console.log("Input is not a string:", typeof text);
return "Error: Input is not a string";
}
try {
// Try to parse as JSON
const jsonObject = JSON.parse(text);
const formattedJSON = JSON.stringify(jsonObject, null, 2);
console.log("Formatted JSON:", formattedJSON); // Debug: Log the result
return formattedJSON;
} catch (jsonError) {
console.log("JSON parse error:", jsonError.message); // Debug: Log the error
// Check if it's a Python-like object
if (text.trim().startsWith('{') || text.trim().startsWith('[')) {
try {
const formattedPython = formatPythonLikeObject(text);
console.log("Formatted Python-like object:", formattedPython); // Debug: Log the result
return formattedPython || text; // Return original text if formatPythonLikeObject returns empty
} catch (pythonError) {
console.log("Python-like object formatting error:", pythonError.message); // Debug: Log the error
}
}
// If it's not JSON or a Python-like object, return the original text
console.log("Returning original text");
return text;
}
}
export function formatPythonLikeObject(text) {
let indent = 0;
let inString = false;
const formatted = [];
for (let i = 0; i < text.length; i++) {
// ... (rest of the function remains the same)
}
return formatted.join('');
}
export function chainCallback(object, property, callback) {
if (object == undefined) {
console.error("Tried to add callback to non-existant object")
return;
}
if (property in object) {
const callback_orig = object[property]
object[property] = function () {
const r = callback_orig.apply(this, arguments);
callback.apply(this, arguments);
return r
};
} else {
object[property] = callback;
}
}
export async function uploadFile(file) {
try {
const body = new FormData();
const i = file.webkitRelativePath.lastIndexOf('/');
const subfolder = file.webkitRelativePath.slice(0,i+1)
const new_file = new File([file], file.name, {
type: file.type,
lastModified: file.lastModified,
});
body.append("image", new_file);
if (i > 0) {
body.append("subfolder", subfolder);
}
const resp = await api.fetchApi("/upload/image", {
method: "POST",
body,
});
if (resp.status === 200) {
return resp.status
} else {
alert(resp.status + " - " + resp.statusText);
}
} catch (error) {
alert(error);
}
}
export function gtUIAddUploadWidget(nodeType, nodeData, widgetName, type="audio") {
chainCallback(nodeType.prototype, "onNodeCreated", function() {
const pathWidget = this.widgets.find((w) => w.name === widgetName);
const fileInput = document.createElement("input");
document.body.append(fileInput);
let uploadWidget = this.addWidget("button", "choose " + type + " to upload", "image", () => {
//clear the active click event
app.canvas.node_widget = null
fileInput.click();
});
uploadWidget.options.serialize = false;
chainCallback(this, "onRemoved", () => {
fileInput?.remove();
});
if (type == "folder") {
Object.assign(fileInput, {
type: "file",
style: "display: none",
webkitdirectory: true,
onchange: async () => {
const directory = fileInput.files[0].webkitRelativePath;
const i = directory.lastIndexOf('/');
if (i <= 0) {
throw "No directory found";
}
const path = directory.slice(0,directory.lastIndexOf('/'))
if (pathWidget.options.values.includes(path)) {
alert("A folder of the same name already exists");
return;
}
let successes = 0;
for(const file of fileInput.files) {
if (await uploadFile(file) == 200) {
successes++;
} else {
//Upload failed, but some prior uploads may have succeeded
//Stop future uploads to prevent cascading failures
//and only add to list if an upload has succeeded
if (successes > 0) {
break
} else {
return;
}
}
}
pathWidget.options.values.push(path);
pathWidget.value = path;
if (pathWidget.callback) {
pathWidget.callback(path)
}
},
});
} else if (type == "text" ) {
console.log("text here")
Object.assign(fileInput, {
type: "file",
accept: "text/plain,text/markdown,text/html,text/csv,text/xml,text/yaml,text/json,application/json,application/pdf,application/x-yaml,application/vnd.ms-excel,application/csv,application/tsv,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,text/tab-separated-values,text/info",
style: "display: none",
onchange: async () => {
if (fileInput.files.length) {
if (await uploadFile(fileInput.files[0]) != 200) {
//upload failed and file can not be added to options
return;
}
const filename = fileInput.files[0].name;
pathWidget.options.values.push(filename);
pathWidget.value = filename;
if (pathWidget.callback) {
pathWidget.callback(filename)
}
}
},
});
} else if (type == "video") {
Object.assign(fileInput, {
type: "file",
accept: "video/webm,video/mp4,video/mkv,image/gif",
style: "display: none",
onchange: async () => {
if (fileInput.files.length) {
if (await uploadFile(fileInput.files[0]) != 200) {
//upload failed and file can not be added to options
return;
}
const filename = fileInput.files[0].name;
pathWidget.options.values.push(filename);
pathWidget.value = filename;
if (pathWidget.callback) {
pathWidget.callback(filename)
}
}
},
});
} else if (type == "audio") {
Object.assign(fileInput, {
type: "file",
accept: "audio/mpeg,audio/wav,audio/x-wav,audio/ogg",
style: "display: none",
onchange: async () => {
if (fileInput.files.length) {
if (await uploadFile(fileInput.files[0]) != 200) {
//upload failed and file can not be added to options
return;
}
const filename = fileInput.files[0].name;
const filetype = fileInput.files[0].type;
pathWidget.options.values.push(filename);
pathWidget.value = filename;
if (pathWidget.callback) {
pathWidget.callback(filename)
}
// Create a URL for the audio file and set it as the source of the audio element
// const audioURL = URL.createObjectURL(filename);
// audioWidget.src = audioURL;
}
},
});
this.onDragOver = function( e) {
if (e.dataTransfer && e.dataTransfer.items) {
const audio = [...e.dataTransfer.items].find((f) => f.kind === "file" && f.type.startsWith("audio/"));
// console.log("dragover: " + audio);
// console.log(audio);
return !!audio;
}
return false;
}
this.onDragDrop = function (e) {
let handled = false;
for (const file of e.dataTransfer.files) {
if (file.type.startsWith("audio/")) {
handled = true;
uploadFile(file, !handled);
handled = true;
const filename = file.name;
pathWidget.options.values.push(filename);
pathWidget.value = filename;
if (pathWidget.callback) {
pathWidget.callback(filename)
}
}
}
return handled;
}
}else {
throw "Unknown upload type"
}
});
}
export async function getLMStudioModels(baseUrl, port) {
const url = `${baseUrl}:${port}/v1/models`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch models: ${response.status}`);
}
const modelsInfo = await response.json();
// Extract the model names
const models = modelsInfo.data.map(model => model.id);
return models;
} catch (error) {
console.error("Error fetching LM Studio models:", error);
return [];
}
}
export async function getOllamaModels(baseUrl, port) {
const url = `${baseUrl}:${port}/api/tags`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch models: ${response.status}`);
}
const modelsInfo = await response.json();
// Extract the model names
const models = modelsInfo.models.map(model => model.name);
return models;
} catch (error) {
console.error("Error fetching Ollama models:", error);
return [];
}
}
export async function updatePromptModelList(node, models) {
const modelWidget = node.widgets.find((w) => w.name === "model" || w.name === "prompt_model");
if (modelWidget){
const selectedItem = modelWidget.value;
modelWidget.options.values = models;
// if (models.length > 0) {
// modelWidget.value = models[0];
// }
const warning = "No models returned from server"
if (models.length == 0){
modelWidget.value = warning
}
if ((selectedItem === "" || selectedItem === null || selectedItem == warning) && models.length > 0 && !models.includes(selectedItem)) {
modelWidget.value = models[0];
}
}
}