Update ashboard, dashboard (~2)
This commit is contained in:
124
dashboard/api.py
124
dashboard/api.py
@@ -303,6 +303,10 @@ class TaskBoardHandler(SimpleHTTPRequestHandler):
|
||||
self.handle_workspace_logs()
|
||||
elif self.path == '/api/eco/status' or self.path.startswith('/api/eco/status?'):
|
||||
self.handle_eco_status()
|
||||
elif self.path == '/api/eco/sessions' or self.path.startswith('/api/eco/sessions?'):
|
||||
self.handle_eco_sessions()
|
||||
elif self.path.startswith('/api/eco/sessions/content'):
|
||||
self.handle_eco_session_content()
|
||||
elif self.path.startswith('/api/eco/logs'):
|
||||
self.handle_eco_logs()
|
||||
elif self.path == '/api/eco/doctor':
|
||||
@@ -2016,15 +2020,119 @@ class TaskBoardHandler(SimpleHTTPRequestHandler):
|
||||
|
||||
services.append(info)
|
||||
|
||||
# Active sessions
|
||||
sessions = []
|
||||
if ECHO_SESSIONS_FILE.exists():
|
||||
try:
|
||||
sessions = json.loads(ECHO_SESSIONS_FILE.read_text())
|
||||
except Exception:
|
||||
pass
|
||||
self.send_json({'services': services})
|
||||
except Exception as e:
|
||||
self.send_json({'error': str(e)}, 500)
|
||||
|
||||
self.send_json({'services': services, 'sessions': sessions})
|
||||
def _eco_channel_map(self):
|
||||
"""Build channel_id -> {name, platform, is_group} from config.json."""
|
||||
config_file = ECHO_CORE_DIR / 'config.json'
|
||||
m = {}
|
||||
try:
|
||||
cfg = json.loads(config_file.read_text())
|
||||
for name, ch in cfg.get('channels', {}).items():
|
||||
m[str(ch['id'])] = {'name': name, 'platform': 'discord'}
|
||||
for name, ch in cfg.get('telegram_channels', {}).items():
|
||||
m[str(ch['id'])] = {'name': name, 'platform': 'telegram'}
|
||||
for name, ch in cfg.get('whatsapp_channels', {}).items():
|
||||
m[str(ch['id'])] = {'name': name, 'platform': 'whatsapp', 'is_group': True}
|
||||
for admin_id in cfg.get('bot', {}).get('admins', []):
|
||||
m.setdefault(str(admin_id), {'name': f'TG DM', 'platform': 'telegram'})
|
||||
wa_owner = cfg.get('whatsapp', {}).get('owner', '')
|
||||
if wa_owner:
|
||||
m.setdefault(f'wa-{wa_owner}', {'name': 'WA Owner', 'platform': 'whatsapp'})
|
||||
except Exception:
|
||||
pass
|
||||
return m
|
||||
|
||||
def _eco_enrich_sessions(self):
|
||||
"""Return enriched sessions list sorted by last_message_at desc."""
|
||||
raw = {}
|
||||
if ECHO_SESSIONS_FILE.exists():
|
||||
try:
|
||||
raw = json.loads(ECHO_SESSIONS_FILE.read_text())
|
||||
except Exception:
|
||||
pass
|
||||
cmap = self._eco_channel_map()
|
||||
sessions = []
|
||||
if isinstance(raw, dict):
|
||||
for ch_id, sdata in raw.items():
|
||||
if 'MagicMock' in ch_id:
|
||||
continue
|
||||
entry = dict(sdata) if isinstance(sdata, dict) else {}
|
||||
entry['channel_id'] = ch_id
|
||||
if ch_id in cmap:
|
||||
entry['platform'] = cmap[ch_id]['platform']
|
||||
entry['channel_name'] = cmap[ch_id]['name']
|
||||
entry['is_group'] = cmap[ch_id].get('is_group', False)
|
||||
elif ch_id.startswith('wa-') or '@g.us' in ch_id or '@s.whatsapp.net' in ch_id:
|
||||
entry['platform'] = 'whatsapp'
|
||||
entry['is_group'] = '@g.us' in ch_id
|
||||
entry['channel_name'] = ('WA Grup' if entry['is_group'] else 'WA DM')
|
||||
elif ch_id.isdigit() and len(ch_id) >= 17:
|
||||
entry['platform'] = 'discord'
|
||||
entry['channel_name'] = 'Discord #' + ch_id[-6:]
|
||||
elif ch_id.isdigit():
|
||||
entry['platform'] = 'telegram'
|
||||
entry['channel_name'] = 'TG ' + ch_id
|
||||
else:
|
||||
entry['platform'] = 'unknown'
|
||||
entry['channel_name'] = ch_id[:20]
|
||||
sessions.append(entry)
|
||||
sessions.sort(key=lambda s: s.get('last_message_at', ''), reverse=True)
|
||||
return sessions
|
||||
|
||||
def handle_eco_sessions(self):
|
||||
"""Return enriched sessions list."""
|
||||
try:
|
||||
self.send_json({'sessions': self._eco_enrich_sessions()})
|
||||
except Exception as e:
|
||||
self.send_json({'error': str(e)}, 500)
|
||||
|
||||
def handle_eco_session_content(self):
|
||||
"""Return conversation messages from a session transcript."""
|
||||
try:
|
||||
params = parse_qs(urlparse(self.path).query)
|
||||
session_id = params.get('id', [''])[0]
|
||||
if not session_id or '/' in session_id or '..' in session_id:
|
||||
self.send_json({'error': 'Invalid session id'}, 400)
|
||||
return
|
||||
|
||||
transcript = Path.home() / '.claude' / 'projects' / '-home-moltbot-echo-core' / f'{session_id}.jsonl'
|
||||
if not transcript.exists():
|
||||
self.send_json({'messages': [], 'error': 'Transcript not found'})
|
||||
return
|
||||
|
||||
messages = []
|
||||
for line in transcript.read_text().splitlines():
|
||||
try:
|
||||
d = json.loads(line)
|
||||
except Exception:
|
||||
continue
|
||||
t = d.get('type', '')
|
||||
if t == 'user':
|
||||
msg = d.get('message', {})
|
||||
content = msg.get('content', '')
|
||||
if isinstance(content, str):
|
||||
# Strip [EXTERNAL CONTENT] wrappers
|
||||
text = content.replace('[EXTERNAL CONTENT]\n', '').replace('\n[END EXTERNAL CONTENT]', '').strip()
|
||||
if text:
|
||||
messages.append({'role': 'user', 'text': text[:2000]})
|
||||
elif t == 'assistant':
|
||||
msg = d.get('message', {})
|
||||
content = msg.get('content', '')
|
||||
if isinstance(content, list):
|
||||
parts = []
|
||||
for block in content:
|
||||
if block.get('type') == 'text':
|
||||
parts.append(block['text'])
|
||||
text = '\n'.join(parts).strip()
|
||||
if text:
|
||||
messages.append({'role': 'assistant', 'text': text[:2000]})
|
||||
elif isinstance(content, str) and content.strip():
|
||||
messages.append({'role': 'assistant', 'text': content[:2000]})
|
||||
|
||||
self.send_json({'messages': messages})
|
||||
except Exception as e:
|
||||
self.send_json({'error': str(e)}, 500)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user