Добавлен полный пайплайн выгрузки записей разговоров из IMAP-почты Yandex, транскрипции через faster-whisper (turbo, CUDA) и сохранения в Directus. Новые файлы: - imap/email_fetcher.py — подключение к IMAP (imap.yandex.ru:993), пагинация по UID (200/страница), автоматическое переподключение при IMAP4.abort (3 retry) - imap/config.py — конфигурация из .env - imap/ingestor.py — основной цикл: чтение письма, парсинг метаданных, сохранение вложения, конвертация в WAV, разделение стереоканалов, транскрипция, запись в Directus; поддержка --limit - imap/parsers/base.py — абстрактный парсер писем - imap/parsers/novofon.py — парсер писем Novofon/Zadarma: темы [АТС Zadarma] и Novofon, тело письма (JSON+HTML), имя файла вложения как fallback; маппинг внутренних номеров 102/201 на виртуальные; _clean_number без + - imap/preprocessor.py — конвертация в WAV (ffmpeg), разделение стереоканалов (левый=callee, правый=caller), get_audio_duration() через ffprobe - imap/stt.py — транскрипция через faster-whisper (turbo, CUDA) - imap/aligner.py — alignment результатов STT - imap/directus.py — клиент Directus: check_call (дедуп), save_call в calls/calls_74951284933, find_contact - match_contacts.py — сопоставление всех звонков с контактами по номеру телефона, заполнение caller_name/callee_name - count_remaining.py — утилита подсчёта оставшихся писем в IMAP Изменения: - .env.example: добавлена секция IMAP (сервер, логин, пароль, папка) - requirements.txt: добавлен imap-tools (IMAP-клиент) Обработано ~3900 звонков из IMAP (3670 в calls + 687 в calls_74951284933). Все записи с длительностью аудио из файла (ffprobe). Все звонки без + в номерах телефонов.
50 lines
1.4 KiB
Python
50 lines
1.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
import httpx, os
|
|
from dotenv import load_dotenv
|
|
from imap_tools import MailBox, AND
|
|
|
|
load_dotenv()
|
|
|
|
c = httpx.Client(
|
|
base_url=os.environ["DIRECTUS_URL"].rstrip("/"),
|
|
headers={"Authorization": "Bearer " + os.environ["DIRECTUS_TOKEN"]},
|
|
)
|
|
|
|
total = 0
|
|
for col in ["calls", "calls_74951284933"]:
|
|
resp = c.get(f"/items/{col}", params={"aggregate[count]": "id"})
|
|
data = resp.json().get("data", {})
|
|
if isinstance(data, list) and data:
|
|
count = data[0].get("count", 0)
|
|
elif isinstance(data, dict):
|
|
count = data.get("count", 0)
|
|
else:
|
|
count = 0
|
|
total += count
|
|
print(f"{col}: {count}")
|
|
print(f"Total in Directus: {total}")
|
|
|
|
mb = MailBox(os.environ["IMAP_SERVER"], 993)
|
|
mb.login(
|
|
os.environ["IMAP_USER"],
|
|
os.environ["IMAP_PASSWORD"],
|
|
initial_folder=os.environ["IMAP_FOLDER"],
|
|
)
|
|
uids = sorted(int(u) for u in mb.uids())
|
|
print(f"Total emails in IMAP: {len(uids)}")
|
|
|
|
call_emails = 0
|
|
total_scanned = 0
|
|
for start in range(0, len(uids), 500):
|
|
chunk = uids[start:start + 500]
|
|
for msg in mb.fetch(AND(uid=f"{chunk[0]}:{chunk[-1]}"), mark_seen=False, bulk=True):
|
|
total_scanned += 1
|
|
subj = (msg.subject or "").lower()
|
|
if "запись разговора" in subj:
|
|
call_emails += 1
|
|
print(f"Scanned: {total_scanned}")
|
|
print(f"Call emails in IMAP: {call_emails}")
|
|
|
|
remaining = call_emails - total
|
|
print(f"Remaining to process: ~{remaining}")
|
|
mb.logout()
|