mirror of
https://kevinblog.sytes.net/Code/Jibo-Revival-Group/JiboOs.git
synced 2026-06-13 09:16:26 +00:00
Removed AI Bridge & temp ROS
This commit is contained in:
@@ -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
@@ -74,17 +74,17 @@ exports.postInit = function (err) {
|
|||||||
this.log.warn('Dynamic skill loader failed (non-fatal):', e.message || e);
|
this.log.warn('Dynamic skill loader failed (non-fatal):', e.message || e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional: AI Bridge (modular; can run models off-robot for now)
|
// Optional: AI Bridge (DEPRICALED)
|
||||||
try {
|
// try {
|
||||||
if (rlog && typeof rlog.raw === 'function') {
|
// if (rlog && typeof rlog.raw === 'function') {
|
||||||
rlog.raw('[BE] initializing AI bridge');
|
// rlog.raw('[BE] initializing AI bridge');
|
||||||
}
|
// }
|
||||||
require('./ai-bridge').initAIBridge(this, jibo);
|
// require('./ai-bridge').initAIBridge(this, jibo);
|
||||||
this.log.info('AI bridge initialized');
|
// this.log.info('AI bridge initialized');
|
||||||
if (rlog && typeof rlog.raw === 'function') {
|
// if (rlog && typeof rlog.raw === 'function') {
|
||||||
rlog.raw('[BE] AI bridge initialized');
|
// rlog.raw('[BE] AI bridge initialized');
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.log.warn('AI bridge init failed (non-fatal):', e.message || e);
|
this.log.warn('AI bridge init failed (non-fatal):', e.message || e);
|
||||||
try {
|
try {
|
||||||
@@ -99,23 +99,23 @@ exports.postInit = function (err) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Optional: rosbridge connector (connects to external rosbridge websocket)
|
// Optional: rosbridge connector (connects to external rosbridge websocket)
|
||||||
try {
|
//try {
|
||||||
try {
|
// try {
|
||||||
var rosbridge = require('./rosbridge');
|
// var rosbridge = require('./rosbridge');
|
||||||
if (rosbridge && typeof rosbridge.init === 'function') {
|
// if (rosbridge && typeof rosbridge.init === 'function') {
|
||||||
rosbridge.init(this, jibo);
|
// rosbridge.init(this, jibo);
|
||||||
if (rlog && typeof rlog.raw === 'function') rlog.raw('[BE] rosbridge connector initialized');
|
// if (rlog && typeof rlog.raw === 'function') rlog.raw('[BE] rosbridge connector initialized');
|
||||||
if (rlog && typeof rlog.info === 'function') rlog.info('be', 'rosbridge connector initialized');
|
// if (rlog && typeof rlog.info === 'function') rlog.info('be', 'rosbridge connector initialized');
|
||||||
else this.log.info('rosbridge connector initialized');
|
// else this.log.info('rosbridge connector initialized');
|
||||||
}
|
// }
|
||||||
} catch (e) {
|
// } catch (e) {
|
||||||
if (rlog && typeof rlog.raw === 'function') rlog.raw('[BE] rosbridge module not present or failed to init (ok)');
|
// 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)');
|
// else this.log.info('rosbridge module not present or failed to init (ok)');
|
||||||
}
|
// }
|
||||||
} catch (e) {
|
// } catch (e) {
|
||||||
if (rlog && typeof rlog.raw === 'function') rlog.raw('[BE] rosbridge init failed: ' + String(e && (e.stack || e.message || 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);
|
// this.log.warn('rosbridge init failed (non-fatal):', e.message || e);
|
||||||
}
|
// }
|
||||||
|
|
||||||
jibo.face.views.changeView({ removeAll: true, leaveEmpty: true }, () => {
|
jibo.face.views.changeView({ removeAll: true, leaveEmpty: true }, () => {
|
||||||
this.selectFirstSkill(this.launchFirstSkill.bind(this));
|
this.selectFirstSkill(this.launchFirstSkill.bind(this));
|
||||||
|
|||||||
@@ -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(); };
|
|
||||||
Binary file not shown.
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "skill",
|
|
||||||
"title": "Clock One (launch jibo-tbd)",
|
|
||||||
"icon": "resources/icons/clock.png",
|
|
||||||
"color": "blue",
|
|
||||||
"order": 20,
|
|
||||||
"skillId": "jibo-tbd"
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"hidden": true,
|
|
||||||
"title": "FunStuffTest Root"
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user