From bf382e623ee0945426ea9ef54e868aa75490aecb Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Sun, 20 Apr 2025 01:40:40 -0300 Subject: [PATCH] feat(gb-llm): Implement email sending and meeting scheduling functionalities; add customer sentiment analysis and opportunity updates --- gb-infra/src/setup.rs | 3 + .../ai/analyze-customer-sentiment.bas | 45 ++++++++++ .../.gbdialog/analytics/sales-performance.bas | 83 +++++++++++++++++++ gb-llm/.gbdialog/business/send-proposal.bas | 25 ++++++ .../.gbdialog/calendar/schedule-meeting.bas | 36 ++++++++ .../communication/keyword-sendmail.bas | 23 +++++ .../conversations/meeting-assistant.bas | 67 +++++++++++++++ gb-llm/.gbdialog/core/system-prompt.bas | 4 + gb-llm/.gbdialog/crm/update-opportunity.bas | 47 +++++++++++ gb-llm/.gbdialog/files/search-documents.bas | 36 ++++++++ gb-llm/.gbdialog/geral.bas | 28 +++++++ gb-llm/.gbdialog/groups/create-workspace.bas | 76 +++++++++++++++++ gb-llm/.gbdialog/health/system-check.bas | 58 +++++++++++++ gb-llm/.gbdialog/scheduled/basic-check.bas | 51 ++++++++++++ gb-llm/.gbdialog/security/access-review.bas | 63 ++++++++++++++ gb-llm/.gbdialog/tools/on-receive-email.bas | 59 +++++++++++++ gb-llm/prompts/send-proposal.txt | 11 --- 17 files changed, 704 insertions(+), 11 deletions(-) create mode 100644 gb-llm/.gbdialog/ai/analyze-customer-sentiment.bas create mode 100644 gb-llm/.gbdialog/analytics/sales-performance.bas create mode 100644 gb-llm/.gbdialog/business/send-proposal.bas create mode 100644 gb-llm/.gbdialog/calendar/schedule-meeting.bas create mode 100644 gb-llm/.gbdialog/communication/keyword-sendmail.bas create mode 100644 gb-llm/.gbdialog/conversations/meeting-assistant.bas create mode 100644 gb-llm/.gbdialog/core/system-prompt.bas create mode 100644 gb-llm/.gbdialog/crm/update-opportunity.bas create mode 100644 gb-llm/.gbdialog/files/search-documents.bas create mode 100644 gb-llm/.gbdialog/geral.bas create mode 100644 gb-llm/.gbdialog/groups/create-workspace.bas create mode 100644 gb-llm/.gbdialog/health/system-check.bas create mode 100644 gb-llm/.gbdialog/scheduled/basic-check.bas create mode 100644 gb-llm/.gbdialog/security/access-review.bas create mode 100644 gb-llm/.gbdialog/tools/on-receive-email.bas delete mode 100644 gb-llm/prompts/send-proposal.txt diff --git a/gb-infra/src/setup.rs b/gb-infra/src/setup.rs index fa613de..0413bbc 100644 --- a/gb-infra/src/setup.rs +++ b/gb-infra/src/setup.rs @@ -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"; diff --git a/gb-llm/.gbdialog/ai/analyze-customer-sentiment.bas b/gb-llm/.gbdialog/ai/analyze-customer-sentiment.bas new file mode 100644 index 0000000..e57c9f2 --- /dev/null +++ b/gb-llm/.gbdialog/ai/analyze-customer-sentiment.bas @@ -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 +} diff --git a/gb-llm/.gbdialog/analytics/sales-performance.bas b/gb-llm/.gbdialog/analytics/sales-performance.bas new file mode 100644 index 0000000..67abf95 --- /dev/null +++ b/gb-llm/.gbdialog/analytics/sales-performance.bas @@ -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 diff --git a/gb-llm/.gbdialog/business/send-proposal.bas b/gb-llm/.gbdialog/business/send-proposal.bas new file mode 100644 index 0000000..e5b7c4f --- /dev/null +++ b/gb-llm/.gbdialog/business/send-proposal.bas @@ -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 diff --git a/gb-llm/.gbdialog/calendar/schedule-meeting.bas b/gb-llm/.gbdialog/calendar/schedule-meeting.bas new file mode 100644 index 0000000..1fbaa49 --- /dev/null +++ b/gb-llm/.gbdialog/calendar/schedule-meeting.bas @@ -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) diff --git a/gb-llm/.gbdialog/communication/keyword-sendmail.bas b/gb-llm/.gbdialog/communication/keyword-sendmail.bas new file mode 100644 index 0000000..f83a0a4 --- /dev/null +++ b/gb-llm/.gbdialog/communication/keyword-sendmail.bas @@ -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 diff --git a/gb-llm/.gbdialog/conversations/meeting-assistant.bas b/gb-llm/.gbdialog/conversations/meeting-assistant.bas new file mode 100644 index 0000000..bfd6c97 --- /dev/null +++ b/gb-llm/.gbdialog/conversations/meeting-assistant.bas @@ -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 diff --git a/gb-llm/.gbdialog/core/system-prompt.bas b/gb-llm/.gbdialog/core/system-prompt.bas new file mode 100644 index 0000000..ec9b2fc --- /dev/null +++ b/gb-llm/.gbdialog/core/system-prompt.bas @@ -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. diff --git a/gb-llm/.gbdialog/crm/update-opportunity.bas b/gb-llm/.gbdialog/crm/update-opportunity.bas new file mode 100644 index 0000000..9795f35 --- /dev/null +++ b/gb-llm/.gbdialog/crm/update-opportunity.bas @@ -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 diff --git a/gb-llm/.gbdialog/files/search-documents.bas b/gb-llm/.gbdialog/files/search-documents.bas new file mode 100644 index 0000000..a8345d0 --- /dev/null +++ b/gb-llm/.gbdialog/files/search-documents.bas @@ -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 diff --git a/gb-llm/.gbdialog/geral.bas b/gb-llm/.gbdialog/geral.bas new file mode 100644 index 0000000..704f4b4 --- /dev/null +++ b/gb-llm/.gbdialog/geral.bas @@ -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 diff --git a/gb-llm/.gbdialog/groups/create-workspace.bas b/gb-llm/.gbdialog/groups/create-workspace.bas new file mode 100644 index 0000000..15d498a --- /dev/null +++ b/gb-llm/.gbdialog/groups/create-workspace.bas @@ -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 +} diff --git a/gb-llm/.gbdialog/health/system-check.bas b/gb-llm/.gbdialog/health/system-check.bas new file mode 100644 index 0000000..2059579 --- /dev/null +++ b/gb-llm/.gbdialog/health/system-check.bas @@ -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 diff --git a/gb-llm/.gbdialog/scheduled/basic-check.bas b/gb-llm/.gbdialog/scheduled/basic-check.bas new file mode 100644 index 0000000..f875150 --- /dev/null +++ b/gb-llm/.gbdialog/scheduled/basic-check.bas @@ -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 diff --git a/gb-llm/.gbdialog/security/access-review.bas b/gb-llm/.gbdialog/security/access-review.bas new file mode 100644 index 0000000..2a56c0d --- /dev/null +++ b/gb-llm/.gbdialog/security/access-review.bas @@ -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 diff --git a/gb-llm/.gbdialog/tools/on-receive-email.bas b/gb-llm/.gbdialog/tools/on-receive-email.bas new file mode 100644 index 0000000..abd0f91 --- /dev/null +++ b/gb-llm/.gbdialog/tools/on-receive-email.bas @@ -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 diff --git a/gb-llm/prompts/send-proposal.txt b/gb-llm/prompts/send-proposal.txt deleted file mode 100644 index 994bf0f..0000000 --- a/gb-llm/prompts/send-proposal.txt +++ /dev/null @@ -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 \ No newline at end of file