О проекте
Команда: Teren Oi
Кейс HackAlem.ai: Спецтрек — Казахтелеком
Стадия: Доведённый продукт
Задача кейса: Агент, сравнивающий документы оргструктуры до и после реорганизации
Суть
Инструмент сравнивает редакции оргдокументов до и после реорганизации: сопоставляет пункты, строит карту изменений подразделений и функций, ищет возможные потери и дубли с цитатами-источниками и формирует заключение в PDF и Word.
Как устроено
Парсеры читают DOCX, PDF и XLSX с привязкой каждого фрагмента к файлу и позиции. Локальный diff сопоставляет пункты (добавлено, удалено, изменено, перенумеровано) без ИИ. По желанию включается AI-анализ: пары фрагментов подбираются для модели OpenAI (gpt-5.6-terra) через pairwise evidence retrieval с бюджетом по назначению, модель строит смысловую карту подразделений и функций и находит риски, а сервер проверяет цитаты по источникам. Результат показывается в React/FastAPI (есть запасной Streamlit) и экспортируется в PDF, DOCX, Markdown и CSV; историю заключений можно сохранить в браузере.
Ключевые решения
- source-traced DOCX/PDF/XLSX parsing
- clause matching/diff
- renumbering detection
- pairwise evidence retrieval
- purpose-based token budgeting
- quote evidence validation
- split/merge department scenarios
- PDF/DOCX report export
Особенности
Разделили результаты: детерминированный локальный diff работает без ключа, а выводы ИИ принимаются только с проверенными цитатами. Интерфейс честно показывает «не проверено», если ИИ выключен. Запуск для жюри двойным кликом через START.bat или через Docker.
Стек
Python · FastAPI · uvicorn · React · TypeScript · Vite · Streamlit · python-docx · Docker Compose
Модели
gpt-5.6-terra (OpenAI)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-2fb67e0d-teren-oi.
README
README.mdTeren Oi
Сравнение редакций организационных документов с проверяемыми источниками. Приложение сопоставляет пункты, показывает изменения подразделений по текстовым признакам и помогает проверить возможную потерю функций или дублирование ответственности. Каждый показанный вывод сопровождается цитатой из конкретной редакции.
Проект команды Teren Oi для HackAlem AI. Основной сценарий: демо в один клик → карта изменений → выводы и источники → заключение PDF/Word. Демо синтетическое; оно не является официальными документами АО «Казахтелеком».
Быстрый запуск для жюри
Скачайте репозиторий (Code → Download ZIP) и распакуйте архив. API-ключ для демонстрации не нужен.
Windows: двойной клик
Нужны установленные Python 3.11+ и Node.js 22.12+ (npm входит в Node.js). Запустите START.bat в корне проекта. Скрипт автоматически:
- Создаст отдельное окружение
.venv-run, сохранив существующие окружения команды. - Установит Python- и JavaScript-библиотеки.
- Соберёт интерфейс и запустит его вместе с API.
- Откроет Teren Oi в браузере.
Держите окно запуска открытым. Для остановки нажмите Ctrl+C. При повторном запуске установка/сборка пропускаются, если соответствующие файлы проекта не изменились. Для воспроизводимости версии Python-библиотек закреплены в constraints.txt, JavaScript — в frontend/package-lock.json. Сборка автозапуска изолирована в .venv-run/frontend и не затрагивает рабочий Vite. При первом запуске нужен интернет для загрузки зависимостей; подготовленное локальное сравнение работает без интернета. OpenAI требует интернет и собственный ключ.
На macOS/Linux с Python и Node.js выполните python3 launch.py. Если порт занят: python launch.py --port 8766. Для подготовки заранее без запуска: python launch.py --prepare-only. Параметр --no-browser отключает автоматическое открытие браузера.
Docker: одна команда
Если установлен и запущен Docker с Compose, Python/Node.js на компьютере не нужны:
docker compose up --build
Откройте http://127.0.0.1:8765/. Образ сам устанавливает библиотеки и кириллические шрифты. Первое построение требует интернет. Для остановки: docker compose down в другом терминале. Для подготовки до демонстрации можно заранее выполнить docker compose build.
Локальный .env необязателен. Compose передаёт OPENAI_API_KEY/OPENAI_MODEL только серверу; .env исключён из контекста сборки образа. После изменения настроек перезапустите контейнер через docker compose up --force-recreate. Порт доступен только на вашем компьютере.
Проверка за минуту
- Нажмите «Загрузить контрольный демо-комплект Казахтелеком» с выключенным ИИ.
- Откройте цитату удалённого пункта и карту изменений.
- Скачайте PDF или Word. Показатели смысловой проверки без ключа честно показывают «не проверено».
- Для проверки ИИ настройте локальный
.env, перезапустите приложение и включите переключатель «AI-анализ».
Если окно сообщает об отсутствии Python/Node.js, установите эти два компонента или выберите Docker-вариант. Ручная установка отдельных библиотек не требуется. При проблемах скачивания проверьте интернет и повторите запуск; сообщение об ошибке останется в окне.
Запуск для разработки
Нужны Python 3.11+, Node.js 22.12+ и npm. Все команды Python выполняйте одним интерпретатором. Рекомендуется отдельное виртуальное окружение.
Терминал 1, корень репозитория, PowerShell:
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
.\.venv\Scripts\python.exe -m uvicorn teren_oi.web:app --host 127.0.0.1 --port 8000 --reload
На macOS/Linux вместо пути к Windows-интерпретатору используйте .venv/bin/python (для создания окружения обычно python3 -m venv .venv). В уже активированном окружении достаточно python -m pip install -e ".[dev]" и python -m uvicorn teren_oi.web:app --reload.
Терминал 2, корень репозитория:
cd frontend
npm ci
npm run dev
Откройте интерфейс. Vite передаёт /api на http://127.0.0.1:8000. Описание HTTP API доступно у запущенного FastAPI. Эти адреса работают локально и не означают публичный деплой.
Для PDF нужен TrueType-шрифт с кириллицей. Поддерживаются системные Arial, DejaVu Sans, Liberation Sans; при их отсутствии положите DejaVuSans.ttf и, по возможности, DejaVuSans-Bold.ttf в src/teren_oi/fonts/. Word создаётся через python-docx.
Настройка ИИ
Без ключа доступны локальное сравнение, цитаты удалённых пунктов, карта изменений и экспорт. Чтобы добавить смысловую проверку:
- Создайте локальный
.envпо образцу.env.example, не перезаписывая существующий файл с настройками. - Укажите
OPENAI_API_KEY; модель по умолчанию —gpt-5.6-terra, её можно изменить черезOPENAI_MODEL. - Перезапустите API, обновите состояние подключения в интерфейсе и включите «AI-анализ» рядом с кнопкой запуска. Выбранный режим применяется и к демо.
.env исключён из Git. Ключ используется только Python-сервером: не помещайте его в React, переменные VITE_*, коммиты или скриншоты. Статус «ключ подключён» означает наличие настройки; действительность ключа, доступ к модели и квота проверяются реальным запросом. Баланс API не определяется этим статусом.
При включённом ИИ сервер передаёт выбранные фрагменты документов в OpenAI API, включая часть сохранённых пунктов для поиска возможных дублей. Для проверки подключения используйте синтетическое демо. Запрос ограничен по объёму, без автоматических повторов; ошибка ИИ сохраняет результат локального сравнения.
Запасной Streamlit
Общий парсер и анализатор также используются исходным интерфейсом:
python -m pip install -e .
python -m streamlit run app.py
Он откроется на localhost:8501. Основной демонстрационный сценарий, явные статусы ИИ и экспорт по серверному идентификатору описаны ниже для React/FastAPI.
Сценарий для жюри
-
Откройте приложение с выключенным «AI-анализ» и нажмите «Загрузить контрольный демо-комплект Казахтелеком». Файлы с диска не нужны; выбранные пользователем документы в этот запрос не попадают.
-
Дождитесь результата. Статус — «ИИ выключен»; карта содержит пять сопоставлений. Ожидаемые детерминированные значения:
Категория Количество Что проверить Добавлено 1 Новый пункт 2.4 про департамент клиентского опыта Удалено 1 Исходный пункт 2.2 про контроль качества Изменено 1 Пункт 2.3 про закрытие заявки Без изменений текста 2 2.1 и перенумерация 2.4 → 2.5 -
Отфильтруйте удалённые пункты, откройте источник 2.2 и проверьте цитату. Локальная находка помечена «Удалённый пункт»: проверьте, перенесена ли функция. Это не вывод ИИ о потере функции. Без ИИ отсутствие найденных дублей не означает, что дублирование проверено.
-
Откройте сохранённый текст 2.4 → 2.5: исходный и новый номера должны быть доступны. Это совпадение текста, а не доказательство сохранения полномочий подразделения.
-
Скачайте PDF и Word. Сверьте числа, цитату 2.2, обе редакции и состояние AI-проверки с экраном; проверьте читаемость кириллицы.
-
Для проверки ИИ вернитесь к документам, включите «AI-анализ» и повторите демо один раз. При успешном запросе появится «Ответ ИИ», статус «AI-проверка выполнена», модель и охват. Нажатие на замечание открывает его источники. Число смысловых выводов зависит от ответа модели; фиксированного ожидаемого числа нет.
-
При отсутствии ключа или ошибке сервиса результат должен объяснять состояние ИИ, сохраняя локальные числа и экспорт. Не считайте отсутствие ai_error самостоятельным признаком успешного вызова.
Дополнительно проверьте светлую/тёмную тему, управление клавиатурой и ширины 320, 390, 768, 1280 и 1440 px. В таблице допустима собственная прокрутка; содержимое страницы и кнопки должны оставаться доступны.
Что считается результатом
Работа с заключением
- Направление: «Поменять редакции местами» меняет файлы и текст; слева старая редакция, справа новая.
- Поиск: текст, цитаты и номера в замечаниях и точной карте; сочетается с фильтрами статуса пункта и подразделения. Смысловая таблица ИИ остаётся полной.
- История: внизу результата задайте название и нажмите «Сохранить в историю». Сохраняется исходное заключение с цитатами, без загруженных файлов. Есть поиск, просмотр, скачивание и отмена последнего удаления до перезагрузки.
- Хранение: только в этом браузере и по этому адресу, до 8 записей и 1,5 млн символов JSON. Автосохранения и командной синхронизации нет. При переполнении скачайте Markdown. Старые сохранённые заключения остаются неизменными.
- Экспорт: PDF/Word — исходное серверное заключение; Markdown — тот же текст без обращения к серверу. CSV содержит всю точную карту независимо от фильтров. PDF/Word из истории форматируются сервером из сохранённого текста без повторного вызова ИИ.
Соответствие обязательным сценариям ТЗ
| Требование | Где смотреть |
|---|---|
| Созданные, сохранённые, преобразованные подразделения | «Подразделения и функции · ИИ», цитаты; при выключенном ИИ только текстовые признаки |
| Сопоставление функций до/после | Смысловая карта функций с подразделениями и источниками |
| Возможные потери, дублирование, конфликты интересов | Замечания ИИ с проверенными цитатами; отсутствие замечаний не гарантирует отсутствия рисков |
| Проверяемые выводы | Раскрываемые источники: редакция, пункт, цитата, файл и позиция при наличии |
| Итоговое заключение | PDF, Word, Markdown с результатами и ограничениями |
| Word / PDF / Excel | DOCX, PDF с текстовым слоем, XLSX; дополнительно TXT и вставка текста |
| Рекомендательный характер | Ограничения на экране и в отчёте; решения требуют проверки ответственным сотрудником |
Границы текущей реализации: OCR, сравнение с внешней нормативной базой и бенчмаркинг других операторов не реализованы. Смысловая проверка требует работающего OpenAI API и ограничена указанным охватом. Наличие цитаты подтверждает источник, но не истинность интерпретации модели. Демонстрационный комплект синтетический; приёмку по контрольным документам организаторов необходимо проводить отдельно.
Локальное сопоставление нормализует регистр и пробелы. Сначала резервируются непустые тексты, встречающиеся ровно один раз в каждой редакции, даже если изменился номер. Затем сопоставляются одинаковые тексты внутри одного номера; оставшиеся пункты с одинаковым номером — по порядку появления. Каждое вхождение сохраняется. Удалённый пункт означает отсутствие найденной пары, а не доказанную потерю функции.
Если текст повторяется, совпадения между разными номерами не выводятся автоматически: определить единственный перенос нельзя. После частичного сопоставления повторяющийся текст тоже не объявляется уникальным. Перенумерация одновременно с переформулировкой, слияния и разделение функций требуют ручной проверки. Нечёткого смыслового сопоставления в локальном алгоритме нет.
Выводы ИИ проходят проверку источников: цитата должна дословно присутствовать в указанной редакции, указанном пункте и отправленном модели фрагменте; повторный номер должен однозначно разрешаться по цитате. Выводы могут быть скрыты из-за неоднозначной цитаты, отсутствия нужной редакции или недостаточной полноты контекста; число отклонённых находок сообщается. Для сигналов о дублировании и конфликте нужны два разных подтверждённых вхождения новой редакции; две цитаты из одного пункта не образуют два источника. Такая проверка подтверждает происхождение цитаты, но не истинность интерпретации, уровня риска или оценки уверенности модели.
«Ответ ИИ» включает формулировки модели с проверенными цитатами. Короткая сводка создаётся сервером из допустимых находок и явно помечается summary_origin: verified_findings. Свободное поле summary исходного ответа модели не публикуется: его утверждения не связаны с доказательствами. Пустая сводка находок не гарантирует отсутствия рисков.
Статусы и охват ИИ
ai.status | Значение |
|---|---|
disabled | Пользователь выбрал локальное сравнение; вызова ИИ не было |
unavailable | ИИ запрошен, но ключ отсутствует на сервере |
succeeded | Вызов модели завершён и структурированный ответ обработан; допустимых выводов может быть ноль |
failed | AI-проверка завершилась ошибкой; локальное сравнение сохранено |
skipped | Вызов не потребовался, например нет изменений для проверки |
Пока HTTP-запрос выполняется, интерфейс показывает ожидание результата. API не передаёт поток этапов или процент выполнения; анимация ожидания не измеряет прогресс сервера.
coverage.before/after показывает извлечённые пункты, ненумерованные блоки и применение временных номеров. ai.coverage считает фрагменты-кандидаты, а не уникальные номера или все абзацы файла: изменённый пункт учитывается дважды, по одному разу для каждой редакции; сохранённый одинаковый текст — один раз из новой редакции; добавленный и удалённый — по одному разу. Поэтому в демо кандидатов 6, хотя в каждом исходном документе по четыре пункта.
Если сохранённый текст совпадает дословно, модель получает явную дополнительную ссылку на его исходный номер в редакции «до». Например, текст нового 2.5 также имеет ссылку на старый 2.4. Тело текста передаётся один раз, поэтому такая ссылка не увеличивает счётчик фрагментов. Совпадение только после нормализации регистра/пробелов не создаёт эту ссылку и не доказывает полный охват старой редакции.
Флаги ai.coverage.before_complete и after_complete отдельно указывают, передан ли полный извлечённый контекст каждой редакции. Интерфейс и отчёт показывают «Полный контекст для ИИ: до / после». Даже «6 из 6 фрагментов» не означает полноту обеих редакций: при совпадении только после нормализации исходная формулировка «до» не отправляется, before_complete=false, а ссылка на неё входит в ai.omitted_refs. Списки omitted_refs и truncated_refs содержат до 50 обозначений пропущенных и сокращённых источников каждый; это пояснения к ограничению, а не полный текст документов.
Поля total_clauses, included_clauses, omitted_clauses, truncated_clauses отражают общий объём кандидатов, включённые, пропущенные и сокращённые фрагменты. Текущий бюджет запроса — не более 32 000 символов сериализованного JSON с учётом экранирования и ссылок на обе редакции (системная инструкция и схема ответа считаются отдельно); один пункт ограничен 1 600 символами. Для сохранённых пунктов резервируется часть бюджета. В состояниях без успешного ответа число включённых фрагментов не следует трактовать как подтверждённый сервером OpenAI охват проверки.
Архитектура и API
flowchart LR
UI[React / TypeScript / Framer Motion] --> API[FastAPI web.py]
API --> READ[readers.py / parsers.py]
READ --> DIFF[diff.py: точный текст и номера]
DIFF --> LOCAL[Локальные сигналы]
DIFF --> AI[analyzer.py: OpenAI, опционально]
AI --> CHECK[evidence.py: проверка цитат]
LOCAL --> CHECK
CHECK --> REPORT[report.py: единое заключение]
REPORT --> UI
REPORT --> STORE[report_store.py: временный снимок]
STORE --> EXPORT[export_formats.py: PDF / Word]
Основные контракты находятся в src/teren_oi/models.py и frontend/src/types.ts. Клиентские запросы — frontend/src/api.ts, экраны — frontend/src/components/, стили — frontend/src/index.css.
Структурированный анализ для команды
analyzer.analyze_structure(comparison, model) возвращает общий AnalysisResponse: department_changes, function_mappings и findings. Он использует тот же ограниченный запрос, что и analyze_with_metadata; отдельный дополнительный вызов модели внутри него не выполняется. analyze_changes остаётся совместимым адаптером для старых клиентов и возвращает список находок. Streamlit использует analyze_with_metadata, чтобы сохранять статус и охват конкретного запуска.
diff.validate_analysis_response проверяет цитаты и достаточность сторон/охвата для этих структур. Создание подразделения требует полного переданного контекста «до», удаление подразделения и статус функции lost — полного контекста «после». Для остальных сопоставлений нужны источники обеих редакций; для переназначения функции — также обе подписи подразделений. Сигнал possible_loss требует цитаты «до» и либо цитаты «после», либо полного нового контекста. Дублирование/конфликт требуют двух разных однозначных источников «после». Полнота означает передачу всех извлечённых вхождений целиком с учётом явных ссылок и отсутствие пропущенных ненумерованных блоков; она не доказывает истинность смыслового вывода.
Веб-интерфейс использует analyze_with_metadata(...).structured: это структурированный результат того же ядра, доступного через analyze_structure, вместе со статусом вызова и охватом. Второго запроса к модели нет. API дополнительно возвращает department_changes, function_mappings и ai_summary; при выключенном/недоступном ИИ списки пусты, сводка равна null.
В результатах появился раздел «Подразделения и функции · ИИ»: исходная и новая функции, подразделения, статус и раскрываемые цитаты с позициями. Эти же оценки и цитаты включаются в PDF/Word. ai_summary собирается сервером из валидированных результатов, а не из свободного резюме модели.
Карточки units используют оценку ИИ при однозначном соответствии имён (регистр и пробелы нормализуются); origin показывает ai или local. Противоречивые оценки одного подразделения не переопределяют локальный статус. При отсутствии оценки сохраняется эвристика по упоминаниям. Валидированное сопоставление функции со статусом retained, changed или reassigned скрывает соответствующий локальный сигнал «Удалённый пункт» только для того же однозначно разрешённого пункта «до»; одинаковых номеров пунктов для этого недостаточно. Например, функция ДНМ из 3.4.а может соответствовать 3.4.в: ИИ оценивает подразделение как сохранённое, а точная карта changes продолжает показывать исходный текстовый diff без изменений.
KPI «Потери функций · ИИ» и «Возможные дубли · ИИ» используют summary.ai_loss_count и ai_duplicate_count: только валидированные находки модели; null означает «не проверено». Удалённые пункты считаются отдельно (summary.removed) и в отчёте вынесены в «Локальные сигналы точного сравнения», отдельно от потерь, оценённых ИИ. Для старых клиентов числовой loss_count сохранён: при успешном ИИ он содержит число AI-сигналов потери, иначе число локальных сигналов; новый UI использует явное nullable-поле.
HTTP-контракт
| Метод | Запрос | Результат |
|---|---|---|
| GET /api/health | Без параметров | Наличие ключа, модель, форматы; без платного вызова |
| POST /api/analyze | multipart/form-data: before_file / before_text, after_file / after_text; use_ai, demo | analysis_id, summary, changes, units, department_changes, function_mappings, findings, ai_summary, ai, coverage, warnings, report_markdown |
| POST /api/export | JSON: analysis_id, format: pdf или docx | Файл из сохранённого сервером заключения |
Для каждой редакции передаётся либо файл, либо текст. При demo=true входные файлы и тексты должны отсутствовать. Лимиты: 12 МиБ на файл, 500 000 символов для вставленного текста. Ошибки API содержат HTTP-статус и error.code / error.message; например 400 для неверного ввода, 413 для превышения объёма. ai_error сохранён для совместимости; актуальное состояние определяется по ai.status.
Находки содержат id, origin: local | ai, объяснение и цитаты с файлом/позицией. Числа рисков считаются по тем же находкам, которые передаются в UI и заключение; это количество замечаний, а не вероятность события.
Жизненный цикл отчёта
React скачивает отчёт через непрогнозируемый analysis_id: сервер преобразует тот же Markdown, который сформировал при анализе. Клиент не пересобирает заключение. Размер итогового Markdown ограничен 4 млн символов; при превышении сравните документы по разделам. Для старых клиентов API также принимает report_markdown вместо analysis_id; этот режим форматирует переданный текст и не подтверждает его связь с ранее выполненным анализом. Оба поля одновременно запрещены.
Снимки хранятся в памяти одного процесса, максимум час: до 32 отчётов и суммарно до 8 000 000 символов. Старые записи могут удаляться раньше по лимиту ёмкости. Перезапуск API, включая --reload, очищает память. Если снимок истёк или удалён, экспорт вернёт 410 REPORT_EXPIRED — повторите анализ. Скачанные файлы сохраняются у пользователя независимо от памяти сервера.
Проверки и сборка
Последняя проверка — 23 сентября 2026
Для версии кода ff0b75f:
- 77 Python-тестов прошли, включая статусы ИИ, проверку цитат, составные номера пунктов, ограничения Office-файлов и экспорт больших документов. Ошибка ИИ в Streamlit проверена с подменой ответа сервиса.
- TypeScript/Vite: сборка успешна.
npm auditне обнаружил уязвимостей,pip checkне обнаружил конфликтов зависимостей на момент проверки. - Браузер: локальное демо, раскрытие источника и фильтрация работают; на ширинах 320, 390, 768, 1280 и 1440 px не обнаружено горизонтального переполнения страницы.
- PDF/Word: сервер возвращает файлы; извлечённый текст содержит кириллические цитаты и отдельный раздел локальных сигналов.
- Автозапуск: проверен на Windows по адресу
127.0.0.1:8765; интерфейс разработки на5173также доступен. - Не проверено в этом аудите: запуск Docker-образа (Docker недоступен в среде проверки) и повторный платный запрос OpenAI. Наличие ключа само по себе не подтверждает доступность модели или квоты.
Повторить проверки
В активированном Python-окружении из корня:
python -m pip install -e ".[dev]"
python -m unittest discover -s tests -v
В PowerShell без активации замените python на ..venv\Scripts\python.exe. Дополнение dev устанавливает httpx для FastAPI TestClient. Тесты проверяют перенумерацию, повторные ID, сохранение вхождений, статусы/охват ИИ, валидацию цитат, ввод и экспорт; ответы внешнего сервиса подменяются, платные запросы не нужны.
Проверка TypeScript и сборка интерфейса:
cd frontend
npm ci
npm run build
Артефакты появятся в frontend/dist/. Команда npm run preview просматривает сборку локально и наследует настроенный Vite-прокси; API на порту 8000 должен работать отдельно. Для размещения статических файлов вне Vite маршрутизацию /api нужно настроить на хостинге. После локальных проверок можно выполнить один реальный AI-запрос на демо через UI; текущий ключ и доступность OpenAI нужны только для него.
Проверка интеграции команды — 23 сентября 2026
На состоянии 19f984b (включает AI-core 2b0057d и интерфейс 1923cb1):
python -m unittest discover -s tests -v— 112 тестов успешно.npm run buildвfrontend/— TypeScript и сборка успешно; предупреждения зависимостей о директивеuse clientне блокируют сборку.- Улучшенный подбор контекста используется существующим
analyze_with_metadata(...).structured; контракт React/FastAPI не менялся. - Проверяются поиск функций при смене подразделения, разделение/объединение функций, валидация источников, локальный fallback и экспорт.
Ответы OpenAI в автоматических тестах подменены. Эти результаты подтверждают интеграцию кода, но не измеряют смысловую точность живой модели на документах организаторов.
Комплекты документов
В каждой колонке можно выбрать или перетащить до 8 файлов DOCX/PDF/XLSX/TXT. Повторный выбор добавляет файлы; крестик удаляет конкретный файл. До 12 МиБ на файл, до 500 000 символов извлечённого текста на комплект. Текст и файлы в одной редакции не смешиваются.
Для соответствующих документов используйте одинаковые имена в комплектах «до» и «после». Имена внутри одной стороны должны быть уникальны. В режиме комплекта ссылка на пункт включает имя файла, исходный номер остаётся в позиции источника. Это защищает от смешения одинаковых номеров разных документов. Порядок загрузки не определяет пары. При разных именах автоматически сопоставляется однозначно совпадающий текст; переформулировки могут выглядеть как удаление/добавление. Смысловое сопоставление выполняет ИИ в пределах доступного контекста. Лимит AI-контекста не увеличивается с числом файлов.
API принимает повторяемые multipart-поля before_files и after_files. Старые одиночные before_file / after_file продолжают работать; смешивание одиночного и множественного поля одной стороны отклоняется.
Ограничения входных данных
- До 12 МиБ на файл и 500 000 символов извлечённого текста. Office-архив: до 64 МиБ после распаковки и 4096 частей; XLSX: до 500 000 просматриваемых ячеек; PDF: до 500 страниц. Пустые форматированные области XLSX тоже входят в лимит: удалите лишние строки/столбцы или разделите файл. Защищённые паролем документы и недопустимые управляющие символы отклоняются с объяснением.
- Поддерживаются составные номера
3.4.аи отдельные подпунктыа)под родительским пунктом. Строки вроде100% заявокне считаются номерами пунктов. - Принимаются DOCX, PDF с текстовым слоем, XLSX и TXT. Сканы требуют внешнего OCR; внутри приложения OCR нет. Пустые или повреждённые файлы возвращают объяснение ошибки.
- Для PDF доступны страница и блок, XLSX — лист и ячейка, TXT — строка, DOCX — абзац/таблица. Это положение извлечённого текста, а не гарантированная страница визуальной вёрстки Word.
- Полностью ненумерованный текст получает временные номера блоков. Из файлов точная исходная позиция таких блоков может быть недоступна. При смешанной структуре ненумерованные блоки не входят в точное сравнение и AI-выборку; их количество показано в предупреждениях.
- Повторяющиеся номера не теряются. Остаточное сопоставление одинаковых номеров по порядку требует проверки экспертом; одинаковая цитата в нескольких вхождениях не даёт однозначного источника для находки.
- Статусы подразделений определяются по названиям и изменениям текста. Они не устанавливают фактическое создание, ликвидацию или реорганизацию отдела.
- Большие документы могут проверяться ИИ частично; усечённые хвосты и пропущенные фрагменты не проверяются моделью. Даже полный охват извлечённых пунктов не включает содержание, которое парсер не прочитал.
План публикации
Текущий запуск рассчитан на локальную демонстрацию. Для публикации соберите frontend/dist/, разместите его за HTTPS и настройте обратный прокси /api на FastAPI либо задайте публичный адрес API через VITE_API_BASE_URL при сборке. Корневой .env предназначен для Python; настройки Vite размещаются в окружении сборки или в frontend/.env.local.
Храните OPENAI_API_KEY только в секретах сервера. Разрешите в CORS только адреса своего интерфейса; сейчас разрешены два локальных адреса на порту 5173. Для текущих снимков используйте один worker FastAPI без --reload; для нескольких процессов/реплик потребуется общее ограниченное хранилище с TTL. Перед публичным доступом добавьте авторизацию, лимиты запросов/расходов и ограничения загрузок на прокси; в локальном MVP этих механизмов нет. Установите кириллические шрифты и повторите сценарий жюри уже на адресе публикации.
Финальная проверка интерфейса и API
23 сентября выполнен один реальный OpenAI-запрос на синтетическом комплекте из четырёх небольших TXT (два до, два после): статус succeeded, один элемент карты функций, одна оценка подразделения, без ошибок; охват 3/3 фрагментов и полный извлечённый контекст обеих редакций. Это проверка подключения и обработки ответа, не оценка точности на всех документах. В результатах файлы показаны отдельными списками «до → после». Длинные названия подразделений и статусы размещены на отдельных строках без сжатия карточек.
Авторы коммитов
История коммитов
- 2026-09-23 17:54revert: restore Teren Oi display namemaxiszero
- 2026-09-23 17:54test: align report metadata expectations with new display namemaxiszero
- 2026-09-23 17:53chore: update display name to Tereñ oimaxiszero
- 2026-09-23 17:49fix: prevent department overlap and clarify source document setsmaxiszero
- 2026-09-23 17:40feat: support document bundles with file-scoped evidencemaxiszero
- 2026-09-23 17:34docs: record verification of integrated team AI coremaxiszero
- 2026-09-23 17:29Merge pull request #3 from BAITC-Hacks/codex/ai-core-retrieval-qualitykairagz27
- 2026-09-23 17:27fix(ai-core): improve retrieval across owners and cover split/merge scenariosMrAgzam
Все коммиты (30)
- 2026-09-23 17:26Remove expert review workflow and refocus results on requirementsmaxiszero
- 2026-09-23 17:17feat: add local review workspace, report history and CSV exportmaxiszero
- 2026-09-23 17:08Merge pull request #2 from BAITC-Hacks/feature/allazhar-structured-integration-latestAllazhar
- 2026-09-23 17:07web: suppress local signals covered by validated mappingsAllazhar
- 2026-09-23 17:04feat(ai-core): add pairwise evidence retrieval and purpose-based budgetingMrAgzam
- 2026-09-23 16:48docs: refresh jury guide and record verified audit resultsmaxiszero
- 2026-09-23 16:45fix: harden document handling and align analysis status and reportsmaxiszero
- 2026-09-23 16:32feat: add isolated one-command launcher and Docker packagingmaxiszero
- 2026-09-23 16:22feat: expose semantic departments and function mappings in web UImaxiszero
- 2026-09-23 16:10merge: integrate team analysis core and preserve verified UI contractmaxiszero
- 2026-09-23 16:04feat: make analysis evidence-based and demo reproduciblemaxiszero
- 2026-09-23 15:57feat: add evidence-validated organization analysis coreMrAgzam
- 2026-09-23 15:40feat: add responsive AI summary to resultsmaxiszero
- 2026-09-23 15:27docs: explain Terra API setupmaxiszero
- 2026-09-23 15:24config: switch analysis model to GPT-5.6 TerraMrAgzam
- 2026-09-23 15:17fix: align both UIs with shared document analysismaxiszero
- 2026-09-23 15:05feat: add React analysis workspace and local APImaxiszero
- 2026-09-23 14:48feat: polish Teren Oi workspace and demo flowmaxiszero
- 2026-09-23 14:43Merge pull request #1 from BAITC-Hacks/feature/allazhar-parsersAllazhar
- 2026-09-23 14:37report: add evidence-grounded markdown and JSON exportAllazhar
- 2026-09-23 14:37parser: add source-traced DOCX PDF XLSX ingestionAllazhar
- 2026-09-23 13:56chore: bootstrap Teren Oi document comparison MVPmaxiszero
Структура репозитория (62 файлов)
.dockerignore .env.example .gitignore Dockerfile README.md START.bat app.py compose.yaml constraints.txt frontend/.gitignore frontend/index.html frontend/package-lock.json frontend/package.json frontend/src/App.tsx frontend/src/api.ts frontend/src/components/AiSummary.tsx frontend/src/components/AnalysisView.tsx frontend/src/components/HistoryPanel.tsx frontend/src/components/ImportView.tsx frontend/src/components/ResultsView.tsx frontend/src/components/SemanticAnalysis.tsx frontend/src/components/Stepper.tsx frontend/src/index.css frontend/src/main.tsx frontend/src/types.ts frontend/src/vite-env.d.ts frontend/src/workspace.ts frontend/tsconfig.app.json frontend/tsconfig.json frontend/tsconfig.node.json frontend/vite.config.ts launch.py pyproject.toml src/teren_oi/__init__.py src/teren_oi/analyzer.py src/teren_oi/diff.py src/teren_oi/document_safety.py src/teren_oi/docx_reader.py src/teren_oi/evidence.py src/teren_oi/export_formats.py src/teren_oi/models.py src/teren_oi/parsers.py src/teren_oi/readers.py src/teren_oi/report.py src/teren_oi/report_store.py src/teren_oi/semantic_view.py src/teren_oi/web.py tests/test_ai_result.py tests/test_analyzer.py tests/test_analyzer_evidence.py tests/test_audit_regressions.py tests/test_clause_matching.py tests/test_diff.py tests/test_document_bundles.py tests/test_export_formats.py tests/test_parsers.py tests/test_report.py tests/test_report_store.py tests/test_retrieval_scenarios.py tests/test_semantic_integration.py tests/test_streamlit_status.py tests/test_web_integration.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.