feat(gb-llm): Implement email sending and meeting scheduling functionalities; add customer sentiment analysis and opportunity updates
This commit is contained in:
parent
a86a965cd0
commit
bf382e623e
17 changed files with 704 additions and 11 deletions
|
@ -11,6 +11,9 @@ use flate2::read::GzDecoder;
|
|||
use tar::Archive;
|
||||
use zip::ZipArchive;
|
||||
|
||||
// TODO: https://helpcenter.onlyoffice.com/docs/installation/docs-community-install-ubuntu.aspx
|
||||
|
||||
|
||||
const INSTALL_DIR: &str = "/opt/gbo";
|
||||
const TEMP_DIR: &str = "/tmp/gbotemp";
|
||||
|
||||
|
|
45
gb-llm/.gbdialog/ai/analyze-customer-sentiment.bas
Normal file
45
gb-llm/.gbdialog/ai/analyze-customer-sentiment.bas
Normal file
|
@ -0,0 +1,45 @@
|
|||
PARAM customer_id AS STRING
|
||||
PARAM time_period AS INTEGER DEFAULT 30
|
||||
|
||||
# Gather customer communications
|
||||
emails = CALL "/storage/json", ".gbdata/communication_logs",
|
||||
"to = '${customer_id}' OR from = '${customer_id}' AND timestamp > NOW() - DAYS(${time_period})"
|
||||
|
||||
support_tickets = CALL "/crm/tickets/list", {
|
||||
"customer_id": customer_id,
|
||||
"created_after": NOW() - DAYS(time_period)
|
||||
}
|
||||
|
||||
meeting_notes = CALL "/crm/meetings/list", {
|
||||
"customer_id": customer_id,
|
||||
"date_after": NOW() - DAYS(time_period)
|
||||
}
|
||||
|
||||
# Combine all text for analysis
|
||||
all_text = ""
|
||||
FOR EACH email IN emails
|
||||
all_text = all_text + email.subject + " " + email.body + " "
|
||||
NEXT
|
||||
|
||||
FOR EACH ticket IN support_tickets
|
||||
all_text = all_text + ticket.description + " " + ticket.resolution + " "
|
||||
NEXT
|
||||
|
||||
FOR EACH meeting IN meeting_notes
|
||||
all_text = all_text + meeting.notes + " "
|
||||
NEXT
|
||||
|
||||
# Analyze sentiment
|
||||
sentiment = CALL "/ai/analyze/text", all_text, "sentiment"
|
||||
|
||||
# Generate insights
|
||||
insights = CALL "/ai/analyze/text", all_text, "key_topics"
|
||||
|
||||
RETURN {
|
||||
"customer_id": customer_id,
|
||||
"time_period": time_period + " days",
|
||||
"sentiment_score": sentiment.score,
|
||||
"sentiment_label": sentiment.label,
|
||||
"key_topics": insights.topics,
|
||||
"recommendations": insights.recommendations
|
||||
}
|
83
gb-llm/.gbdialog/analytics/sales-performance.bas
Normal file
83
gb-llm/.gbdialog/analytics/sales-performance.bas
Normal file
|
@ -0,0 +1,83 @@
|
|||
PARAM period AS STRING DEFAULT "month"
|
||||
PARAM team_id AS STRING OPTIONAL
|
||||
|
||||
# Determine date range
|
||||
IF period = "week" THEN
|
||||
start_date = NOW() - DAYS(7)
|
||||
ELSEIF period = "month" THEN
|
||||
start_date = NOW() - DAYS(30)
|
||||
ELSEIF period = "quarter" THEN
|
||||
start_date = NOW() - DAYS(90)
|
||||
ELSEIF period = "year" THEN
|
||||
start_date = NOW() - DAYS(365)
|
||||
ELSE
|
||||
RETURN "Invalid period specified. Use 'week', 'month', 'quarter', or 'year'."
|
||||
END IF
|
||||
|
||||
# Construct team filter
|
||||
team_filter = ""
|
||||
IF team_id IS NOT NULL THEN
|
||||
team_filter = " AND team_id = '" + team_id + "'"
|
||||
END IF
|
||||
|
||||
# Get sales data
|
||||
opportunities = QUERY "SELECT * FROM Opportunities WHERE close_date >= '${start_date}'" + team_filter
|
||||
closed_won = QUERY "SELECT * FROM Opportunities WHERE status = 'Won' AND close_date >= '${start_date}'" + team_filter
|
||||
closed_lost = QUERY "SELECT * FROM Opportunities WHERE status = 'Lost' AND close_date >= '${start_date}'" + team_filter
|
||||
|
||||
# Calculate metrics
|
||||
total_value = 0
|
||||
FOR EACH opp IN closed_won
|
||||
total_value = total_value + opp.value
|
||||
NEXT
|
||||
|
||||
win_rate = LEN(closed_won) / (LEN(closed_won) + LEN(closed_lost)) * 100
|
||||
|
||||
# Get performance by rep
|
||||
sales_reps = QUERY "SELECT owner_id, COUNT(*) as deals, SUM(value) as total_value FROM Opportunities WHERE status = 'Won' AND close_date >= '${start_date}'" + team_filter + " GROUP BY owner_id"
|
||||
|
||||
# Generate report
|
||||
report = CALL "/analytics/reports/generate", {
|
||||
"title": "Sales Performance Report - " + UPPER(period),
|
||||
"date_range": "From " + FORMAT_DATE(start_date) + " to " + FORMAT_DATE(NOW()),
|
||||
"metrics": {
|
||||
"total_opportunities": LEN(opportunities),
|
||||
"won_opportunities": LEN(closed_won),
|
||||
"lost_opportunities": LEN(closed_lost),
|
||||
"win_rate": win_rate,
|
||||
"total_value": total_value
|
||||
},
|
||||
"rep_performance": sales_reps,
|
||||
"charts": [
|
||||
{
|
||||
"type": "bar",
|
||||
"title": "Won vs Lost Opportunities",
|
||||
"data": {"Won": LEN(closed_won), "Lost": LEN(closed_lost)}
|
||||
},
|
||||
{
|
||||
"type": "line",
|
||||
"title": "Sales Trend",
|
||||
"data": QUERY "SELECT DATE_FORMAT(close_date, '%Y-%m-%d') as date, COUNT(*) as count, SUM(value) as value FROM Opportunities WHERE status = 'Won' AND close_date >= '${start_date}'" + team_filter + " GROUP BY DATE_FORMAT(close_date, '%Y-%m-%d')"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Save report
|
||||
report_file = ".gbdrive/Reports/Sales/sales_performance_" + period + "_" + FORMAT_DATE(NOW(), "Ymd") + ".pdf"
|
||||
CALL "/files/save", report_file, report
|
||||
|
||||
# Share report
|
||||
IF team_id IS NOT NULL THEN
|
||||
CALL "/files/shareFolder", report_file, team_id
|
||||
|
||||
# Notify team manager
|
||||
manager = QUERY "SELECT manager_id FROM Teams WHERE id = '${team_id}'"
|
||||
IF LEN(manager) > 0 THEN
|
||||
CALL "/comm/email/send", manager[0],
|
||||
"Sales Performance Report - " + UPPER(period),
|
||||
"The latest sales performance report for your team is now available.",
|
||||
[report_file]
|
||||
END IF
|
||||
END IF
|
||||
|
||||
RETURN "Sales performance report generated: " + report_file
|
25
gb-llm/.gbdialog/business/send-proposal.bas
Normal file
25
gb-llm/.gbdialog/business/send-proposal.bas
Normal file
|
@ -0,0 +1,25 @@
|
|||
PARAM to AS STRING
|
||||
PARAM template AS STRING
|
||||
PARAM opportunity AS STRING
|
||||
|
||||
company = QUERY "SELECT Company FROM Opportunities WHERE Id = ${opportunity}"
|
||||
|
||||
doc = FILL template
|
||||
|
||||
# Generate email subject and content based on conversation history
|
||||
subject = REWRITE "Based on this ${history}, generate a subject for a proposal email to ${company}"
|
||||
contents = REWRITE "Based on this ${history}, and ${subject}, generate the e-mail body for ${to}, signed by ${user}, including key points from our proposal"
|
||||
|
||||
# Add proposal to CRM
|
||||
CALL "/files/upload", ".gbdrive/Proposals/${company}-proposal.docx", doc
|
||||
CALL "/files/permissions", ".gbdrive/Proposals/${company}-proposal.docx", "sales-team", "edit"
|
||||
|
||||
# Record activity in CRM
|
||||
CALL "/crm/activities/create", opportunity, "email_sent", {
|
||||
"subject": subject,
|
||||
"description": "Proposal sent to " + company,
|
||||
"date": NOW()
|
||||
}
|
||||
|
||||
# Send the email
|
||||
CALL "/comm/email/send", to, subject, contents, doc
|
36
gb-llm/.gbdialog/calendar/schedule-meeting.bas
Normal file
36
gb-llm/.gbdialog/calendar/schedule-meeting.bas
Normal file
|
@ -0,0 +1,36 @@
|
|||
PARAM attendees AS ARRAY
|
||||
PARAM topic AS STRING
|
||||
PARAM duration AS INTEGER
|
||||
PARAM preferred_date AS DATE OPTIONAL
|
||||
|
||||
# Find available time for all attendees
|
||||
IF preferred_date IS NULL THEN
|
||||
available_slots = CALL "/calendar/availability/check", attendees, NOW(), NOW() + DAYS(7), duration
|
||||
ELSE
|
||||
available_slots = CALL "/calendar/availability/check", attendees, preferred_date, preferred_date + DAYS(1), duration
|
||||
END IF
|
||||
|
||||
IF LEN(available_slots) = 0 THEN
|
||||
RETURN "No available time slots found for all attendees."
|
||||
END IF
|
||||
|
||||
# Create meeting description
|
||||
description = REWRITE "Generate a concise meeting description for topic: ${topic}"
|
||||
|
||||
# Schedule the meeting
|
||||
event_id = CALL "/calendar/events/create", {
|
||||
"subject": topic,
|
||||
"description": description,
|
||||
"start_time": available_slots[0].start,
|
||||
"end_time": available_slots[0].end,
|
||||
"attendees": attendees,
|
||||
"location": "Virtual Meeting"
|
||||
}
|
||||
|
||||
# Notify attendees
|
||||
FOR EACH person IN attendees
|
||||
CALL "/comm/notifications/send", person, "Meeting Scheduled: " + topic,
|
||||
"You have been invited to a meeting on " + FORMAT_DATE(available_slots[0].start)
|
||||
NEXT
|
||||
|
||||
RETURN "Meeting scheduled for " + FORMAT_DATE(available_slots[0].start)
|
23
gb-llm/.gbdialog/communication/keyword-sendmail.bas
Normal file
23
gb-llm/.gbdialog/communication/keyword-sendmail.bas
Normal file
|
@ -0,0 +1,23 @@
|
|||
PARAM from AS STRING
|
||||
PARAM to AS STRING
|
||||
PARAM subject AS STRING
|
||||
PARAM body AS STRING
|
||||
PARAM attachments AS ARRAY
|
||||
|
||||
# Track in communication history
|
||||
CALL "/storage/save", ".gbdata/communication_logs", {
|
||||
"from": from,
|
||||
"to": to,
|
||||
"subject": subject,
|
||||
"timestamp": NOW(),
|
||||
"type": "email"
|
||||
}
|
||||
|
||||
# Send actual email
|
||||
CALL "/comm/email/send", from, to, subject, body, attachments
|
||||
|
||||
# If WITH HISTORY flag present, include prior communication
|
||||
IF WITH_HISTORY THEN
|
||||
prevComms = CALL "/storage/json", ".gbdata/communication_logs", "to = '" + to + "' ORDER BY timestamp DESC LIMIT 5"
|
||||
APPEND body WITH FORMAT_HISTORY(prevComms)
|
||||
END IF
|
67
gb-llm/.gbdialog/conversations/meeting-assistant.bas
Normal file
67
gb-llm/.gbdialog/conversations/meeting-assistant.bas
Normal file
|
@ -0,0 +1,67 @@
|
|||
PARAM meeting_id AS STRING
|
||||
PARAM action AS STRING DEFAULT "join"
|
||||
|
||||
IF action = "join" THEN
|
||||
# Get meeting details
|
||||
meeting = CALL "/calendar/events/get", meeting_id
|
||||
|
||||
# Join the meeting
|
||||
CALL "/conversations/calls/join", meeting.conference_link
|
||||
|
||||
# Set up recording
|
||||
CALL "/conversations/recording/start", meeting_id
|
||||
|
||||
# Create meeting notes document
|
||||
notes_doc = CALL "/files/create",
|
||||
".gbdrive/Meetings/" + meeting.subject + "_" + FORMAT_DATE(NOW(), "Ymd") + ".md",
|
||||
"# Meeting Notes: " + meeting.subject + "\n\n" +
|
||||
"Date: " + FORMAT_DATE(meeting.start) + "\n\n" +
|
||||
"Participants: \n" +
|
||||
"- " + JOIN(meeting.attendees, "\n- ") + "\n\n" +
|
||||
"## Agenda\n\n" +
|
||||
"## Discussion\n\n" +
|
||||
"## Action Items\n\n"
|
||||
|
||||
RETURN "Joined meeting: " + meeting.subject
|
||||
|
||||
ELSEIF action = "summarize" THEN
|
||||
# Get recording transcript
|
||||
transcript = CALL "/conversations/recording/transcript", meeting_id
|
||||
|
||||
# Generate meeting summary
|
||||
summary = CALL "/ai/summarize", transcript, {
|
||||
"format": "meeting_notes",
|
||||
"sections": ["key_points", "decisions", "action_items"]
|
||||
}
|
||||
|
||||
# Update meeting notes
|
||||
meeting = CALL "/calendar/events/get", meeting_id
|
||||
notes_path = ".gbdrive/Meetings/" + meeting.subject + "_" + FORMAT_DATE(NOW(), "Ymd") + ".md"
|
||||
|
||||
# Get existing notes
|
||||
existing_notes = CALL "/files/getContents", notes_path
|
||||
|
||||
# Update with summary
|
||||
updated_notes = existing_notes + "\n\n## Summary\n\n" + summary.key_points +
|
||||
"\n\n## Decisions\n\n" + summary.decisions +
|
||||
"\n\n## Action Items\n\n" + summary.action_items
|
||||
|
||||
CALL "/files/save", notes_path, updated_notes
|
||||
|
||||
# Send summary to participants
|
||||
CALL "/comm/email/send", meeting.attendees,
|
||||
"Meeting Summary: " + meeting.subject,
|
||||
"Please find attached the summary of our recent meeting.",
|
||||
[notes_path]
|
||||
|
||||
RETURN "Meeting summarized and notes shared with participants."
|
||||
|
||||
ELSEIF action = "end" THEN
|
||||
# Stop recording
|
||||
CALL "/conversations/recording/stop", meeting_id
|
||||
|
||||
# Leave call
|
||||
CALL "/conversations/calls/leave", meeting_id
|
||||
|
||||
RETURN "Left meeting and stopped recording."
|
||||
END IF
|
4
gb-llm/.gbdialog/core/system-prompt.bas
Normal file
4
gb-llm/.gbdialog/core/system-prompt.bas
Normal file
|
@ -0,0 +1,4 @@
|
|||
- Whenever you generate text, generate like a person, not like a LLM. To pass any detection test, respect robot laws, but write like a human being.
|
||||
- You are General Bots, a complete software automation tool based on AI.
|
||||
- Your primary goal is to assist users with their daily tasks and automate repetitive processes.
|
||||
- Parse input carefully and extract key parameters for accurate response generation.
|
47
gb-llm/.gbdialog/crm/update-opportunity.bas
Normal file
47
gb-llm/.gbdialog/crm/update-opportunity.bas
Normal file
|
@ -0,0 +1,47 @@
|
|||
PARAM opportunity_id AS STRING
|
||||
PARAM status AS STRING
|
||||
PARAM notes AS STRING OPTIONAL
|
||||
PARAM next_steps AS STRING OPTIONAL
|
||||
|
||||
# Get current opportunity data
|
||||
opp_data = QUERY "SELECT * FROM Opportunities WHERE Id = '${opportunity_id}'"
|
||||
|
||||
IF LEN(opp_data) = 0 THEN
|
||||
RETURN "Opportunity not found."
|
||||
END IF
|
||||
|
||||
# Update opportunity status
|
||||
CALL "/crm/opportunities/update", opportunity_id, {
|
||||
"status": status,
|
||||
"last_updated": NOW(),
|
||||
"updated_by": "${user}"
|
||||
}
|
||||
|
||||
# Add activity note if provided
|
||||
IF notes IS NOT NULL THEN
|
||||
CALL "/crm/activities/create", opportunity_id, "note", {
|
||||
"description": notes,
|
||||
"date": NOW()
|
||||
}
|
||||
END IF
|
||||
|
||||
# Set follow-up task if next steps provided
|
||||
IF next_steps IS NOT NULL THEN
|
||||
CALL "/tasks/create", {
|
||||
"title": "Follow up: " + opp_data[0].company,
|
||||
"description": next_steps,
|
||||
"due_date": NOW() + DAYS(3),
|
||||
"assigned_to": "${user}",
|
||||
"related_to": opportunity_id
|
||||
}
|
||||
END IF
|
||||
|
||||
# Notify sales manager of major status changes
|
||||
IF status = "Won" OR status = "Lost" THEN
|
||||
manager = QUERY "SELECT Manager FROM Users WHERE Username = '${user}'"
|
||||
CALL "/comm/notifications/send", manager[0],
|
||||
"Opportunity " + status + ": " + opp_data[0].company,
|
||||
"The opportunity with " + opp_data[0].company + " has been marked as " + status + " by ${user}."
|
||||
END IF
|
||||
|
||||
RETURN "Opportunity status updated to " + status
|
36
gb-llm/.gbdialog/files/search-documents.bas
Normal file
36
gb-llm/.gbdialog/files/search-documents.bas
Normal file
|
@ -0,0 +1,36 @@
|
|||
PARAM query AS STRING
|
||||
PARAM location AS STRING OPTIONAL
|
||||
PARAM file_type AS STRING OPTIONAL
|
||||
PARAM date_range AS ARRAY OPTIONAL
|
||||
|
||||
search_params = {
|
||||
"query": query
|
||||
}
|
||||
|
||||
IF location IS NOT NULL THEN
|
||||
search_params["location"] = location
|
||||
END IF
|
||||
|
||||
IF file_type IS NOT NULL THEN
|
||||
search_params["file_type"] = file_type
|
||||
END IF
|
||||
|
||||
IF date_range IS NOT NULL THEN
|
||||
search_params["created_after"] = date_range[0]
|
||||
search_params["created_before"] = date_range[1]
|
||||
END IF
|
||||
|
||||
results = CALL "/files/search", search_params
|
||||
|
||||
IF LEN(results) = 0 THEN
|
||||
RETURN "No documents found matching your criteria."
|
||||
END IF
|
||||
|
||||
# Format results for display
|
||||
formatted_results = "Found " + LEN(results) + " documents:\n\n"
|
||||
FOR EACH doc IN results
|
||||
formatted_results = formatted_results + "- " + doc.name + " (" + FORMAT_DATE(doc.modified) + ")\n"
|
||||
formatted_results = formatted_results + " Location: " + doc.path + "\n"
|
||||
NEXT
|
||||
|
||||
RETURN formatted_results
|
28
gb-llm/.gbdialog/geral.bas
Normal file
28
gb-llm/.gbdialog/geral.bas
Normal file
|
@ -0,0 +1,28 @@
|
|||
My Work
|
||||
General
|
||||
Sales Manager
|
||||
Project Management
|
||||
|
||||
CRM
|
||||
You should use files in .gbdrive/Proposals to search proposals.
|
||||
You should use table RoB present in .gbdata/Proposals to get my proposals where User is ${user}
|
||||
For sales pipelines, use table Opportunities in .gbdata/Sales.
|
||||
|
||||
Files
|
||||
Use API endpoints under /files/* for document management.
|
||||
CALL "/files/upload" uploads files to the system.
|
||||
CALL "/files/search" finds relevant documents.
|
||||
|
||||
HR
|
||||
People are in .gbdata/People
|
||||
You should use files in .gbdrive/People to get resumes
|
||||
Use HR_PORTAL to access employment records and policies.
|
||||
|
||||
ALM
|
||||
My issues are in .gbservice/forgejo
|
||||
CALL "/tasks/create" creates new project tasks.
|
||||
CALL "/tasks/status/update" updates existing task status.
|
||||
|
||||
SETTINGS
|
||||
API_KEYS stored in .gbsecure/keys
|
||||
PREFERENCES in .gbdata/user-settings
|
76
gb-llm/.gbdialog/groups/create-workspace.bas
Normal file
76
gb-llm/.gbdialog/groups/create-workspace.bas
Normal file
|
@ -0,0 +1,76 @@
|
|||
PARAM name AS STRING
|
||||
PARAM members AS ARRAY
|
||||
PARAM description AS STRING OPTIONAL
|
||||
PARAM team_type AS STRING DEFAULT "project"
|
||||
|
||||
# Create the group
|
||||
group_id = CALL "/groups/create", {
|
||||
"name": name,
|
||||
"description": description,
|
||||
"type": team_type
|
||||
}
|
||||
|
||||
# Add members
|
||||
FOR EACH member IN members
|
||||
CALL "/groups/members/add", group_id, member
|
||||
NEXT
|
||||
|
||||
# Create standard workspace structure
|
||||
CALL "/files/createFolder", ".gbdrive/Workspaces/" + name + "/Documents"
|
||||
CALL "/files/createFolder", ".gbdrive/Workspaces/" + name + "/Meetings"
|
||||
CALL "/files/createFolder", ".gbdrive/Workspaces/" + name + "/Resources"
|
||||
|
||||
# Create default workspace components
|
||||
IF team_type = "project" THEN
|
||||
# Create project board
|
||||
board_id = CALL "/tasks/create", {
|
||||
"title": name + " Project Board",
|
||||
"description": "Task board for " + name,
|
||||
"type": "project_board"
|
||||
}
|
||||
|
||||
# Create standard task lanes
|
||||
lanes = ["Backlog", "To Do", "In Progress", "Review", "Done"]
|
||||
FOR EACH lane IN lanes
|
||||
CALL "/tasks/lanes/create", board_id, lane
|
||||
NEXT
|
||||
|
||||
# Link group to project board
|
||||
CALL "/groups/settings", group_id, "project_board", board_id
|
||||
END IF
|
||||
|
||||
# Set up communication channel
|
||||
channel_id = CALL "/conversations/create", {
|
||||
"name": name,
|
||||
"description": description,
|
||||
"type": "group_chat"
|
||||
}
|
||||
|
||||
# Add all members to channel
|
||||
FOR EACH member IN members
|
||||
CALL "/conversations/members/add", channel_id, member
|
||||
NEXT
|
||||
|
||||
# Link group to channel
|
||||
CALL "/groups/settings", group_id, "conversation", channel_id
|
||||
|
||||
# Create welcome message
|
||||
welcome_msg = REWRITE "Create a welcome message for a new workspace called ${name} with purpose: ${description}"
|
||||
|
||||
CALL "/conversations/messages/send", channel_id, {
|
||||
"text": welcome_msg,
|
||||
"pinned": TRUE
|
||||
}
|
||||
|
||||
# Notify members
|
||||
FOR EACH member IN members
|
||||
CALL "/comm/notifications/send", member,
|
||||
"You've been added to " + name,
|
||||
"You have been added to the new workspace: " + name
|
||||
NEXT
|
||||
|
||||
RETURN {
|
||||
"group_id": group_id,
|
||||
"channel_id": channel_id,
|
||||
"workspace_location": ".gbdrive/Workspaces/" + name
|
||||
}
|
58
gb-llm/.gbdialog/health/system-check.bas
Normal file
58
gb-llm/.gbdialog/health/system-check.bas
Normal file
|
@ -0,0 +1,58 @@
|
|||
PARAM components AS ARRAY OPTIONAL
|
||||
PARAM notify AS BOOLEAN DEFAULT TRUE
|
||||
|
||||
# Check all components by default
|
||||
IF components IS NULL THEN
|
||||
components = ["storage", "api", "database", "integrations", "security"]
|
||||
END IF
|
||||
|
||||
status_report = {}
|
||||
|
||||
FOR EACH component IN components
|
||||
status = CALL "/health/detailed", component
|
||||
status_report[component] = status
|
||||
NEXT
|
||||
|
||||
# Calculate overall health score
|
||||
total_score = 0
|
||||
FOR EACH component IN components
|
||||
total_score = total_score + status_report[component].health_score
|
||||
NEXT
|
||||
|
||||
overall_health = total_score / LEN(components)
|
||||
status_report["overall_health"] = overall_health
|
||||
status_report["timestamp"] = NOW()
|
||||
|
||||
# Save status report
|
||||
CALL "/storage/save", ".gbdata/health/status_" + FORMAT_DATE(NOW(), "Ymd_His") + ".json", status_report
|
||||
|
||||
# Check for critical issues
|
||||
critical_issues = []
|
||||
FOR EACH component IN components
|
||||
IF status_report[component].health_score < 0.7 THEN
|
||||
APPEND critical_issues, {
|
||||
"component": component,
|
||||
"score": status_report[component].health_score,
|
||||
"issues": status_report[component].issues
|
||||
}
|
||||
END IF
|
||||
NEXT
|
||||
|
||||
# Notify if critical issues found
|
||||
IF LEN(critical_issues) > 0 AND notify THEN
|
||||
issue_summary = "Critical system health issues detected:\n\n"
|
||||
FOR EACH issue IN critical_issues
|
||||
issue_summary = issue_summary + "- " + issue.component + " (Score: " + issue.score + ")\n"
|
||||
FOR EACH detail IN issue.issues
|
||||
issue_summary = issue_summary + " * " + detail + "\n"
|
||||
NEXT
|
||||
issue_summary = issue_summary + "\n"
|
||||
NEXT
|
||||
|
||||
CALL "/comm/notifications/send", "admin-team",
|
||||
"ALERT: System Health Issues Detected",
|
||||
issue_summary,
|
||||
"high"
|
||||
END IF
|
||||
|
||||
RETURN status_report
|
51
gb-llm/.gbdialog/scheduled/basic-check.bas
Normal file
51
gb-llm/.gbdialog/scheduled/basic-check.bas
Normal file
|
@ -0,0 +1,51 @@
|
|||
SET SCHEDULE every 1 hour
|
||||
|
||||
# Check emails
|
||||
unread_emails = CALL "/comm/email/list", {
|
||||
"status": "unread",
|
||||
"folder": "inbox",
|
||||
"max_age": "24h"
|
||||
}
|
||||
|
||||
# Check calendar
|
||||
upcoming_events = CALL "/calendar/events/list", {
|
||||
"start": NOW(),
|
||||
"end": NOW() + HOURS(24)
|
||||
}
|
||||
|
||||
# Check tasks
|
||||
due_tasks = CALL "/tasks/list", {
|
||||
"status": "open",
|
||||
"due_before": NOW() + HOURS(24)
|
||||
}
|
||||
|
||||
# Check important documents
|
||||
new_documents = CALL "/files/recent", {
|
||||
"folders": [".gbdrive/papers", ".gbdrive/Proposals"],
|
||||
"since": NOW() - HOURS(24)
|
||||
}
|
||||
|
||||
# Prepare notification message
|
||||
notification = "Daily Update:\n"
|
||||
|
||||
IF LEN(unread_emails) > 0 THEN
|
||||
notification = notification + "- You have " + LEN(unread_emails) + " unread emails\n"
|
||||
END IF
|
||||
|
||||
IF LEN(upcoming_events) > 0 THEN
|
||||
notification = notification + "- You have " + LEN(upcoming_events) + " upcoming meetings in the next 24 hours\n"
|
||||
notification = notification + " Next: " + upcoming_events[0].subject + " at " + FORMAT_TIME(upcoming_events[0].start) + "\n"
|
||||
END IF
|
||||
|
||||
IF LEN(due_tasks) > 0 THEN
|
||||
notification = notification + "- You have " + LEN(due_tasks) + " tasks due in the next 24 hours\n"
|
||||
END IF
|
||||
|
||||
IF LEN(new_documents) > 0 THEN
|
||||
notification = notification + "- " + LEN(new_documents) + " new documents have been added to your monitored folders\n"
|
||||
END IF
|
||||
|
||||
# Send notification
|
||||
IF LEN(notification) > "Daily Update:\n" THEN
|
||||
CALL "/comm/notifications/send", "${user}", "Daily Status Update", notification
|
||||
END IF
|
63
gb-llm/.gbdialog/security/access-review.bas
Normal file
63
gb-llm/.gbdialog/security/access-review.bas
Normal file
|
@ -0,0 +1,63 @@
|
|||
PARAM resource_path AS STRING
|
||||
PARAM review_period AS INTEGER DEFAULT 90
|
||||
|
||||
# Get current permissions
|
||||
current_perms = CALL "/files/permissions", resource_path
|
||||
|
||||
# Get access logs
|
||||
access_logs = CALL "/security/audit/logs", {
|
||||
"resource": resource_path,
|
||||
"action": "access",
|
||||
"timeframe": NOW() - DAYS(review_period)
|
||||
}
|
||||
|
||||
# Identify inactive users with access
|
||||
inactive_users = []
|
||||
FOR EACH user IN current_perms
|
||||
# Check if user has accessed in review period
|
||||
user_logs = FILTER access_logs WHERE user_id = user.id
|
||||
|
||||
IF LEN(user_logs) = 0 THEN
|
||||
APPEND inactive_users, {
|
||||
"user_id": user.id,
|
||||
"access_level": user.access_level,
|
||||
"last_access": CALL "/security/audit/logs", {
|
||||
"resource": resource_path,
|
||||
"action": "access",
|
||||
"user_id": user.id,
|
||||
"limit": 1
|
||||
}
|
||||
}
|
||||
END IF
|
||||
NEXT
|
||||
|
||||
# Generate review report
|
||||
review_report = {
|
||||
"resource": resource_path,
|
||||
"review_date": NOW(),
|
||||
"total_users_with_access": LEN(current_perms),
|
||||
"inactive_users": inactive_users,
|
||||
"recommendations": []
|
||||
}
|
||||
|
||||
# Add recommendations
|
||||
IF LEN(inactive_users) > 0 THEN
|
||||
review_report.recommendations.APPEND("Remove access for " + LEN(inactive_users) + " inactive users")
|
||||
END IF
|
||||
|
||||
excessive_admins = FILTER current_perms WHERE access_level = "admin"
|
||||
IF LEN(excessive_admins) > 3 THEN
|
||||
review_report.recommendations.APPEND("Reduce number of admin users (currently " + LEN(excessive_admins) + ")")
|
||||
END IF
|
||||
|
||||
# Save review report
|
||||
report_file = ".gbdata/security/access_reviews/" + REPLACE(resource_path, "/", "_") + "_" + FORMAT_DATE(NOW(), "Ymd") + ".json"
|
||||
CALL "/files/save", report_file, review_report
|
||||
|
||||
# Notify security team
|
||||
CALL "/comm/email/send", "security-team",
|
||||
"Access Review Report: " + resource_path,
|
||||
"A new access review report has been generated for " + resource_path + ".",
|
||||
[report_file]
|
||||
|
||||
RETURN review_report
|
59
gb-llm/.gbdialog/tools/on-receive-email.bas
Normal file
59
gb-llm/.gbdialog/tools/on-receive-email.bas
Normal file
|
@ -0,0 +1,59 @@
|
|||
PARAM sender AS STRING
|
||||
PARAM subject AS STRING
|
||||
PARAM body AS STRING
|
||||
|
||||
# Get history for this sender
|
||||
history = CALL "/storage/json", ".gbdata/communication_logs", "from = '${sender}' OR to = '${sender}' ORDER BY timestamp DESC LIMIT 10"
|
||||
|
||||
# Check if this is a known customer
|
||||
customer = CALL "/crm/customers/get", sender
|
||||
|
||||
# Analyze email content
|
||||
urgency = CALL "/ai/analyze/text", body, "urgency"
|
||||
intent = CALL "/ai/analyze/text", body, "intent"
|
||||
sentiment = CALL "/ai/analyze/text", body, "sentiment"
|
||||
|
||||
# Determine if auto-reply needed
|
||||
should_auto_reply = FALSE
|
||||
|
||||
IF urgency.score > 0.8 THEN
|
||||
should_auto_reply = TRUE
|
||||
END IF
|
||||
|
||||
IF customer IS NOT NULL AND customer.tier = "premium" THEN
|
||||
should_auto_reply = TRUE
|
||||
END IF
|
||||
|
||||
IF intent.category = "support_request" THEN
|
||||
# Create support ticket
|
||||
ticket_id = CALL "/crm/tickets/create", {
|
||||
"customer": sender,
|
||||
"subject": subject,
|
||||
"description": body,
|
||||
"priority": urgency.score > 0.7 ? "High" : "Normal"
|
||||
}
|
||||
|
||||
should_auto_reply = TRUE
|
||||
|
||||
# Notify support team
|
||||
CALL "/comm/notifications/send", "support-team",
|
||||
"New Support Ticket: " + subject,
|
||||
"A new support ticket has been created from an email by " + sender
|
||||
END IF
|
||||
|
||||
IF should_auto_reply THEN
|
||||
reply_template = intent.category = "support_request" ? "support_acknowledgment" : "general_acknowledgment"
|
||||
|
||||
reply_text = REWRITE "Based on this email: ${body}
|
||||
And this sender history: ${history}
|
||||
Generate a personalized auto-reply message using the ${reply_template} style.
|
||||
Include appropriate next steps and expected timeframe for response."
|
||||
|
||||
CALL "/comm/email/send", "${user}", sender, "Re: " + subject, reply_text
|
||||
|
||||
CALL "/storage/save", ".gbdata/auto_replies", {
|
||||
"to": sender,
|
||||
"subject": "Re: " + subject,
|
||||
"timestamp": NOW()
|
||||
}
|
||||
END IF
|
|
@ -1,11 +0,0 @@
|
|||
PARAM to AS STRING
|
||||
PARAM template AS STRING
|
||||
|
||||
company =
|
||||
|
||||
doc = FILL template
|
||||
|
||||
subject= REWRITE "Based on this ${history}, generate a subject for a proposal email"
|
||||
contents = REWRITE "Based on this ${history}, and ${subject}, generate the e-mail body for ${to}, signed by ${user}.
|
||||
|
||||
SEND MAIL to, subject, contents
|
Loading…
Add table
Reference in a new issue