diff --git a/app.py b/app.py index b46b123a..6b863be9 100644 --- a/app.py +++ b/app.py @@ -7,7 +7,6 @@ This file is the entry point to the webui. """ from lollms.utilities import PackageManager from fastapi.middleware.cors import CORSMiddleware -from starlette.middleware.base import BaseHTTPMiddleware import threading import time @@ -71,7 +70,7 @@ packages: List[Tuple[str, str]] = [ ("freedom_search", "0.1.9"), ("scrapemaster", "0.2.1"), ("lollms_client", "0.7.5"), - ("lollmsvectordb", "1.1.4"), + ("lollmsvectordb", "1.1.5"), ] def check_pn_libs(): @@ -87,8 +86,6 @@ def check_pn_libs(): from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from starlette.responses import FileResponse -from fastapi.responses import HTMLResponse -from lollms.app import LollmsApplication from lollms.paths import LollmsPaths from lollms.main_config import LOLLMSConfig from lollms.utilities import trace_exception diff --git a/lollms_core b/lollms_core index c1ae28eb..81ef55bc 160000 --- a/lollms_core +++ b/lollms_core @@ -1 +1 @@ -Subproject commit c1ae28eb76f40e86c5f6381268269a87b4b1affe +Subproject commit 81ef55bc9e08825ef59e8a81f448843c2c6e3cf3 diff --git a/web/dist/assets/index-C-GomgrB.js b/web/dist/assets/index-BVOYu6DW.js similarity index 99% rename from web/dist/assets/index-C-GomgrB.js rename to web/dist/assets/index-BVOYu6DW.js index 596d8ebb..3397e77d 100644 --- a/web/dist/assets/index-C-GomgrB.js +++ b/web/dist/assets/index-BVOYu6DW.js @@ -3973,7 +3973,7 @@ ${e} `}strong({tokens:e}){return`${this.parser.parseInline(e)}`}em({tokens:e}){return`${this.parser.parseInline(e)}`}codespan({text:e}){return`${e}`}br(e){return"
"}del({tokens:e}){return`${this.parser.parseInline(e)}`}link({href:e,title:t,tokens:s}){const i=this.parser.parseInline(s),r=d2(e);if(r===null)return i;e=r;let o='",o}image({href:e,title:t,text:s}){const i=d2(e);if(i===null)return s;e=i;let r=`${s}{const d=a[c].flat(1/0);s=s.concat(this.walkTokens(d,t))}):a.tokens&&(s=s.concat(this.walkTokens(a.tokens,t)))}}return s}use(...e){const t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(s=>{const i={...s};if(i.async=this.defaults.async||i.async||!1,s.extensions&&(s.extensions.forEach(r=>{if(!r.name)throw new Error("extension name required");if("renderer"in r){const o=t.renderers[r.name];o?t.renderers[r.name]=function(...a){let c=r.renderer.apply(this,a);return c===!1&&(c=o.apply(this,a)),c}:t.renderers[r.name]=r.renderer}if("tokenizer"in r){if(!r.level||r.level!=="block"&&r.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");const o=t[r.level];o?o.unshift(r.tokenizer):t[r.level]=[r.tokenizer],r.start&&(r.level==="block"?t.startBlock?t.startBlock.push(r.start):t.startBlock=[r.start]:r.level==="inline"&&(t.startInline?t.startInline.push(r.start):t.startInline=[r.start]))}"childTokens"in r&&r.childTokens&&(t.childTokens[r.name]=r.childTokens)}),i.extensions=t),s.renderer){const r=this.defaults.renderer||new wu(this.defaults);for(const o in s.renderer){if(!(o in r))throw new Error(`renderer '${o}' does not exist`);if(["options","parser"].includes(o))continue;const a=o,c=s.renderer[a],d=r[a];r[a]=(...u)=>{let _=c.apply(r,u);return _===!1&&(_=d.apply(r,u)),_||""}}i.renderer=r}if(s.tokenizer){const r=this.defaults.tokenizer||new xu(this.defaults);for(const o in s.tokenizer){if(!(o in r))throw new Error(`tokenizer '${o}' does not exist`);if(["options","rules","lexer"].includes(o))continue;const a=o,c=s.tokenizer[a],d=r[a];r[a]=(...u)=>{let _=c.apply(r,u);return _===!1&&(_=d.apply(r,u)),_}}i.tokenizer=r}if(s.hooks){const r=this.defaults.hooks||new Pl;for(const o in s.hooks){if(!(o in r))throw new Error(`hook '${o}' does not exist`);if(["options","block"].includes(o))continue;const a=o,c=s.hooks[a],d=r[a];Pl.passThroughHooks.has(o)?r[a]=u=>{if(this.defaults.async)return Promise.resolve(c.call(r,u)).then(m=>d.call(r,m));const _=c.call(r,u);return d.call(r,_)}:r[a]=(...u)=>{let _=c.apply(r,u);return _===!1&&(_=d.apply(r,u)),_}}i.hooks=r}if(s.walkTokens){const r=this.defaults.walkTokens,o=s.walkTokens;i.walkTokens=function(a){let c=[];return c.push(o.call(this,a)),r&&(c=c.concat(r.call(this,a))),c}}this.defaults={...this.defaults,...i}}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return ys.lex(e,t??this.defaults)}parser(e,t){return Es.parse(e,t??this.defaults)}parseMarkdown(e){return(s,i)=>{const r={...i},o={...this.defaults,...r},a=this.onError(!!o.silent,!!o.async);if(this.defaults.async===!0&&r.async===!1)return a(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof s>"u"||s===null)return a(new Error("marked(): input parameter is undefined or null"));if(typeof s!="string")return a(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(s)+", string expected"));o.hooks&&(o.hooks.options=o,o.hooks.block=e);const c=o.hooks?o.hooks.provideLexer():e?ys.lex:ys.lexInline,d=o.hooks?o.hooks.provideParser():e?Es.parse:Es.parseInline;if(o.async)return Promise.resolve(o.hooks?o.hooks.preprocess(s):s).then(u=>c(u,o)).then(u=>o.hooks?o.hooks.processAllTokens(u):u).then(u=>o.walkTokens?Promise.all(this.walkTokens(u,o.walkTokens)).then(()=>u):u).then(u=>d(u,o)).then(u=>o.hooks?o.hooks.postprocess(u):u).catch(a);try{o.hooks&&(s=o.hooks.preprocess(s));let u=c(s,o);o.hooks&&(u=o.hooks.processAllTokens(u)),o.walkTokens&&this.walkTokens(u,o.walkTokens);let _=d(u,o);return o.hooks&&(_=o.hooks.postprocess(_)),_}catch(u){return a(u)}}}onError(e,t){return s=>{if(s.message+=` Please report this to https://github.com/markedjs/marked.`,e){const i="

An error occurred:

"+ns(s.message+"",!0)+"
";return t?Promise.resolve(i):i}if(t)return Promise.reject(s);throw s}}}const go=new u2t;function Ut(n,e){return go.parse(n,e)}Ut.options=Ut.setOptions=function(n){return go.setOptions(n),Ut.defaults=go.defaults,DO(Ut.defaults),Ut};Ut.getDefaults=Ny;Ut.defaults=Eo;Ut.use=function(...n){return go.use(...n),Ut.defaults=go.defaults,DO(Ut.defaults),Ut};Ut.walkTokens=function(n,e){return go.walkTokens(n,e)};Ut.parseInline=go.parseInline;Ut.Parser=Es;Ut.parser=Es.parse;Ut.Renderer=wu;Ut.TextRenderer=Ly;Ut.Lexer=ys;Ut.lexer=ys.lex;Ut.Tokenizer=xu;Ut.Hooks=Pl;Ut.parse=Ut;Ut.options;Ut.setOptions;Ut.use;Ut.walkTokens;Ut.parseInline;Es.parse;ys.lex;const p2t={components:{AppCard:Iwt},data(){return{apps:[],githubApps:[],favorites:[],selectedCategory:"all",selectedApp:null,appCode:"",loading:!1,message:"",successMessage:!0,searchQuery:"",selectedFile:null,isUploading:!1,error:"",sortBy:"update",sortOrder:"desc",showOnlyInstalled:!1,showOnlyUnInstalled:!1}},computed:{currentCategoryName(){return this.selectedCategory==="all"?"All Apps":this.selectedCategory},combinedApps(){this.apps.map(e=>e.name);const n=new Map(this.apps.map(e=>[e.name,{...e,installed:!0,existsInFolder:!0}]));return this.githubApps.forEach(e=>{n.has(e.name)||n.set(e.name,{...e,installed:!1,existsInFolder:!1})}),Array.from(n.values())},categories(){return[...new Set(this.combinedApps.map(n=>n.category))]},filteredApps(){return this.combinedApps.filter(n=>{const e=n.name.toLowerCase().includes(this.searchQuery.toLowerCase())||n.description.toLowerCase().includes(this.searchQuery.toLowerCase())||n.author.toLowerCase().includes(this.searchQuery.toLowerCase()),t=this.selectedCategory==="all"||n.category===this.selectedCategory,s=this.showOnlyInstalled&&n.installed||this.showOnlyUnInstalled&&!n.installed||!this.showOnlyInstalled&&!this.showOnlyUnInstalled;return e&&t&&s})},sortedAndFilteredApps(){return this.filteredApps.sort((n,e)=>{let t=0;switch(this.sortBy){case"name":t=n.name.localeCompare(e.name);break;case"author":t=n.author.localeCompare(e.author);break;case"date":t=new Date(n.creation_date)-new Date(e.creation_date);break;case"update":t=new Date(n.last_update_date)-new Date(e.last_update_date);break}return this.sortOrder==="asc"?t:-t})},favoriteApps(){return this.combinedApps.filter(n=>this.favorites.includes(n.uid))}},methods:{toggleSortOrder(){this.sortOrder=this.sortOrder==="asc"?"desc":"asc"},toggleFavorite(n){const e=this.favorites.indexOf(n);e===-1?this.favorites.push(n):this.favorites.splice(e,1),this.saveFavoritesToLocalStorage()},saveFavoritesToLocalStorage(){localStorage.setItem("appZooFavorites",JSON.stringify(this.favorites))},loadFavoritesFromLocalStorage(){const n=localStorage.getItem("appZooFavorites");console.log("savedFavorites",n),n&&(this.favorites=JSON.parse(n))},startServer(n){const e={client_id:this.$store.state.client_id,app_name:n};this.$store.state.messageBox.showBlockingMessage(`Loading server. -This may take some time the first time as some libraries need to be installed.`),Z.post("/apps/start_server",e).then(t=>{this.$store.state.messageBox.hideMessage(),console.log("Server start initiated:",t.data.message),this.$notify({type:"success",title:"Server Starting",text:t.data.message})}).catch(t=>{var s,i;this.$store.state.messageBox.hideMessage(),console.error("Error starting server:",t),this.$notify({type:"error",title:"Server Start Failed",text:((i=(s=t.response)==null?void 0:s.data)==null?void 0:i.detail)||"An error occurred while starting the server"})})},triggerFileInput(){this.$refs.fileInput.click()},onFileSelected(n){this.selectedFile=n.target.files[0],this.message="",this.error="",this.uploadApp()},async uploadApp(){var e,t;if(!this.selectedFile){this.error="Please select a file to upload.";return}this.isUploading=!0,this.message="",this.error="";const n=new FormData;n.append("file",this.selectedFile),n.append("client_id",this.$store.state.client_id);try{const s=await Z.post("/upload_app",n,{headers:{"Content-Type":"multipart/form-data"}});this.message=s.data.message,this.$refs.fileInput.value="",this.selectedFile=null}catch(s){console.error("Error uploading app:",s),this.error=((t=(e=s.response)==null?void 0:e.data)==null?void 0:t.detail)||"Failed to upload the app. Please try again."}finally{this.isUploading=!1}},async fetchApps(){this.loading=!0;try{const n=await Z.get("/apps");this.apps=n.data,this.showMessage("Refresh successful!",!0)}catch{this.showMessage("Failed to refresh apps.",!1)}finally{this.loading=!1}},async openAppsFolder(){this.loading=!0;try{console.log("opening apps folder");const n=await Z.post("/show_apps_folder",{client_id:this.$store.state.client_id})}catch{this.showMessage("Failed to open apps folder.",!1)}finally{this.loading=!1}},async fetchGithubApps(){this.loading=!0;try{const n=await Z.get("/github/apps");this.githubApps=n.data.apps,await this.fetchApps()}catch{this.showMessage("Failed to refresh GitHub apps.",!1)}finally{this.loading=!1}},async handleAppClick(n){if(n.installed){this.selectedApp=n;const e=await Z.get(`/apps/${n.folder_name}/README.md`);this.appCode=Ut(e.data)}else this.showMessage(`Please install ${n.folder_name} to view its code.`,!1)},backToZoo(){this.selectedApp=null,this.appCode=""},async installApp(n){this.loading=!0,this.$store.state.messageBox.showBlockingMessage(`Installing app ${n}`);try{await Z.post(`/install/${n}`,{client_id:this.$store.state.client_id}),this.showMessage("Installation succeeded!",!0)}catch{this.showMessage("Installation failed.",!1)}finally{this.loading=!1,this.fetchApps(),this.fetchGithubApps(),this.$store.state.messageBox.hideMessage()}},async uninstallApp(n){this.loading=!0;try{await Z.post(`/uninstall/${n}`,{client_id:this.$store.state.client_id}),this.showMessage("Uninstallation succeeded!",!0)}catch{this.showMessage("Uninstallation failed.",!1)}finally{this.loading=!1,this.fetchApps()}},async deleteApp(n){this.loading=!0;try{await Z.post(`/delete/${n}`,{client_id:this.$store.state.client_id}),this.showMessage("Deletion succeeded!",!0)}catch{this.showMessage("Deletion failed.",!1)}finally{this.loading=!1,this.fetchApps()}},async editApp(n){this.loading=!0;try{const e=await Z.post("/open_app_in_vscode",{client_id:this.$store.state.client_id,app_name:n.folder_name});this.showMessage(e.data.message,!0)}catch{this.showMessage("Failed to open folder in VSCode.",!1)}finally{this.loading=!1}},async downloadApp(n){this.isLoading=!0,this.error=null;try{const e=await Z.post("/download_app",{client_id:this.$store.state.client_id,app_name:n},{responseType:"arraybuffer"}),t=e.headers["content-disposition"],s=t&&t.match(/filename="?(.+)"?/i),i=s?s[1]:"app.zip",r=new Blob([e.data],{type:"application/zip"}),o=window.URL.createObjectURL(r),a=document.createElement("a");a.style.display="none",a.href=o,a.download=i,document.body.appendChild(a),a.click(),window.URL.revokeObjectURL(o),document.body.removeChild(a)}catch(e){console.error("Error downloading app:",e),this.error="Failed to download the app. Please try again."}finally{this.isLoading=!1}},openApp(n){n.installed?window.open(`/apps/${n.folder_name}/index.html?client_id=${this.$store.state.client_id}`,"_blank"):this.showMessage(`Please install ${n.name} before opening.`,!1)},showMessage(n,e){this.message=n,this.successMessage=e,setTimeout(()=>{this.message=""},3e3)}},mounted(){this.fetchGithubApps(),this.loadFavoritesFromLocalStorage()}},f2t={class:"app-zoo background-color w-full p-6 overflow-y-auto scrollbar-thin scrollbar-track-bg-light-tone scrollbar-thumb-bg-light-tone-panel hover:scrollbar-thumb-primary dark:scrollbar-track-bg-dark-tone dark:scrollbar-thumb-bg-dark-tone-panel dark:hover:scrollbar-thumb-primary active:scrollbar-thumb-secondary"},_2t={class:"panels-color shadow-lg rounded-lg p-4 max-w-4xl mx-auto mb-50 pb-50"},m2t={class:"flex flex-wrap items-center justify-between gap-4"},h2t={class:"flex items-center space-x-4"},g2t=["disabled"],b2t={key:0},y2t={key:1,class:"error"},E2t={class:"relative flex-grow max-w-md"},v2t={class:"flex items-center space-x-4"},S2t=["value"],T2t={class:"flex items-center space-x-4"},x2t={for:"installed-only",class:"font-semibold"},C2t={for:"installed-only",class:"font-semibold"},w2t={class:"flex items-center space-x-4"},R2t={key:0,class:"flex justify-center items-center space-x-2 my-8","aria-live":"polite"},A2t={key:1},N2t={class:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-8"},M2t={class:"text-2xl font-bold mb-4"},O2t={class:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"},I2t={key:2,class:"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"},k2t={class:"bg-white rounded-lg p-6 w-11/12 h-5/6 flex flex-col"},D2t={class:"flex justify-between items-center mb-4"},L2t={class:"text-2xl font-bold"},P2t=["srcdoc"],F2t={key:1,class:"text-center text-red-500"};function U2t(n,e,t,s,i,r){const o=et("app-card");return T(),w("div",f2t,[l("nav",_2t,[l("div",m2t,[l("div",h2t,[l("button",{onClick:e[0]||(e[0]=(...a)=>r.fetchGithubApps&&r.fetchGithubApps(...a)),class:"btn btn-primary","aria-label":"Refresh apps from GitHub"},e[11]||(e[11]=[l("svg",{class:"w-5 h-5 mr-2",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg"},[l("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"})],-1),Ze(" Refresh ")])),l("button",{onClick:e[1]||(e[1]=(...a)=>r.openAppsFolder&&r.openAppsFolder(...a)),class:"btn btn-secondary","aria-label":"Open apps folder"},e[12]||(e[12]=[l("svg",{class:"w-5 h-5 mr-2",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg"},[l("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M5 19a2 2 0 01-2-2V7a2 2 0 012-2h4l2 2h4a2 2 0 012 2v1M5 19h14a2 2 0 002-2v-5a2 2 0 00-2-2H9a2 2 0 00-2 2v5a2 2 0 01-2 2z"})],-1),Ze(" Open Folder ")])),l("input",{type:"file",onChange:e[2]||(e[2]=(...a)=>r.onFileSelected&&r.onFileSelected(...a)),accept:".zip",ref:"fileInput",style:{display:"none"}},null,544),l("button",{onClick:e[3]||(e[3]=(...a)=>r.triggerFileInput&&r.triggerFileInput(...a)),disabled:i.isUploading,class:"btn-secondary text-green-500 hover:text-green-600 transition duration-300 ease-in-out",title:"Upload App"},W(i.isUploading?"Uploading...":"Upload App"),9,g2t)]),i.message?(T(),w("p",b2t,W(i.message),1)):B("",!0),i.error?(T(),w("p",y2t,W(i.error),1)):B("",!0),l("div",E2t,[D(l("input",{"onUpdate:modelValue":e[4]||(e[4]=a=>i.searchQuery=a),placeholder:"Search apps...",class:"w-full border-b-2 border-gray-300 px-4 py-2 pl-10 focus:outline-none focus:border-blue-500 transition duration-300 ease-in-out","aria-label":"Search apps"},null,512),[[ue,i.searchQuery]]),e[13]||(e[13]=l("svg",{class:"w-5 h-5 text-gray-400 absolute left-3 top-1/2 transform -translate-y-1/2",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg"},[l("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})],-1))]),l("div",v2t,[e[15]||(e[15]=l("label",{for:"category-select",class:"font-semibold"},"Category:",-1)),D(l("select",{id:"category-select","onUpdate:modelValue":e[5]||(e[5]=a=>i.selectedCategory=a),class:"border-2 border-gray-300 rounded-md px-2 py-1"},[e[14]||(e[14]=l("option",{value:"all"},"All Categories",-1)),(T(!0),w(Be,null,Xe(r.categories,a=>(T(),w("option",{key:a,value:a},W(a),9,S2t))),128))],512),[[It,i.selectedCategory]])]),l("div",T2t,[l("label",x2t,[D(l("input",{id:"installed-only",type:"checkbox","onUpdate:modelValue":e[6]||(e[6]=a=>i.showOnlyInstalled=a),class:"mr-2"},null,512),[[qe,i.showOnlyInstalled]]),e[16]||(e[16]=Ze(" Show only installed apps "))]),l("label",C2t,[D(l("input",{id:"uninstalled-only",type:"checkbox","onUpdate:modelValue":e[7]||(e[7]=a=>i.showOnlyUnInstalled=a),class:"mr-2"},null,512),[[qe,i.showOnlyUnInstalled]]),e[17]||(e[17]=Ze(" Show only non installed apps "))])]),l("div",w2t,[e[19]||(e[19]=l("label",{for:"sort-select",class:"font-semibold"},"Sort by:",-1)),D(l("select",{id:"sort-select","onUpdate:modelValue":e[8]||(e[8]=a=>i.sortBy=a),class:"border-2 border-gray-300 rounded-md px-2 py-1"},e[18]||(e[18]=[l("option",{value:"name"},"Name",-1),l("option",{value:"author"},"Author",-1),l("option",{value:"date"},"Creation Date",-1),l("option",{value:"update"},"Last Update",-1)]),512),[[It,i.sortBy]]),l("button",{onClick:e[9]||(e[9]=(...a)=>r.toggleSortOrder&&r.toggleSortOrder(...a)),class:"btn btn-secondary"},W(i.sortOrder==="asc"?"↑":"↓"),1)])])]),i.loading?(T(),w("div",R2t,e[20]||(e[20]=[l("div",{class:"animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-blue-500"},null,-1),l("span",{class:"text-xl text-gray-700 font-semibold"},"Loading...",-1)]))):(T(),w("div",A2t,[e[21]||(e[21]=l("h2",{class:"text-2xl font-bold mb-4"},"Favorite Apps",-1)),l("div",N2t,[(T(!0),w(Be,null,Xe(r.favoriteApps,a=>(T(),at(o,{key:a.uid,app:a,onToggleFavorite:r.toggleFavorite,onInstall:r.installApp,onUninstall:r.uninstallApp,onDelete:r.deleteApp,onEdit:r.editApp,onDownload:r.downloadApp,onHelp:r.handleAppClick,onOpen:r.openApp,onStartServer:r.startServer},null,8,["app","onToggleFavorite","onInstall","onUninstall","onDelete","onEdit","onDownload","onHelp","onOpen","onStartServer"]))),128))]),l("h2",M2t,W(r.currentCategoryName)+" ("+W(r.sortedAndFilteredApps.length)+")",1),l("div",O2t,[(T(!0),w(Be,null,Xe(r.sortedAndFilteredApps,a=>(T(),at(o,{key:a.uid,app:a,onToggleFavorite:r.toggleFavorite,onInstall:r.installApp,onUninstall:r.uninstallApp,onDelete:r.deleteApp,onEdit:r.editApp,onDownload:r.downloadApp,onHelp:r.handleAppClick,onOpen:r.openApp,onStartServer:r.startServer},null,8,["app","onToggleFavorite","onInstall","onUninstall","onDelete","onEdit","onDownload","onHelp","onOpen","onStartServer"]))),128))])])),i.selectedApp?(T(),w("div",I2t,[l("div",k2t,[l("div",D2t,[l("h2",L2t,W(i.selectedApp.name),1),l("button",{onClick:e[10]||(e[10]=(...a)=>r.backToZoo&&r.backToZoo(...a)),class:"bg-gray-300 hover:bg-gray-400 px-4 py-2 rounded-lg transition duration-300 ease-in-out"},"Close")]),i.appCode?(T(),w("iframe",{key:0,srcdoc:i.appCode,class:"flex-grow border-none"},null,8,P2t)):(T(),w("p",F2t,"Please install this app to view its code."))])])):B("",!0),i.message?(T(),w("div",{key:3,class:Ue(["fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-md",{"bg-green-100 text-green-800":i.successMessage,"bg-red-100 text-red-800":!i.successMessage}])},W(i.message),3)):B("",!0)])}const B2t=it(p2t,[["render",U2t]]),G2t={components:{PersonalityEntry:Y0},data(){return{personalities:[],githubApps:[],favorites:[],selectedCategory:"all",selectedApp:null,appCode:"",loading:!1,message:"",successMessage:!0,searchQuery:"",selectedFile:null,isUploading:!1,error:"",sortBy:"name",sortOrder:"asc"}},computed:{currentCategoryName(){return this.selectedCategory=="all"?"All Personalities":this.selectedCategory},configFile:{get(){return this.$store.state.config},set(n){this.$store.commit("setConfig",n)}},combinedApps(){this.personalities.map(e=>e.name);const n=new Map(this.personalities.map(e=>[e.name,{...e,installed:!0,existsInFolder:!0}]));return this.githubApps.forEach(e=>{n.has(e.name)||n.set(e.name,{...e,installed:!1,existsInFolder:!1})}),Array.from(n.values())},categories(){return[...new Set(this.combinedApps.map(n=>n.category))].sort((n,e)=>n.localeCompare(e))},filteredApps(){return this.combinedApps.filter(n=>{const e=n.name.toLowerCase().includes(this.searchQuery.toLowerCase())||n.author.toLowerCase().includes(this.searchQuery.toLowerCase())||n.description.toLowerCase().includes(this.searchQuery.toLowerCase()),t=this.selectedCategory==="all"||n.category===this.selectedCategory;return e&&t})},sortedAndFilteredApps(){return this.filteredApps.sort((n,e)=>{let t=0;switch(this.sortBy){case"name":t=n.name.localeCompare(e.name);break;case"author":t=n.author.localeCompare(e.author);break;case"date":t=new Date(n.creation_date)-new Date(e.creation_date);break;case"update":t=new Date(n.last_update_date)-new Date(e.last_update_date);break}return this.sortOrder==="asc"?t:-t})},favoriteApps(){return this.combinedApps.filter(n=>this.favorites.includes(n.uid))}},methods:{async onPersonalitySelected(n){if(console.log("on pers",n),this.isLoading&&this.$store.state.toast.showToast("Loading... please wait",4,!1),this.isLoading=!0,console.log("selecting ",n),n){if(n.selected){this.$store.state.toast.showToast("Personality already selected",4,!0),this.isLoading=!1;return}let e=n.language==null?n.full_path:n.full_path+":"+n.language;if(console.log("pth",e),n.isMounted&&this.configFile.personalities.includes(e)){const t=await this.select_personality(n);console.log("pers is mounted",t),t&&t.status&&t.active_personality_id>-1?this.$store.state.toast.showToast(`Selected personality: +This may take some time the first time as some libraries need to be installed.`),Z.post("/apps/start_server",e).then(t=>{this.$store.state.messageBox.hideMessage(),console.log("Server start initiated:",t.data.message),this.$notify({type:"success",title:"Server Starting",text:t.data.message})}).catch(t=>{var s,i;this.$store.state.messageBox.hideMessage(),console.error("Error starting server:",t),this.$notify({type:"error",title:"Server Start Failed",text:((i=(s=t.response)==null?void 0:s.data)==null?void 0:i.detail)||"An error occurred while starting the server"})})},triggerFileInput(){this.$refs.fileInput.click()},onFileSelected(n){this.selectedFile=n.target.files[0],this.message="",this.error="",this.uploadApp()},async uploadApp(){var e,t;if(!this.selectedFile){this.error="Please select a file to upload.";return}this.isUploading=!0,this.message="",this.error="";const n=new FormData;n.append("file",this.selectedFile),n.append("client_id",this.$store.state.client_id);try{const s=await Z.post("/upload_app",n,{headers:{"Content-Type":"multipart/form-data"}});this.message=s.data.message,this.$refs.fileInput.value="",this.selectedFile=null}catch(s){console.error("Error uploading app:",s),this.error=((t=(e=s.response)==null?void 0:e.data)==null?void 0:t.detail)||"Failed to upload the app. Please try again."}finally{this.isUploading=!1}},async fetchApps(){this.loading=!0;try{const n=await Z.get("/apps");this.apps=n.data,this.showMessage("Refresh successful!",!0)}catch{this.showMessage("Failed to refresh apps.",!1)}finally{this.loading=!1}},async openAppsFolder(){this.loading=!0;try{console.log("opening apps folder");const n=await Z.post("/show_apps_folder",{client_id:this.$store.state.client_id})}catch{this.showMessage("Failed to open apps folder.",!1)}finally{this.loading=!1}},async fetchGithubApps(){this.loading=!0;try{const n=await Z.get("/github/apps");this.githubApps=n.data.apps,await this.fetchApps()}catch{this.showMessage("Failed to refresh GitHub apps.",!1)}finally{this.loading=!1}},async handleAppClick(n){if(n.installed){this.selectedApp=n;const e=await Z.get(`/apps/${n.folder_name}/README.md`);this.appCode=Ut(e.data)}else this.showMessage(`Please install ${n.folder_name} to view its code.`,!1)},backToZoo(){this.selectedApp=null,this.appCode=""},async installApp(n){this.loading=!0,this.$store.state.messageBox.showBlockingMessage(`Installing app ${n}`);try{await Z.post(`/install/${n}`,{client_id:this.$store.state.client_id}),this.showMessage("Installation succeeded!",!0)}catch{this.showMessage("Installation failed.",!1)}finally{this.loading=!1,this.fetchApps(),this.fetchGithubApps(),this.$store.state.messageBox.hideMessage()}},async uninstallApp(n){this.loading=!0;try{await Z.post(`/uninstall/${n}`,{client_id:this.$store.state.client_id}),this.showMessage("Uninstallation succeeded!",!0)}catch{this.showMessage("Uninstallation failed.",!1)}finally{this.loading=!1,this.fetchApps()}},async deleteApp(n){this.loading=!0;try{await Z.post(`/delete/${n}`,{client_id:this.$store.state.client_id}),this.showMessage("Deletion succeeded!",!0)}catch{this.showMessage("Deletion failed.",!1)}finally{this.loading=!1,this.fetchApps()}},async editApp(n){this.loading=!0;try{const e=await Z.post("/open_app_in_vscode",{client_id:this.$store.state.client_id,app_name:n.folder_name});this.showMessage(e.data.message,!0)}catch{this.showMessage("Failed to open folder in VSCode.",!1)}finally{this.loading=!1}},async downloadApp(n){this.isLoading=!0,this.error=null;try{const e=await Z.post("/download_app",{client_id:this.$store.state.client_id,app_name:n},{responseType:"arraybuffer"}),t=e.headers["content-disposition"],s=t&&t.match(/filename="?(.+)"?/i),i=s?s[1]:"app.zip",r=new Blob([e.data],{type:"application/zip"}),o=window.URL.createObjectURL(r),a=document.createElement("a");a.style.display="none",a.href=o,a.download=i,document.body.appendChild(a),a.click(),window.URL.revokeObjectURL(o),document.body.removeChild(a)}catch(e){console.error("Error downloading app:",e),this.error="Failed to download the app. Please try again."}finally{this.isLoading=!1}},openApp(n){n.installed?window.open(`/apps/${n.folder_name}/index.html?client_id=${this.$store.state.client_id}`,"_blank"):this.showMessage(`Please install ${n.name} before opening.`,!1)},showMessage(n,e){this.message=n,this.successMessage=e,setTimeout(()=>{this.message=""},3e3)}},mounted(){this.fetchGithubApps(),this.loadFavoritesFromLocalStorage()}},f2t={class:"app-zoo background-color w-full p-6 min-h-screen overflow-y-auto"},_2t={class:"panels-color shadow-lg rounded-lg p-4 max-w-4xl mx-auto mb-8"},m2t={class:"flex flex-wrap items-center justify-between gap-4"},h2t={class:"flex items-center space-x-4"},g2t=["disabled"],b2t={key:0},y2t={key:1,class:"error"},E2t={class:"relative flex-grow max-w-md"},v2t={class:"flex items-center space-x-4"},S2t=["value"],T2t={class:"flex items-center space-x-4"},x2t={for:"installed-only",class:"font-semibold"},C2t={for:"installed-only",class:"font-semibold"},w2t={class:"flex items-center space-x-4"},R2t={key:0,class:"flex justify-center items-center space-x-2 my-8","aria-live":"polite"},A2t={key:1,class:"pb-20"},N2t={class:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-8"},M2t={class:"text-2xl font-bold mb-4"},O2t={class:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"},I2t={key:2,class:"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"},k2t={class:"bg-white rounded-lg p-6 w-11/12 h-5/6 flex flex-col"},D2t={class:"flex justify-between items-center mb-4"},L2t={class:"text-2xl font-bold"},P2t=["srcdoc"],F2t={key:1,class:"text-center text-red-500"};function U2t(n,e,t,s,i,r){const o=et("app-card");return T(),w("div",f2t,[l("nav",_2t,[l("div",m2t,[l("div",h2t,[l("button",{onClick:e[0]||(e[0]=(...a)=>r.fetchGithubApps&&r.fetchGithubApps(...a)),class:"btn btn-primary","aria-label":"Refresh apps from GitHub"},e[11]||(e[11]=[l("svg",{class:"w-5 h-5 mr-2",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg"},[l("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"})],-1),Ze(" Refresh ")])),l("button",{onClick:e[1]||(e[1]=(...a)=>r.openAppsFolder&&r.openAppsFolder(...a)),class:"btn btn-secondary","aria-label":"Open apps folder"},e[12]||(e[12]=[l("svg",{class:"w-5 h-5 mr-2",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg"},[l("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M5 19a2 2 0 01-2-2V7a2 2 0 012-2h4l2 2h4a2 2 0 012 2v1M5 19h14a2 2 0 002-2v-5a2 2 0 00-2-2H9a2 2 0 00-2 2v5a2 2 0 01-2 2z"})],-1),Ze(" Open Folder ")])),l("input",{type:"file",onChange:e[2]||(e[2]=(...a)=>r.onFileSelected&&r.onFileSelected(...a)),accept:".zip",ref:"fileInput",style:{display:"none"}},null,544),l("button",{onClick:e[3]||(e[3]=(...a)=>r.triggerFileInput&&r.triggerFileInput(...a)),disabled:i.isUploading,class:"btn-secondary text-green-500 hover:text-green-600 transition duration-300 ease-in-out",title:"Upload App"},W(i.isUploading?"Uploading...":"Upload App"),9,g2t)]),i.message?(T(),w("p",b2t,W(i.message),1)):B("",!0),i.error?(T(),w("p",y2t,W(i.error),1)):B("",!0),l("div",E2t,[D(l("input",{"onUpdate:modelValue":e[4]||(e[4]=a=>i.searchQuery=a),placeholder:"Search apps...",class:"w-full border-b-2 border-gray-300 px-4 py-2 pl-10 focus:outline-none focus:border-blue-500 transition duration-300 ease-in-out","aria-label":"Search apps"},null,512),[[ue,i.searchQuery]]),e[13]||(e[13]=l("svg",{class:"w-5 h-5 text-gray-400 absolute left-3 top-1/2 transform -translate-y-1/2",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg"},[l("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})],-1))]),l("div",v2t,[e[15]||(e[15]=l("label",{for:"category-select",class:"font-semibold"},"Category:",-1)),D(l("select",{id:"category-select","onUpdate:modelValue":e[5]||(e[5]=a=>i.selectedCategory=a),class:"border-2 border-gray-300 rounded-md px-2 py-1"},[e[14]||(e[14]=l("option",{value:"all"},"All Categories",-1)),(T(!0),w(Be,null,Xe(r.categories,a=>(T(),w("option",{key:a,value:a},W(a),9,S2t))),128))],512),[[It,i.selectedCategory]])]),l("div",T2t,[l("label",x2t,[D(l("input",{id:"installed-only",type:"checkbox","onUpdate:modelValue":e[6]||(e[6]=a=>i.showOnlyInstalled=a),class:"mr-2"},null,512),[[qe,i.showOnlyInstalled]]),e[16]||(e[16]=Ze(" Show only installed apps "))]),l("label",C2t,[D(l("input",{id:"uninstalled-only",type:"checkbox","onUpdate:modelValue":e[7]||(e[7]=a=>i.showOnlyUnInstalled=a),class:"mr-2"},null,512),[[qe,i.showOnlyUnInstalled]]),e[17]||(e[17]=Ze(" Show only non installed apps "))])]),l("div",w2t,[e[19]||(e[19]=l("label",{for:"sort-select",class:"font-semibold"},"Sort by:",-1)),D(l("select",{id:"sort-select","onUpdate:modelValue":e[8]||(e[8]=a=>i.sortBy=a),class:"border-2 border-gray-300 rounded-md px-2 py-1"},e[18]||(e[18]=[l("option",{value:"name"},"Name",-1),l("option",{value:"author"},"Author",-1),l("option",{value:"date"},"Creation Date",-1),l("option",{value:"update"},"Last Update",-1)]),512),[[It,i.sortBy]]),l("button",{onClick:e[9]||(e[9]=(...a)=>r.toggleSortOrder&&r.toggleSortOrder(...a)),class:"btn btn-secondary"},W(i.sortOrder==="asc"?"↑":"↓"),1)])])]),i.loading?(T(),w("div",R2t,e[20]||(e[20]=[l("div",{class:"animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-blue-500"},null,-1),l("span",{class:"text-xl text-gray-700 font-semibold"},"Loading...",-1)]))):(T(),w("div",A2t,[e[21]||(e[21]=l("h2",{class:"text-2xl font-bold mb-4"},"Favorite Apps",-1)),l("div",N2t,[(T(!0),w(Be,null,Xe(r.favoriteApps,a=>(T(),at(o,{key:a.uid,app:a,onToggleFavorite:r.toggleFavorite,onInstall:r.installApp,onUninstall:r.uninstallApp,onDelete:r.deleteApp,onEdit:r.editApp,onDownload:r.downloadApp,onHelp:r.handleAppClick,onOpen:r.openApp,onStartServer:r.startServer},null,8,["app","onToggleFavorite","onInstall","onUninstall","onDelete","onEdit","onDownload","onHelp","onOpen","onStartServer"]))),128))]),l("h2",M2t,W(r.currentCategoryName)+" ("+W(r.sortedAndFilteredApps.length)+")",1),l("div",O2t,[(T(!0),w(Be,null,Xe(r.sortedAndFilteredApps,a=>(T(),at(o,{key:a.uid,app:a,onToggleFavorite:r.toggleFavorite,onInstall:r.installApp,onUninstall:r.uninstallApp,onDelete:r.deleteApp,onEdit:r.editApp,onDownload:r.downloadApp,onHelp:r.handleAppClick,onOpen:r.openApp,onStartServer:r.startServer},null,8,["app","onToggleFavorite","onInstall","onUninstall","onDelete","onEdit","onDownload","onHelp","onOpen","onStartServer"]))),128))])])),i.selectedApp?(T(),w("div",I2t,[l("div",k2t,[l("div",D2t,[l("h2",L2t,W(i.selectedApp.name),1),l("button",{onClick:e[10]||(e[10]=(...a)=>r.backToZoo&&r.backToZoo(...a)),class:"bg-gray-300 hover:bg-gray-400 px-4 py-2 rounded-lg transition duration-300 ease-in-out"},"Close")]),i.appCode?(T(),w("iframe",{key:0,srcdoc:i.appCode,class:"flex-grow border-none"},null,8,P2t)):(T(),w("p",F2t,"Please install this app to view its code."))])])):B("",!0),i.message?(T(),w("div",{key:3,class:Ue(["fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-md",{"bg-green-100 text-green-800":i.successMessage,"bg-red-100 text-red-800":!i.successMessage}])},W(i.message),3)):B("",!0)])}const B2t=it(p2t,[["render",U2t]]),G2t={components:{PersonalityEntry:Y0},data(){return{personalities:[],githubApps:[],favorites:[],selectedCategory:"all",selectedApp:null,appCode:"",loading:!1,message:"",successMessage:!0,searchQuery:"",selectedFile:null,isUploading:!1,error:"",sortBy:"name",sortOrder:"asc"}},computed:{currentCategoryName(){return this.selectedCategory=="all"?"All Personalities":this.selectedCategory},configFile:{get(){return this.$store.state.config},set(n){this.$store.commit("setConfig",n)}},combinedApps(){this.personalities.map(e=>e.name);const n=new Map(this.personalities.map(e=>[e.name,{...e,installed:!0,existsInFolder:!0}]));return this.githubApps.forEach(e=>{n.has(e.name)||n.set(e.name,{...e,installed:!1,existsInFolder:!1})}),Array.from(n.values())},categories(){return[...new Set(this.combinedApps.map(n=>n.category))].sort((n,e)=>n.localeCompare(e))},filteredApps(){return this.combinedApps.filter(n=>{const e=n.name.toLowerCase().includes(this.searchQuery.toLowerCase())||n.author.toLowerCase().includes(this.searchQuery.toLowerCase())||n.description.toLowerCase().includes(this.searchQuery.toLowerCase()),t=this.selectedCategory==="all"||n.category===this.selectedCategory;return e&&t})},sortedAndFilteredApps(){return this.filteredApps.sort((n,e)=>{let t=0;switch(this.sortBy){case"name":t=n.name.localeCompare(e.name);break;case"author":t=n.author.localeCompare(e.author);break;case"date":t=new Date(n.creation_date)-new Date(e.creation_date);break;case"update":t=new Date(n.last_update_date)-new Date(e.last_update_date);break}return this.sortOrder==="asc"?t:-t})},favoriteApps(){return this.combinedApps.filter(n=>this.favorites.includes(n.uid))}},methods:{async onPersonalitySelected(n){if(console.log("on pers",n),this.isLoading&&this.$store.state.toast.showToast("Loading... please wait",4,!1),this.isLoading=!0,console.log("selecting ",n),n){if(n.selected){this.$store.state.toast.showToast("Personality already selected",4,!0),this.isLoading=!1;return}let e=n.language==null?n.full_path:n.full_path+":"+n.language;if(console.log("pth",e),n.isMounted&&this.configFile.personalities.includes(e)){const t=await this.select_personality(n);console.log("pers is mounted",t),t&&t.status&&t.active_personality_id>-1?this.$store.state.toast.showToast(`Selected personality: `+n.name,4,!0):this.$store.state.toast.showToast(`Error on select personality: `+n.name,4,!1),this.isLoading=!1}else console.log("mounting pers"),this.mountPersonality(n);Le(()=>{feather.replace()})}},onModelSelected(n){if(this.isLoading){this.$store.state.toast.showToast("Loading... please wait",4,!1);return}n&&(n.isInstalled?this.update_model(n.model.name).then(e=>{console.log("update_model",e),this.configFile.model_name=n.model.name,e.status?(this.$store.state.toast.showToast(`Selected model: `+n.name,4,!0),Le(()=>{feather.replace(),this.is_loading_zoo=!1}),this.updateModelsZoo(),this.api_get_req("get_model_status").then(t=>{this.$store.commit("setIsModelOk",t)})):(this.$store.state.toast.showToast(`Couldn't select model: diff --git a/web/dist/index.html b/web/dist/index.html index 1fd1430d..fbc97b47 100644 --- a/web/dist/index.html +++ b/web/dist/index.html @@ -6,7 +6,7 @@ LoLLMS WebUI - + diff --git a/web/src/views/AppsZoo.vue b/web/src/views/AppsZoo.vue index 90ac7462..a469fd3f 100644 --- a/web/src/views/AppsZoo.vue +++ b/web/src/views/AppsZoo.vue @@ -1,6 +1,6 @@ +