Импорт старой переписки из экспорта Telegram Desktop

- /import: прислать result.json с подписью /import в чат или боту в личку (или ответить на файл)
- Парсер экспорта (zod): текст частями, упоминания по имени-ссылке, медиа, служебные сообщения
- Импорт идемпотентен и не перезаписывает живые сообщения и ники
- Экспорт другого чата в группе отклоняется; в личке чат определяется по экспорту
- CLI import-history для файлов больше 20 МБ
- /context показывает ID чата
- Общие downloadFile и MEDIA_LABELS для живых сообщений, фото и импорта

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
yunogasai
2026-09-24 20:18:43 +02:00
parent e812f1b1e2
commit 510221fd3c
17 changed files with 417 additions and 38 deletions

View File

@@ -0,0 +1,46 @@
import type { ParsedChatExport } from "../libs/telegram-export.js";
import type { ChatMemberRepository } from "../repositories/chat-member-repository.js";
import type { MessageRepository } from "../repositories/message-repository.js";
interface HistoryImportServiceDeps {
messageRepository: MessageRepository;
chatMemberRepository: ChatMemberRepository;
/** Сколько последних сообщений каждого чата хранить — импорт тоже в него упирается. */
historyLimit: number;
}
export interface ImportResult {
/** Сообщений в экспорте (без служебных и пустых). */
total: number;
/** Сколько новых сообщений добавлено. */
inserted: number;
/** Сколько сообщений чата в истории после импорта и обрезки лимитом. */
stored: number;
historyLimit: number;
/** Сколько новых участников узнал бот. */
newMembers: number;
}
/** Загружает экспорт чата из Telegram Desktop в историю бота. */
export const createHistoryImportService = ({
messageRepository,
chatMemberRepository,
historyLimit,
}: HistoryImportServiceDeps) => {
const importChat = (exported: ParsedChatExport): ImportResult => {
const newMembers = chatMemberRepository.insertManyIfMissing(exported.chatId, exported.profiles);
const inserted = messageRepository.insertManyAndPrune(exported.chatId, exported.messages, historyLimit);
return {
total: exported.messages.length,
inserted,
stored: messageRepository.statsByChat(exported.chatId).count,
historyLimit,
newMembers,
};
};
return { importChat };
};
export type HistoryImportService = ReturnType<typeof createHistoryImportService>;