groqnote_dev / public /utils.js
trretretret's picture
fix
06c9e63
const utils = {
Recorder: class Recorder {
constructor() {
this.isRecording = false;
this.mediaRecorder;
this.encodeType = "audio/mpeg";
this.language = "en";
this.recordingColor = "lightblue";
this.autoStop=true;
}
async startRecording(
targetElement,
silenceHandler = () => {
console.log("silence detect");
},
autoStop = true
) {
targetElement = targetElement || document.querySelector(`#whisper_voice_button`);
this.stopRecording();
console.log("start recording");
return navigator.mediaDevices
.getUserMedia({ audio: true })
.then((stream) => {
this.mediaRecorder = new MediaRecorder(stream);
let silenceStart = Date.now();
let silenceDuration = 0;
let mediaRecorder = this.mediaRecorder;
let audioChunks = [];
mediaRecorder.start();
this.isRecording = true;
targetElement.style.backgroundColor = "rgba(173, 216, 230, 0.3)";
let volumeInterval;
let audioContext;
audioContext = new AudioContext();
const analyser = audioContext.createAnalyser();
const microphone = audioContext.createMediaStreamSource(
mediaRecorder.stream
);
microphone.connect(analyser);
analyser.fftSize = 512;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
const updateButtonFontSize = () => {
analyser.getByteFrequencyData(dataArray);
let sum = 0;
for (let i = 0; i < bufferLength; i++) {
sum += dataArray[i];
}
let averageVolume = sum / bufferLength;
if (averageVolume < 10) {
silenceDuration = Date.now() - silenceStart;
if (silenceDuration > 1000) {
silenceHandler();
}
} else {
silenceStart = Date.now();
}
let scale = 3 + averageVolume / 15;
targetElement.style.transform = `scale(${scale})`;
};
volumeInterval = setInterval(updateButtonFontSize, 100);
mediaRecorder.addEventListener("dataavailable", (event) => {
console.log("dataavailable");
audioChunks.push(event.data);
});
return new Promise((resolve, reject) => {
mediaRecorder.addEventListener("stop", async () => {
this.isRecording = false;
console.log("stop");
clearInterval(volumeInterval);
const audioBlob = new Blob(audioChunks, {
type: this.encodeType,
});
targetElement.style.transform = `scale(1)`;
targetElement.style.background = "transparent";
audioContext?.close();
mediaRecorder.stream.getTracks().forEach((track) => track.stop());
console.log("resolved ");
resolve(audioBlob);
});
});
})
.catch((error) => {
if (
error.name === "PermissionDeniedError" ||
error.name === "NotAllowedError"
) {
console.error("User denied permission to access audio");
console.log("Audio permission denied");
} else {
console.error(
"An error occurred while accessing the audio device",
error
);
}
});
}
async startRecordingWithSilenceDetection(
targetElement,silenceHandler = () => console.log("silence detect")) {
let autoStop = this.autoStop || true;
this.stopRecording();
console.log("start recording");
return navigator.mediaDevices
.getUserMedia({ audio: true })
.then((stream) => {
this.mediaRecorder = new MediaRecorder(stream);
let startTime = Date.now();
let isSilent = false;
let isLongSilent = true;
let silenceStart = Date.now();
let silenceDuration = 0;
let mediaRecorder = this.mediaRecorder;
let audioChunks = [];
mediaRecorder.start();
this.isRecording = true;
targetElement.style.backgroundColor = "rgba(173, 216, 230, 0.3)";
let volumeInterval;
let audioContext;
audioContext = new AudioContext();
const analyser = audioContext.createAnalyser();
const microphone = audioContext.createMediaStreamSource(
mediaRecorder.stream
);
microphone.connect(analyser);
analyser.fftSize = 512;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
const handleAudioData = () => {
analyser.getByteFrequencyData(dataArray);
let sum = 0;
for (let i = 0; i < bufferLength; i++) {
sum += dataArray[i];
}
let averageVolume = sum / bufferLength;
if (averageVolume < 15) {
if (isSilent) {
silenceDuration = Date.now() - silenceStart;
if (silenceDuration > 3000) {
isLongSilent = true;
mediaRecorder.requestData();
silenceStart = Date.now();
}
} else {
silenceDuration = Date.now() - silenceStart;
if (silenceDuration > 1000) {
isSilent = true;
console.log('change isSilent to true');
mediaRecorder.requestData();
}
}
} else {
isSilent = false;
isLongSilent = false;
silenceStart = Date.now();
}
let scale = 3 + averageVolume / 15;
targetElement.style.transform = `scale(${scale})`;
};
volumeInterval = setInterval(handleAudioData, 100);
let counter = 0;
let firstdata;
setTimeout(() => {
mediaRecorder.requestData();
}, 200);
mediaRecorder.addEventListener("dataavailable", (event) => {
if (autoStop === true) {
if (Date.now() - startTime > 10000) {
mediaRecorder.stop();
}
}
counter++;
if (counter <= 1) {
firstdata = event.data;
if (event.data.size > 0) {
audioChunks.push(event.data);
}
return;
}
console.log("dataavailable", event.data);
if (isLongSilent) {
console.log("dataavailable,Long silent will do noting", event.data);
return;
}
silenceHandler(new Blob([firstdata, event.data], { type: mediaRecorder.mimeType }));
});
return new Promise((resolve, reject) => {
mediaRecorder.addEventListener("stop", async () => {
this.isRecording = false;
console.log("stop");
clearInterval(volumeInterval);
const audioBlob = new Blob(audioChunks, {
type: this.encodeType,
});
targetElement.style.transform = `scale(1)`;
targetElement.style.background = "transparent";
audioContext?.close();
mediaRecorder.stream.getTracks().forEach((track) => track.stop());
console.log("resolved ");
resolve(audioBlob);
});
});
})
.catch((error) => {
if (
error.name === "PermissionDeniedError" ||
error.name === "NotAllowedError"
) {
console.error("User denied permission to access audio");
showNotification("Audio permission denied");
} else {
console.error(
"An error occurred while accessing the audio device",
error
);
showNotification("Error accessing audio device");
}
});
}
stopRecording() {
this.isRecording = false;
this.mediaRecorder?.stop();
this.mediaRecorder?.audioContext?.close();
this.mediaRecorder?.stream?.getTracks().forEach((track) => track.stop());
}
},
tts: function synthesizeSpeech(text = 'test text', voice = 'alloy') {
let url = `https://im1111-free-get-tts.hf.space/tts/${encodeURIComponent(text)}`;
let container = document.getElementById("devlent_tts_container");
if (!container) {
container = document.createElement("div");
container.id = "devlent_tts_container";
document.body.appendChild(container);
}
let audio = document.getElementById("tts_audio");
if (!audio) {
audio = document.createElement("audio");
audio.id = "tts_audio";
container.appendChild(audio);
let button = document.createElement("button");
button.innerHTML = "x";
button.style.backgroundColor = 'transparent';
button.style.marginLeft = '10px';
button.addEventListener('pointerdown', () => container.style.display = "none")
let br = document.createElement('br');
container.prepend(br);
container.prepend(button);
}
container.style.display = "block";
container.style.position = "fixed";
container.style.top = "20px";
container.style.right = "0";
container.style.height = 'fit-content'
if (!text) return;
audio.src = url;
audio.controls = true;
audio.autoplay = true;
utils.dragElement(container, container)
},
stt: async (audioBlob) => {
const formData = new FormData();
formData.append("file", audioBlob, "audio.mp3");
formData.append("model", "whisper-large-v3");
try {
const response = await fetch('/openai/v1/audio/transcriptions', {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(`Error: ${response.status} ${response.statusText}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('There was an error with the transcription request:', error);
}
},
checkValidString(str) {
if (str === undefined || str === null || str.trim() === "") {
return false;
}
if (str === "undefined" || str === "null") {
return false;
}
return true;
},
getCurrentLineString(element) {
const selection = window.getSelection();
const range = selection.getRangeAt(0);
const node = range.startContainer;
const offset = range.startOffset;
if (node.nodeType === Node.TEXT_NODE) {
const text = node.textContent;
const lineStart = text.lastIndexOf('\n', offset) + 1;
const lineEnd = text.indexOf('\n', offset);
const line = lineEnd === -1 ? text.slice(lineStart) : text.slice(lineStart, lineEnd);
return line;
}
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
let currentNode, currentLine = '';
while (currentNode = walker.nextNode()) {
const text = currentNode.textContent;
const lines = text.split('\n');
for (let i = 0; i < lines.length; i++) {
if (range.intersectsNode(currentNode)) {
currentLine = lines[i];
break;
}
}
if (currentLine !== '') {
break;
}
}
return currentLine;
},
getCursorPosition(element) {
let caretOffset = 0;
const doc = element.ownerDocument || element.document;
const win = doc.defaultView || doc.parentWindow;
let sel;
if (typeof win.getSelection != "undefined") {
sel = win.getSelection();
if (sel.rangeCount > 0) {
const range = sel.getRangeAt(0);
const preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(element);
preCaretRange.setEnd(range.endContainer, range.endOffset);
caretOffset = preCaretRange.toString().length;
}
} else if ((sel = doc.selection) && sel.type != "Control") {
const textRange = sel.createRange();
const preCaretTextRange = doc.body.createTextRange();
preCaretTextRange.moveToElementText(element);
preCaretTextRange.setEndPoint("EndToEnd", textRange);
caretOffset = preCaretTextRange.text.length;
}
console.log('caretOffset:',caretOffset);
return caretOffset;
}
,
getCurrentBlock(elem) {
elem=elem.parentElement;
const cursorPosition = this.getCursorPosition(elem);
const text = elem.innerText;
let blockStart = text.indexOf('\n\n', cursorPosition) + 2;
if (blockStart === 1) { // if we're at the start of the text
blockStart = 0;
}
let blockEnd = text.lastIndexOf('\n\n', cursorPosition);
if (blockEnd === -1) { // if we're at the end of the text
blockEnd = text.length;
}
return text.substring(blockStart, blockEnd).trim();
}
,
isEditableElement: function isEditableElement(element) {
while (element) {
if (element.contentEditable === "true") {
return true;
}
element = element.parentElement;
}
return false;
},
disableSelect: function disableSelect(element) {
element.style.userSelect = "none";
element.addEventListener("pointerdown", (e) => {
e.preventDefault();
});
},
getSelectionText: function getSelectionText() {
let activeElement = document.activeElement;
if (activeElement && activeElement.value) {
return activeElement.value.substring(
activeElement.selectionStart,
activeElement.selectionEnd
);
} else {
return window.getSelection().toString();
}
},
makeButtonFeedback: function makeButtonFeedback(button) {
let originalColor = button.style.backgroundColor || "white";
button.addEventListener("pointerdown", function () {
button.style.backgroundColor = "lightblue";
});
button.addEventListener("pointerup", function () {
setTimeout(() => { button.style.backgroundColor = originalColor; }, 1000)
});
button.addEventListener("pointercancel", function () {
setTimeout(() => { button.style.backgroundColor = originalColor; }, 1000)
});
},
showToast: function showToast(
text,
x = 0,
y = 0,
w = 200,
h = 0,
duration = 1000,
zIndex = 9999
) {
const textArea = document.createElement("textarea");
textArea.value = text;
textArea.style.width = w + "px";
textArea.style.height = h === 0 ? "auto" : h + "px";
textArea.style.borderWidth = "0";
textArea.style.outline = "none";
textArea.style.position = "fixed";
textArea.style.left = x + "px";
textArea.style.top = y + "px";
textArea.style.zIndex = zIndex;
textArea.style.backgroundColor="black";
textArea.style.color="white";
textArea.disabled = true;
document.body.appendChild(textArea);
setTimeout(() => {
document.body.removeChild(textArea);
}, duration);
},
copyToClipboard: function copyToClipboard(text) {
const textArea = document.createElement("textarea");
textArea.value = text;
textArea.style.width = "50%";
textArea.style.height = "100px";
textArea.style.borderWidth = "0";
textArea.style.outline = "none";
textArea.style.position = "fixed";
textArea.style.left = "0";
textArea.style.top = "0";
textArea.style.zIndex = "9999999";
textArea.style.backgroundColor="black";
textArea.style.color="white";
document.body.appendChild(textArea);
textArea.select();
document.execCommand("copy");
textArea.disabled = true;
textArea.value = "copyed to clipboard \n" + textArea.value;
textArea.scrollTo(10000, 100000);
setTimeout(() => {
document.body.removeChild(textArea);
}, 1000);
},
writeText: function writeText(targetElement, text, prefix = " ", endfix = " ") {
console.log("writeText(): ", targetElement);
document.execCommand("insertText", false, `${prefix}${text}${endfix}`) || utils.copyToClipboard(text);
},
dragElement: function dragElement(elmnt, movableElmnt = elmnt.parentElement, speed = 1) {
elmnt.style.touchAction = "none";
let pos1 = 0,
pos2 = 0,
pos3 = 0,
pos4 = 0;
let rmShadeTimeout;
let shadeDiv;
elmnt.addEventListener("pointerdown", (e) => {
dragMouseDown(e);
});
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.body.addEventListener("pointermove", elementDrag);
document.body.addEventListener("pointerup", closeDragElement);
shadeDiv =
document.querySelector("#shadeDivForDragElement") ||
document.createElement("div");
shadeDiv.id = "shadeDivForDragElement";
shadeDiv.style.width = "300vw";
shadeDiv.style.height = "300vh";
shadeDiv.style.position = "fixed";
shadeDiv.style.top = "0";
shadeDiv.style.left = "0";
shadeDiv.style.backgroundColor = "rgb(230,230,230,0.2)";
shadeDiv.style.zIndex = 100000;
document.body.appendChild(shadeDiv);
rmShadeTimeout = setTimeout(() => {
let shadeDiv = document.querySelector("#shadeDivForDragElement");
shadeDiv && document.body.removeChild(shadeDiv);
}, 10000);
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
movableElmnt.style.position = "fixed";
movableElmnt.style.top = e.clientY - elmnt.clientHeight / 2 + "px";
movableElmnt.style.left = e.clientX - elmnt.clientWidth / 2 + "px";
}
function closeDragElement() {
console.log("closeDragElement(): pointerup");
document.body.removeEventListener("pointermove", elementDrag);
document.body.removeEventListener("pointerup", closeDragElement);
document.body.removeChild(
document.querySelector("#shadeDivForDragElement")
);
}
},
renderMarkdown(mdString, targetElement) {
let headerPattern = /^(#{1,6})\s*(.*)$/gm;
const boldPattern = /\*\*(.*?)\*\*/g;
const linkPattern = /\[(.*?)\]\((.*?)\)/g;
const newlinePattern = /(?:\n)/g;
const inlineCodePattern = /```(.*?)```/g;
const codeBlockPattern = /```(\w+)?\n(.*?)```/gs;
let html = mdString;
let parts = html.split("```");
for (let i = 0; i < parts.length; i++) {
if (i % 2 === 0) {
parts[i] = parts[i].replace(headerPattern, (match, hash, content) => {
const level = hash.length;
return `<h${level}>${content}</h${level}>`;
});
parts[i] = parts[i].replace(newlinePattern, (match, hash, content) => {
const level = hash.length;
return `<br>`;
});
}
}
html = parts.join("```");
html = html.replace(boldPattern, "<strong>$1</strong>");
html = html.replace(linkPattern, '<a href="$2">$1</a>');
html = html.replace(codeBlockPattern, (match, language, code) => {
return `
<div class="code-block">
<button class="copy-code-btn">Copy</button>
<button class="insert-code-btn">Insert</button>
<pre id='devilentCodePre'><xmp>${code}</xmp></pre>
</div>
`;
});
html = html.replace(inlineCodePattern, "<code>$1</code>");
targetElement.innerHTML = html;
const buttons = targetElement.querySelectorAll(".code-block button");
buttons.forEach((btn) => {
btn.addEventListener("pointerdown", (e) => {
e.preventDefault();
const code = btn.parentElement.querySelector("pre").innerText;
if (btn.classList.contains("copy-code-btn")) {
utils.copyToClipboard(code);
} else if (btn.classList.contains("insert-code-btn")) {
console.log("insert button down");
utils.writeText(document.activeElement, code, "", "");
}
});
});
const copyButton = document.createElement("button");
copyButton.innerText = "Copy";
copyButton.addEventListener("pointerdown", (e) => {
e.preventDefault();
e.stopPropagation();
utils.copyToClipboard(mdString);
});
const insertButton = document.createElement("button");
insertButton.innerText = "Insert";
insertButton.addEventListener("pointerdown", (e) => {
e.preventDefault();
e.stopPropagation();
utils.writeText(document.activeElement, mdString, "", "");
});
copyButton.classList.add("copy-btn");
insertButton.classList.add("insert-btn");
let editButton = document.createElement("button");
editButton.innerText = "Edit";
editButton.addEventListener("pointerdown", (e) => {
e.preventDefault();
if (targetElement.isEditableElement) {
targetElement.setAttribute('contenteditable', 'false');
}
else {
targetElement.setAttribute('contenteditable', 'true');
}
});
editButton.classList.add("copy-btn");
const closeButton = document.createElement("button");
closeButton.innerText = "Close";
closeButton.addEventListener("pointerdown", (e) => {
e.preventDefault();
targetElement.remove();
});
closeButton.classList.add("copy-btn");
let buttonContainer = document.createElement("div");
buttonContainer.classList.add("button-container");
buttonContainer.appendChild(copyButton);
buttonContainer.appendChild(insertButton);
buttonContainer.appendChild(closeButton);
buttonContainer.appendChild(editButton);
const parentElement = targetElement;
buttonContainer.style.width = "100%";
buttonContainer.style.backgroundColor = parentElement.style.backgroundColor;
buttonContainer.style.color =
"lighten(" + buttonContainer.style.backgroundColor + ", 20%)";
targetElement.prepend(buttonContainer);
utils.dragElement(buttonContainer, targetElement);
targetElement.classList.add("markdown-container");
let markdownContainers =
document.getElementsByClassName("markdown-container");
for (let i = 0; i < markdownContainers.length; i++) {
markdownContainers[i].style.fontFamily = "Arial, sans-serif";
markdownContainers[i].style.lineHeight = "1.6";
markdownContainers[i].style.maxWidth = "800px";
markdownContainers[i].style.margin = "0 auto";
markdownContainers[i].style.padding = "0px";
markdownContainers[i].style.backgroundColor = "azure";
markdownContainers[i].style.overflow = "auto";
markdownContainers[i].style.boxShadow = "0px 0px 50px rgba(0, 0, 0, 0.4)";
}
let codeBlocks = document.getElementsByClassName("code-block");
for (let i = 0; i < codeBlocks.length; i++) {
codeBlocks[i].style.position = "relative";
}
let insertCodeBtns = document.getElementsByClassName("insert-code-btn");
let codecopyBtns = document.getElementsByClassName("copy-code-btn");
for (let i = 0; i < codecopyBtns.length; i++) {
codecopyBtns[i].style.top = "0";
codecopyBtns[i].style.position = "absolute";
codecopyBtns[i].style.right = "0";
codecopyBtns[i].style.margin = "5px";
codecopyBtns[i].style.padding = "2px 5px";
codecopyBtns[i].style.fontSize = "12px";
codecopyBtns[i].style.border = "none";
codecopyBtns[i].style.borderRadius = "3px";
codecopyBtns[i].style.backgroundColor = "#007bff";
codecopyBtns[i].style.color = "white";
codecopyBtns[i].style.cursor = "pointer";
}
for (let i = 0; i < insertCodeBtns.length; i++) {
insertCodeBtns[i].style.position = "absolute";
insertCodeBtns[i].style.top = "0";
insertCodeBtns[i].style.right = "50px";
insertCodeBtns[i].style.margin = "5px";
insertCodeBtns[i].style.padding = "2px 5px";
insertCodeBtns[i].style.fontSize = "12px";
insertCodeBtns[i].style.border = "none";
insertCodeBtns[i].style.borderRadius = "3px";
insertCodeBtns[i].style.backgroundColor = "#007bff";
insertCodeBtns[i].style.color = "white";
insertCodeBtns[i].style.cursor = "pointer";
}
let copyBtns = document.getElementsByClassName("copy-btn");
let insertBtns = document.getElementsByClassName("insert-btn");
for (let i = 0; i < copyBtns.length; i++) {
copyBtns[i].style.margin = "5px";
copyBtns[i].style.padding = "2px 5px";
copyBtns[i].style.fontSize = "12px";
copyBtns[i].style.border = "none";
copyBtns[i].style.borderRadius = "3px";
copyBtns[i].style.backgroundColor = "#007bff";
copyBtns[i].style.color = "white";
copyBtns[i].style.cursor = "pointer";
}
for (let i = 0; i < insertBtns.length; i++) {
insertBtns[i].style.margin = "5px";
insertBtns[i].style.padding = "2px 5px";
insertBtns[i].style.fontSize = "12px";
insertBtns[i].style.border = "none";
insertBtns[i].style.borderRadius = "3px";
insertBtns[i].style.backgroundColor = "#007bff";
insertBtns[i].style.color = "white";
insertBtns[i].style.cursor = "pointer";
}
let pres = targetElement.getElementsByTagName("pre");
for (let i = 0; i < pres.length; i++) {
pres[i].style.backgroundColor = "#f7f7f7";
pres[i].style.borderRadius = "5px";
pres[i].style.padding = "10px";
pres[i].style.whiteSpace = "pre-wrap";
pres[i].style.wordBreak = "break-all";
}
let codes = targetElement.getElementsByTagName("code");
for (let i = 0; i < codes.length; i++) {
codes[i].style.backgroundColor = "#f1f1f1";
codes[i].style.borderRadius = "3px";
codes[i].style.padding = "2px 5px";
codes[i].style.fontFamily = "'Courier New', Courier, monospace";
}
},
displayMarkdown(mdString) {
let containerID = "ai_input_md_dispalyer";
let container = document.getElementById(containerID);
if (container === null) {
container =
document.getElementById(containerID) || document.createElement("div");
container.id = containerID;
document.body.appendChild(container);
container.style.zIndex = "100000";
container.style.position = "fixed";
container.style.top = "70vh";
container.style.left = "0";
container.style.height = "40vh";
container.style.width = "80vw";
container.style.backgroundColor = "rgba{20,20,50,1}";
}
utils.renderMarkdown(mdString, container);
let div = document.createElement('div');
div.style.height = '3000px';
container.appendChild(div)
},
moveElementNearMouse: (mElem, targetElement, alwayInWindow = true, event) => {
let x = event.clientX + 200;
let y = event.clientY - 20;
console.log('moveElementNearMouse: ', x, y);
if (alwayInWindow) {
x = Math.abs(x);
y = Math.abs(y);
x = Math.min(x, window.innerWidth - mElem.clientWidth);
y = Math.min(y, window.innerHeight - 10 - mElem.clientHeight);
}
mElem.style.left = x + "px";
mElem.style.top = y + "px";
},
addEventListenerForActualClick(element, handler) {
let initialX, initialY;
let startTime;
element.addEventListener("pointerdown", (event) => {
initialX = event.clientX;
initialY = event.clientY;
startTime = Date.now();
});
element.addEventListener("pointerup", (event) => {
const deltaX = Math.abs(event.clientX - initialX);
const deltaY = Math.abs(event.clientY - initialY);
if (deltaX <= 10 && deltaY <= 10 && Date.now() - startTime < 1000) {
console.log(
"Minimal mouse movement (< 10px in either direction) and short duration click detected."
);
handler(event);
}
});
},
sendKeyEvent(element, key, modifiers) {
const eventDown = new KeyboardEvent("keydown", {
key: key,
code: key.toUpperCase(),
bubbles: true,
cancelable: true,
...modifiers,
});
const eventUp = new KeyboardEvent("keyup", {
key: key,
code: key.toUpperCase(),
bubbles: true,
cancelable: true,
...modifiers,
});
element.dispatchEvent(eventDown);
element.dispatchEvent(eventUp);
},
blobToBase64: function blobToBase64(blob) {
if (!(blob instanceof Blob)) {
throw new TypeError("Parameter must be a Blob object.");
}
if (!blob.size) {
throw new Error("Empty Blob provided.");
}
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result.split(",")[1]);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
},
playAudioBlob: function playAudioBlob(blob, autoPlay = true) {
const audio = new Audio();
audio.src = URL.createObjectURL(blob);
audio.controls = true;
document.body.prepend(audio);
if (autoPlay === true) {
audio
.play()
.then(() => {
console.log("Audio played successfully!");
})
.catch((error) => {
console.error("Error playing audio:", error);
});
}
},
async AIComplete(userText, option = {
url: '/openai/v1/chat/completions',
model: 'llama3-70b-8192',
max_tokens: 8000,
}) {
console.log("AIcomplete(): ", userText);
if (utils.checkValidString(userText) === false) {
return;
}
let response = await fetch(
option.url,
{
headers: {
accept: "*/*",
"content-type": "application/json",
},
body: JSON.stringify({
messages: [{
"role": "system",
"content": "be concise and clear."
},
{ role: "user", content: userText }],
model: option.model,
tools: [],
temperature: 0.7,
top_p: 0.8,
max_tokens: option.max_tokens || 1000000,
}),
method: "POST",
}
);
response = await response.json();
let responseMessage = response?.choices[0]?.message?.content;
console.log("[leptonComplete(text)]", responseMessage);
let mdContainer = document.createElement("div");
document.body.appendChild(mdContainer);
utils.displayMarkdown(userText + "\n\n" + option.model + '\n' + responseMessage);
return response;
}
};
// ... (Other external API functions: sendAudioToApi, whisperjaxws,
// sendAudioToCFWhisperApi, sendAudioToHFWhisperApi) ...
export { utils };