diff --git a/backend/packages/harness/deerflow/community/mattermost_notify/__init__.py b/backend/packages/harness/deerflow/community/mattermost_notify/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/packages/harness/deerflow/community/mattermost_notify/tools.py b/backend/packages/harness/deerflow/community/mattermost_notify/tools.py new file mode 100644 index 0000000..4f4259b --- /dev/null +++ b/backend/packages/harness/deerflow/community/mattermost_notify/tools.py @@ -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)}) diff --git a/backend/packages/harness/deerflow/community/searxng_search/__init__.py b/backend/packages/harness/deerflow/community/searxng_search/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/packages/harness/deerflow/community/searxng_search/tools.py b/backend/packages/harness/deerflow/community/searxng_search/tools.py new file mode 100644 index 0000000..6c2e5a6 --- /dev/null +++ b/backend/packages/harness/deerflow/community/searxng_search/tools.py @@ -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) diff --git a/docker/nginx/nginx.local.conf b/docker/nginx/nginx.local.conf index 289c388..c270b54 100644 --- a/docker/nginx/nginx.local.conf +++ b/docker/nginx/nginx.local.conf @@ -24,7 +24,7 @@ http { } upstream frontend { - server 127.0.0.1:3000; + server 127.0.0.1:3002; } server { diff --git a/skills/public/weval-crm-enrichment/SKILL.md b/skills/public/weval-crm-enrichment/SKILL.md new file mode 100644 index 0000000..97d45cd --- /dev/null +++ b/skills/public/weval-crm-enrichment/SKILL.md @@ -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. diff --git a/skills/public/weval-ethica-research/SKILL.md b/skills/public/weval-ethica-research/SKILL.md new file mode 100644 index 0000000..57b35a1 --- /dev/null +++ b/skills/public/weval-ethica-research/SKILL.md @@ -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) diff --git a/skills/public/weval-infra-monitor/SKILL.md b/skills/public/weval-infra-monitor/SKILL.md new file mode 100644 index 0000000..bfe49d4 --- /dev/null +++ b/skills/public/weval-infra-monitor/SKILL.md @@ -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}}'` diff --git a/skills/public/weval-proposal-generator/SKILL.md b/skills/public/weval-proposal-generator/SKILL.md new file mode 100644 index 0000000..eb00787 --- /dev/null +++ b/skills/public/weval-proposal-generator/SKILL.md @@ -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.