aboutsummaryrefslogtreecommitdiff
path: root/chat/chat-modules.js
diff options
context:
space:
mode:
Diffstat (limited to 'chat/chat-modules.js')
-rw-r--r--chat/chat-modules.js365
1 files changed, 365 insertions, 0 deletions
diff --git a/chat/chat-modules.js b/chat/chat-modules.js
new file mode 100644
index 0000000..8483d48
--- /dev/null
+++ b/chat/chat-modules.js
@@ -0,0 +1,365 @@
+/*
+ * Version: 1.0.0-lite
+ * ChatStudio Lite - Module System
+ * Module CRUD, import/export, module list rendering, AI module generator.
+ * Module format: { id, name, desc, prompt, help, commands }
+ */
+
+const DEFAULT_MODULES = [
+ {
+ id: 'default',
+ name: 'AI Chat',
+ desc: 'General purpose AI assistant',
+ prompt: 'You are a helpful AI assistant on WebX11. You have access to these tools:\n\n1. **Search:** /api/search?q=QUERY - Searches the web via DuckDuckGo. Returns HTML results. Use this for current events, facts, and web information.\n\n2. **Fetch:** /api/fetch?url=URL - Fetches content from any URL. Use this to read web pages, APIs, or documents.\n\n3. **Commands:** Users can type /help, /search [query], /fetch [url], /explain [code], /status, /clear directly.\n\nWhen a user asks about current events, recent info, or something you dont know, suggest they use /search or tell them to ask you to search the web. If they provide a URL, offer to fetch it.\n\nBe concise, helpful, and use the available tools when appropriate.',
+ help: 'Just type any question! I can help with:\n- Current events (I can search the web)\n- Web pages (I can fetch URLs)\n- Coding questions\n- General knowledge\n- Problem solving\n\nTry: /search latest news',
+ commands: '/help, /search, /fetch, /explain, /status, /clear'
+ },
+ {
+ id: 'search',
+ name: 'Search',
+ desc: 'Search the web for information',
+ prompt: 'You are a web search assistant. When asked about current events, recent information, or things you dont know, suggest searching the web. Provide helpful search suggestions.',
+ help: 'Use /search [query] to get search suggestions.\n\nExample: /search Python tutorials',
+ commands: '/search, /find'
+ },
+ {
+ id: 'fetch',
+ name: 'URL Fetch',
+ desc: 'Fetch content from URLs',
+ prompt: 'You can fetch content from URLs using the fetch tool. When a user provides a URL, use the fetch tool to get its content.',
+ help: 'Provide a URL and I can fetch its content.\n\nJust paste any URL in the chat!',
+ commands: '/fetch, /get'
+ },
+ {
+ id: 'summarize',
+ name: 'Summarizer',
+ desc: 'Summarize long text',
+ prompt: 'You are a text summarization expert. When given text, provide a clear summary highlighting the key points.',
+ help: 'Paste long text and Ill summarize it.\n\nUse /summary for a brief overview.',
+ commands: '/summarize, /summary'
+ },
+ {
+ id: 'plan',
+ name: 'Planner',
+ desc: 'Create plans and todo lists',
+ prompt: 'You are a planning assistant. Help users break down tasks into steps, create schedules, and organize work.',
+ help: 'Tell me what you want to accomplish and Ill help create a plan!\n\nCommands:\n- /plan [goal] - Create a plan\n- /todo - Show current todos',
+ commands: '/plan, /todo'
+ },
+ {
+ id: 'code',
+ name: 'Code Helper',
+ desc: 'Programming assistance',
+ prompt: 'You are a coding expert. Help with code explanations, debugging, writing, and best practices. Provide clear, working code examples.',
+ help: 'I can help with:\n- Explaining code\n- Debugging errors\n- Writing new code\n- Code reviews\n\nJust paste your code and ask!',
+ commands: '/code, /debug, /explain'
+ },
+ {
+ id: 'translate',
+ name: 'Translator',
+ desc: 'Translate between languages',
+ prompt: 'You are a multilingual translator. Translate text between languages accurately while preserving meaning.',
+ help: 'Translate text by specifying languages:\n\n- /translate [text] to [language]\n- /es Hello - translate to Spanish\n- /en Hola - translate to English',
+ commands: '/translate, /es, /fr, /de, /zh'
+ },
+ {
+ id: 'webx11-help',
+ name: 'WebX11 Help',
+ desc: 'Help with WebX11 Spaces',
+ prompt: 'You are a WebX11 Spaces help assistant. Help users with:\n- Creating and managing their web space\n- Using the dashboard\n- Uploading files\n- Custom domains\n- Module system\n- Any technical questions',
+ help: 'WebX11 Spaces Help:\n\n- Dashboard: Upload & manage files\n- Register: Create your space\n- Chat: AI assistant\n- Modules: Specialized tools\n\nType /help for more!',
+ commands: '/help, /webx11, /space'
+ }
+];
+
+var modules = [];
+var currentModule = 'default';
+var editingModuleId = null;
+
+var STORAGE_KEY = 'webx11_chat_modules';
+
+function loadModules() {
+ try {
+ var saved = localStorage.getItem(STORAGE_KEY);
+ if (saved) {
+ modules = JSON.parse(b64_to_utf8(saved));
+ } else {
+ modules = JSON.parse(JSON.stringify(DEFAULT_MODULES));
+ saveModules();
+ }
+ } catch (e) {
+ console.warn('Failed to load modules:', e);
+ modules = JSON.parse(JSON.stringify(DEFAULT_MODULES));
+ }
+ renderModuleList();
+ updateHelpPanel();
+}
+
+function saveModules() {
+ try {
+ var encoded = utf8_to_b64(JSON.stringify(modules));
+ localStorage.setItem(STORAGE_KEY, encoded);
+ } catch (e) {
+ console.warn('Failed to save modules:', e);
+ }
+}
+
+function renderModuleList() {
+ var list = document.getElementById('moduleList');
+ list.innerHTML = modules.map(function (m) {
+ var isActive = m.id === currentModule;
+ var actions = m.id !== 'default'
+ ? '<div class="module-actions">' +
+ '<button class="module-action-btn" onclick="event.stopPropagation(); copyModule(\'' + escapeHtml(m.id) + '\')" title="Copy">Copy</button>' +
+ '<button class="module-action-btn delete" onclick="event.stopPropagation(); deleteModule(\'' + escapeHtml(m.id) + '\')" title="Delete">Del</button>' +
+ '</div>'
+ : '';
+ return '<div class="module-item' + (isActive ? ' active' : '') + '" onclick="switchModule(\'' + escapeHtml(m.id) + '\')" oncontextmenu="moduleContextMenu(event, \'' + escapeHtml(m.id) + '\')">' +
+ '<div class="module-name">' + escapeHtml(m.name) + '</div>' +
+ '<div class="module-desc">' + escapeHtml(m.desc) + '</div>' +
+ actions +
+ '</div>';
+ }).join('');
+}
+
+function getCurrentModule() {
+ return modules.find(function (m) { return m.id === currentModule; });
+}
+
+function switchModule(id) {
+ currentModule = id;
+ renderModuleList();
+ updateHelpPanel();
+ var found = modules.find(function (m) { return m.id === id; });
+ showToast('Switched to ' + (found ? found.name : 'module'));
+ addLog('Module', 'Switched to ' + (found ? found.name : id));
+}
+
+function updateHelpPanel() {
+ var mod = modules.find(function (m) { return m.id === currentModule; });
+ if (mod) {
+ document.getElementById('helpTitle').textContent = mod.name;
+ document.getElementById('helpText').textContent = mod.help || 'No help available.';
+ var cmds = mod.commands ? mod.commands.split(',').map(function (c) { return c.trim(); }) : [];
+ document.getElementById('helpCommands').innerHTML = cmds.map(function (c) {
+ return '<span class="help-cmd">' + escapeHtml(c) + '</span>';
+ }).join('');
+ }
+}
+
+function moduleContextMenu(e, id) {
+ e.preventDefault();
+ if (id === 'default') return;
+ var action = prompt('Module actions: edit, copy, delete (or cancel)');
+ if (!action) return;
+ var a = action.toLowerCase().trim();
+ if (a === 'edit') {
+ editModule(id);
+ } else if (a === 'copy') {
+ copyModule(id);
+ } else if (a === 'delete') {
+ deleteModule(id);
+ }
+}
+
+function copyModule(id) {
+ var mod = modules.find(function (m) { return m.id === id; });
+ if (!mod) return;
+ var newId = id + '_copy_' + Date.now();
+ var newModule = JSON.parse(JSON.stringify(mod));
+ newModule.id = newId;
+ newModule.name = mod.name + ' (Copy)';
+ modules.push(newModule);
+ saveModules();
+ renderModuleList();
+ showToast('Module copied!');
+}
+
+function deleteModule(id) {
+ if (!confirm('Delete this module?')) return;
+ modules = modules.filter(function (m) { return m.id !== id; });
+ if (currentModule === id) {
+ currentModule = 'default';
+ }
+ saveModules();
+ renderModuleList();
+ updateHelpPanel();
+ showToast('Module deleted');
+}
+
+function editModule(id) {
+ openModuleModal(id);
+}
+
+function openModuleModal(editId) {
+ editId = editId || null;
+ editingModuleId = editId;
+ document.getElementById('moduleModalTitle').textContent = editId ? 'Edit Module' : 'Add Module';
+
+ if (editId) {
+ var mod = modules.find(function (m) { return m.id === editId; });
+ if (mod) {
+ document.getElementById('moduleName').value = mod.name;
+ document.getElementById('moduleDesc').value = mod.desc;
+ document.getElementById('modulePrompt').value = mod.prompt;
+ document.getElementById('moduleHelp').value = mod.help;
+ document.getElementById('moduleCommands').value = mod.commands;
+ }
+ } else {
+ document.getElementById('moduleName').value = '';
+ document.getElementById('moduleDesc').value = '';
+ document.getElementById('modulePrompt').value = '';
+ document.getElementById('moduleHelp').value = '';
+ document.getElementById('moduleCommands').value = '';
+ }
+
+ document.getElementById('aiModuleDesc').value = '';
+ document.getElementById('moduleModal').classList.add('open');
+}
+
+function closeModuleModal() {
+ document.getElementById('moduleModal').classList.remove('open');
+ editingModuleId = null;
+}
+
+function saveModule() {
+ var name = document.getElementById('moduleName').value.trim();
+ var desc = document.getElementById('moduleDesc').value.trim();
+ var prompt = document.getElementById('modulePrompt').value.trim();
+ var help = document.getElementById('moduleHelp').value.trim();
+ var commands = document.getElementById('moduleCommands').value.trim();
+
+ if (!name) {
+ showToast('Please enter a module name');
+ return;
+ }
+
+ if (editingModuleId) {
+ var idx = modules.findIndex(function (m) { return m.id === editingModuleId; });
+ if (idx !== -1) {
+ modules[idx] = {
+ id: modules[idx].id,
+ name: name,
+ desc: desc,
+ prompt: prompt,
+ help: help,
+ commands: commands
+ };
+ }
+ } else {
+ var id = name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
+ modules.push({
+ id: id,
+ name: name,
+ desc: desc,
+ prompt: prompt,
+ help: help,
+ commands: commands
+ });
+ }
+
+ saveModules();
+ renderModuleList();
+ closeModuleModal();
+ showToast(editingModuleId ? 'Module updated!' : 'Module added!');
+}
+
+// === AI Module Generator ===
+
+async function generateModuleWithAI() {
+ var desc = document.getElementById('aiModuleDesc').value.trim();
+ if (!desc) {
+ showToast('Please describe what the module should do');
+ return;
+ }
+
+ var btn = event.target;
+ btn.disabled = true;
+ btn.textContent = 'Generating...';
+
+ try {
+ var headers = { 'Content-Type': 'application/json' };
+ if (typeof OLLAMA_API_KEY !== 'undefined' && OLLAMA_API_KEY) {
+ headers['Authorization'] = 'Bearer ' + OLLAMA_API_KEY;
+ }
+
+ var response = await fetch((typeof OLLAMA_URL !== 'undefined' ? OLLAMA_URL : '/ollama') + '/api/generate', {
+ method: 'POST',
+ headers: headers,
+ body: JSON.stringify({
+ model: document.getElementById('modelSelect').value,
+ prompt: 'Generate a chat module specification for WebX11 AI Chat.\n\nModule description: ' + desc + '\n\nRespond with a JSON object containing:\n{\n "name": "Module Name",\n "desc": "Short description (5-10 words)",\n "prompt": "System prompt/instructions for the AI (2-3 sentences)",\n "help": "How to use this module (3-5 bullet points)",\n "commands": "comma-separated commands, at least 3"\n}\n\nOnly respond with valid JSON, no other text.',
+ stream: false
+ })
+ });
+
+ if (!response.ok) throw new Error('AI request failed');
+
+ var data = await response.json();
+ var result = JSON.parse(data.response);
+
+ document.getElementById('moduleName').value = result.name || '';
+ document.getElementById('moduleDesc').value = result.desc || '';
+ document.getElementById('modulePrompt').value = result.prompt || '';
+ document.getElementById('moduleHelp').value = result.help || '';
+ document.getElementById('moduleCommands').value = result.commands || '';
+
+ showToast('Module generated! Review and save.');
+ } catch (e) {
+ console.error('Generation error:', e);
+ showToast('Failed to generate: ' + e.message);
+ } finally {
+ btn.disabled = false;
+ btn.textContent = 'Generate with AI';
+ }
+}
+
+// === Import / Export ===
+
+function exportModules() {
+ var data = JSON.stringify(modules, null, 2);
+ var blob = new Blob([data], { type: 'application/json' });
+ var url = URL.createObjectURL(blob);
+ var a = document.createElement('a');
+ a.href = url;
+ a.download = 'webx11-modules.json';
+ a.click();
+ URL.revokeObjectURL(url);
+ showToast('Modules exported!');
+}
+
+function importModules() {
+ var input = document.createElement('input');
+ input.type = 'file';
+ input.accept = '.json';
+ input.onchange = async function (e) {
+ var file = e.target.files[0];
+ if (!file) return;
+ try {
+ var text = await file.text();
+ var imported = JSON.parse(text);
+ if (Array.isArray(imported)) {
+ for (var i = 0; i < imported.length; i++) {
+ var m = imported[i];
+ m.id = m.id + '_imported';
+ modules.push(m);
+ }
+ saveModules();
+ renderModuleList();
+ updateHelpPanel();
+ showToast('Modules imported!');
+ } else {
+ showToast('Invalid format');
+ }
+ } catch (err) {
+ showToast('Import failed: ' + err.message);
+ }
+ };
+ input.click();
+}
+
+
+// Load modules from storage (runs after core.js)
+
+// Auto-init once DOM + deps are ready
+document.addEventListener('DOMContentLoaded', function() { loadModules(); });