191 lines
7.9 KiB
Python
Executable File
191 lines
7.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
WEVAL Meeting Rooms Auto-Populator — FIXED 18avr 2026
|
|
Pipeline: Paperclip → Registry → Enterprise → Meeting Rooms
|
|
Runs via cron every 6h30: updates room agents from live infrastructure data
|
|
|
|
FIX: regex updated to match enterprise-model.html actual agent format:
|
|
{n:'NAME',rm:'ROOM',d:'DESC',p:'...',...,F:0|1,...}
|
|
"""
|
|
import json, subprocess, re, os, datetime
|
|
|
|
LOG = []
|
|
def log(msg):
|
|
LOG.append(f"[{datetime.datetime.now().strftime('%H:%M:%S')}] {msg}")
|
|
print(msg)
|
|
|
|
# 1. Read enterprise-model agents (source of truth for active agents)
|
|
def get_enterprise_agents():
|
|
try:
|
|
f = '/var/www/html/enterprise-model.html'
|
|
c = open(f).read()
|
|
agents = []
|
|
# Correct format: {n:'NAME',rm:'DEPT',d:'DESC',p:'PURPOSE',...F:0|1,...}
|
|
# rm = room/dept (ceo, sal, con, dev, qa, l99, sec, srv, ops, dock, mta, pha, saas, ai, wevia, plat, cron, dead, meet, lean, dir)
|
|
pattern = r"\{n:'([^']+)',rm:'([^']+)'[^}]*?F:(\d)"
|
|
for m in re.finditer(pattern, c):
|
|
agents.append({
|
|
'name': m.group(1),
|
|
'dept': m.group(2), # rm value (room/dept id)
|
|
'active': int(m.group(3))
|
|
})
|
|
return agents
|
|
except Exception as e:
|
|
log(f"ERR enterprise: {e}")
|
|
return []
|
|
|
|
# 2. Read registry for crons/pipelines
|
|
def get_registry():
|
|
try:
|
|
r = subprocess.run(['curl','-s','--max-time','5','http://localhost/api/registry.php'],
|
|
capture_output=True, text=True, timeout=10)
|
|
return json.loads(r.stdout) if r.stdout else {}
|
|
except:
|
|
return {}
|
|
|
|
# 3. Read Docker containers
|
|
def get_docker():
|
|
try:
|
|
r = subprocess.run(['docker','ps','--format','{{.Names}}'], capture_output=True, text=True, timeout=10)
|
|
return r.stdout.strip().split('\n') if r.stdout.strip() else []
|
|
except:
|
|
return []
|
|
|
|
# 4. Map agents to meeting rooms based on:
|
|
# (a) Direct room/dept alias mapping (rm value → room_id)
|
|
# (b) Keyword matching on name/description
|
|
#
|
|
# An agent CAN appear in multiple rooms.
|
|
|
|
# Direct rm (dept) → meeting_room mapping
|
|
DEPT_TO_ROOM = {
|
|
'ceo': ['strat', 'biz'], # strategy + business
|
|
'dir': ['strat'], # directors = strategic
|
|
'sal': ['biz'], # sales
|
|
'con': ['biz', 'strat'], # consultants
|
|
'sdlc': ['dev'], # dev pipeline
|
|
'dev': ['dev'], # dev lab
|
|
'qa': ['dev'], # QA
|
|
'l99': ['dev'], # L99 pilot
|
|
'sec': ['sec'], # security
|
|
'srv': ['infra'], # infra/servers
|
|
'ops': ['infra', 'transit'], # monitoring + transit
|
|
'dock': ['infra'], # Docker services
|
|
'mta': ['infra'], # mail transport
|
|
'pha': ['biz'], # pharma
|
|
'saas': ['biz'], # SaaS
|
|
'ai': ['ia'], # AI engine
|
|
'wevia': ['ia', 'strat'], # WEVIA core = IA + strategic
|
|
'plat': ['transit'], # platform transversal
|
|
'cron': ['transit', 'infra'], # crons = ops/transit
|
|
'meet': ['strat'], # meeting rooms = strategic
|
|
'lean': ['strat'], # lean = strategic
|
|
'dead': [], # archived — no room
|
|
'wire': ['transit'], # to wire = transit
|
|
'intg': ['transit'], # to integrate = transit
|
|
'dorm': ['transit'], # dormants = transit
|
|
}
|
|
|
|
ROOM_KEYWORDS = {
|
|
'strat': ['master','opus','life','blade','mirofish','maitre','chef','lead','ceo','strategy','director','weval','plan','visio'],
|
|
'infra': ['cortex','prometheus','kuma','sentinel','docker','infra','monitor','disk','server','pmta','kumo','ops','watchdog','guard'],
|
|
'dev': ['nonreg','l99','wedroid','wevcode','evomaster','langfuse','playwright','git','code','test','qa','debug','dev','claude','claw','goose','blueprint','forge'],
|
|
'sec': ['dark','crowd','authentik','aegis','vault','strix','nuclei','security','scan','sso','ban','rgpd','audit','verifier'],
|
|
'biz': ['paperclip','enterprise','ethica','crm','n8n','twenty','active','lead','pipeline','hcp','b2b','sales','proposal','contract','kaouther','marketing','revenue','stripe'],
|
|
'ia': ['ollama','qdrant','deerflow','dify','searx','supermemory','mastra','goose','skillsmith','aios','ai','llm','rag','cerebras','groq','gemini','cog','brain','anything','crewai','autogen','cognitive'],
|
|
'transit': ['scanner','factory','rnd','browser','mattermost','plausible','wiki','github','automation','backup','sync','relay','bridge','oss','archi'],
|
|
}
|
|
|
|
def assign_rooms(agents, docker_containers):
|
|
rooms = {k: [] for k in ROOM_KEYWORDS}
|
|
seen = {k: set() for k in ROOM_KEYWORDS}
|
|
|
|
for agent in agents:
|
|
name_lower = agent['name'].lower()
|
|
dept_lower = agent['dept'].lower()
|
|
added = False
|
|
|
|
# Strategy A: direct dept → room mapping
|
|
if dept_lower in DEPT_TO_ROOM:
|
|
for room_id in DEPT_TO_ROOM[dept_lower]:
|
|
if agent['name'] not in seen[room_id]:
|
|
rooms[room_id].append(agent)
|
|
seen[room_id].add(agent['name'])
|
|
added = True
|
|
|
|
# Strategy B: keyword fallback
|
|
for room_id, keywords in ROOM_KEYWORDS.items():
|
|
if agent['name'] in seen[room_id]:
|
|
continue
|
|
for kw in keywords:
|
|
if kw in name_lower or kw in dept_lower:
|
|
rooms[room_id].append(agent)
|
|
seen[room_id].add(agent['name'])
|
|
break
|
|
|
|
# Add Docker containers as infra/ia agents
|
|
docker_room_map = {
|
|
'prometheus': 'infra', 'node-exporter': 'infra', 'uptime-kuma': 'infra',
|
|
'loki': 'infra', 'plausible': 'transit',
|
|
'mattermost': 'transit', 'twenty': 'biz',
|
|
'searxng': 'ia', 'qdrant': 'ia', 'langfuse': 'ia',
|
|
'n8n': 'transit', 'authentik-server': 'sec', 'vaultwarden': 'sec',
|
|
'deerflow': 'ia', 'gitea': 'transit',
|
|
}
|
|
for container in docker_containers:
|
|
cname = container.strip().lower()
|
|
if not cname: continue
|
|
for key, room_id in docker_room_map.items():
|
|
if key in cname and f"[docker] {container}" not in seen[room_id]:
|
|
rooms[room_id].append({'name': f"[docker] {container}", 'dept': 'docker', 'active': 1})
|
|
seen[room_id].add(f"[docker] {container}")
|
|
break
|
|
|
|
return rooms
|
|
|
|
# 5. Generate meeting room JSON for the page to consume
|
|
def generate_meeting_data():
|
|
log("=== MEETING ROOMS AUTO-POPULATOR (FIXED 18avr) ===")
|
|
|
|
agents = get_enterprise_agents()
|
|
log(f"Enterprise: {len(agents)} agents")
|
|
|
|
registry = get_registry()
|
|
log(f"Registry: {len(registry)} sections" if isinstance(registry, dict) else "Registry: unavailable")
|
|
|
|
docker = get_docker()
|
|
log(f"Docker: {len(docker)} containers")
|
|
|
|
rooms = assign_rooms(agents, docker)
|
|
|
|
result = {
|
|
'timestamp': datetime.datetime.now().isoformat(),
|
|
'source': 'auto-populator-v2-fixed-18avr',
|
|
'enterprise_total_agents': len(agents),
|
|
'docker_total': len(docker),
|
|
'rooms': {}
|
|
}
|
|
|
|
for room_id, room_agents in rooms.items():
|
|
active_count = sum(1 for a in room_agents if a.get('active', 0) == 1)
|
|
result['rooms'][room_id] = {
|
|
'count': len(room_agents),
|
|
'agents': [a['name'] for a in room_agents[:25]], # cap 25/room (was 15)
|
|
'active': active_count,
|
|
'dead': len(room_agents) - active_count,
|
|
}
|
|
log(f" {room_id}: {len(room_agents)} agents ({active_count} active)")
|
|
|
|
out = '/var/www/html/api/meeting-rooms-data.json'
|
|
with open(out, 'w') as f:
|
|
json.dump(result, f, indent=2, ensure_ascii=False)
|
|
log(f"Output: {out}")
|
|
|
|
with open('/var/www/html/api/meeting-rooms-populator.log', 'w') as f:
|
|
f.write('\n'.join(LOG))
|
|
|
|
return result
|
|
|
|
if __name__ == '__main__':
|
|
generate_meeting_data()
|