ext-parser.js 7.44 KB
 /*
  * Модуль для сбора отладочных сообщений о вызове внешних функций
  * и генерации диалогов из реплик, собранных во время разговора
  */

const dialogue_pauses = [
  {
    delay: -1000,
    text: "!!! (перебивание разговора)"
  },
  {
    delay: 2000,
    text: "... (пауза 2 секунды)"
  },
  {
    delay: 5000,
    text: "... (пауза 5 секунд)"
  },
  {
    delay: 8000,
    text: "... (пауза 8 секунд)"
  }
];

module.exports = exports = {
  collect_msg(collection, event) {
    if (event?.time === undefined) return;
    if (event?.incoming === undefined) return;
    if (event?.msg === undefined) return;
    if (event?.msg?.msgId === undefined) return;

    const msgId = event.msg.msgId;
    if (msgId != "JobCommunicationMessage") return;

    if (event?.msg?.content === undefined) return;
    if (event?.msg?.content?.id === undefined) return;
    if (event?.msg?.content?.type === undefined) return;

    const content = event.msg.content;
    const content_id = content.id;
    const content_type = content.type;
    const event_work = "work";

    if (collection[content_id] === undefined) collection[content_id] = {};

    switch (content_type) {
      case "request":
        const params = {};
        for (const [param, value] of Object.entries(content.parameters)) {
          const decoded = JSON.parse(value) ?? value;
          params[param] = decoded;
        }
        collection[content_id][content_type] = {
          time: event.time,
          incoming: event.incoming,
          method: content.method,
          parameters: params
        };
        break
      case "response":
        const decoded = JSON.parse(content.result) ?? content.result;
        collection[content_id][content_type] = {
          time: event.time,
          incoming: event.incoming,
          result: decoded
        };
        const request = collection[content_id].request;
        const startTime = (new Date(request.time)).getTime();
        const finishTime = (new Date(event.time)).getTime();
        collection[content_id][event_work] = {
          start: request.time,
          finish: event.time,
          duration: (finishTime - startTime) / 1000
        };
        break
      default:
        break;
    }
  },

  // Построение отчёта по вызовам внешних функций
  build_graph_call_list(collection) {
    const graph_calls = [];
    let max_duration = 0;
    for (const [id, event] of Object.entries(collection)) {
      var wrong_event = false;
      // Если, почему-то, у события из коллекции обращений
      // к внешним функциям не было запроса к функции или
      // ответа от неё, переходим к обработке следующего
      // события вызова внешней функции
      if (event.request === undefined) wrong_event = true;
      if (event.response === undefined) wrong_event = true;
      if (wrong_event) {
        console.log("wrong external function call info");
        try {
          console.log(JSON.stringify(event, undefined, 2));
        } catch {
          console.log(event);
        }
        continue;
      }

      const entry = {};
      entry.startTime = new Date(event.work.start)
      entry.endTime = new Date(event.work.finish);
      entry.duration = event.work.duration;
      entry.method = event.request.method;
      entry.parameters = event.request.parameters;
      entry.result = event.response.result;
      if (max_duration < event.work.duration)
        max_duration = event.work.duration;
      graph_calls.push(entry);
    }
    graph_calls.sort(function compare(a, b) {
      a_start = a.startTime.getTime();
      a_finish = a.endTime.getTime();
      b_start = b.startTime.getTime();
      b_finish = b.endTime.getTime();
      if (a_start  < b_start) return -1;
      if (a_start  > b_start) return 1;
      if (a_finish < b_finish) return -1;
      if (a_finish > b_finish) return 1;
      return 0;
    });
    return {
      max_duration: max_duration,
      graph_calls: graph_calls
    };
  },

  // Создание текста реплики диалога из объекта типа "transcription"
  build_replic(ts, entry) {
    rts = entry.startTime.getTime();
    dts = rts - ts;
    dts_m = Math.floor(dts / 60000);
    dts_s = ((dts - (dts_m * 60000)) / 1000).toFixed(1);
    if (dts_m < 10) dts_m = '0' + dts_m;
    if (dts_s < 10) dts_s = '0' + dts_s;

    hours   = entry.startTime.getHours();
    minutes = entry.startTime.getMinutes();
    seconds = entry.startTime.getSeconds();
    if (hours < 10)    hours    = '0' + hours;
    if (minutes < 10)  minutes  = '0' + minutes;
    if (seconds < 10)  seconds  = '0' + seconds;

    speaker = entry.speaker;
    if (speaker === "ai") speaker = "   ai";
    replic = speaker + ': [' + hours + ':' + minutes + ':' + seconds + ' '
                        + dts_m + ':' + dts_s + '] - ' + entry.text + "\n";
    return replic;
  },

  // Построение текста диалога из массива объектов типа "transcription"
  build_dialogue_text (ts, replics) {
    replics.sort(function compare(a, b) {
      a_start = a.startTime.getTime();
      a_finish = a.endTime.getTime();
      b_start = b.startTime.getTime();
      b_finish = b.endTime.getTime();
      if (a_start  < b_start) return -1;
      if (a_start  > b_start) return 1;
      if (a_finish < b_finish) return -1;
      if (a_finish > b_finish) return 1;
      return 0;
    });

    let dialogue = "";
    let interruption = false;

    const replics_count = replics.length;
    if (replics_count == 0) return {
      interruption: interruption,
      dialogue: dialogue
    };

    dialogue_pauses.sort(function compare(a, b) {
      if (a.delay < b.delay) return -1;
      if (a.delay > b.delay) return 1;
      return 0;
    });

    let sys_msg = {
      speaker: "  sys",
      text: "/ -=#=- /",
      startTime: new Date(),
      endTime: new Date()
    };

    var prev = replics[0];
    dialogue = dialogue + this.build_replic(ts, prev);
    for (var i = 1; i < replics_count; i ++) {
      var entry = replics[i];
      var prev_finish = prev.endTime.getTime();
      var entry_start = entry.startTime.getTime();
      var different = entry_start - prev_finish;
      var j = dialogue_pauses.length;
      while (j > 0) {
        j --;
        var pause = dialogue_pauses[j];
        if ((j > 0) && (different > pause.delay)) {
          sys_msg.startTime = new Date(prev_finish);
          sys_msg.endTime = new Date(entry_start);
          sys_msg.text = "/ " + pause.text + " /";
          dialogue = dialogue + this.build_replic(ts, sys_msg);
          break;
        }
        if ((j == 0) && (different < pause.delay)) {
          sys_msg.startTime = new Date(entry_start);
          sys_msg.endTime = new Date(prev_finish);
          sys_msg.text = "/ " + pause.text + " /";
          dialogue = dialogue + this.build_replic(ts, sys_msg);
          if (entry.speaker == "ai") interruption = true;
          else {
            var entry_finish = entry.endTime.getTime();
            if (entry_finish < prev_finish) interruption = true;
          }
        }
      }
      dialogue = dialogue + this.build_replic(ts, entry);
      prev = entry;
    }

    return {
      interruption: interruption,
      dialogue: dialogue
    };
  }

};