Compare commits
No commits in common. "20e502e0cb8ff0fca5825ae5483a38d2fedb3ee5" and "98fb0b31a6e14aefbd6c77cf41dda2028b64dfda" have entirely different histories.
20e502e0cb
...
98fb0b31a6
49 changed files with 1740 additions and 1156 deletions
|
|
@ -30,11 +30,6 @@ embedding-url,http://localhost:8082
|
||||||
embedding-model,../../../../data/llm/bge-small-en-v1.5-f32.gguf
|
embedding-model,../../../../data/llm/bge-small-en-v1.5-f32.gguf
|
||||||
,
|
,
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# VECTOR DATABASE CONFIGURATION
|
|
||||||
# ============================================================================
|
|
||||||
vectordb-url,https://localhost:6333
|
|
||||||
,
|
|
||||||
# ============================================================================
|
|
||||||
# LLM SERVER CONFIGURATION
|
# LLM SERVER CONFIGURATION
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
llm-server,true
|
llm-server,true
|
||||||
|
|
|
||||||
|
697
dev-chat.html
Normal file
697
dev-chat.html
Normal file
|
|
@ -0,0 +1,697 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Dev Chat Widget</title>
|
||||||
|
<style>
|
||||||
|
/* Dev Chat Floating Button */
|
||||||
|
#dev-chat-btn {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.4);
|
||||||
|
z-index: 99999;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-btn:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
box-shadow: 0 6px 24px rgba(102, 126, 234, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-btn svg {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-btn .badge {
|
||||||
|
position: absolute;
|
||||||
|
top: -4px;
|
||||||
|
right: -4px;
|
||||||
|
background: #ef4444;
|
||||||
|
color: white;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dev Chat Panel */
|
||||||
|
#dev-chat-panel {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 90px;
|
||||||
|
right: 20px;
|
||||||
|
width: 380px;
|
||||||
|
height: 520px;
|
||||||
|
background: #0f172a;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||||
|
z-index: 99998;
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-panel.open {
|
||||||
|
display: flex;
|
||||||
|
animation: slideUp 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideUp {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
#dev-chat-header {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: white;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-header .dev-badge {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-header button {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-header button:hover {
|
||||||
|
background: rgba(255,255,255,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Messages Area */
|
||||||
|
#dev-chat-messages {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dev-msg {
|
||||||
|
max-width: 85%;
|
||||||
|
padding: 10px 14px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.4;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dev-msg.user {
|
||||||
|
background: #667eea;
|
||||||
|
color: white;
|
||||||
|
align-self: flex-end;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dev-msg.bot {
|
||||||
|
background: #1e293b;
|
||||||
|
color: #e2e8f0;
|
||||||
|
align-self: flex-start;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dev-msg.system {
|
||||||
|
background: #064e3b;
|
||||||
|
color: #6ee7b7;
|
||||||
|
align-self: center;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dev-msg.error {
|
||||||
|
background: #7f1d1d;
|
||||||
|
color: #fca5a5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dev-msg pre {
|
||||||
|
background: #000;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin: 8px 0 0 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dev-msg code {
|
||||||
|
font-family: 'Fira Code', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Typing Indicator */
|
||||||
|
.typing-indicator {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: #1e293b;
|
||||||
|
border-radius: 12px;
|
||||||
|
align-self: flex-start;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typing-indicator span {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background: #64748b;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: typing 1.4s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
|
||||||
|
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
|
||||||
|
|
||||||
|
@keyframes typing {
|
||||||
|
0%, 60%, 100% { transform: translateY(0); }
|
||||||
|
30% { transform: translateY(-6px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input Area */
|
||||||
|
#dev-chat-input-area {
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: #1e293b;
|
||||||
|
border-top: 1px solid #334155;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-input {
|
||||||
|
flex: 1;
|
||||||
|
background: #0f172a;
|
||||||
|
border: 1px solid #334155;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
color: #e2e8f0;
|
||||||
|
font-size: 14px;
|
||||||
|
outline: none;
|
||||||
|
resize: none;
|
||||||
|
min-height: 20px;
|
||||||
|
max-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-input:focus {
|
||||||
|
border-color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-input::placeholder {
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-send {
|
||||||
|
background: #667eea;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-send:hover {
|
||||||
|
background: #5a67d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-send:disabled {
|
||||||
|
background: #334155;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-send svg {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quick Actions */
|
||||||
|
#dev-chat-actions {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: #1e293b;
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dev-action-btn {
|
||||||
|
background: #334155;
|
||||||
|
border: none;
|
||||||
|
color: #94a3b8;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dev-action-btn:hover {
|
||||||
|
background: #475569;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* File Changes Indicator */
|
||||||
|
.file-change {
|
||||||
|
background: #1e293b;
|
||||||
|
border-left: 3px solid #22c55e;
|
||||||
|
padding: 8px 12px;
|
||||||
|
margin: 4px 0;
|
||||||
|
border-radius: 0 8px 8px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-change.modified { border-color: #f59e0b; }
|
||||||
|
.file-change.deleted { border-color: #ef4444; }
|
||||||
|
.file-change.created { border-color: #22c55e; }
|
||||||
|
|
||||||
|
.file-change .path {
|
||||||
|
color: #94a3b8;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scrollbar */
|
||||||
|
#dev-chat-messages::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-messages::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dev-chat-messages::-webkit-scrollbar-thumb {
|
||||||
|
background: #334155;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<!-- Dev Chat Floating Button -->
|
||||||
|
<button id="dev-chat-btn" onclick="toggleDevChat()" title="Dev Chat (Ctrl+Shift+D)">
|
||||||
|
<svg viewBox="0 0 24 24">
|
||||||
|
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||||
|
<circle cx="12" cy="10" r="1.5"/>
|
||||||
|
<circle cx="8" cy="10" r="1.5"/>
|
||||||
|
<circle cx="16" cy="10" r="1.5"/>
|
||||||
|
</svg>
|
||||||
|
<span class="badge" id="dev-chat-badge">0</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Dev Chat Panel -->
|
||||||
|
<div id="dev-chat-panel">
|
||||||
|
<div id="dev-chat-header">
|
||||||
|
<h3>
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="white">
|
||||||
|
<path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/>
|
||||||
|
</svg>
|
||||||
|
Dev Chat
|
||||||
|
<span class="dev-badge">DEV</span>
|
||||||
|
</h3>
|
||||||
|
<button onclick="toggleDevChat()" title="Close">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="dev-chat-actions">
|
||||||
|
<button class="dev-action-btn" onclick="sendQuick('show tables')">📋 Tables</button>
|
||||||
|
<button class="dev-action-btn" onclick="sendQuick('list files')">📁 Files</button>
|
||||||
|
<button class="dev-action-btn" onclick="sendQuick('reload app')">🔄 Reload</button>
|
||||||
|
<button class="dev-action-btn" onclick="sendQuick('show errors')">⚠️ Errors</button>
|
||||||
|
<button class="dev-action-btn" onclick="clearChat()">🗑️ Clear</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="dev-chat-messages">
|
||||||
|
<div class="dev-msg system">
|
||||||
|
Dev mode active. Talk to test your app or modify files.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="dev-chat-input-area">
|
||||||
|
<textarea
|
||||||
|
id="dev-chat-input"
|
||||||
|
placeholder="Ask anything or describe changes..."
|
||||||
|
rows="1"
|
||||||
|
onkeydown="handleKeyDown(event)"
|
||||||
|
></textarea>
|
||||||
|
<button id="dev-chat-send" onclick="sendMessage()">
|
||||||
|
<svg viewBox="0 0 24 24">
|
||||||
|
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const DEV_CHAT_CONFIG = {
|
||||||
|
apiEndpoint: '/api/chat/dev',
|
||||||
|
wsEndpoint: '/ws/dev',
|
||||||
|
storageKey: 'dev_chat_history',
|
||||||
|
maxHistory: 50
|
||||||
|
};
|
||||||
|
|
||||||
|
let devChatOpen = false;
|
||||||
|
let ws = null;
|
||||||
|
let isTyping = false;
|
||||||
|
|
||||||
|
// Toggle chat panel
|
||||||
|
function toggleDevChat() {
|
||||||
|
devChatOpen = !devChatOpen;
|
||||||
|
const panel = document.getElementById('dev-chat-panel');
|
||||||
|
panel.classList.toggle('open', devChatOpen);
|
||||||
|
|
||||||
|
if (devChatOpen) {
|
||||||
|
document.getElementById('dev-chat-input').focus();
|
||||||
|
connectWebSocket();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keyboard shortcut: Ctrl+Shift+D
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.ctrlKey && e.shiftKey && e.key === 'D') {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleDevChat();
|
||||||
|
}
|
||||||
|
// Escape to close
|
||||||
|
if (e.key === 'Escape' && devChatOpen) {
|
||||||
|
toggleDevChat();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle input keydown
|
||||||
|
function handleKeyDown(e) {
|
||||||
|
if (e.key === 'Enter' && !e.shiftKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
sendMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send message
|
||||||
|
async function sendMessage() {
|
||||||
|
const input = document.getElementById('dev-chat-input');
|
||||||
|
const text = input.value.trim();
|
||||||
|
if (!text) return;
|
||||||
|
|
||||||
|
// Add user message
|
||||||
|
addMessage(text, 'user');
|
||||||
|
input.value = '';
|
||||||
|
|
||||||
|
// Show typing
|
||||||
|
showTyping();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Send via WebSocket if connected, else HTTP
|
||||||
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
type: 'dev_message',
|
||||||
|
content: text,
|
||||||
|
context: {
|
||||||
|
url: window.location.href,
|
||||||
|
app: getAppName()
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
const response = await fetch(DEV_CHAT_CONFIG.apiEndpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
message: text,
|
||||||
|
context: {
|
||||||
|
url: window.location.href,
|
||||||
|
app: getAppName()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
hideTyping();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
handleBotResponse(data);
|
||||||
|
} else {
|
||||||
|
addMessage('Error connecting to dev server', 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
hideTyping();
|
||||||
|
addMessage('Connection error: ' + err.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send quick action
|
||||||
|
function sendQuick(text) {
|
||||||
|
document.getElementById('dev-chat-input').value = text;
|
||||||
|
sendMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add message to chat
|
||||||
|
function addMessage(text, type = 'bot') {
|
||||||
|
const messages = document.getElementById('dev-chat-messages');
|
||||||
|
const msg = document.createElement('div');
|
||||||
|
msg.className = `dev-msg ${type}`;
|
||||||
|
|
||||||
|
// Parse markdown-style code blocks
|
||||||
|
if (type === 'bot' && text.includes('```')) {
|
||||||
|
msg.innerHTML = parseCodeBlocks(text);
|
||||||
|
} else {
|
||||||
|
msg.textContent = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.appendChild(msg);
|
||||||
|
messages.scrollTop = messages.scrollHeight;
|
||||||
|
|
||||||
|
// Save to history
|
||||||
|
saveHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse code blocks
|
||||||
|
function parseCodeBlocks(text) {
|
||||||
|
return text.replace(/```(\w*)\n?([\s\S]*?)```/g, (match, lang, code) => {
|
||||||
|
return `<pre><code class="${lang}">${escapeHtml(code.trim())}</code></pre>`;
|
||||||
|
}).replace(/\n/g, '<br>');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escape HTML
|
||||||
|
function escapeHtml(text) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.textContent = text;
|
||||||
|
return div.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show file change
|
||||||
|
function showFileChange(path, type = 'modified') {
|
||||||
|
const messages = document.getElementById('dev-chat-messages');
|
||||||
|
const change = document.createElement('div');
|
||||||
|
change.className = `file-change ${type}`;
|
||||||
|
change.innerHTML = `
|
||||||
|
<span>${type === 'created' ? '➕' : type === 'deleted' ? '➖' : '✏️'}</span>
|
||||||
|
<span class="path">${path}</span>
|
||||||
|
`;
|
||||||
|
messages.appendChild(change);
|
||||||
|
messages.scrollTop = messages.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle bot response
|
||||||
|
function handleBotResponse(data) {
|
||||||
|
hideTyping();
|
||||||
|
|
||||||
|
if (data.message) {
|
||||||
|
addMessage(data.message, 'bot');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.files_changed) {
|
||||||
|
data.files_changed.forEach(f => {
|
||||||
|
showFileChange(f.path, f.type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.reload) {
|
||||||
|
addMessage('Reloading app...', 'system');
|
||||||
|
setTimeout(() => location.reload(), 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typing indicator
|
||||||
|
function showTyping() {
|
||||||
|
if (isTyping) return;
|
||||||
|
isTyping = true;
|
||||||
|
|
||||||
|
const messages = document.getElementById('dev-chat-messages');
|
||||||
|
const typing = document.createElement('div');
|
||||||
|
typing.id = 'typing-indicator';
|
||||||
|
typing.className = 'typing-indicator';
|
||||||
|
typing.innerHTML = '<span></span><span></span><span></span>';
|
||||||
|
messages.appendChild(typing);
|
||||||
|
messages.scrollTop = messages.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideTyping() {
|
||||||
|
isTyping = false;
|
||||||
|
const typing = document.getElementById('typing-indicator');
|
||||||
|
if (typing) typing.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebSocket connection
|
||||||
|
function connectWebSocket() {
|
||||||
|
if (ws && ws.readyState === WebSocket.OPEN) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
|
ws = new WebSocket(`${protocol}//${location.host}${DEV_CHAT_CONFIG.wsEndpoint}`);
|
||||||
|
|
||||||
|
ws.onopen = () => {
|
||||||
|
addMessage('Connected to dev server', 'system');
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
|
||||||
|
switch (data.type) {
|
||||||
|
case 'message':
|
||||||
|
hideTyping();
|
||||||
|
addMessage(data.content, 'bot');
|
||||||
|
break;
|
||||||
|
case 'file_changed':
|
||||||
|
showFileChange(data.path, data.change_type);
|
||||||
|
break;
|
||||||
|
case 'reload':
|
||||||
|
addMessage('Files changed. Reloading...', 'system');
|
||||||
|
setTimeout(() => location.reload(), 500);
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
hideTyping();
|
||||||
|
addMessage(data.content, 'error');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = () => {
|
||||||
|
// Reconnect after 3s
|
||||||
|
setTimeout(connectWebSocket, 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = (err) => {
|
||||||
|
console.error('Dev chat WS error:', err);
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.error('WebSocket connection failed:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get app name from URL
|
||||||
|
function getAppName() {
|
||||||
|
const match = location.pathname.match(/\/apps\/([^\/]+)/);
|
||||||
|
return match ? match[1] : 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear chat
|
||||||
|
function clearChat() {
|
||||||
|
const messages = document.getElementById('dev-chat-messages');
|
||||||
|
messages.innerHTML = '<div class="dev-msg system">Chat cleared. Dev mode active.</div>';
|
||||||
|
localStorage.removeItem(DEV_CHAT_CONFIG.storageKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save/load history using user_data virtual table
|
||||||
|
function saveHistory() {
|
||||||
|
const messages = document.getElementById('dev-chat-messages');
|
||||||
|
const history = Array.from(messages.children).map(m => ({
|
||||||
|
type: m.classList[1],
|
||||||
|
text: m.textContent
|
||||||
|
})).slice(-DEV_CHAT_CONFIG.maxHistory);
|
||||||
|
|
||||||
|
// Store in user_data via API
|
||||||
|
fetch('/api/db/user_data', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
key: 'dev_chat_history',
|
||||||
|
app: getAppName(),
|
||||||
|
data: history
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
// Fallback to localStorage
|
||||||
|
localStorage.setItem(DEV_CHAT_CONFIG.storageKey, JSON.stringify(history));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadHistory() {
|
||||||
|
// Try to load from user_data
|
||||||
|
fetch(`/api/db/user_data?key=dev_chat_history&app=${getAppName()}`)
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data && data.data) {
|
||||||
|
data.data.forEach(m => addMessage(m.text, m.type));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// Fallback to localStorage
|
||||||
|
const saved = localStorage.getItem(DEV_CHAT_CONFIG.storageKey);
|
||||||
|
if (saved) {
|
||||||
|
JSON.parse(saved).forEach(m => addMessage(m.text, m.type));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize on load if dev mode
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
// Only show in dev mode (check URL param or cookie)
|
||||||
|
const isDevMode = location.search.includes('dev=1') ||
|
||||||
|
document.cookie.includes('dev_mode=1') ||
|
||||||
|
location.hostname === 'localhost';
|
||||||
|
|
||||||
|
if (!isDevMode) {
|
||||||
|
document.getElementById('dev-chat-btn').style.display = 'none';
|
||||||
|
document.getElementById('dev-chat-panel').style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1043
drive.html
Normal file
1043
drive.html
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,35 +0,0 @@
|
||||||
{
|
|
||||||
"name": "employee-engage",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Employee engagement surveys and sentiment analysis",
|
|
||||||
"author": "General Bots",
|
|
||||||
"category": "hr",
|
|
||||||
"tags": ["engagement", "surveys", "pulse", "sentiment", "feedback", "hr"],
|
|
||||||
"entry_dialog": "default.gbdialog",
|
|
||||||
"features": {
|
|
||||||
"engagement_surveys": true,
|
|
||||||
"pulse_checks": true,
|
|
||||||
"sentiment_analysis": true,
|
|
||||||
"anonymous_feedback": true,
|
|
||||||
"results_dashboard": true,
|
|
||||||
"ai_insights": true
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"default_anonymous": true,
|
|
||||||
"pulse_frequency": "weekly",
|
|
||||||
"sentiment_threshold": 0.3,
|
|
||||||
"auto_escalate_negative": true,
|
|
||||||
"survey_reminder_days": 3
|
|
||||||
},
|
|
||||||
"permissions": {
|
|
||||||
"create_survey": ["hr", "admin"],
|
|
||||||
"view_results": ["hr", "admin", "manager"],
|
|
||||||
"submit_feedback": ["all"],
|
|
||||||
"manage_settings": ["admin"]
|
|
||||||
},
|
|
||||||
"integrations": {
|
|
||||||
"calendar": true,
|
|
||||||
"mail": true,
|
|
||||||
"analytics": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,185 +0,0 @@
|
||||||
PARAM action AS STRING LIKE "survey" DESCRIPTION "Action to perform: survey, pulse, results, feedback"
|
|
||||||
PARAM survey_type AS STRING LIKE "engagement" DESCRIPTION "Survey type: engagement, pulse, onboarding, exit" OPTIONAL
|
|
||||||
PARAM anonymous AS BOOLEAN LIKE TRUE DESCRIPTION "Anonymous responses" OPTIONAL
|
|
||||||
|
|
||||||
DESCRIPTION "Employee engagement surveys and sentiment analysis"
|
|
||||||
|
|
||||||
SELECT CASE UCASE(action)
|
|
||||||
|
|
||||||
CASE "SURVEY"
|
|
||||||
survey_id = GUID()
|
|
||||||
survey_name = ASK "What is the name of this survey?"
|
|
||||||
target_audience = ASK "Who should receive this survey? (all, department, team, or comma-separated emails)"
|
|
||||||
|
|
||||||
questions = NEW ARRAY
|
|
||||||
adding_questions = TRUE
|
|
||||||
|
|
||||||
WHILE adding_questions
|
|
||||||
question_text = ASK "Enter survey question (or 'done' to finish):"
|
|
||||||
IF UCASE(question_text) = "DONE" THEN
|
|
||||||
adding_questions = FALSE
|
|
||||||
ELSE
|
|
||||||
question_type = ASK "Question type? (scale, choice, text, nps)"
|
|
||||||
|
|
||||||
WITH question
|
|
||||||
id = GUID()
|
|
||||||
text = question_text
|
|
||||||
type = question_type
|
|
||||||
END WITH
|
|
||||||
|
|
||||||
IF question_type = "scale" THEN
|
|
||||||
question.min_label = "Strongly Disagree"
|
|
||||||
question.max_label = "Strongly Agree"
|
|
||||||
question.scale = 5
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF question_type = "choice" THEN
|
|
||||||
options_text = ASK "Enter options (comma-separated):"
|
|
||||||
question.options = SPLIT(options_text, ",")
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF question_type = "nps" THEN
|
|
||||||
question.min_label = "Not Likely"
|
|
||||||
question.max_label = "Very Likely"
|
|
||||||
question.scale = 10
|
|
||||||
END IF
|
|
||||||
|
|
||||||
PUSH questions, question
|
|
||||||
END IF
|
|
||||||
END WHILE
|
|
||||||
|
|
||||||
WITH survey
|
|
||||||
id = survey_id
|
|
||||||
name = survey_name
|
|
||||||
type = survey_type
|
|
||||||
questions = questions
|
|
||||||
target = target_audience
|
|
||||||
anonymous = anonymous
|
|
||||||
status = "draft"
|
|
||||||
created_at = NOW()
|
|
||||||
END WITH
|
|
||||||
|
|
||||||
SAVE survey TO "surveys"
|
|
||||||
|
|
||||||
launch_now = ASK "Launch survey now? (yes/no)"
|
|
||||||
IF UCASE(launch_now) = "YES" THEN
|
|
||||||
survey.status = "active"
|
|
||||||
survey.launched_at = NOW()
|
|
||||||
SAVE survey TO "surveys"
|
|
||||||
TALK "Survey launched! Notifications sent to " + target_audience
|
|
||||||
ELSE
|
|
||||||
TALK "Survey saved as draft. Launch when ready from the dashboard."
|
|
||||||
END IF
|
|
||||||
|
|
||||||
CASE "PULSE"
|
|
||||||
pulse_id = GUID()
|
|
||||||
pulse_question = ASK "What quick question do you want to ask?"
|
|
||||||
pulse_frequency = ASK "How often? (daily, weekly, biweekly)"
|
|
||||||
|
|
||||||
WITH pulse
|
|
||||||
id = pulse_id
|
|
||||||
question = pulse_question
|
|
||||||
frequency = pulse_frequency
|
|
||||||
anonymous = TRUE
|
|
||||||
status = "active"
|
|
||||||
created_at = NOW()
|
|
||||||
responses = NEW ARRAY
|
|
||||||
END WITH
|
|
||||||
|
|
||||||
SAVE pulse TO "pulses"
|
|
||||||
TALK "Pulse check created. First pulse will be sent based on " + pulse_frequency + " schedule."
|
|
||||||
|
|
||||||
CASE "RESULTS"
|
|
||||||
surveys = FIND "surveys" WHERE status = "completed" OR status = "active"
|
|
||||||
|
|
||||||
IF LEN(surveys) = 0 THEN
|
|
||||||
TALK "No surveys with results found."
|
|
||||||
ELSE
|
|
||||||
survey_list = ""
|
|
||||||
FOR i = 0 TO LEN(surveys) - 1
|
|
||||||
survey_list = survey_list + (i + 1) + ". " + surveys[i].name + " (" + surveys[i].status + ")\n"
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
selection = ASK "Select survey to view results:\n" + survey_list
|
|
||||||
selected_survey = surveys[INT(selection) - 1]
|
|
||||||
|
|
||||||
responses = FIND "responses" WHERE survey_id = selected_survey.id
|
|
||||||
|
|
||||||
total_responses = LEN(responses)
|
|
||||||
|
|
||||||
IF total_responses = 0 THEN
|
|
||||||
TALK "No responses yet for this survey."
|
|
||||||
ELSE
|
|
||||||
TALK "📊 Results for: " + selected_survey.name
|
|
||||||
TALK "Total responses: " + total_responses
|
|
||||||
|
|
||||||
FOR q = 0 TO LEN(selected_survey.questions) - 1
|
|
||||||
question = selected_survey.questions[q]
|
|
||||||
TALK "\n📋 " + question.text
|
|
||||||
|
|
||||||
IF question.type = "scale" OR question.type = "nps" THEN
|
|
||||||
sum = 0
|
|
||||||
FOR r = 0 TO LEN(responses) - 1
|
|
||||||
answer = responses[r].answers[q]
|
|
||||||
sum = sum + answer
|
|
||||||
END FOR
|
|
||||||
avg = sum / total_responses
|
|
||||||
TALK "Average: " + FORMAT(avg, "0.0") + " / " + question.scale
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF question.type = "choice" THEN
|
|
||||||
FOR opt = 0 TO LEN(question.options) - 1
|
|
||||||
count = 0
|
|
||||||
FOR r = 0 TO LEN(responses) - 1
|
|
||||||
IF responses[r].answers[q] = question.options[opt] THEN
|
|
||||||
count = count + 1
|
|
||||||
END IF
|
|
||||||
END FOR
|
|
||||||
pct = (count / total_responses) * 100
|
|
||||||
TALK question.options[opt] + ": " + FORMAT(pct, "0") + "%"
|
|
||||||
END FOR
|
|
||||||
END IF
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
sentiment = ANALYZE SENTIMENT FROM responses
|
|
||||||
TALK "\n🎯 Overall Sentiment: " + sentiment.label + " (" + FORMAT(sentiment.score * 100, "0") + "% positive)"
|
|
||||||
END IF
|
|
||||||
END IF
|
|
||||||
|
|
||||||
CASE "FEEDBACK"
|
|
||||||
feedback_type = ASK "Feedback type? (anonymous, identified, suggestion)"
|
|
||||||
feedback_text = ASK "Enter your feedback:"
|
|
||||||
|
|
||||||
WITH feedback
|
|
||||||
id = GUID()
|
|
||||||
type = feedback_type
|
|
||||||
content = feedback_text
|
|
||||||
anonymous = (feedback_type = "anonymous")
|
|
||||||
sentiment = ANALYZE SENTIMENT FROM feedback_text
|
|
||||||
created_at = NOW()
|
|
||||||
END WITH
|
|
||||||
|
|
||||||
SAVE feedback TO "feedback"
|
|
||||||
|
|
||||||
TALK "Thank you for your feedback!"
|
|
||||||
|
|
||||||
IF feedback.sentiment.score < 0.3 THEN
|
|
||||||
TALK "We noticed this might be a concern. Would you like to speak with HR?"
|
|
||||||
escalate = ASK "Request HR follow-up? (yes/no)"
|
|
||||||
IF UCASE(escalate) = "YES" THEN
|
|
||||||
feedback.escalated = TRUE
|
|
||||||
feedback.escalated_at = NOW()
|
|
||||||
SAVE feedback TO "feedback"
|
|
||||||
TALK "HR has been notified and will follow up."
|
|
||||||
END IF
|
|
||||||
END IF
|
|
||||||
|
|
||||||
CASE ELSE
|
|
||||||
TALK "Employee Engagement System"
|
|
||||||
TALK "Available actions:"
|
|
||||||
TALK "• survey - Create and launch engagement surveys"
|
|
||||||
TALK "• pulse - Quick pulse checks"
|
|
||||||
TALK "• results - View survey results and analytics"
|
|
||||||
TALK "• feedback - Submit anonymous feedback"
|
|
||||||
|
|
||||||
END SELECT
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
{
|
|
||||||
"name": "team-feedback",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Team feedback and pulse surveys for managers",
|
|
||||||
"author": "General Bots",
|
|
||||||
"category": "hr",
|
|
||||||
"tags": ["pulse", "feedback", "team", "manager", "surveys", "hr"],
|
|
||||||
"entry_dialog": "default.gbdialog",
|
|
||||||
"features": {
|
|
||||||
"pulse_surveys": true,
|
|
||||||
"team_health": true,
|
|
||||||
"sentiment_analysis": true,
|
|
||||||
"trend_tracking": true,
|
|
||||||
"action_items": true,
|
|
||||||
"ai_insights": true
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"default_frequency": "weekly",
|
|
||||||
"anonymous_responses": true,
|
|
||||||
"alert_threshold": 3.0,
|
|
||||||
"trend_periods": 4,
|
|
||||||
"auto_remind": true,
|
|
||||||
"reminder_hours": 24
|
|
||||||
},
|
|
||||||
"templates": {
|
|
||||||
"wellbeing": {
|
|
||||||
"name": "Team Wellbeing",
|
|
||||||
"questions": 4
|
|
||||||
},
|
|
||||||
"workload": {
|
|
||||||
"name": "Workload Check",
|
|
||||||
"questions": 4
|
|
||||||
},
|
|
||||||
"collaboration": {
|
|
||||||
"name": "Collaboration Health",
|
|
||||||
"questions": 4
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"permissions": {
|
|
||||||
"create_pulse": ["manager", "hr", "admin"],
|
|
||||||
"view_results": ["manager", "hr", "admin"],
|
|
||||||
"respond": ["team_member"],
|
|
||||||
"manage_actions": ["manager", "hr", "admin"]
|
|
||||||
},
|
|
||||||
"integrations": {
|
|
||||||
"tasks": true,
|
|
||||||
"calendar": true,
|
|
||||||
"mail": true,
|
|
||||||
"analytics": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,219 +0,0 @@
|
||||||
PARAM action AS STRING LIKE "pulse" DESCRIPTION "Action: pulse, review, insights, actions"
|
|
||||||
PARAM team_id AS STRING DESCRIPTION "Team identifier" OPTIONAL
|
|
||||||
PARAM period AS STRING LIKE "weekly" DESCRIPTION "Review period" OPTIONAL
|
|
||||||
|
|
||||||
DESCRIPTION "Team feedback and pulse surveys for managers"
|
|
||||||
|
|
||||||
SELECT CASE UCASE(action)
|
|
||||||
|
|
||||||
CASE "PULSE"
|
|
||||||
pulse_id = GUID()
|
|
||||||
pulse_name = ASK "Name this pulse check (e.g., 'Weekly Team Health'):"
|
|
||||||
|
|
||||||
template = ASK "Use template? (wellbeing, workload, collaboration, custom)"
|
|
||||||
|
|
||||||
questions = NEW ARRAY
|
|
||||||
|
|
||||||
IF template = "wellbeing" THEN
|
|
||||||
PUSH questions, { text: "How are you feeling about work this week?", type: "scale", scale: 5 }
|
|
||||||
PUSH questions, { text: "Do you feel supported by your team?", type: "scale", scale: 5 }
|
|
||||||
PUSH questions, { text: "Is your workload manageable?", type: "scale", scale: 5 }
|
|
||||||
PUSH questions, { text: "Any blockers or concerns?", type: "text" }
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF template = "workload" THEN
|
|
||||||
PUSH questions, { text: "How would you rate your current workload?", type: "scale", scale: 5 }
|
|
||||||
PUSH questions, { text: "Do you have clarity on priorities?", type: "scale", scale: 5 }
|
|
||||||
PUSH questions, { text: "Are deadlines realistic?", type: "scale", scale: 5 }
|
|
||||||
PUSH questions, { text: "What would help you be more productive?", type: "text" }
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF template = "collaboration" THEN
|
|
||||||
PUSH questions, { text: "How effective is team communication?", type: "scale", scale: 5 }
|
|
||||||
PUSH questions, { text: "Do you feel your input is valued?", type: "scale", scale: 5 }
|
|
||||||
PUSH questions, { text: "How well is the team working together?", type: "scale", scale: 5 }
|
|
||||||
PUSH questions, { text: "Suggestions for better collaboration?", type: "text" }
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF template = "custom" THEN
|
|
||||||
adding = TRUE
|
|
||||||
WHILE adding
|
|
||||||
q_text = ASK "Enter question (or 'done'):"
|
|
||||||
IF UCASE(q_text) = "DONE" THEN
|
|
||||||
adding = FALSE
|
|
||||||
ELSE
|
|
||||||
q_type = ASK "Type? (scale/text/choice)"
|
|
||||||
WITH q
|
|
||||||
text = q_text
|
|
||||||
type = q_type
|
|
||||||
scale = 5
|
|
||||||
END WITH
|
|
||||||
PUSH questions, q
|
|
||||||
END IF
|
|
||||||
END WHILE
|
|
||||||
END IF
|
|
||||||
|
|
||||||
frequency = ASK "Send frequency? (once, daily, weekly, biweekly, monthly)"
|
|
||||||
|
|
||||||
WITH pulse
|
|
||||||
id = pulse_id
|
|
||||||
name = pulse_name
|
|
||||||
template = template
|
|
||||||
questions = questions
|
|
||||||
frequency = frequency
|
|
||||||
team_id = team_id
|
|
||||||
anonymous = TRUE
|
|
||||||
status = "active"
|
|
||||||
created_at = NOW()
|
|
||||||
END WITH
|
|
||||||
|
|
||||||
SAVE pulse TO "team_pulses"
|
|
||||||
TALK "Pulse '" + pulse_name + "' created! First survey sends based on " + frequency + " schedule."
|
|
||||||
|
|
||||||
CASE "REVIEW"
|
|
||||||
pulses = FIND "team_pulses" WHERE team_id = team_id OR team_id = NULL
|
|
||||||
|
|
||||||
IF LEN(pulses) = 0 THEN
|
|
||||||
TALK "No pulse surveys found. Create one first with action=pulse"
|
|
||||||
ELSE
|
|
||||||
pulse_list = ""
|
|
||||||
FOR i = 0 TO LEN(pulses) - 1
|
|
||||||
pulse_list = pulse_list + (i + 1) + ". " + pulses[i].name + "\n"
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
selection = ASK "Select pulse to review:\n" + pulse_list
|
|
||||||
selected = pulses[INT(selection) - 1]
|
|
||||||
|
|
||||||
responses = FIND "pulse_responses" WHERE pulse_id = selected.id
|
|
||||||
|
|
||||||
IF LEN(responses) = 0 THEN
|
|
||||||
TALK "No responses yet."
|
|
||||||
ELSE
|
|
||||||
TALK "📊 " + selected.name + " Results"
|
|
||||||
TALK "Responses: " + LEN(responses)
|
|
||||||
|
|
||||||
FOR q = 0 TO LEN(selected.questions) - 1
|
|
||||||
question = selected.questions[q]
|
|
||||||
TALK "\n" + question.text
|
|
||||||
|
|
||||||
IF question.type = "scale" THEN
|
|
||||||
sum = 0
|
|
||||||
FOR r = 0 TO LEN(responses) - 1
|
|
||||||
sum = sum + responses[r].answers[q]
|
|
||||||
END FOR
|
|
||||||
avg = sum / LEN(responses)
|
|
||||||
|
|
||||||
bar = ""
|
|
||||||
filled = INT(avg)
|
|
||||||
FOR b = 1 TO 5
|
|
||||||
IF b <= filled THEN
|
|
||||||
bar = bar + "█"
|
|
||||||
ELSE
|
|
||||||
bar = bar + "░"
|
|
||||||
END IF
|
|
||||||
END FOR
|
|
||||||
TALK bar + " " + FORMAT(avg, "0.0") + "/5"
|
|
||||||
|
|
||||||
IF avg < 3 THEN
|
|
||||||
TALK "⚠️ Area needs attention"
|
|
||||||
END IF
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF question.type = "text" THEN
|
|
||||||
TALK "Comments:"
|
|
||||||
FOR r = 0 TO LEN(responses) - 1
|
|
||||||
IF responses[r].answers[q] <> "" THEN
|
|
||||||
TALK "• " + responses[r].answers[q]
|
|
||||||
END IF
|
|
||||||
END FOR
|
|
||||||
END IF
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
trend = FIND "pulse_trends" WHERE pulse_id = selected.id ORDER BY date DESC LIMIT 4
|
|
||||||
IF LEN(trend) > 1 THEN
|
|
||||||
TALK "\n📈 Trend (last 4 periods):"
|
|
||||||
FOR t = 0 TO LEN(trend) - 1
|
|
||||||
TALK trend[t].date + ": " + FORMAT(trend[t].avg_score, "0.0")
|
|
||||||
END FOR
|
|
||||||
END IF
|
|
||||||
END IF
|
|
||||||
END IF
|
|
||||||
|
|
||||||
CASE "INSIGHTS"
|
|
||||||
TALK "🔍 AI-Generated Team Insights"
|
|
||||||
|
|
||||||
responses = FIND "pulse_responses" WHERE team_id = team_id ORDER BY created_at DESC LIMIT 50
|
|
||||||
text_feedback = ""
|
|
||||||
FOR r = 0 TO LEN(responses) - 1
|
|
||||||
FOR a = 0 TO LEN(responses[r].answers) - 1
|
|
||||||
IF TYPEOF(responses[r].answers[a]) = "string" THEN
|
|
||||||
text_feedback = text_feedback + responses[r].answers[a] + " "
|
|
||||||
END IF
|
|
||||||
END FOR
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
IF text_feedback <> "" THEN
|
|
||||||
themes = ANALYZE THEMES FROM text_feedback
|
|
||||||
sentiment = ANALYZE SENTIMENT FROM text_feedback
|
|
||||||
|
|
||||||
TALK "\n🎯 Key Themes:"
|
|
||||||
FOR t = 0 TO LEN(themes) - 1
|
|
||||||
TALK "• " + themes[t].topic + " (" + themes[t].count + " mentions)"
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
TALK "\n😊 Team Sentiment: " + sentiment.label
|
|
||||||
TALK "Positive: " + FORMAT(sentiment.positive * 100, "0") + "%"
|
|
||||||
TALK "Neutral: " + FORMAT(sentiment.neutral * 100, "0") + "%"
|
|
||||||
TALK "Negative: " + FORMAT(sentiment.negative * 100, "0") + "%"
|
|
||||||
|
|
||||||
IF sentiment.negative > 0.3 THEN
|
|
||||||
TALK "\n⚠️ Elevated negative sentiment detected. Consider scheduling team discussion."
|
|
||||||
END IF
|
|
||||||
ELSE
|
|
||||||
TALK "Not enough feedback data for insights. Run more pulse surveys."
|
|
||||||
END IF
|
|
||||||
|
|
||||||
CASE "ACTIONS"
|
|
||||||
TALK "📋 Suggested Actions Based on Feedback"
|
|
||||||
|
|
||||||
low_scores = FIND "pulse_trends" WHERE avg_score < 3 AND team_id = team_id
|
|
||||||
|
|
||||||
IF LEN(low_scores) > 0 THEN
|
|
||||||
TALK "\nAreas needing attention:"
|
|
||||||
FOR s = 0 TO LEN(low_scores) - 1
|
|
||||||
TALK "• " + low_scores[s].question_text + " (Score: " + FORMAT(low_scores[s].avg_score, "0.0") + ")"
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
create_action = ASK "Create action item? (yes/no)"
|
|
||||||
IF UCASE(create_action) = "YES" THEN
|
|
||||||
action_text = ASK "Describe the action:"
|
|
||||||
due_date = ASK "Due date (YYYY-MM-DD):"
|
|
||||||
owner = ASK "Owner (email):"
|
|
||||||
|
|
||||||
WITH action_item
|
|
||||||
id = GUID()
|
|
||||||
description = action_text
|
|
||||||
due = due_date
|
|
||||||
assigned_to = owner
|
|
||||||
team_id = team_id
|
|
||||||
source = "team_feedback"
|
|
||||||
status = "open"
|
|
||||||
created_at = NOW()
|
|
||||||
END WITH
|
|
||||||
|
|
||||||
SAVE action_item TO "action_items"
|
|
||||||
TALK "Action item created and assigned to " + owner
|
|
||||||
END IF
|
|
||||||
ELSE
|
|
||||||
TALK "No critical areas identified. Team health looks good!"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
CASE ELSE
|
|
||||||
TALK "Team Feedback System"
|
|
||||||
TALK "Available actions:"
|
|
||||||
TALK "• pulse - Create quick team surveys"
|
|
||||||
TALK "• review - View pulse results"
|
|
||||||
TALK "• insights - AI-generated team insights"
|
|
||||||
TALK "• actions - Review and create action items"
|
|
||||||
|
|
||||||
END SELECT
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
' Content Moderation Workflow with AI
|
|
||||||
USE KB "community-guidelines"
|
|
||||||
USE TOOL "image-analysis"
|
|
||||||
USE TOOL "text-sentiment"
|
|
||||||
|
|
||||||
ORCHESTRATE WORKFLOW "content-moderation"
|
|
||||||
|
|
||||||
STEP 1: BOT "content-analyzer" "scan content"
|
|
||||||
' Multi-modal content analysis
|
|
||||||
|
|
||||||
STEP 2: BOT "policy-checker" "verify guidelines"
|
|
||||||
' Check against community standards
|
|
||||||
|
|
||||||
IF toxicity_score > 0.7 OR contains_explicit_content = true THEN
|
|
||||||
STEP 3: BOT "auto-moderator" "remove content"
|
|
||||||
PUBLISH EVENT "content_removed"
|
|
||||||
ELSE IF toxicity_score > 0.4 THEN
|
|
||||||
STEP 4: HUMAN APPROVAL FROM "moderator@platform.com"
|
|
||||||
TIMEOUT 3600 ' 1 hour for borderline content
|
|
||||||
ON TIMEOUT: APPROVE WITH WARNING
|
|
||||||
END IF
|
|
||||||
|
|
||||||
' Enhanced LLM for context understanding
|
|
||||||
result = LLM "Analyze content context and cultural sensitivity"
|
|
||||||
WITH OPTIMIZE FOR "quality"
|
|
||||||
WITH MAX_COST 0.05
|
|
||||||
|
|
||||||
IF result.contains("cultural_sensitivity_issue") THEN
|
|
||||||
STEP 5: BOT "cultural-advisor" "review context"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
' Learn from moderation decisions
|
|
||||||
BOT SHARE MEMORY "moderation_patterns" WITH "content-analyzer-v2"
|
|
||||||
|
|
||||||
PUBLISH EVENT "moderation_complete"
|
|
||||||
|
|
||||||
TALK "Content moderation completed"
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
' Example: Customer Support Workflow with Enhanced Orchestration
|
|
||||||
' This demonstrates the new ORCHESTRATE WORKFLOW, event system, and bot memory sharing
|
|
||||||
|
|
||||||
USE KB "support-policies"
|
|
||||||
USE TOOL "check-order"
|
|
||||||
USE TOOL "process-refund"
|
|
||||||
|
|
||||||
' Set up event handlers
|
|
||||||
ON EVENT "approval_received" DO
|
|
||||||
TALK "Manager approval received, processing refund..."
|
|
||||||
END ON
|
|
||||||
|
|
||||||
ON EVENT "timeout_occurred" DO
|
|
||||||
TALK "Approval timeout, escalating to director..."
|
|
||||||
END ON
|
|
||||||
|
|
||||||
' Main workflow orchestration
|
|
||||||
ORCHESTRATE WORKFLOW "customer-complaint-resolution"
|
|
||||||
|
|
||||||
STEP 1: BOT "classifier" "analyze complaint"
|
|
||||||
' Classifier bot analyzes the complaint and sets variables
|
|
||||||
|
|
||||||
STEP 2: BOT "order-checker" "validate order details"
|
|
||||||
' Order checker validates the order and warranty status
|
|
||||||
|
|
||||||
' Conditional logic based on order value
|
|
||||||
IF order_amount > 100 THEN
|
|
||||||
STEP 3: HUMAN APPROVAL FROM "manager@company.com"
|
|
||||||
TIMEOUT 1800 ' 30 minutes
|
|
||||||
ON TIMEOUT: ESCALATE TO "director@company.com"
|
|
||||||
|
|
||||||
' Wait for approval event
|
|
||||||
WAIT FOR EVENT "approval_received" TIMEOUT 3600
|
|
||||||
END IF
|
|
||||||
|
|
||||||
STEP 4: PARALLEL
|
|
||||||
BRANCH A: BOT "refund-processor" "process refund"
|
|
||||||
BRANCH B: BOT "inventory-updater" "update stock levels"
|
|
||||||
END PARALLEL
|
|
||||||
|
|
||||||
STEP 5: BOT "follow-up" "schedule customer check-in"
|
|
||||||
DELAY 86400 ' 24 hours later
|
|
||||||
|
|
||||||
' Share successful resolution patterns with other support bots
|
|
||||||
BOT SHARE MEMORY "successful_resolution_method" WITH "support-bot-2"
|
|
||||||
BOT SHARE MEMORY "customer_satisfaction_score" WITH "support-bot-3"
|
|
||||||
|
|
||||||
' Sync knowledge from master support bot
|
|
||||||
BOT SYNC MEMORY FROM "master-support-bot"
|
|
||||||
|
|
||||||
' Publish completion event for analytics
|
|
||||||
PUBLISH EVENT "workflow_completed"
|
|
||||||
|
|
||||||
TALK "Customer complaint resolved successfully!"
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"name": "Customer Support Workflow",
|
|
||||||
"description": "Advanced customer support workflow with multi-agent orchestration, event handling, and bot memory sharing",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"author": "General Bots",
|
|
||||||
"category": "customer-support",
|
|
||||||
"keywords": ["workflow", "orchestration", "customer-support", "multi-agent"],
|
|
||||||
"features": [
|
|
||||||
"Multi-step workflow orchestration",
|
|
||||||
"Human approval integration",
|
|
||||||
"Event-driven coordination",
|
|
||||||
"Cross-bot memory sharing",
|
|
||||||
"Parallel processing",
|
|
||||||
"Automatic escalation"
|
|
||||||
],
|
|
||||||
"requirements": {
|
|
||||||
"tools": ["check-order", "process-refund"],
|
|
||||||
"knowledge_bases": ["support-policies"],
|
|
||||||
"bots": ["classifier", "order-checker", "refund-processor", "inventory-updater", "follow-up"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
' Marketing Campaign Automation
|
|
||||||
USE KB "brand-guidelines"
|
|
||||||
USE TOOL "social-media-post"
|
|
||||||
USE TOOL "email-sender"
|
|
||||||
USE TOOL "analytics-tracker"
|
|
||||||
|
|
||||||
ORCHESTRATE WORKFLOW "marketing-campaign"
|
|
||||||
|
|
||||||
STEP 1: BOT "audience-segmenter" "analyze target demographics"
|
|
||||||
' AI-powered audience analysis
|
|
||||||
|
|
||||||
STEP 2: BOT "content-creator" "generate campaign materials"
|
|
||||||
' Multi-modal content generation
|
|
||||||
|
|
||||||
' Smart LLM routing for different content types
|
|
||||||
email_content = LLM "Create engaging email subject line"
|
|
||||||
WITH OPTIMIZE FOR "cost"
|
|
||||||
|
|
||||||
social_content = LLM "Create viral social media post"
|
|
||||||
WITH OPTIMIZE FOR "quality"
|
|
||||||
WITH MAX_LATENCY 5000
|
|
||||||
|
|
||||||
STEP 3: PARALLEL
|
|
||||||
BRANCH A: BOT "email-scheduler" "send email campaign"
|
|
||||||
BRANCH B: BOT "social-scheduler" "post to social media"
|
|
||||||
BRANCH C: BOT "ad-manager" "launch paid ads"
|
|
||||||
END PARALLEL
|
|
||||||
|
|
||||||
' Wait for initial results
|
|
||||||
WAIT FOR EVENT "campaign_metrics_ready" TIMEOUT 7200
|
|
||||||
|
|
||||||
STEP 4: BOT "performance-analyzer" "analyze results"
|
|
||||||
|
|
||||||
IF engagement_rate < 0.02 THEN
|
|
||||||
STEP 5: BOT "optimizer" "adjust campaign parameters"
|
|
||||||
PUBLISH EVENT "campaign_optimized"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
' Share successful campaign patterns
|
|
||||||
BOT SHARE MEMORY "high_engagement_content" WITH "content-creator-v2"
|
|
||||||
BOT SHARE MEMORY "optimal_timing" WITH "scheduler-bots"
|
|
||||||
|
|
||||||
PUBLISH EVENT "campaign_complete"
|
|
||||||
|
|
||||||
TALK "Marketing campaign launched and optimized!"
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
' E-commerce Order Processing Workflow
|
|
||||||
USE KB "order-policies"
|
|
||||||
USE TOOL "validate-payment"
|
|
||||||
USE TOOL "reserve-inventory"
|
|
||||||
USE TOOL "send-confirmation"
|
|
||||||
|
|
||||||
ORCHESTRATE WORKFLOW "order-processing"
|
|
||||||
|
|
||||||
STEP 1: BOT "fraud-detector" "analyze transaction"
|
|
||||||
' AI-powered fraud detection
|
|
||||||
|
|
||||||
STEP 2: BOT "inventory-checker" "verify availability"
|
|
||||||
' Check stock levels and reserve items
|
|
||||||
|
|
||||||
IF fraud_score > 0.8 THEN
|
|
||||||
STEP 3: HUMAN APPROVAL FROM "security@store.com"
|
|
||||||
TIMEOUT 900 ' 15 minutes for high-risk orders
|
|
||||||
ON TIMEOUT: REJECT ORDER
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF payment_method = "credit_card" THEN
|
|
||||||
STEP 4: BOT "payment-processor" "charge card"
|
|
||||||
ELSE
|
|
||||||
STEP 4: BOT "payment-processor" "process alternative"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
STEP 5: PARALLEL
|
|
||||||
BRANCH A: BOT "shipping-optimizer" "select carrier"
|
|
||||||
BRANCH B: BOT "inventory-updater" "update stock"
|
|
||||||
BRANCH C: BOT "notification-sender" "send confirmation"
|
|
||||||
END PARALLEL
|
|
||||||
|
|
||||||
' Share successful processing patterns
|
|
||||||
BOT SHARE MEMORY "fraud_indicators" WITH "fraud-detector-backup"
|
|
||||||
BOT SHARE MEMORY "shipping_preferences" WITH "logistics-bot"
|
|
||||||
|
|
||||||
' Publish completion event
|
|
||||||
PUBLISH EVENT "order_processed"
|
|
||||||
|
|
||||||
TALK "Order processed successfully!"
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
{
|
|
||||||
"name": "broadcast",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Internal communications and broadcast messaging",
|
|
||||||
"author": "General Bots",
|
|
||||||
"category": "productivity",
|
|
||||||
"tags": ["broadcast", "communications", "announcements", "campaigns", "newsletter"],
|
|
||||||
"entry_dialog": "default.gbdialog",
|
|
||||||
"features": {
|
|
||||||
"multi_channel": true,
|
|
||||||
"campaign_management": true,
|
|
||||||
"templates": true,
|
|
||||||
"scheduling": true,
|
|
||||||
"analytics": true,
|
|
||||||
"ai_content": true
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"default_channels": ["email", "chat"],
|
|
||||||
"require_approval": false,
|
|
||||||
"track_opens": true,
|
|
||||||
"track_clicks": true,
|
|
||||||
"max_recipients": 10000
|
|
||||||
},
|
|
||||||
"channels": {
|
|
||||||
"email": {
|
|
||||||
"enabled": true,
|
|
||||||
"track_opens": true
|
|
||||||
},
|
|
||||||
"chat": {
|
|
||||||
"enabled": true,
|
|
||||||
"channel_name": "announcements"
|
|
||||||
},
|
|
||||||
"social": {
|
|
||||||
"enabled": false,
|
|
||||||
"platforms": ["linkedin"]
|
|
||||||
},
|
|
||||||
"sms": {
|
|
||||||
"enabled": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"permissions": {
|
|
||||||
"create_campaign": ["communications", "hr", "admin"],
|
|
||||||
"send_campaign": ["communications", "admin"],
|
|
||||||
"view_analytics": ["communications", "hr", "admin", "manager"],
|
|
||||||
"manage_templates": ["communications", "admin"]
|
|
||||||
},
|
|
||||||
"integrations": {
|
|
||||||
"mail": true,
|
|
||||||
"social": true,
|
|
||||||
"analytics": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,257 +0,0 @@
|
||||||
PARAM action AS STRING LIKE "campaign" DESCRIPTION "Action: campaign, send, schedule, templates, analytics"
|
|
||||||
PARAM channel AS STRING LIKE "all" DESCRIPTION "Channel: all, email, chat, social, sms" OPTIONAL
|
|
||||||
PARAM audience AS STRING DESCRIPTION "Target audience" OPTIONAL
|
|
||||||
|
|
||||||
DESCRIPTION "Internal communications and broadcast messaging"
|
|
||||||
|
|
||||||
SELECT CASE UCASE(action)
|
|
||||||
|
|
||||||
CASE "CAMPAIGN"
|
|
||||||
campaign_id = GUID()
|
|
||||||
campaign_name = ASK "Campaign name:"
|
|
||||||
campaign_goal = ASK "Campaign goal (awareness, engagement, action):"
|
|
||||||
|
|
||||||
TALK "📢 Creating broadcast campaign: " + campaign_name
|
|
||||||
|
|
||||||
message_subject = ASK "Message subject/title:"
|
|
||||||
message_body = ASK "Message content (supports markdown):"
|
|
||||||
|
|
||||||
use_ai = ASK "Use AI to improve message? (yes/no)"
|
|
||||||
IF UCASE(use_ai) = "YES" THEN
|
|
||||||
tone = ASK "Desired tone? (professional, friendly, urgent, inspirational)"
|
|
||||||
improved = IMPROVE TEXT message_body WITH TONE tone
|
|
||||||
TALK "AI-improved version:"
|
|
||||||
TALK improved
|
|
||||||
use_improved = ASK "Use improved version? (yes/no)"
|
|
||||||
IF UCASE(use_improved) = "YES" THEN
|
|
||||||
message_body = improved
|
|
||||||
END IF
|
|
||||||
END IF
|
|
||||||
|
|
||||||
channels_input = ASK "Select channels (comma-separated: email, chat, social, sms, or 'all'):"
|
|
||||||
IF UCASE(channels_input) = "ALL" THEN
|
|
||||||
selected_channels = ["email", "chat", "social", "sms"]
|
|
||||||
ELSE
|
|
||||||
selected_channels = SPLIT(channels_input, ",")
|
|
||||||
END IF
|
|
||||||
|
|
||||||
audience_type = ASK "Audience? (all, department, role, group, custom)"
|
|
||||||
IF audience_type = "custom" THEN
|
|
||||||
audience_filter = ASK "Enter audience filter (emails or group name):"
|
|
||||||
ELSE
|
|
||||||
audience_filter = audience_type
|
|
||||||
END IF
|
|
||||||
|
|
||||||
WITH campaign
|
|
||||||
id = campaign_id
|
|
||||||
name = campaign_name
|
|
||||||
goal = campaign_goal
|
|
||||||
subject = message_subject
|
|
||||||
body = message_body
|
|
||||||
channels = selected_channels
|
|
||||||
audience = audience_filter
|
|
||||||
status = "draft"
|
|
||||||
created_at = NOW()
|
|
||||||
END WITH
|
|
||||||
|
|
||||||
SAVE campaign TO "broadcast_campaigns"
|
|
||||||
|
|
||||||
preview = ASK "Preview campaign? (yes/no)"
|
|
||||||
IF UCASE(preview) = "YES" THEN
|
|
||||||
TALK "📧 Subject: " + campaign.subject
|
|
||||||
TALK "📝 Body: " + campaign.body
|
|
||||||
TALK "📡 Channels: " + JOIN(campaign.channels, ", ")
|
|
||||||
TALK "👥 Audience: " + campaign.audience
|
|
||||||
END IF
|
|
||||||
|
|
||||||
TALK "Campaign saved. Use action=send or action=schedule to distribute."
|
|
||||||
|
|
||||||
CASE "SEND"
|
|
||||||
campaigns = FIND "broadcast_campaigns" WHERE status = "draft" OR status = "scheduled"
|
|
||||||
|
|
||||||
IF LEN(campaigns) = 0 THEN
|
|
||||||
TALK "No campaigns ready to send. Create one first with action=campaign"
|
|
||||||
ELSE
|
|
||||||
campaign_list = ""
|
|
||||||
FOR i = 0 TO LEN(campaigns) - 1
|
|
||||||
campaign_list = campaign_list + (i + 1) + ". " + campaigns[i].name + " (" + campaigns[i].status + ")\n"
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
selection = ASK "Select campaign to send:\n" + campaign_list
|
|
||||||
selected = campaigns[INT(selection) - 1]
|
|
||||||
|
|
||||||
confirm = ASK "Send '" + selected.name + "' now to " + selected.audience + "? (yes/no)"
|
|
||||||
IF UCASE(confirm) = "YES" THEN
|
|
||||||
recipients = GET_RECIPIENTS(selected.audience)
|
|
||||||
sent_count = 0
|
|
||||||
|
|
||||||
FOR ch = 0 TO LEN(selected.channels) - 1
|
|
||||||
channel_name = selected.channels[ch]
|
|
||||||
|
|
||||||
IF channel_name = "email" THEN
|
|
||||||
SEND MAIL TO recipients SUBJECT selected.subject BODY selected.body
|
|
||||||
sent_count = sent_count + LEN(recipients)
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF channel_name = "chat" THEN
|
|
||||||
POST TO "internal_announcements" CONTENT selected.body
|
|
||||||
sent_count = sent_count + 1
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF channel_name = "social" THEN
|
|
||||||
POST TO "linkedin" CONTENT selected.body
|
|
||||||
sent_count = sent_count + 1
|
|
||||||
END IF
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
selected.status = "sent"
|
|
||||||
selected.sent_at = NOW()
|
|
||||||
selected.recipients_count = sent_count
|
|
||||||
SAVE selected TO "broadcast_campaigns"
|
|
||||||
|
|
||||||
TALK "✅ Campaign sent successfully!"
|
|
||||||
TALK "Recipients reached: " + sent_count
|
|
||||||
ELSE
|
|
||||||
TALK "Send cancelled."
|
|
||||||
END IF
|
|
||||||
END IF
|
|
||||||
|
|
||||||
CASE "SCHEDULE"
|
|
||||||
campaigns = FIND "broadcast_campaigns" WHERE status = "draft"
|
|
||||||
|
|
||||||
IF LEN(campaigns) = 0 THEN
|
|
||||||
TALK "No draft campaigns to schedule."
|
|
||||||
ELSE
|
|
||||||
campaign_list = ""
|
|
||||||
FOR i = 0 TO LEN(campaigns) - 1
|
|
||||||
campaign_list = campaign_list + (i + 1) + ". " + campaigns[i].name + "\n"
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
selection = ASK "Select campaign to schedule:\n" + campaign_list
|
|
||||||
selected = campaigns[INT(selection) - 1]
|
|
||||||
|
|
||||||
schedule_date = ASK "Schedule date (YYYY-MM-DD):"
|
|
||||||
schedule_time = ASK "Schedule time (HH:MM):"
|
|
||||||
schedule_tz = ASK "Timezone (e.g., America/New_York):"
|
|
||||||
|
|
||||||
selected.status = "scheduled"
|
|
||||||
selected.scheduled_for = schedule_date + "T" + schedule_time
|
|
||||||
selected.timezone = schedule_tz
|
|
||||||
SAVE selected TO "broadcast_campaigns"
|
|
||||||
|
|
||||||
TALK "📅 Campaign scheduled for " + schedule_date + " at " + schedule_time + " " + schedule_tz
|
|
||||||
|
|
||||||
CASE "TEMPLATES"
|
|
||||||
template_action = ASK "Templates action? (list, create, use)"
|
|
||||||
|
|
||||||
IF template_action = "list" THEN
|
|
||||||
templates = FIND "broadcast_templates"
|
|
||||||
IF LEN(templates) = 0 THEN
|
|
||||||
TALK "No templates found. Create one with templates action=create"
|
|
||||||
ELSE
|
|
||||||
TALK "📋 Available templates:"
|
|
||||||
FOR t = 0 TO LEN(templates) - 1
|
|
||||||
TALK (t + 1) + ". " + templates[t].name + " - " + templates[t].category
|
|
||||||
END FOR
|
|
||||||
END IF
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF template_action = "create" THEN
|
|
||||||
template_name = ASK "Template name:"
|
|
||||||
template_category = ASK "Category (announcement, newsletter, alert, event):"
|
|
||||||
template_subject = ASK "Subject template:"
|
|
||||||
template_body = ASK "Body template (use {{variable}} for placeholders):"
|
|
||||||
|
|
||||||
WITH template
|
|
||||||
id = GUID()
|
|
||||||
name = template_name
|
|
||||||
category = template_category
|
|
||||||
subject = template_subject
|
|
||||||
body = template_body
|
|
||||||
created_at = NOW()
|
|
||||||
END WITH
|
|
||||||
|
|
||||||
SAVE template TO "broadcast_templates"
|
|
||||||
TALK "Template saved!"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF template_action = "use" THEN
|
|
||||||
templates = FIND "broadcast_templates"
|
|
||||||
IF LEN(templates) = 0 THEN
|
|
||||||
TALK "No templates available."
|
|
||||||
ELSE
|
|
||||||
template_list = ""
|
|
||||||
FOR t = 0 TO LEN(templates) - 1
|
|
||||||
template_list = template_list + (t + 1) + ". " + templates[t].name + "\n"
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
selection = ASK "Select template:\n" + template_list
|
|
||||||
selected_template = templates[INT(selection) - 1]
|
|
||||||
|
|
||||||
TALK "Using template: " + selected_template.name
|
|
||||||
TALK "Subject: " + selected_template.subject
|
|
||||||
TALK "Body: " + selected_template.body
|
|
||||||
TALK "Run action=campaign to create a campaign using this template."
|
|
||||||
END IF
|
|
||||||
END IF
|
|
||||||
|
|
||||||
CASE "ANALYTICS"
|
|
||||||
period = ASK "Analytics period? (week, month, quarter, all)"
|
|
||||||
|
|
||||||
campaigns = FIND "broadcast_campaigns" WHERE status = "sent"
|
|
||||||
|
|
||||||
IF LEN(campaigns) = 0 THEN
|
|
||||||
TALK "No sent campaigns to analyze."
|
|
||||||
ELSE
|
|
||||||
total_sent = 0
|
|
||||||
total_opened = 0
|
|
||||||
total_clicked = 0
|
|
||||||
|
|
||||||
TALK "📊 Broadcast Analytics"
|
|
||||||
TALK "═══════════════════════════════════"
|
|
||||||
|
|
||||||
FOR c = 0 TO LEN(campaigns) - 1
|
|
||||||
campaign = campaigns[c]
|
|
||||||
opens = campaign.opens_count
|
|
||||||
clicks = campaign.clicks_count
|
|
||||||
sent = campaign.recipients_count
|
|
||||||
|
|
||||||
IF opens = NULL THEN opens = 0
|
|
||||||
IF clicks = NULL THEN clicks = 0
|
|
||||||
IF sent = NULL THEN sent = 0
|
|
||||||
|
|
||||||
total_sent = total_sent + sent
|
|
||||||
total_opened = total_opened + opens
|
|
||||||
total_clicked = total_clicked + clicks
|
|
||||||
|
|
||||||
open_rate = 0
|
|
||||||
IF sent > 0 THEN
|
|
||||||
open_rate = (opens / sent) * 100
|
|
||||||
END IF
|
|
||||||
|
|
||||||
TALK "\n📢 " + campaign.name
|
|
||||||
TALK " Sent: " + sent + " | Opens: " + opens + " (" + FORMAT(open_rate, "0") + "%)"
|
|
||||||
END FOR
|
|
||||||
|
|
||||||
TALK "\n═══════════════════════════════════"
|
|
||||||
TALK "TOTALS"
|
|
||||||
TALK "Campaigns: " + LEN(campaigns)
|
|
||||||
TALK "Messages sent: " + total_sent
|
|
||||||
|
|
||||||
overall_open_rate = 0
|
|
||||||
IF total_sent > 0 THEN
|
|
||||||
overall_open_rate = (total_opened / total_sent) * 100
|
|
||||||
END IF
|
|
||||||
TALK "Overall open rate: " + FORMAT(overall_open_rate, "0") + "%"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
CASE ELSE
|
|
||||||
TALK "📢 Broadcast Communication System"
|
|
||||||
TALK "Available actions:"
|
|
||||||
TALK "• campaign - Create a new broadcast campaign"
|
|
||||||
TALK "• send - Send a campaign immediately"
|
|
||||||
TALK "• schedule - Schedule a campaign for later"
|
|
||||||
TALK "• templates - Manage message templates"
|
|
||||||
TALK "• analytics - View campaign performance"
|
|
||||||
|
|
||||||
END SELECT
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
PARAM query AS STRING
|
|
||||||
|
|
||||||
existing = SEARCH PRODUCTS query, 1
|
|
||||||
IF LEN(existing) > 0 THEN
|
|
||||||
RETURN existing[0]
|
|
||||||
END IF
|
|
||||||
|
|
||||||
info = LLM "Extract product info: " + query + ". Return JSON with name, category, brand, description"
|
|
||||||
|
|
||||||
SAVE "products" WITH name AS info.name, category AS info.category, brand AS info.brand, description AS info.description, is_active AS true
|
|
||||||
|
|
||||||
RETURN FIND "products" WITH "name = '" + info.name + "'"
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
PARAM product_id AS STRING
|
|
||||||
PARAM quantity AS INTEGER
|
|
||||||
|
|
||||||
product = PRODUCT product_id
|
|
||||||
IF NOT product THEN
|
|
||||||
RETURN WITH error AS "Product not found"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF NOT quantity THEN
|
|
||||||
quantity = 1
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF NOT product.gross_weight THEN
|
|
||||||
dims = LLM "Estimate shipping dimensions for: " + product.name + ". Return JSON with length_cm, width_cm, height_cm, weight_kg"
|
|
||||||
UPDATE "products" WITH length AS dims.length_cm, width AS dims.width_cm, height AS dims.height_cm, gross_weight AS dims.weight_kg WHERE id = product_id
|
|
||||||
product = PRODUCT product_id
|
|
||||||
END IF
|
|
||||||
|
|
||||||
volume = product.length * product.width * product.height * quantity
|
|
||||||
volumetric_weight = volume / 5000
|
|
||||||
actual_weight = product.gross_weight * quantity
|
|
||||||
billable = MAX actual_weight, volumetric_weight
|
|
||||||
|
|
||||||
|
|
||||||
RETURN WITH product_id AS product_id, quantity AS quantity, length AS product.length, width AS product.width, height AS product.height, weight AS product.gross_weight, volume_cm3 AS volume, billable_weight_kg AS billable
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
PARAM query AS STRING
|
|
||||||
|
|
||||||
categories = FIND "categories"
|
|
||||||
similar = SEARCH PRODUCTS query, 5
|
|
||||||
result = LLM "Classify '" + query + "' into: " + categories + ". Similar: " + similar + ". Return JSON with category_id, name, confidence, brand, type"
|
|
||||||
|
|
||||||
cached = FIND "products" WITH "name LIKE '%" + query + "%'"
|
|
||||||
IF cached THEN
|
|
||||||
RETURN cached
|
|
||||||
END IF
|
|
||||||
|
|
||||||
SAVE "products" WITH name AS query, category AS result.name, brand AS result.brand, external_metadata AS result
|
|
||||||
RETURN result
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
PARAM product_id AS STRING
|
|
||||||
|
|
||||||
product = PRODUCT product_id
|
|
||||||
IF NOT product THEN
|
|
||||||
RETURN WITH error AS "Product not found"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF product.description AND product.brand THEN
|
|
||||||
RETURN product
|
|
||||||
END IF
|
|
||||||
|
|
||||||
query = product.name + " " + product.category
|
|
||||||
links = SCRAPE_ALL "https://www.google.com/search?q=" + query, "a"
|
|
||||||
links = FIRST links, 10
|
|
||||||
|
|
||||||
enriched = []
|
|
||||||
FOR i = 0 TO 2
|
|
||||||
IF links[i] THEN
|
|
||||||
content = SCRAPE links[i], "body"
|
|
||||||
PUSH enriched, content
|
|
||||||
END IF
|
|
||||||
NEXT
|
|
||||||
|
|
||||||
result = LLM "Analyze these product descriptions: " + enriched + ". Create best description for: " + product.name + ". Return JSON with description, brand, material, features"
|
|
||||||
|
|
||||||
UPDATE "products" WITH description AS result.description, brand AS result.brand, material AS result.material, external_metadata AS result WHERE id = product_id
|
|
||||||
|
|
||||||
RETURN PRODUCT product_id
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
PARAM product_id AS STRING
|
|
||||||
|
|
||||||
product = PRODUCT product_id
|
|
||||||
IF NOT product THEN
|
|
||||||
RETURN WITH error AS "Product not found"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
IF product.tax_code THEN
|
|
||||||
RETURN WITH tax_code AS product.tax_code, tax_class AS product.tax_class
|
|
||||||
END IF
|
|
||||||
|
|
||||||
info = LLM "Get NCM/tax classification for: " + product.name + " " + product.category + ". Return JSON with tax_code, tax_class, description"
|
|
||||||
UPDATE "products" WITH tax_code AS info.tax_code, tax_class AS info.tax_class WHERE id = product_id
|
|
||||||
|
|
||||||
RETURN WITH tax_code AS info.tax_code, tax_class AS info.tax_class, description AS info.description
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
PARAM image AS STRING
|
|
||||||
|
|
||||||
barcode = SCAN BARCODE image
|
|
||||||
IF NOT barcode THEN
|
|
||||||
RETURN WITH error AS "No barcode found"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
ean = barcode.data
|
|
||||||
cached = FIND "products" WITH "global_trade_number = '" + ean + "'"
|
|
||||||
IF cached THEN
|
|
||||||
RETURN cached
|
|
||||||
END IF
|
|
||||||
|
|
||||||
data = GET "https://world.openfoodfacts.org/api/v0/product/" + ean + ".json"
|
|
||||||
IF data.product THEN
|
|
||||||
SAVE "products" WITH name AS data.product.product_name, brand AS data.product.brands, global_trade_number AS ean, description AS data.product.generic_name, category AS data.product.categories, net_weight AS data.product.quantity
|
|
||||||
RETURN FIND "products" WITH "global_trade_number = '" + ean + "'"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
info = LLM "Search product info for EAN: " + ean + ". Return JSON with name, brand, description, category"
|
|
||||||
SAVE "products" WITH name AS info.name, brand AS info.brand, description AS info.description, category AS info.category, global_trade_number AS ean
|
|
||||||
|
|
||||||
RETURN FIND "products" WITH "global_trade_number = '" + ean + "'"
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
PARAM image AS STRING
|
|
||||||
|
|
||||||
description = SEE image
|
|
||||||
similar = SEARCH PRODUCTS description, 5
|
|
||||||
|
|
||||||
IF LEN(similar) > 0 THEN
|
|
||||||
RETURN similar[0]
|
|
||||||
END IF
|
|
||||||
|
|
||||||
product = LLM "Extract product info from: " + description + ". Return JSON with name, brand, category, color, material"
|
|
||||||
SAVE "products" WITH name AS product.name, brand AS product.brand, category AS product.category, color AS product.color, material AS product.material
|
|
||||||
|
|
||||||
RETURN FIND "products" WITH "name = '" + product.name + "'"
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
PARAM query AS STRING
|
|
||||||
|
|
||||||
cached = FIND "products" WITH "name ILIKE '%" + query + "%' OR description ILIKE '%" + query + "%'"
|
|
||||||
IF cached THEN
|
|
||||||
RETURN cached
|
|
||||||
END IF
|
|
||||||
|
|
||||||
result = SEARCH PRODUCTS query, 10
|
|
||||||
IF LEN(result) = 0 THEN
|
|
||||||
web = SCRAPE_ALL "https://www.google.com/search?q=" + query + "+product", ".g"
|
|
||||||
result = LLM "Extract products from: " + web + ". Return JSON array with name, price, description"
|
|
||||||
END IF
|
|
||||||
|
|
||||||
enhanced = LLM "Add descriptions: " + result + ". Return JSON array with id, name, price, description, stock"
|
|
||||||
|
|
||||||
FOR EACH item IN enhanced
|
|
||||||
SAVE "products" WITH name AS item.name, description AS item.description, price AS item.price, external_metadata AS item
|
|
||||||
NEXT
|
|
||||||
|
|
||||||
RETURN enhanced
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
name,value
|
|
||||||
bot-name,store-server
|
|
||||||
bot-description,Store Server API - Product search, classification, barcode scanning and enrichment
|
|
||||||
botmodels-enabled,true
|
|
||||||
llm-provider,openai
|
|
||||||
llm-model,gpt-4o
|
|
||||||
|
Loading…
Add table
Reference in a new issue