systemd+skills+mattermost
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Mattermost Notification Tool for DeerFlow.
|
||||
Posts notifications to Mattermost via incoming webhook.
|
||||
Set MATTERMOST_WEBHOOK_URL in .env
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
from langchain.tools import tool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
MATTERMOST_WEBHOOK_URL = os.environ.get("MATTERMOST_WEBHOOK_URL", "")
|
||||
|
||||
|
||||
@tool("notify_team", parse_docstring=True)
|
||||
def notify_team_tool(
|
||||
message: str,
|
||||
channel: str = "",
|
||||
username: str = "DeerFlow Agent",
|
||||
) -> str:
|
||||
"""Send a notification to the WEVAL team via Mattermost. Use this after completing research, enrichment, or any task that the team should know about.
|
||||
|
||||
Args:
|
||||
message: The message to send. Supports Markdown formatting.
|
||||
channel: Optional channel override (e.g. #general, #alerts). Leave empty for default.
|
||||
username: Display name for the bot. Default is DeerFlow Agent.
|
||||
"""
|
||||
if not MATTERMOST_WEBHOOK_URL:
|
||||
return json.dumps({"error": "MATTERMOST_WEBHOOK_URL not configured in .env"})
|
||||
|
||||
try:
|
||||
import urllib.request
|
||||
|
||||
payload = {
|
||||
"text": message,
|
||||
"username": username,
|
||||
"icon_url": "https://weval-consulting.com/assets/logo-weval-png-DChrMGao.png",
|
||||
}
|
||||
if channel:
|
||||
payload["channel"] = channel
|
||||
|
||||
data = json.dumps(payload).encode()
|
||||
req = urllib.request.Request(
|
||||
MATTERMOST_WEBHOOK_URL,
|
||||
data=data,
|
||||
headers={"Content-Type": "application/json"},
|
||||
)
|
||||
|
||||
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||
result = resp.read().decode()
|
||||
|
||||
return json.dumps({"status": "sent", "response": result})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Mattermost notification failed: {e}")
|
||||
return json.dumps({"error": str(e)})
|
||||
@@ -0,0 +1,94 @@
|
||||
"""
|
||||
Web Search Tool - Search the web using SearXNG (replaces DDG which has DNS issues).
|
||||
SearXNG runs on localhost:8080.
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
from langchain.tools import tool
|
||||
|
||||
from deerflow.config import get_app_config
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
SEARXNG_URL = os.environ.get("SEARXNG_URL", "http://127.0.0.1:8080")
|
||||
|
||||
|
||||
def _search_text(
|
||||
query: str,
|
||||
max_results: int = 5,
|
||||
language: str = "auto",
|
||||
safesearch: int = 1,
|
||||
) -> list[dict]:
|
||||
"""
|
||||
Execute text search using SearXNG.
|
||||
"""
|
||||
try:
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
|
||||
params = urllib.parse.urlencode({
|
||||
"q": query,
|
||||
"format": "json",
|
||||
"categories": "general",
|
||||
"language": language,
|
||||
"safesearch": safesearch,
|
||||
})
|
||||
|
||||
url = f"{SEARXNG_URL}/search?{params}"
|
||||
req = urllib.request.Request(url)
|
||||
req.add_header("Accept", "application/json")
|
||||
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
data = json.loads(resp.read().decode())
|
||||
|
||||
results = data.get("results", [])[:max_results]
|
||||
return results
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to search web via SearXNG: {e}")
|
||||
return []
|
||||
|
||||
|
||||
@tool("web_search", parse_docstring=True)
|
||||
def web_search_tool(
|
||||
query: str,
|
||||
max_results: int = 5,
|
||||
) -> str:
|
||||
"""Search the web for information. Use this tool to find current information, news, articles, and facts from the internet.
|
||||
|
||||
Args:
|
||||
query: Search keywords describing what you want to find. Be specific for better results.
|
||||
max_results: Maximum number of results to return. Default is 5.
|
||||
"""
|
||||
config = get_app_config().get_tool_config("web_search")
|
||||
|
||||
if config is not None and "max_results" in config.model_extra:
|
||||
max_results = config.model_extra.get("max_results", max_results)
|
||||
|
||||
results = _search_text(
|
||||
query=query,
|
||||
max_results=max_results,
|
||||
)
|
||||
|
||||
if not results:
|
||||
return json.dumps({"error": "No results found", "query": query}, ensure_ascii=False)
|
||||
|
||||
normalized_results = [
|
||||
{
|
||||
"title": r.get("title", ""),
|
||||
"url": r.get("url", r.get("href", r.get("link", ""))),
|
||||
"content": r.get("content", r.get("body", r.get("snippet", ""))),
|
||||
}
|
||||
for r in results
|
||||
]
|
||||
|
||||
output = {
|
||||
"query": query,
|
||||
"total_results": len(normalized_results),
|
||||
"results": normalized_results,
|
||||
}
|
||||
|
||||
return json.dumps(output, indent=2, ensure_ascii=False)
|
||||
@@ -24,7 +24,7 @@ http {
|
||||
}
|
||||
|
||||
upstream frontend {
|
||||
server 127.0.0.1:3000;
|
||||
server 127.0.0.1:3002;
|
||||
}
|
||||
|
||||
server {
|
||||
|
||||
44
skills/public/weval-crm-enrichment/SKILL.md
Normal file
44
skills/public/weval-crm-enrichment/SKILL.md
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
name: weval-crm-enrichment
|
||||
description: Enrich company and contact data for WEVAL Consulting CRM pipeline via Twenty CRM API. Use when asked about CRM stats, companies, deals, contacts, or pipeline data.
|
||||
---
|
||||
|
||||
# WEVAL CRM Enrichment Skill
|
||||
|
||||
## Purpose
|
||||
Enrich company and contact data for WEVAL Consulting CRM pipeline.
|
||||
|
||||
## Available APIs
|
||||
- CRM Stats: `GET https://weval-consulting.com/api/crm-api.php?action=stats`
|
||||
- Companies: `GET https://weval-consulting.com/api/crm-api.php?action=companies`
|
||||
- Deals: `GET https://weval-consulting.com/api/crm-api.php?action=deals`
|
||||
- Contacts: `GET https://weval-consulting.com/api/crm-api.php?action=contacts`
|
||||
- Enrich Domain: `POST https://weval-consulting.com/api/crm-api.php?action=enrich` body: `{"domain":"example.com","company_id":1}`
|
||||
- Add Contact: `POST https://weval-consulting.com/api/crm-api.php?action=contacts` body: `{"first_name":"","last_name":"","email":"","company_id":1}`
|
||||
|
||||
## Bash Tools Available
|
||||
```bash
|
||||
# theHarvester - find emails/subdomains for a domain
|
||||
theHarvester -d example.com -b google,bing,duckduckgo -l 50
|
||||
|
||||
# emailfinder - find email patterns
|
||||
emailfinder -d example.com
|
||||
|
||||
# Direct DB query
|
||||
PGPASSWORD=admin123 psql -U admin -h 127.0.0.1 -d weval_crm -c "SELECT * FROM crm.companies;"
|
||||
|
||||
# LinkedIn data via SearXNG
|
||||
curl -s "http://127.0.0.1:8080/search?q=site:linkedin.com+COMPANY+NAME+morocco&format=json"
|
||||
```
|
||||
|
||||
## Workflow
|
||||
1. Fetch current companies from CRM API via web_fetch
|
||||
2. For each company domain, use bash to run theHarvester
|
||||
3. Parse discovered emails and create contacts via API
|
||||
4. Research LinkedIn/web via web_search for decision-maker names
|
||||
5. Generate enrichment report with new contacts found
|
||||
|
||||
## Context
|
||||
WEVAL Consulting - sovereign AI consulting firm in Casablanca, Morocco.
|
||||
Key clients: Cosumar, Carrefour Maroc, Vistex, Huawei Cloud, Confluent Digital, Groupe Ethica.
|
||||
Focus: ERP/SAP, Cloud, Supply Chain, Life Sciences/Pharma, Cybersecurity.
|
||||
46
skills/public/weval-ethica-research/SKILL.md
Normal file
46
skills/public/weval-ethica-research/SKILL.md
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
name: weval-ethica-research
|
||||
description: Query Ethica database for real-time campaign KPIs, HCP analytics, send tracking, and campaign performance across Morocco, Tunisia, and Algeria. Use when asked about Ethica campaigns, HCP counts, open rates, or pharma outreach metrics.
|
||||
---
|
||||
|
||||
# WEVAL Ethica Campaign KPIs & HCP Analytics Skill
|
||||
|
||||
## Purpose
|
||||
Query Ethica database for real-time campaign KPIs and HCP analytics.
|
||||
|
||||
## Database Access
|
||||
- Server: S95 (95.216.167.89), SSH port 49222
|
||||
- DB: adx_system, schema: ethica (22 tables)
|
||||
- Credentials: admin/admin123
|
||||
- Access: ssh -p 49222 root@95.216.167.89 "PGPASSWORD=admin123 psql -U admin -h 127.0.0.1 -d adx_system -c SQL"
|
||||
|
||||
## Key Tables
|
||||
- campaigns: id, name, status, target_specialites, target_pays, sent/open/click/bounce counts
|
||||
- send_log: campaign_id, hcp_id, email, sent_at, status
|
||||
- tracking_opens: campaign_id, hcp_id, opened_at
|
||||
- tracking_clicks: campaign_id, hcp_id, clicked_at, url
|
||||
- medecins_validated: 123K HCPs (nom, prenom, specialite, email, telephone, ville, pays)
|
||||
- consent_log: GDPR consent tracking
|
||||
- senders: sender domains and warmup status
|
||||
|
||||
## Current State (27 mars 2026)
|
||||
- Campaigns: 1 (Lancement Ethica Pharma Mars 2026), status=paused, 0 sent
|
||||
- HCPs: 123,032 validated (MA, TN, DZ)
|
||||
- Sends: 0 (not yet launched)
|
||||
- Tracking: 2 opens, 2 clicks (test)
|
||||
|
||||
## KPI Queries
|
||||
|
||||
### Campaign Overview
|
||||
SELECT id, name, status, target_pays, sent_count, open_count, click_count, bounce_count FROM ethica.campaigns ORDER BY created_at DESC;
|
||||
|
||||
### HCP Stats by Specialty
|
||||
SELECT specialite, pays, COUNT(*) as total, COUNT(email) AS with_email FROM ethica.medecins_validated GROUP BY specialite, pays ORDER BY total DESC LIMIT 20;
|
||||
|
||||
## Workflow
|
||||
1. Identify campaign by name or ID
|
||||
2. Query overview for totals
|
||||
3. Calculate rates only when sent_count > 0
|
||||
4. Compare to pharma benchmarks: open 18-25 pct, click 2-5 pct
|
||||
5. NEVER fabricate data - report exactly what DB returns
|
||||
6. Flag empty data (0 sends = pre-launch)
|
||||
29
skills/public/weval-infra-monitor/SKILL.md
Normal file
29
skills/public/weval-infra-monitor/SKILL.md
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: weval-infra-monitor
|
||||
description: Use this skill to monitor WEVAL infrastructure status, check server health, verify services are running, and diagnose issues across S204, S95, and S151 servers.
|
||||
---
|
||||
|
||||
# WEVAL Infrastructure Monitor Skill
|
||||
|
||||
## Servers
|
||||
- **S204** (weval-consulting.com): nginx, PHP 8.5, PostgreSQL 13, 14 Docker containers, Ollama
|
||||
- **S95** (95.216.167.89): Apache, PMTA v5.0r3, Node.js WEVADS v2, PostgreSQL
|
||||
- **S151** (151.80.235.110): OVH, tracking relay, Ollama granite4, OpenClaw, DeerFlow sandbox
|
||||
|
||||
## Health Endpoints
|
||||
- Chat API: `https://weval-consulting.com/api/weval-ia`
|
||||
- Fast API: `https://weval-consulting.com/api/weval-ia-fast.php`
|
||||
- Ethica: `https://ethica.wevup.app/ethica-app-v3.html`
|
||||
- CRM: `https://weval-consulting.com/api/crm-api.php?action=stats`
|
||||
- DeerFlow: `http://localhost:2024/ok`
|
||||
- Ollama S204: `http://localhost:11435/api/ps`
|
||||
- Ollama S151: `http://151.80.235.110:11434/api/ps`
|
||||
|
||||
## Chat Monitor
|
||||
- 30 systems dashboard: `https://weval-consulting.com/test-report/wevia-chat-monitor.html`
|
||||
|
||||
## Key Metrics to Check
|
||||
- PHP workers: `pgrep -c php-fpm8.5`
|
||||
- Disk: `df -h /`
|
||||
- Memory: `free -m`
|
||||
- Docker: `docker ps --format '{{.Names}} {{.Status}}'`
|
||||
33
skills/public/weval-proposal-generator/SKILL.md
Normal file
33
skills/public/weval-proposal-generator/SKILL.md
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: weval-proposal-generator
|
||||
description: Generate professional commercial proposals (devis) for WEVAL Consulting deals. Use when asked to create a proposal, quote, or commercial offer.
|
||||
---
|
||||
|
||||
# WEVAL Proposal Generator Skill
|
||||
|
||||
## Purpose
|
||||
Generate professional commercial proposals (devis) for WEVAL Consulting deals.
|
||||
|
||||
## Available APIs
|
||||
- Get Deals: `GET https://weval-consulting.com/api/crm-api.php?action=deals`
|
||||
- Generate Proposal: `POST https://weval-consulting.com/api/crm-api.php?action=proposal_generate` body: `{"deal_id":1}`
|
||||
- PDF Generation: `POST https://weval-consulting.com/api/weval-ia-pdf.php` body: `{"message":"...","title":"..."}`
|
||||
|
||||
## Template Structure
|
||||
1. Executive Summary (client name, project scope, WEVAL value proposition)
|
||||
2. Understanding of Needs (client challenges, market context)
|
||||
3. Proposed Solution (methodology, deliverables, WEVAL expertise)
|
||||
4. Project Timeline (phases, milestones, Gantt-style)
|
||||
5. Pricing Table (modules, unit prices, total)
|
||||
6. Terms & Conditions (payment terms, SLA, confidentiality)
|
||||
7. WEVAL References (similar projects delivered)
|
||||
|
||||
## Pricing Guidelines
|
||||
- Consulting day rate: 5,000-8,000 MAD / 500-800 EUR
|
||||
- ERP/SAP projects: 200,000-2,000,000 MAD
|
||||
- Digital transformation: 100,000-500,000 MAD
|
||||
- Pharma/Life Sciences: 50,000-200,000 MAD per brand
|
||||
|
||||
## Context
|
||||
WEVAL Consulting — 200+ projects, 8 countries, 97% satisfaction rate.
|
||||
Partners: SAP, Vistex, Huawei Cloud.
|
||||
Reference in New Issue
Block a user