Add subtitle
This commit is contained in:
@@ -8,6 +8,7 @@ function nodeObserve(node:HTMLElement){
|
||||
const triggerName = node.getAttribute('risu-trigger');
|
||||
const btnEvent = node.getAttribute('risu-btn');
|
||||
const observerAdded = node.getAttribute('risu-observer');
|
||||
const hlLang = node.getAttribute('x-hl-lang');
|
||||
|
||||
if(observerAdded){
|
||||
return
|
||||
@@ -45,13 +46,65 @@ function nodeObserve(node:HTMLElement){
|
||||
node.setAttribute('risu-observer', 'true');
|
||||
return
|
||||
}
|
||||
|
||||
if(hlLang){
|
||||
node.addEventListener('contextmenu', (e)=>{
|
||||
e.preventDefault();
|
||||
const menu = document.createElement('div');
|
||||
menu.setAttribute('class', 'fixed z-50 min-w-[160px] py-2 bg-gray-800 rounded-lg border border-gray-700')
|
||||
|
||||
const copyOption = document.createElement('div');
|
||||
copyOption.textContent = 'Copy';
|
||||
copyOption.setAttribute('class', 'px-4 py-2 text-sm text-gray-300 hover:bg-gray-700 cursor-pointer')
|
||||
copyOption.addEventListener('click', ()=>{
|
||||
navigator.clipboard.writeText(node.getAttribute('x-hl-text'));
|
||||
menu.remove();
|
||||
})
|
||||
|
||||
const downloadOption = document.createElement('div');
|
||||
downloadOption.textContent = 'Download';
|
||||
downloadOption.setAttribute('class', 'px-4 py-2 text-sm text-gray-300 hover:bg-gray-700 cursor-pointer')
|
||||
downloadOption.addEventListener('click', ()=>{
|
||||
const a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(new Blob([node.getAttribute('x-hl-text')], {type: 'text/plain'}));
|
||||
a.download = 'code.' + hlLang;
|
||||
a.click();
|
||||
menu.remove();
|
||||
})
|
||||
|
||||
menu.appendChild(copyOption);
|
||||
menu.appendChild(downloadOption);
|
||||
|
||||
menu.style.left = e.clientX + 'px';
|
||||
menu.style.top = e.clientY + 'px';
|
||||
|
||||
document.body.appendChild(menu);
|
||||
|
||||
document.addEventListener('click', ()=>{
|
||||
menu.remove();
|
||||
}, {once: true})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export async function startObserveDom(){
|
||||
//For codeblock we are using MutationObserver since it doesn't appear well
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if(node instanceof HTMLElement){
|
||||
nodeObserve(node);
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
//We are using a while loop intead of MutationObserver because MutationObserver is expensive for just a few elements
|
||||
while(true){
|
||||
document.querySelectorAll('[risu-trigger]').forEach(nodeObserve);
|
||||
document.querySelectorAll('[risu-btn]').forEach(nodeObserve);
|
||||
document.querySelectorAll('[x-hl-lang]').forEach(nodeObserve);
|
||||
await sleep(100);
|
||||
}
|
||||
}
|
||||
@@ -117,18 +117,30 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
//import language if not already loaded
|
||||
//we do not refactor this to a function because we want to keep vite to only import the languages that are needed
|
||||
let languageModule:any = null
|
||||
let shotLang = ''
|
||||
switch(lang){
|
||||
case 'js':
|
||||
case 'javascript':{
|
||||
lang = 'javascript'
|
||||
shotLang = 'js'
|
||||
if(!hljs.getLanguage('javascript')){
|
||||
languageModule = await import('highlight.js/lib/languages/javascript')
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'txt':
|
||||
case 'vtt':{
|
||||
shotLang = lang
|
||||
lang = 'plaintext'
|
||||
if(!hljs.getLanguage('plaintext')){
|
||||
languageModule = await import('highlight.js/lib/languages/plaintext')
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'py':
|
||||
case 'python':{
|
||||
lang = 'python'
|
||||
shotLang = 'py'
|
||||
if(!hljs.getLanguage('python')){
|
||||
languageModule = await import('highlight.js/lib/languages/python')
|
||||
}
|
||||
@@ -136,6 +148,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
}
|
||||
case 'css':{
|
||||
lang = 'css'
|
||||
shotLang = 'css'
|
||||
if(!hljs.getLanguage('css')){
|
||||
languageModule = await import('highlight.js/lib/languages/css')
|
||||
}
|
||||
@@ -144,6 +157,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
case 'xml':
|
||||
case 'html':{
|
||||
lang = 'xml'
|
||||
shotLang = 'xml'
|
||||
if(!hljs.getLanguage('xml')){
|
||||
languageModule = await import('highlight.js/lib/languages/xml')
|
||||
}
|
||||
@@ -151,6 +165,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
}
|
||||
case 'lua':{
|
||||
lang = 'lua'
|
||||
shotLang = 'lua'
|
||||
if(!hljs.getLanguage('lua')){
|
||||
languageModule = await import('highlight.js/lib/languages/lua')
|
||||
}
|
||||
@@ -158,6 +173,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
}
|
||||
case 'dart':{
|
||||
lang = 'dart'
|
||||
shotLang = 'dart'
|
||||
if(!hljs.getLanguage('dart')){
|
||||
languageModule = await import('highlight.js/lib/languages/dart')
|
||||
}
|
||||
@@ -165,6 +181,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
}
|
||||
case 'java':{
|
||||
lang = 'java'
|
||||
shotLang = 'java'
|
||||
if(!hljs.getLanguage('java')){
|
||||
languageModule = await import('highlight.js/lib/languages/java')
|
||||
}
|
||||
@@ -172,6 +189,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
}
|
||||
case 'rust':{
|
||||
lang = 'rust'
|
||||
shotLang = 'rs'
|
||||
if(!hljs.getLanguage('rust')){
|
||||
languageModule = await import('highlight.js/lib/languages/rust')
|
||||
}
|
||||
@@ -180,6 +198,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
case 'c':
|
||||
case 'cpp':{
|
||||
lang = 'cpp'
|
||||
shotLang = 'cpp'
|
||||
if(!hljs.getLanguage('cpp')){
|
||||
languageModule = await import('highlight.js/lib/languages/cpp')
|
||||
}
|
||||
@@ -188,6 +207,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
case 'csharp':
|
||||
case 'cs':{
|
||||
lang = 'csharp'
|
||||
shotLang = 'cs'
|
||||
if(!hljs.getLanguage('csharp')){
|
||||
languageModule = await import('highlight.js/lib/languages/csharp')
|
||||
}
|
||||
@@ -196,6 +216,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
case 'ts':
|
||||
case 'typescript':{
|
||||
lang = 'typescript'
|
||||
shotLang = 'ts'
|
||||
if(!hljs.getLanguage('typescript')){
|
||||
languageModule = await import('highlight.js/lib/languages/typescript')
|
||||
}
|
||||
@@ -203,6 +224,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
}
|
||||
case 'json':{
|
||||
lang = 'json'
|
||||
shotLang = 'json'
|
||||
if(!hljs.getLanguage('json')){
|
||||
languageModule = await import('highlight.js/lib/languages/json')
|
||||
}
|
||||
@@ -210,6 +232,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
}
|
||||
case 'yaml':{
|
||||
lang = 'yaml'
|
||||
shotLang = 'yml'
|
||||
if(!hljs.getLanguage('yaml')){
|
||||
languageModule = await import('highlight.js/lib/languages/yaml')
|
||||
}
|
||||
@@ -217,6 +240,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
}
|
||||
case 'shell':{
|
||||
lang = 'shell'
|
||||
shotLang = 'sh'
|
||||
if(!hljs.getLanguage('shell')){
|
||||
languageModule = await import('highlight.js/lib/languages/shell')
|
||||
}
|
||||
@@ -224,6 +248,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
}
|
||||
case 'bash':{
|
||||
lang = 'bash'
|
||||
shotLang = 'sh'
|
||||
if(!hljs.getLanguage('bash')){
|
||||
languageModule = await import('highlight.js/lib/languages/bash')
|
||||
}
|
||||
@@ -231,6 +256,7 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
}
|
||||
default:{
|
||||
lang = 'none'
|
||||
shotLang = 'none'
|
||||
}
|
||||
}
|
||||
if(languageModule){
|
||||
@@ -244,7 +270,9 @@ async function renderHighlightableMarkdown(data:string) {
|
||||
language: lang,
|
||||
ignoreIllegals: true
|
||||
}).value
|
||||
rendered = rendered.replace(placeholder, `<pre class="hljs"><code>${highlighted}</code></pre>`)
|
||||
rendered = rendered.replace(placeholder, `<pre class="hljs" x-hl-lang="${shotLang}" x-hl-text="${
|
||||
Buffer.from(code).toString('hex')
|
||||
}"><code>${highlighted}</code></pre>`)
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -492,8 +520,8 @@ export async function ParseMarkdown(
|
||||
data = await renderHighlightableMarkdown(data)
|
||||
}
|
||||
return decodeStyle(DOMPurify.sanitize(data, {
|
||||
ADD_TAGS: ["iframe", "style", "risu-style", "x-em"],
|
||||
ADD_ATTR: ["allow", "allowfullscreen", "frameborder", "scrolling", "risu-btn", 'risu-trigger', 'risu-mark'],
|
||||
ADD_TAGS: ["iframe", "style", "risu-style", "x-em",],
|
||||
ADD_ATTR: ["allow", "allowfullscreen", "frameborder", "scrolling", "risu-btn", 'risu-trigger', 'risu-mark', 'x-hl-lang', 'x-hl-text'],
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -500,12 +500,12 @@ async function requestOpenAI(arg:RequestDataArgumentExtended):Promise<requestDat
|
||||
}
|
||||
else{
|
||||
const prevChat = reformatedChat[reformatedChat.length-1]
|
||||
if(prevChat.role === chat.role){
|
||||
if(prevChat?.role === chat.role){
|
||||
reformatedChat[reformatedChat.length-1].content += '\n' + chat.content
|
||||
continue
|
||||
}
|
||||
else if(chat.role === 'system'){
|
||||
if(prevChat.role === 'user'){
|
||||
if(prevChat?.role === 'user'){
|
||||
reformatedChat[reformatedChat.length-1].content += '\nSystem:' + chat.content
|
||||
}
|
||||
else{
|
||||
@@ -1387,14 +1387,50 @@ async function requestGoogleCloudVertex(arg:RequestDataArgumentExtended):Promise
|
||||
for(let i=0;i<formated.length;i++){
|
||||
const chat = formated[i]
|
||||
|
||||
if(i === 0){
|
||||
if(chat.role === 'user' || chat.role === 'assistant'){
|
||||
reformatedChat.push({
|
||||
role: chat.role === 'user' ? 'USER' : 'MODEL',
|
||||
parts: [{
|
||||
text: chat.content
|
||||
}]
|
||||
})
|
||||
const prevChat = reformatedChat[reformatedChat.length-1]
|
||||
const qRole =
|
||||
chat.role === 'user' ? 'USER' :
|
||||
chat.role === 'assistant' ? 'MODEL' :
|
||||
chat.role
|
||||
|
||||
if (chat.multimodals && chat.multimodals.length > 0 && chat.role === "user") {
|
||||
let geminiParts: GeminiPart[] = [];
|
||||
|
||||
geminiParts.push({
|
||||
text: chat.content,
|
||||
});
|
||||
|
||||
for (const modal of chat.multimodals) {
|
||||
if (
|
||||
(modal.type === "image" && arg.modelInfo.flags.includes(LLMFlags.hasImageInput)) ||
|
||||
(modal.type === "audio" && arg.modelInfo.flags.includes(LLMFlags.hasAudioInput)) ||
|
||||
(modal.type === "video" && arg.modelInfo.flags.includes(LLMFlags.hasVideoInput))
|
||||
) {
|
||||
const dataurl = modal.base64;
|
||||
const base64 = dataurl.split(",")[1];
|
||||
const mediaType = dataurl.split(";")[0].split(":")[1];
|
||||
|
||||
geminiParts.push({
|
||||
inlineData: {
|
||||
mimeType: mediaType,
|
||||
data: base64,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
reformatedChat.push({
|
||||
role: "USER",
|
||||
parts: geminiParts,
|
||||
});
|
||||
|
||||
} else if (prevChat?.role === qRole) {
|
||||
reformatedChat[reformatedChat.length-1].parts[0].text += '\n' + chat.content
|
||||
continue
|
||||
}
|
||||
else if(chat.role === 'system'){
|
||||
if(prevChat?.role === 'USER'){
|
||||
reformatedChat[reformatedChat.length-1].parts[0].text += '\nsystem:' + chat.content
|
||||
}
|
||||
else{
|
||||
reformatedChat.push({
|
||||
@@ -1405,78 +1441,22 @@ async function requestGoogleCloudVertex(arg:RequestDataArgumentExtended):Promise
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
else if(chat.role === 'assistant' || chat.role === 'user'){
|
||||
reformatedChat.push({
|
||||
role: chat.role === 'user' ? 'USER' : 'MODEL',
|
||||
parts: [{
|
||||
text: chat.content
|
||||
}]
|
||||
})
|
||||
}
|
||||
else{
|
||||
const prevChat = reformatedChat[reformatedChat.length-1]
|
||||
const qRole =
|
||||
chat.role === 'user' ? 'USER' :
|
||||
chat.role === 'assistant' ? 'MODEL' :
|
||||
chat.role
|
||||
|
||||
if (chat.multimodals && chat.multimodals.length > 0 && chat.role === "user") {
|
||||
let geminiParts: GeminiPart[] = [];
|
||||
|
||||
geminiParts.push({
|
||||
text: chat.content,
|
||||
});
|
||||
|
||||
for (const modal of chat.multimodals) {
|
||||
if (
|
||||
(modal.type === "image" && arg.modelInfo.flags.includes(LLMFlags.hasImageInput)) ||
|
||||
(modal.type === "audio" && arg.modelInfo.flags.includes(LLMFlags.hasAudioInput)) ||
|
||||
(modal.type === "video" && arg.modelInfo.flags.includes(LLMFlags.hasVideoInput))
|
||||
) {
|
||||
const dataurl = modal.base64;
|
||||
const base64 = dataurl.split(",")[1];
|
||||
const mediaType = dataurl.split(";")[0].split(":")[1];
|
||||
|
||||
geminiParts.push({
|
||||
inlineData: {
|
||||
mimeType: mediaType,
|
||||
data: base64,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
reformatedChat.push({
|
||||
role: "USER",
|
||||
parts: geminiParts,
|
||||
});
|
||||
|
||||
} else if (prevChat.role === qRole) {
|
||||
reformatedChat[reformatedChat.length-1].parts[0].text += '\n' + chat.content
|
||||
continue
|
||||
}
|
||||
else if(chat.role === 'system'){
|
||||
if(prevChat.role === 'USER'){
|
||||
reformatedChat[reformatedChat.length-1].parts[0].text += '\nsystem:' + chat.content
|
||||
}
|
||||
else{
|
||||
reformatedChat.push({
|
||||
role: "USER",
|
||||
parts: [{
|
||||
text: chat.role + ':' + chat.content
|
||||
}]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
else if(chat.role === 'assistant' || chat.role === 'user'){
|
||||
reformatedChat.push({
|
||||
role: chat.role === 'user' ? 'USER' : 'MODEL',
|
||||
parts: [{
|
||||
text: chat.content
|
||||
}]
|
||||
})
|
||||
}
|
||||
else{
|
||||
reformatedChat.push({
|
||||
role: "USER",
|
||||
parts: [{
|
||||
text: chat.role + ':' + chat.content
|
||||
}]
|
||||
})
|
||||
}
|
||||
reformatedChat.push({
|
||||
role: "USER",
|
||||
parts: [{
|
||||
text: chat.role + ':' + chat.content
|
||||
}]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user