the apps zoo is here Brainwave version
5
app.py
@ -35,7 +35,7 @@ if not PackageManager.check_package_installed_with_version("freedom_search", exp
|
||||
PackageManager.install_or_update("freedom-search")
|
||||
ASCIIColors.success("OK")
|
||||
|
||||
expected_scrapemaster_version = "0.1.4"
|
||||
expected_scrapemaster_version = "0.1.5"
|
||||
ASCIIColors.yellow(f"Checking scrapemaster ({expected_scrapemaster_version}) ...", end="", flush=True)
|
||||
if not PackageManager.check_package_installed_with_version("scrapemaster", expected_scrapemaster_version):
|
||||
PackageManager.install_or_update("scrapemaster")
|
||||
@ -214,6 +214,7 @@ if __name__ == "__main__":
|
||||
from endpoints.lollms_webui_infos import router as lollms_webui_infos_router
|
||||
from endpoints.lollms_message import router as lollms_message_router
|
||||
from endpoints.lollms_advanced import router as lollms_advanced_router
|
||||
from endpoints.lollms_apps import router as lollms_apps_router
|
||||
from endpoints.chat_bar import router as chat_bar_router
|
||||
|
||||
from endpoints.lollms_help import router as help_router
|
||||
@ -255,6 +256,8 @@ if __name__ == "__main__":
|
||||
app.include_router(lollms_message_router)
|
||||
app.include_router(lollms_user_router)
|
||||
app.include_router(lollms_advanced_router)
|
||||
app.include_router(lollms_apps_router)
|
||||
|
||||
app.include_router(chat_bar_router)
|
||||
app.include_router(help_router)
|
||||
app.include_router(lollms_xtts_add_router)
|
||||
|
BIN
assets/logo.ico
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 1.8 MiB |
BIN
assets/logo.png
Before Width: | Height: | Size: 782 KiB After Width: | Height: | Size: 1.8 MiB |
149
endpoints/lollms_apps.py
Normal file
@ -0,0 +1,149 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from fastapi.responses import FileResponse
|
||||
from lollms_webui import LOLLMSWebUI
|
||||
from pydantic import BaseModel
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import uuid
|
||||
import os
|
||||
import requests
|
||||
import yaml
|
||||
|
||||
router = APIRouter()
|
||||
lollmsElfServer: LOLLMSWebUI = LOLLMSWebUI.get_instance()
|
||||
|
||||
class AuthRequest(BaseModel):
|
||||
client_id: str
|
||||
|
||||
class AppInfo:
|
||||
def __init__(self, uid: str, name: str, icon: str, description: str, author:str, version:str, model_name:str, disclaimer:str):
|
||||
self.uid = uid
|
||||
self.name = name
|
||||
self.icon = icon
|
||||
self.description = description
|
||||
self.author = author
|
||||
self.version = version
|
||||
self.model_name = model_name
|
||||
self.disclaimer = disclaimer
|
||||
|
||||
@router.get("/apps")
|
||||
async def list_apps():
|
||||
apps = []
|
||||
binding_models_path = lollmsElfServer.lollms_paths.apps_zoo_path
|
||||
|
||||
for app_name in binding_models_path.iterdir():
|
||||
if app_name.is_dir():
|
||||
icon_path = app_name / "icon.png"
|
||||
description_path = app_name / "description.yaml"
|
||||
description = ""
|
||||
author = ""
|
||||
version = ""
|
||||
model_name = ""
|
||||
disclaimer = ""
|
||||
|
||||
if description_path.exists():
|
||||
with open(description_path, 'r') as file:
|
||||
data = yaml.safe_load(file)
|
||||
description = data.get('description', '')
|
||||
author = data.get('author', '')
|
||||
version = data.get('version', '')
|
||||
model_name = data.get('model_name', '')
|
||||
disclaimer = data.get('disclaimer', 'No disclaimer provided.')
|
||||
|
||||
if icon_path.exists():
|
||||
uid = str(uuid.uuid4())
|
||||
apps.append(AppInfo(
|
||||
uid=uid,
|
||||
name=app_name.name,
|
||||
icon=f"/apps/{app_name.name}/icon",
|
||||
description=description,
|
||||
author=author,
|
||||
version=version,
|
||||
model_name=model_name,
|
||||
disclaimer=disclaimer
|
||||
))
|
||||
|
||||
return apps
|
||||
|
||||
|
||||
@router.post("/apps/{app_name}/code")
|
||||
async def get_app_code(app_name: str, auth: AuthRequest):
|
||||
app_path = lollmsElfServer.lollms_paths.apps_zoo_path / app_name / "index.html"
|
||||
if not app_path.exists():
|
||||
raise HTTPException(status_code=404, detail="App not found")
|
||||
return FileResponse(app_path)
|
||||
|
||||
|
||||
@router.post("/install/{app_name}")
|
||||
async def install_app(app_name: str, auth: AuthRequest):
|
||||
# Create the app directory
|
||||
app_path = lollmsElfServer.lollms_paths.apps_zoo_path / app_name
|
||||
os.makedirs(app_path, exist_ok=True)
|
||||
|
||||
# Define the URLs for the files to download
|
||||
files_to_download = {
|
||||
"icon.png": f"https://github.com/ParisNeo/lollms_apps_zoo/raw/main/{app_name}/icon.png",
|
||||
"description.yaml": f"https://raw.githubusercontent.com/ParisNeo/lollms_apps_zoo/main/{app_name}/description.yaml",
|
||||
"index.html": f"https://raw.githubusercontent.com/ParisNeo/lollms_apps_zoo/main/{app_name}/index.html"
|
||||
}
|
||||
|
||||
# Download each file
|
||||
for file_name, url in files_to_download.items():
|
||||
response = requests.get(url)
|
||||
if response.status_code == 200:
|
||||
with open(app_path / file_name, 'wb') as f:
|
||||
f.write(response.content)
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail=f"{file_name} not found on GitHub")
|
||||
|
||||
return {"message": f"App {app_name} installed successfully."}
|
||||
|
||||
@router.post("/uninstall/{app_name}")
|
||||
async def uninstall_app(app_name: str, auth: AuthRequest):
|
||||
app_path = lollmsElfServer.lollms_paths.apps_zoo_path / app_name
|
||||
if app_path.exists():
|
||||
shutil.rmtree(app_path)
|
||||
return {"message": f"App {app_name} uninstalled successfully."}
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail="App not found")
|
||||
|
||||
|
||||
@router.get("/github/apps")
|
||||
async def fetch_github_apps():
|
||||
github_repo_url = "https://api.github.com/repos/ParisNeo/lollms_apps_zoo/contents"
|
||||
response = requests.get(github_repo_url)
|
||||
|
||||
if response.status_code == 200:
|
||||
apps = []
|
||||
for item in response.json():
|
||||
if item['type'] == 'dir':
|
||||
app_name = item['name']
|
||||
description_url = f"https://api.github.com/repos/ParisNeo/lollms_apps_zoo/contents/{app_name}/description.yaml"
|
||||
icon_url = f"https://github.com/ParisNeo/lollms_apps_zoo/blob/main/{app_name}/icon.png?raw=true"
|
||||
|
||||
# Fetch description.yaml
|
||||
description_response = requests.get(description_url)
|
||||
description_data = {}
|
||||
if description_response.status_code == 200:
|
||||
description_data = yaml.safe_load(requests.get(description_url).text)
|
||||
|
||||
apps.append(AppInfo(
|
||||
uid=str(uuid.uuid4()),
|
||||
name=app_name,
|
||||
icon=icon_url,
|
||||
description=description_data.get('description', ''),
|
||||
author=description_data.get('author', ''),
|
||||
version=description_data.get('version', ''),
|
||||
model_name=description_data.get('model_name', ''),
|
||||
disclaimer=description_data.get('disclaimer', 'No disclaimer provided.')
|
||||
))
|
||||
return {"apps": apps}
|
||||
else:
|
||||
raise HTTPException(status_code=response.status_code, detail="Failed to fetch apps from GitHub")
|
||||
|
||||
@router.get("/apps/{app_name}/icon")
|
||||
async def get_app_icon(app_name: str):
|
||||
icon_path = lollmsElfServer.lollms_paths.apps_zoo_path / app_name / "icon.png"
|
||||
if not icon_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Icon not found")
|
||||
return FileResponse(icon_path)
|
@ -1 +1 @@
|
||||
Subproject commit ae1cd019e1053c1ecf0fe6b0821c36d9754bfc07
|
||||
Subproject commit 9e4159c1103e61b5178d32ac2f16aa762376520d
|
@ -71,7 +71,7 @@ def terminate_thread(thread):
|
||||
else:
|
||||
ASCIIColors.yellow("Canceled successfully")# The current version of the webui
|
||||
|
||||
lollms_webui_version="10 (🧠)"
|
||||
lollms_webui_version="10 (Brainwaves)"
|
||||
|
||||
|
||||
|
||||
|
8
web/dist/assets/index-2bf4e8d6.css
vendored
8
web/dist/assets/index-4578000a.css
vendored
Normal file
BIN
web/dist/assets/logo-e4c6fdd2.png
vendored
Normal file
After Width: | Height: | Size: 1.8 MiB |
BIN
web/dist/assets/logo-f63ca8ad.png
vendored
Before Width: | Height: | Size: 782 KiB |
4
web/dist/index.html
vendored
@ -6,8 +6,8 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LoLLMS WebUI</title>
|
||||
<script type="module" crossorigin src="/assets/index-2de3b115.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-2bf4e8d6.css">
|
||||
<script type="module" crossorigin src="/assets/index-b768925e.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-4578000a.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
Before Width: | Height: | Size: 782 KiB After Width: | Height: | Size: 1.8 MiB |
@ -21,6 +21,16 @@
|
||||
>
|
||||
Playground
|
||||
</RouterLink>
|
||||
<RouterLink
|
||||
:to="{ name: 'AppsZoo' }"
|
||||
class="inline-block border-l border-t border-r rounded-t py-2 px-4 text-blue-700 font-semibold"
|
||||
:class="{
|
||||
'text-green-600 hover:text-green-500 dark:text-green-100 font-bold bg-bg-secondary shadow-no-bottom': isRouteActive('AppsZoo'),
|
||||
'bounce-in': isRouteActive('AppsZoo'),
|
||||
}"
|
||||
>
|
||||
Apps Zoo
|
||||
</RouterLink>
|
||||
<RouterLink
|
||||
v-if="$store.state.config.enable_sd_service | $store.state.config.active_tti_service== 'autosd'"
|
||||
:to="{ name: 'AutoSD' }"
|
||||
|
@ -10,17 +10,24 @@ import InteractiveView from '../views/InteractiveView.vue'
|
||||
import NodesView from '../views/NodesView.vue'
|
||||
import ComfyuiView from '../views/ComfyuiView.vue'
|
||||
import AutoSDView from '../views/AutoSDView.vue'
|
||||
import AppsZoo from '../views/AppsZoo.vue'
|
||||
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/apps_view/',
|
||||
name: 'AppsZoo',
|
||||
component: AppsZoo
|
||||
},
|
||||
{
|
||||
path: '/auto_sd_view/',
|
||||
name: 'AutoSD',
|
||||
component: AutoSDView
|
||||
},
|
||||
{
|
||||
path: '/autosd_view/',
|
||||
path: '/comfyui_view/',
|
||||
name: 'ComfyUI',
|
||||
component: ComfyuiView
|
||||
},
|
||||
|
@ -1,13 +1,12 @@
|
||||
<template>
|
||||
<div class="app-zoo">
|
||||
<h1 class="text-3xl font-bold mb-4">Apps Zoo</h1>
|
||||
<button @click="fetchGithubApps" class="bg-green-500 text-white px-4 py-2 rounded mb-4">Fetch GitHub Apps</button>
|
||||
<div class="app-list grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div class="app-zoo w-full">
|
||||
<button @click="fetchGithubApps" class="bg-green-500 text-white px-4 py-2 rounded mb-4">Refresh apps from github</button>
|
||||
<div class="app-list grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 w-full">
|
||||
<div
|
||||
v-for="app in apps"
|
||||
v-for="app in combinedApps"
|
||||
:key="app.uid"
|
||||
class="app-card border rounded-lg shadow-lg p-4 cursor-pointer hover:shadow-xl transition"
|
||||
@click="selectApp(app)"
|
||||
@click="handleAppClick(app)"
|
||||
>
|
||||
<img :src="app.icon" alt="App Icon" class="w-16 h-16 mx-auto mb-2" />
|
||||
<p class="text-center font-semibold">{{ app.name }}</p>
|
||||
@ -15,19 +14,19 @@
|
||||
<p class="text-center text-sm text-gray-600">Version: {{ app.version }}</p>
|
||||
<label class="text-center text-sm text-gray-600" for="app-description">Description:</label>
|
||||
<p id="app-description" class="text-center text-sm text-gray-600">{{ app.description }}</p>
|
||||
<p class="text-center text-sm text-gray-600">AI Model: {{ app.aiModel }}</p>
|
||||
<p class="text-center text-sm text-gray-600">AI Model: {{ app.model_name }}</p>
|
||||
<p class="text-center text-sm text-gray-600 italic">Disclaimer: {{ app.disclaimer }}</p>
|
||||
<div class="flex justify-between mt-2">
|
||||
<button @click.stop="installApp(app.name)" class="bg-blue-500 text-white px-2 py-1 rounded">Install</button>
|
||||
<button @click.stop="uninstallApp(app.name)" class="bg-red-500 text-white px-2 py-1 rounded">Uninstall</button>
|
||||
<button v-if="!app.installed" @click.stop="installApp(app.name)" class="bg-blue-500 text-white px-2 py-1 rounded">Install</button>
|
||||
<button v-if="app.installed" @click.stop="uninstallApp(app.name)" class="bg-red-500 text-white px-2 py-1 rounded">Uninstall</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selectedApp" class="app-render fixed inset-0 bg-white z-50 flex flex-col items-center justify-center">
|
||||
<button @click="backToZoo" class="absolute top-4 right-4 bg-gray-300 px-2 py-1 rounded">Back</button>
|
||||
<h2 class="text-2xl font-bold mb-4">Rendering: {{ selectedApp.name }}</h2>
|
||||
<iframe :srcdoc="appCode" class="app-frame w-full h-full border-none"></iframe>
|
||||
<iframe v-if="appCode" :srcdoc="appCode" class="app-frame w-full h-full border-none"></iframe>
|
||||
<p v-else class="text-center text-red-500">Please install this app to view its code.</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -39,25 +38,45 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
apps: [],
|
||||
githubApps: [],
|
||||
selectedApp: null,
|
||||
appCode: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
combinedApps() {
|
||||
const installedAppNames = this.apps.map(app => app.name);
|
||||
const localAppsMap = new Map(this.apps.map(app => [app.name, { ...app, installed: true }]));
|
||||
|
||||
this.githubApps.forEach(app => {
|
||||
if (!localAppsMap.has(app.name)) {
|
||||
localAppsMap.set(app.name, { ...app, installed: false });
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(localAppsMap.values());
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async fetchApps() {
|
||||
const response = await axios.get('/apps');
|
||||
this.apps = response.data;
|
||||
},
|
||||
async fetchGithubApps() {
|
||||
await axios.get('/github/apps');
|
||||
const response = await axios.get('/github/apps');
|
||||
this.githubApps = response.data.apps;
|
||||
this.fetchApps(); // Refresh the app list after fetching GitHub apps
|
||||
},
|
||||
async selectApp(app) {
|
||||
this.selectedApp = app;
|
||||
const response = await axios.post(`/apps/${app.name}/code`, {
|
||||
client_id: this.$store.state.client_id,
|
||||
});
|
||||
this.appCode = response.data;
|
||||
async handleAppClick(app) {
|
||||
if (app.installed) {
|
||||
this.selectedApp = app;
|
||||
const response = await axios.post(`/apps/${app.name}/code`, {
|
||||
client_id: this.$store.state.client_id,
|
||||
});
|
||||
this.appCode = response.data;
|
||||
} else {
|
||||
alert(`Please install ${app.name} to view its code.`);
|
||||
}
|
||||
},
|
||||
backToZoo() {
|
||||
this.selectedApp = null;
|
||||
@ -68,6 +87,7 @@ export default {
|
||||
client_id: this.$store.state.client_id,
|
||||
});
|
||||
this.fetchApps(); // Refresh the app list
|
||||
this.fetchGithubApps(); // Refresh GitHub apps
|
||||
},
|
||||
async uninstallApp(appName) {
|
||||
await axios.post(`/uninstall/${appName}`, {
|
||||
@ -77,7 +97,8 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchApps();
|
||||
this.fetchGithubApps(); // Fetch GitHub apps when the component is mounted
|
||||
this.fetchApps(); // Also fetch local apps
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -92,6 +113,7 @@ export default {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
.app-frame {
|
||||
width: 100%;
|
||||
|
@ -703,7 +703,7 @@ export default {
|
||||
if (res.data && Object.keys(res.data).length > 0) {
|
||||
|
||||
// open form
|
||||
|
||||
const bindingEntry = this.$store.state.bindingsZoo.find(item=>item.name == this.state.config.binding_name)
|
||||
this.$store.state.universalForm.showForm(res.data, "Binding settings - " + bindingEntry.binding.name, "Save changes", "Cancel").then(res => {
|
||||
// send new data
|
||||
try {
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit a03ecace40232953deccfa922f409c8462d00042
|
||||
Subproject commit d60251156075278e62eb78c2a9beb05c3eb1690d
|