Compare commits

...

9 commits

49 changed files with 1156 additions and 1740 deletions

View file

@ -30,6 +30,11 @@ 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

1 name,value
30 embedding-model,../../../../data/llm/bge-small-en-v1.5-f32.gguf
31 ,
32 # ============================================================================
33 # VECTOR DATABASE CONFIGURATION
34 # ============================================================================
35 vectordb-url,https://localhost:6333
36 ,
37 # ============================================================================
38 # LLM SERVER CONFIGURATION
39 # ============================================================================
40 llm-server,true

View file

@ -1,697 +0,0 @@
<!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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,35 @@
{
"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
}
}

View file

@ -0,0 +1,185 @@
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

View file

@ -0,0 +1,51 @@
{
"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
}
}

View file

@ -0,0 +1,219 @@
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

View file

@ -0,0 +1,37 @@
' 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"

View file

@ -0,0 +1,54 @@
' 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!"

View file

@ -0,0 +1,21 @@
{
"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"]
}
}

View file

@ -0,0 +1,45 @@
' 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!"

View file

@ -0,0 +1,40 @@
' 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!"

View file

@ -0,0 +1,52 @@
{
"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
}
}

View file

@ -0,0 +1,257 @@
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

View file

@ -0,0 +1,12 @@
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 + "'"

View file

@ -0,0 +1,25 @@
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

View file

@ -0,0 +1,13 @@
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

View file

@ -0,0 +1,28 @@
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

View file

@ -0,0 +1,15 @@
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

View file

@ -0,0 +1,23 @@
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 + "'"

View file

@ -0,0 +1,13 @@
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 + "'"

View file

@ -0,0 +1,20 @@
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

View file

@ -0,0 +1,6 @@
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
1 name,value
2 bot-name,store-server
3 bot-description,Store Server API - Product search, classification, barcode scanning and enrichment
4 botmodels-enabled,true
5 llm-provider,openai
6 llm-model,gpt-4o