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 tar::Archive;
|
||||||
use zip::ZipArchive;
|
use zip::ZipArchive;
|
||||||
|
|
||||||
|
// TODO: https://helpcenter.onlyoffice.com/docs/installation/docs-community-install-ubuntu.aspx
|
||||||
|
|
||||||
|
|
||||||
const INSTALL_DIR: &str = "/opt/gbo";
|
const INSTALL_DIR: &str = "/opt/gbo";
|
||||||
const TEMP_DIR: &str = "/tmp/gbotemp";
|
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