skillok meeting
ad47f897f99f8450c300100150f8c07c6061d85a
Перейти к файлу
Код
meeting srcmain.ts
anc Этап 1: запись встречи в Zoom, живая расшифровка и разбор - crates/audio: захват звука процесса Zoom и микрофона (WASAPI, process loopback), формат 16 кГц моно, нарезка на куски по паузам с отсевом тишины, распознавание начала и конца встречи по звуковой сессии Zoom. - Ядро: запись двух дорожек → Whisper через OpenRouter → расшифровка, живой конспект раз в три минуты, по окончании — разбор сам; звук удаляется после разбора, если не включено хранение. - Контроллер: слежу за Zoom → прошу предупредить участников → пишу; запись вручную, пауза, стоп; прерванная запись помечается при запуске. - Трей, уведомления, крестик прячет окно, запуск вместе с Windows. - Интерфейс: главный экран с карточкой состояния (задача #1), живая расшифровка и конспект на экране встречи, новые настройки. - reqwest на системном TLS: под Windows без C-кода ring. - 67 тестов; код под Windows проверен компиляцией и clippy с Mac, на Windows не запускался. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> 169ce64 30 сентября 2026 г.
main.ts
// Маршрутизация по хешу: #/ (главная), #/meeting/<id>/<вкладка>[/<реплика>], #/settings.

import { renderHome } from "./views/home";
import { renderMeeting, type Tab } from "./views/meeting";
import { renderSettings } from "./views/settings";
import { errorText } from "./api";
import { esc } from "./dom";
import { Scope } from "./scope";

const app = document.getElementById("app")!;
let scope = new Scope();

async function route(): Promise<void> {
  scope.dispose();
  scope = new Scope();
  const [section, id, tab, target] = location.hash.replace(/^#\/?/, "").split("/");
  for (const a of document.querySelectorAll<HTMLAnchorElement>("[data-nav]")) {
    const current = a.dataset.nav === (section === "settings" ? "settings" : "home");
    if (current) a.setAttribute("aria-current", "page");
    else a.removeAttribute("aria-current");
  }
  try {
    if (section === "meeting" && id) {
      await renderMeeting(app, scope, decodeURIComponent(id), (tab as Tab) || "transcript", target ? Number(target) : null);
    } else if (section === "settings") {
      await renderSettings(app);
    } else {
      await renderHome(app, scope);
    }
  } catch (e) {
    app.innerHTML = `<p class="error">${esc(errorText(e))}</p>`;
  }
}

window.addEventListener("hashchange", route);
route();