skillok meeting
393887285dfc8accae94edba2c7c575b098e705e
Перейти к файлу
Код
meeting srcscope.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 г.
scope.ts
// Область экрана: подписки и таймеры, которые снимаются при уходе с него.

export class Scope {
  private disposers: (() => void)[] = [];
  private closed = false;

  /** Подписка на событие ядра: `on(events.status(cb))`. */
  on(unsubscribe: Promise<() => void>): void {
    unsubscribe.then((off) => (this.closed ? off() : this.disposers.push(off)));
  }

  every(ms: number, fn: () => void): void {
    const id = window.setInterval(fn, ms);
    this.disposers.push(() => clearInterval(id));
  }

  /** Вложенная область: снимается вместе с этой или раньше — сама. */
  child(): Scope {
    const c = new Scope();
    this.disposers.push(() => c.dispose());
    return c;
  }

  get alive(): boolean {
    return !this.closed;
  }

  dispose(): void {
    this.closed = true;
    this.disposers.splice(0).forEach((off) => off());
  }
}