Removed AI Bridge & temp ROS

This commit is contained in:
2026-04-23 20:28:29 +03:00
parent a735d9cf67
commit 8ec7aa937d
8 changed files with 28 additions and 3258 deletions

View File

@@ -1,31 +0,0 @@
{
"enabled": false,
"mode": "TEXT",
"serverBaseUrl": "http://192.168.2.28:24605",
"recordSeconds": 5,
"useDumpStateAudio": true,
"useAsrServiceStt": true,
"asrServiceHost": "127.0.0.1",
"asrServicePort": 8088,
"asrAudioSourceId": "alsa1",
"asrTimeoutMs": 15000,
"asrServiceDebugWs": false,
"asrAutoStart": true,
"wakeupChitchatPhrases": [
"hello",
"howdy",
"hi",
"hey",
"look what i found",
"nice to see you",
"good morning",
"good afternoon",
"good evening"
],
"followupEnabled": true,
"followupDelayMs": 250
}

File diff suppressed because it is too large Load Diff

View File

@@ -74,17 +74,17 @@ exports.postInit = function (err) {
this.log.warn('Dynamic skill loader failed (non-fatal):', e.message || e);
}
// Optional: AI Bridge (modular; can run models off-robot for now)
try {
if (rlog && typeof rlog.raw === 'function') {
rlog.raw('[BE] initializing AI bridge');
}
require('./ai-bridge').initAIBridge(this, jibo);
this.log.info('AI bridge initialized');
if (rlog && typeof rlog.raw === 'function') {
rlog.raw('[BE] AI bridge initialized');
}
}
// Optional: AI Bridge (DEPRICALED)
// try {
// if (rlog && typeof rlog.raw === 'function') {
// rlog.raw('[BE] initializing AI bridge');
// }
// require('./ai-bridge').initAIBridge(this, jibo);
// this.log.info('AI bridge initialized');
// if (rlog && typeof rlog.raw === 'function') {
// rlog.raw('[BE] AI bridge initialized');
// }
// }
catch (e) {
this.log.warn('AI bridge init failed (non-fatal):', e.message || e);
try {
@@ -99,23 +99,23 @@ exports.postInit = function (err) {
}
}
// Optional: rosbridge connector (connects to external rosbridge websocket)
try {
try {
var rosbridge = require('./rosbridge');
if (rosbridge && typeof rosbridge.init === 'function') {
rosbridge.init(this, jibo);
if (rlog && typeof rlog.raw === 'function') rlog.raw('[BE] rosbridge connector initialized');
if (rlog && typeof rlog.info === 'function') rlog.info('be', 'rosbridge connector initialized');
else this.log.info('rosbridge connector initialized');
}
} catch (e) {
if (rlog && typeof rlog.raw === 'function') rlog.raw('[BE] rosbridge module not present or failed to init (ok)');
else this.log.info('rosbridge module not present or failed to init (ok)');
}
} catch (e) {
if (rlog && typeof rlog.raw === 'function') rlog.raw('[BE] rosbridge init failed: ' + String(e && (e.stack || e.message || e)));
this.log.warn('rosbridge init failed (non-fatal):', e.message || e);
}
//try {
// try {
// var rosbridge = require('./rosbridge');
// if (rosbridge && typeof rosbridge.init === 'function') {
// rosbridge.init(this, jibo);
// if (rlog && typeof rlog.raw === 'function') rlog.raw('[BE] rosbridge connector initialized');
// if (rlog && typeof rlog.info === 'function') rlog.info('be', 'rosbridge connector initialized');
// else this.log.info('rosbridge connector initialized');
// }
// } catch (e) {
// if (rlog && typeof rlog.raw === 'function') rlog.raw('[BE] rosbridge module not present or failed to init (ok)');
// else this.log.info('rosbridge module not present or failed to init (ok)');
// }
// } catch (e) {
// if (rlog && typeof rlog.raw === 'function') rlog.raw('[BE] rosbridge init failed: ' + String(e && (e.stack || e.message || e)));
// this.log.warn('rosbridge init failed (non-fatal):', e.message || e);
// }
jibo.face.views.changeView({ removeAll: true, leaveEmpty: true }, () => {
this.selectFirstSkill(this.launchFirstSkill.bind(this));

View File

@@ -1,463 +0,0 @@
"use strict";
// Simple ROS bridge client for Jibo BE
// - Connects to a rosbridge websocket and subscribes to /jibo_remote
// - Handles do_enter_rosbridge_skill and do_exit_rosbridge_skill commands
var WebSocket = null;
try { WebSocket = require('ws'); } catch (e) { WebSocket = null; }
var urlLib = require('url');
var DEFAULT_WS = process.env.ROSBRIDGE_WS || 'ws://192.168.1.5:9090';
var state = {
ws: null,
subId: null,
reconnectTimer: null,
lastProcessed: {},
};
// Robot logger (available on BE runtime)
var rlog = null;
try {
if (typeof global !== 'undefined' && global.__rlog) rlog = global.__rlog;
if (!rlog) rlog = require('./robot-logger');
} catch (e) { rlog = null; }
function rlogRaw(s) {
try { if (rlog && typeof rlog.raw === 'function') return rlog.raw(String(s || '')); } catch (e) {}
try { console.log(String(s || '')); } catch (e) {}
}
function rlogInfo(tag, text, data) {
try {
if (rlog && typeof rlog.info === 'function') return rlog.info(String(tag || 'rosbridge'), String(text || ''), data || {});
} catch (e) {}
try { console.log('[INFO]', String(tag || 'rosbridge'), String(text || ''), data || ''); } catch (e) {}
}
function rlogWarn(tag, text, data) {
try {
if (rlog && typeof rlog.warn === 'function') return rlog.warn(String(tag || 'rosbridge'), String(text || ''), data || {});
} catch (e) {}
try { console.warn('[WARN]', String(tag || 'rosbridge'), String(text || ''), data || ''); } catch (e) {}
}
function parseWsUrl(s) {
try { return String(s || '').trim(); } catch (e) { return DEFAULT_WS; }
}
function getCandidateWsUrls(beRuntime) {
var list = [];
try {
var envUrl = process.env.ROSBRIDGE_WS;
if (envUrl) list.push(parseWsUrl(envUrl));
} catch (e) {}
try {
var cfg = beRuntime && beRuntime.config && beRuntime.config.rosbridge && beRuntime.config.rosbridge.ws;
if (cfg) list.push(parseWsUrl(cfg));
} catch (e) {}
// Common fallbacks
list.push('ws://127.0.0.1:9090');
list.push(DEFAULT_WS);
// Attempt gateway-derived host if available
try {
var os = require('os');
var ifaces = os.networkInterfaces();
Object.keys(ifaces || {}).forEach(function (k) {
(ifaces[k] || []).forEach(function (info) {
if (!info || info.internal || info.family !== 'IPv4') return;
var parts = String(info.address).split('.');
if (parts.length === 4) {
// guess the gateway as .1
parts[3] = '1';
list.push('ws://' + parts.join('.') + ':9090');
}
});
});
} catch (e) {}
// Deduplicate while keeping order
var seen = {};
var out = [];
for (var i = 0; i < list.length; i++) {
try {
var v = String(list[i] || '').trim();
if (!v) continue;
if (!seen[v]) { seen[v] = true; out.push(v); }
} catch (e) {}
}
return out;
}
function sendWs(obj) {
try {
if (!state.ws || state.ws.readyState !== 1) {
rlogWarn('rosbridge', 'ws not open, drop send', { obj: obj });
return;
}
var payload = JSON.stringify(obj);
rlogInfo('rosbridge', 'ws.send', { payload: obj });
state.ws.send(payload);
} catch (e) { /* ignore */ }
}
function subscribe(topic, type) {
// rosbridge subscribe message
var id = 'sub_' + Date.now() + '_' + Math.floor(Math.random() * 1000);
state.subId = id;
rlogInfo('rosbridge', 'subscribe', { id: id, topic: topic, type: type });
sendWs({ op: 'subscribe', id: id, type: type || '', topic: topic });
}
function unsubscribe() {
if (!state.subId) return;
rlogInfo('rosbridge', 'unsubscribe', { id: state.subId });
sendWs({ op: 'unsubscribe', id: state.subId });
state.subId = null;
}
function connect(wsUrl, onMessage) {
var url = parseWsUrl(wsUrl || DEFAULT_WS);
rlogInfo('rosbridge', 'connect attempt', { url: url });
try {
if (WebSocket) {
state.ws = new WebSocket(url);
} else {
// try built-in if ws not present (not ideal)
var Ws = require('websocket').w3cwebsocket;
state.ws = new Ws(url);
}
} catch (e) {
rlogWarn('rosbridge', 'connect failed', { err: String(e) });
scheduleReconnect(wsUrl, onMessage);
return;
}
state.ws.onopen = function () {
rlogInfo('rosbridge', 'ws open');
try {
subscribe('/jibo_remote', '/jibo_msgs/JiboRemote');
} catch (e) { rlogWarn('rosbridge', 'subscribe failed on open /jibo_remote', { err: String(e) }); }
try {
subscribe('/jibo', '/jibo_msgs/JiboAction');
} catch (e) { rlogWarn('rosbridge', 'subscribe failed on open /jibo', { err: String(e) }); }
};
state.ws.onmessage = function (evt) {
rlogRaw('[rosbridge] raw message: ' + (evt && evt.data ? String(evt.data) : ''));
var data = null;
try { data = JSON.parse(evt.data); } catch (e) { rlogWarn('rosbridge', 'json parse failed', { err: String(e), raw: String(evt && evt.data) }); return; }
// rosbridge wraps messages with { op: 'publish', topic: '...', msg: {...} }
if (data && data.op === 'publish') {
try {
var topic = data.topic || 'unknown';
// Throttle frequent messages per-topic to avoid blocking the BE event loop.
var minMs = parseInt(process.env.ROSBRIDGE_MIN_INTERVAL_MS || '200', 10) || 200;
var now = Date.now();
var last = state.lastProcessed[topic] || 0;
if (now - last < minMs) {
rlogInfo('rosbridge', 'throttled publish', { topic: topic, droppedMs: now - last, minMs: minMs });
return;
}
state.lastProcessed[topic] = now;
// Defer handling so heavy work doesn't block the socket message parser.
var handler = function () {
try {
rlogInfo('rosbridge', 'publish received', { topic: data.topic, msg: data.msg });
if (data.msg) onMessage && onMessage(data.msg, data.topic);
} catch (e) { rlogWarn('rosbridge', 'publish handler error', { err: String(e) }); }
};
if (typeof setImmediate === 'function') setImmediate(handler); else setTimeout(handler, 0);
} catch (e) {
rlogWarn('rosbridge', 'error handling publish', { err: String(e) });
}
return;
}
rlogInfo('rosbridge', 'ws message', { op: data && data.op, data: data });
};
state.ws.onclose = function (ev) { rlogWarn('rosbridge', 'ws closed', { code: ev && ev.code, reason: ev && ev.reason }); scheduleReconnect(wsUrl, onMessage); };
state.ws.onerror = function (err) { rlogWarn('rosbridge', 'ws error', { err: String(err) }); };
}
function scheduleReconnect(wsUrl, onMessage) {
if (state.reconnectTimer) return;
rlogInfo('rosbridge', 'scheduling reconnect', { delayMs: 5000 });
state.reconnectTimer = setTimeout(function () {
state.reconnectTimer = null;
rlogInfo('rosbridge', 'reconnecting now');
connect(wsUrl, onMessage);
}, 5000);
}
// Try a list of candidate URLs sequentially until one connects.
function connectToCandidates(beRuntime, onMessage) {
var candidates = getCandidateWsUrls(beRuntime);
var idx = 0;
function tryNext() {
if (state.ws && state.ws.readyState === 1) return; // already connected
if (idx >= candidates.length) {
rlogWarn('rosbridge', 'no candidates left, will schedule reconnect');
scheduleReconnect(candidates[0], onMessage);
return;
}
var url = candidates[idx++];
rlogInfo('rosbridge', 'trying candidate', { url: url });
// attempt connect and use a short timeout to move to next candidate
var tried = false;
var timeout = setTimeout(function () {
if (tried) return;
tried = true;
try { if (state.ws) state.ws.close(); } catch (e) {}
rlogWarn('rosbridge', 'candidate timeout, trying next', { url: url });
// small delay before next
setTimeout(tryNext, 250);
}, 3500);
try {
// reuse existing connect path but attach temporary handlers
var prevOnOpen = state.ws && state.ws.onopen;
connect(url, function (msg, topic) {
clearTimeout(timeout);
onMessage && onMessage(msg, topic);
});
// when open, cancel other attempts
(function (u) {
var wsInst = state.ws;
if (!wsInst) return;
var origOnOpen = wsInst.onopen;
wsInst.onopen = function (ev) {
clearTimeout(timeout);
rlogInfo('rosbridge', 'connected candidate', { url: u });
try { if (typeof origOnOpen === 'function') origOnOpen.call(wsInst, ev); } catch (e) {}
};
// if it closes or errors before open, try next
var origOnClose = wsInst.onclose;
wsInst.onclose = function (ev) {
clearTimeout(timeout);
if (!tried) {
tried = true;
rlogWarn('rosbridge', 'candidate closed before ready, next', { url: u });
setTimeout(tryNext, 250);
}
try { if (typeof origOnClose === 'function') origOnClose.call(wsInst, ev); } catch (e) {}
};
var origOnError = wsInst.onerror;
wsInst.onerror = function (err) {
clearTimeout(timeout);
if (!tried) {
tried = true;
rlogWarn('rosbridge', 'candidate error, next', { url: u, err: String(err) });
try { if (wsInst) wsInst.close(); } catch (e) {}
setTimeout(tryNext, 250);
}
try { if (typeof origOnError === 'function') origOnError.call(wsInst, err); } catch (e) {}
};
})(url);
} catch (e) {
clearTimeout(timeout);
rlogWarn('rosbridge', 'connect threw, trying next', { url: url, err: String(e) });
setTimeout(tryNext, 250);
}
}
tryNext();
}
function close() {
rlogInfo('rosbridge', 'close requested');
try { unsubscribe(); } catch (e) { rlogWarn('rosbridge', 'unsubscribe failed', { err: String(e) }); }
try { if (state.ws) state.ws.close(); } catch (e) { rlogWarn('rosbridge', 'ws close failed', { err: String(e) }); }
state.ws = null;
if (state.reconnectTimer) { clearTimeout(state.reconnectTimer); state.reconnectTimer = null; }
}
exports.init = function (beRuntime, jibo) {
// Prefer robot-logger when available
var rlog = null;
try {
if (beRuntime && beRuntime.rlog) rlog = beRuntime.rlog;
if (!rlog && typeof global !== 'undefined' && global.__rlog) rlog = global.__rlog;
if (!rlog) rlog = require('./robot-logger');
} catch (e) {
rlog = null;
}
var log = rlog || (beRuntime && beRuntime.log) || console;
var wsUrl = (beRuntime && beRuntime.config && beRuntime.config.rosbridge && beRuntime.config.rosbridge.ws) || DEFAULT_WS;
function logInfo(text, data) {
try {
if (rlog && typeof rlog.info === 'function') return rlog.info('rosbridge', String(text || ''), data || {});
if (log && typeof log.info === 'function') return log.info(String(text || ''));
console.log(String(text || ''));
} catch (e) { /* ignore */ }
}
function logWarn(text, data) {
try {
if (rlog && typeof rlog.warn === 'function') return rlog.warn('rosbridge', String(text || ''), data || {});
if (log && typeof log.warn === 'function') return log.warn(String(text || ''));
console.warn(String(text || ''));
} catch (e) { /* ignore */ }
}
function handleMsg(msg, topic) {
try {
if (msg.do_enter_rosbridge_skill) {
logInfo('enter request', msg);
// Launch a named skill if provided
var skillName = msg.launch_skill || msg.skill || '@be/main-menu';
try {
// Attempt lifecycle-based redirect for a proper skill switch
var path = require('path');
var SkillSwitchData = null;
try {
if (typeof global !== 'undefined' && global && global.be && global.be.constructor) {
SkillSwitchData = global.be.constructor.SkillSwitchData;
}
} catch (e) { SkillSwitchData = null; }
function _interop(m) { return (m && (m.__esModule || m.default)) ? (m.default || m) : m; }
var SkillSwitchDataCtor = null;
if (SkillSwitchData) SkillSwitchDataCtor = _interop(SkillSwitchData);
if (!SkillSwitchDataCtor) {
try { SkillSwitchDataCtor = require(path.join(jibo.utils.PathUtils.findRoot(), 'SkillSwitchData')); } catch (e) { try { const Root = require(path.join(jibo.utils.PathUtils.findRoot(), 'index.js')); SkillSwitchDataCtor = (Root && (Root.SkillSwitchData || (Root.default && Root.default.SkillSwitchData))) || undefined; } catch (e2) { SkillSwitchDataCtor = null; } }
}
var skillObj = beRuntime && beRuntime.skills ? beRuntime.skills[skillName] : null;
if (skillObj && SkillSwitchDataCtor) {
var ssd = new (SkillSwitchDataCtor)(skillObj, {});
try { require('./lifecycle').redirect.call(beRuntime, ssd); logInfo('requested skill redirect', { skill: skillName }); } catch (e) { logWarn('skill redirect failed', { err: String(e), skill: skillName }); }
} else {
logWarn('skill not found or SkillSwitchDataCtor missing', { skill: skillName });
}
} catch (e) {
logWarn('enter handling failed', { err: String(e) });
}
}
if (msg.do_exit_rosbridge_skill) {
logInfo('exit request', msg);
try {
// Redirect to idle via lifecycle
var path2 = require('path');
var SkillSwitchData2 = null;
try {
if (typeof global !== 'undefined' && global && global.be && global.be.constructor) {
SkillSwitchData2 = global.be.constructor.SkillSwitchData;
}
} catch (e) { SkillSwitchData2 = null; }
var SkillSwitchDataCtor2 = SkillSwitchData2 ? _interop(SkillSwitchData2) : null;
if (!SkillSwitchDataCtor2) {
try { SkillSwitchDataCtor2 = require(path2.join(jibo.utils.PathUtils.findRoot(), 'SkillSwitchData')); } catch (e) { try { const Root = require(path2.join(jibo.utils.PathUtils.findRoot(), 'index.js')); SkillSwitchDataCtor2 = (Root && (Root.SkillSwitchData || (Root.default && Root.default.SkillSwitchData))) || undefined; } catch (e2) { SkillSwitchDataCtor2 = null; } }
}
var idleSkill = beRuntime && beRuntime.idle ? beRuntime.idle : null;
if (idleSkill && SkillSwitchDataCtor2) {
var ssd2 = new (SkillSwitchDataCtor2)(idleSkill, {});
try { require('./lifecycle').redirect.call(beRuntime, ssd2); logInfo('requested redirect to idle'); } catch (e) { logWarn('idle redirect failed', { err: String(e) }); }
} else {
logWarn('idle redirect failed - missing idleSkill or ctor');
}
} catch (e) { logWarn('exit handling failed', { err: String(e) }); }
}
// Handle /jibo actions (e.g., TTS)
if (topic === '/jibo' || topic === 'jibo') {
try {
if (msg.do_tts || msg.do_tts === true || msg.tts_text) {
var t = msg.tts_text || msg.tts || msg.text || '';
if (t && t.length) {
logInfo('jibo action TTS', { text: t });
try {
// Normalize: if payload is JSON object string like '{"text":"..."}', extract.
try {
if (typeof t === 'string' && t.trim().charAt(0) === '{' && t.indexOf('"text"') !== -1) {
var parsed = JSON.parse(t);
if (parsed && parsed.text) t = parsed.text;
}
} catch (e) { /* ignore parse error */ }
// Detect ESML/SSML-like input and request SSML mode when present
function _isEsml(s) {
try {
if (!s || typeof s !== 'string') return false;
var ls = s.toLowerCase();
return ls.indexOf('<es') !== -1 || ls.indexOf('<speak') !== -1 || ls.indexOf('<ssml') !== -1;
} catch (e) { return false; }
}
function _ensureSpeakWrapper(s) {
try {
if (!s) return s;
var trimmed = s.trim();
if (trimmed.toLowerCase().indexOf('<speak') === 0) return s;
return '<speak>' + s + '</speak>';
} catch (e) { return s; }
}
var useEsml = _isEsml(t);
if (useEsml && jibo && jibo.tts && typeof jibo.tts.speak === 'function') {
var payload = _ensureSpeakWrapper(String(t));
jibo.tts.speak(payload, { mode: jibo.tts.TTSMode ? jibo.tts.TTSMode.SSML : undefined });
} else if (jibo && jibo.tts && typeof jibo.tts.speak === 'function') {
jibo.tts.speak(String(t), { mode: jibo.tts.TTSMode ? jibo.tts.TTSMode.TEXT : undefined });
} else if (beRuntime && beRuntime.api && typeof beRuntime.api.speak === 'function') { beRuntime.api.speak({ text: String(t), mode: useEsml ? 'ssml' : 'text' });
} else if (jibo && jibo.api && typeof jibo.api.speak === 'function') {
jibo.api.speak({ text: String(t), mode: useEsml ? 'ssml' : 'text' });
} else {
logWarn('no speak API available', { t: t });
}
} catch (e) { logWarn('tts speak failed', { err: String(e) }); }
}
}
} catch (e) { logWarn('failed handling /jibo action', { err: String(e), topic: topic, msg: msg }); }
}
if (msg.tts_text) {
try {
// Normalize and speak similar to /jibo handling
var txt = msg.tts_text;
try {
if (typeof txt === 'string' && txt.trim().charAt(0) === '{' && txt.indexOf('"text"') !== -1) {
var p2 = JSON.parse(txt);
if (p2 && p2.text) txt = p2.text;
}
} catch (e) {}
// Reuse ESML detection logic
function _isEsml2(s) {
try {
if (!s || typeof s !== 'string') return false;
var ls = s.toLowerCase();
return ls.indexOf('<es') !== -1 || ls.indexOf('<speak') !== -1 || ls.indexOf('<ssml') !== -1;
} catch (e) { return false; }
}
function _ensureSpeakWrapper2(s) {
try {
if (!s) return s;
var trimmed = s.trim();
if (trimmed.toLowerCase().indexOf('<speak') === 0) return s;
return '<speak>' + s + '</speak>';
} catch (e) { return s; }
}
var useEsml2 = _isEsml2(txt);
if (useEsml2 && jibo && jibo.tts && typeof jibo.tts.speak === 'function') {
var payload2 = _ensureSpeakWrapper2(String(txt));
jibo.tts.speak(payload2, { mode: jibo.tts.TTSMode ? jibo.tts.TTSMode.SSML : undefined });
} else if (jibo && jibo.tts && typeof jibo.tts.speak === 'function') {
jibo.tts.speak(String(txt), { mode: jibo.tts.TTSMode ? jibo.tts.TTSMode.TEXT : undefined });
} else if (beRuntime && beRuntime.api && typeof beRuntime.api.speak === 'function') {
beRuntime.api.speak({ text: String(txt), mode: useEsml2 ? 'ssml' : 'text' });
} else if (jibo && jibo.api && typeof jibo.api.speak === 'function') {
jibo.api.speak({ text: String(txt), mode: useEsml2 ? 'ssml' : 'text' });
} else {
logWarn('no speak API available for tts_text', { tts_text: txt });
}
} catch (e) { logWarn('tts speak failed', { err: String(e) }); }
}
} catch (e) { logWarn('rosbridge handleMsg error', { err: String(e) }); }
}
connect(wsUrl, handleMsg);
return {
close: close,
};
};
exports.shutdown = function () { close(); };

View File

@@ -1,8 +0,0 @@
{
"type": "skill",
"title": "Clock One (launch jibo-tbd)",
"icon": "resources/icons/clock.png",
"color": "blue",
"order": 20,
"skillId": "jibo-tbd"
}

View File

@@ -1,8 +0,0 @@
{
"type": "skill",
"title": "Fun One (launch jibo-tbd)",
"icon": "resources/icons/fun-stuff.png",
"color": "orange",
"order": 10,
"skillId": "jibo-tbd"
}

View File

@@ -1,4 +0,0 @@
{
"hidden": true,
"title": "FunStuffTest Root"
}