fix
This commit is contained in:
@@ -14,7 +14,27 @@
|
||||
- `{chapter_title}` — название главы
|
||||
- `{full_analysis_json}` — полный JSON анализа (склейка блоков framework + insights + application + limitations)
|
||||
|
||||
## Использование
|
||||
## Скрипт через Ollama
|
||||
|
||||
`run_consistency_ollama.py` — один вызов Ollama для проверки согласованности блоков. На выходе один JSON-файл.
|
||||
|
||||
**Вход (по умолчанию):**
|
||||
- `../1_анализ_главы/merge.json` — полный анализ (framework, insights, application, limitations)
|
||||
- `../1_анализ_главы/вход_главы.json` — метаданные главы (book_title, chapter_title)
|
||||
|
||||
**Выход:** `consistency_result.json` в каталоге скрипта (или путь через `-o`).
|
||||
|
||||
**Формат выхода:** `verdict` (ok | needs_review | bad), `score`, `inconsistencies` — список рассогласованностей с полями type, location, summary.
|
||||
|
||||
**Запуск:**
|
||||
```bash
|
||||
cd 2b_финальная_валидация_согласованности
|
||||
python3 run_consistency_ollama.py
|
||||
# с указанием путей:
|
||||
python3 run_consistency_ollama.py --merge /path/to/merge.json --chapter /path/to/вход_главы.json -o consistency_result.json
|
||||
```
|
||||
|
||||
## Использование в пайплайне
|
||||
|
||||
Вызывается после шага 2a (склейка блоков). При вердикте bad или needs_review — флаг `needs_review` по главе; опционально — «примиряющий» промпт для минимальных правок.
|
||||
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
{
|
||||
"framework": {
|
||||
"terms": {
|
||||
"стимул": "что в окружающей среде заставляет человека действовать",
|
||||
"привычка": "повторяющееся действие, которое становится автоматическим",
|
||||
"подкрепление": "воздействие, усиливающее вероятность повторения действия",
|
||||
"среда": "окружение, влияющее на поведение через стимулы и ограничения",
|
||||
"желание, вызванное стимулом": "непроизвольная тяга к действию, спровоцированному внешним триггером",
|
||||
"аутокаталитический процесс": "процесс, усиливающий себя сам"
|
||||
},
|
||||
"principles": [
|
||||
{
|
||||
"title": "Среда формирует поведение",
|
||||
"description": "Человек не управляет привычками напрямую, а воздействует на окружение, чтобы оно вело его к нужным действиям",
|
||||
"example": "Убрать телефон с рабочего стола, чтобы не отвлекаться на соцсети",
|
||||
"chains": [
|
||||
{
|
||||
"cause": "Человек находится в среде с доступными стимулами для нежелательной привычки",
|
||||
"mechanism": "Стимул активирует уже сформированную привычку, которая запускает автоматическое действие",
|
||||
"result": "Человек повторяет вредную привычку, не осознавая этого"
|
||||
},
|
||||
{
|
||||
"cause": "Изменяется среда, удаляются стимулы, провоцирующие нежелательную привычку",
|
||||
"mechanism": "Отсутствие триггеров снижает вероятность срабатывания привычки",
|
||||
"result": "Человек реже проявляет нежелательное поведение"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Привычки не исчезают, они только временно подавлены",
|
||||
"description": "Даже если человек перестаёт делать что-то, привычка остаётся в мозге и может вернуться при подходящих условиях",
|
||||
"example": "Человек перестаёт курить, но снова начинает после посещения места, где раньше курил",
|
||||
"chains": [
|
||||
{
|
||||
"cause": "Человек прекращает проявлять вредную привычку",
|
||||
"mechanism": "Мозг сохраняет нейронные связи, связанные с этой привычкой",
|
||||
"result": "Привычка может вернуться, если появятся подходящие стимулы"
|
||||
},
|
||||
{
|
||||
"cause": "Окружение меняется, и в нем появляются триггеры, связанные с прошлой привычкой",
|
||||
"mechanism": "Стимулы запускают автоматические паттерны поведения",
|
||||
"result": "Человек снова начинает делать то, что уже перестал"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Самоконтроль — это краткосрочный, а не долгосрочный инструмент",
|
||||
"description": "Противостояние искушению неэффективно на длительном сроке, нужно менять контекст",
|
||||
"example": "Человек отказывается от сладкого, но возвращается к нему после стрессового дня",
|
||||
"chains": [
|
||||
{
|
||||
"cause": "Человек пытается контролировать себя в момент искушения",
|
||||
"mechanism": "Это требует энергии и усилий, которые невозможно поддерживать всегда",
|
||||
"result": "Человек устаёт от борьбы и возвращается к нежелательной привычке"
|
||||
},
|
||||
{
|
||||
"cause": "Человек изменяет окружение, чтобы искушения стали менее доступными",
|
||||
"mechanism": "Стимулы для плохого поведения становятся незаметными или невозможными",
|
||||
"result": "Человек реже сталкивается с искушением"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Дисциплина — это настройка среды, а не внутреннее усилие",
|
||||
"description": "Сильные люди не просто дисциплинированы, а живут в среде, которая поддерживает их цели",
|
||||
"example": "Человек встаёт раньше, потому что спальня тёмная и не имеет гаджетов",
|
||||
"chains": [
|
||||
{
|
||||
"cause": "Человек пытается быть дисциплинированным только силой воли",
|
||||
"mechanism": "Это требует большого количества энергии и часто неудачно",
|
||||
"result": "Человек теряет мотивацию и возвращается к нежелательному поведению"
|
||||
},
|
||||
{
|
||||
"cause": "Человек настраивает окружение так, чтобы хорошее поведение было лёгким",
|
||||
"mechanism": "Стимулы для правильных действий становятся более доступными",
|
||||
"result": "Человек чаще выбирает здоровые привычки"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Негативные эмоции усиливают негативное поведение",
|
||||
"description": "Стресс, тревога и другие негативные чувства провоцируют возвращение к вредным привычкам",
|
||||
"example": "Человек садится на диван и ест шоколад, когда ему плохо",
|
||||
"chains": [
|
||||
{
|
||||
"cause": "Человек испытывает стресс или негативные эмоции",
|
||||
"mechanism": "Это активирует привычку, которая помогает снизить дискомфорт",
|
||||
"result": "Человек снова начинает делать то, что раньше снимало напряжение"
|
||||
},
|
||||
{
|
||||
"cause": "Человек пытается избавиться от вредной привычки, но не меняет среду",
|
||||
"mechanism": "Стресс и негативные эмоции остаются, усиливая желание к действию",
|
||||
"result": "Человек возвращается к нежелательной привычке"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"insights": [
|
||||
{
|
||||
"title": "Среда влияет на привычки больше, чем сила воли",
|
||||
"description": "Чтобы изменить привычку, нужно изменить окружение, а не надеяться только на самоконтроль",
|
||||
"example": "Убрать телефон с рабочего стола, чтобы не отвлекаться на соцсети"
|
||||
},
|
||||
{
|
||||
"title": "Привычки не исчезают, только временно подавляются",
|
||||
"description": "Даже если человек перестаёт курить или есть сладкое, эти привычки остаются в мозге и могут вернуться при подходящих условиях",
|
||||
"example": "После посещения бара человек снова начинает пить, не осознавая этого"
|
||||
},
|
||||
{
|
||||
"title": "Негативные эмоции усиливают вредное поведение",
|
||||
"description": "Стресс, тревога и другие негативные чувства могут спровоцировать возвращение к старым привычкам",
|
||||
"example": "После ссоры человек снова начинает есть вредную пищу, чтобы успокоиться"
|
||||
},
|
||||
{
|
||||
"title": "Сокращение стимулов уменьшает повторение нежелательного поведения",
|
||||
"description": "Удаление триггеров, связанных с вредной привычкой, снижает вероятность её возобновления",
|
||||
"example": "Убрать сигареты из дома, чтобы уменьшить вероятность их употребления"
|
||||
},
|
||||
{
|
||||
"title": "Самоконтроль — это временная стратегия, а не долгосрочное решение",
|
||||
"description": "Постоянно бороться с искушением утомительно и непрочное; нужно настраивать среду так, чтобы искушений не было совсем",
|
||||
"example": "Поставить телефон в другую комнату, чтобы не проверять соцсети во время работы"
|
||||
}
|
||||
],
|
||||
"application": {
|
||||
"techniques": [
|
||||
{
|
||||
"name": "Снижение доступности стимула",
|
||||
"goal": "Уменьшение вероятности повторения нежелательной привычки за счёт удаления её триггеров",
|
||||
"context_example": "Вечер после работы, когда тянет залипнуть в телефон и проверять соцсети",
|
||||
"steps": [
|
||||
"Определите конкретный стимул (например, наличие телефона на столе)",
|
||||
"Уберите объект из зоны видимости или досягаемости (например, оставьте телефон в другой комнате)",
|
||||
"Запишите дату и время изменения (для отслеживания эффективности)"
|
||||
],
|
||||
"client_phrase": "Уберите источник искушения из вашей среды — действие станет менее вероятным",
|
||||
"success_criteria": "Частота использования телефона в моменты, когда это не нужно, снижается с 5 раз/день до 1–2 раз/день за 2 недели"
|
||||
}
|
||||
]
|
||||
},
|
||||
"limitations": [
|
||||
{
|
||||
"description": "Идеи не работают, если триггер (то, что в окружении запускает действие) не устранён или остаётся доступным, так как привычка может вернуться при появлении стимула",
|
||||
"when_relevant": "Когда человек не полностью убирает триггер из своей среды или сталкивается с ним в новой обстановке",
|
||||
"example": "Человек удалил сигареты из дома, но снова начинает курить на работе среди коллег-курильщиков"
|
||||
},
|
||||
{
|
||||
"description": "Техники могут не сработать, если негативные эмоции (стресс, тревога) остаются необратленными и усиливают нежелательное поведение",
|
||||
"when_relevant": "Когда человек продолжает испытывать сильный стресс или эмоциональные трудности, не решая их на уровне среды",
|
||||
"example": "Человек убрал телефон из комнаты, но всё равно переедает перед сном из-за хронической тревоги"
|
||||
},
|
||||
{
|
||||
"description": "Изменения среды могут быть недостаточны, если привычка закреплена на уровне автоматических нейронных паттернов и не сопровождается новыми, здоровыми привычками",
|
||||
"when_relevant": "Когда человек устраняет триггер, но не вводит альтернативное поведение для подкрепления",
|
||||
"example": "Человек убрал телевизор из спальни, но не нашёл замену в виде чтения или медитации и проводит время впустую"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
{
|
||||
"framework": {
|
||||
"terms": {
|
||||
"стимул": "что в окружающей среде заставляет человека действовать",
|
||||
"привычка": "повторяющееся действие, которое становится автоматическим",
|
||||
"подкрепление": "воздействие, усиливающее вероятность повторения действия",
|
||||
"среда": "окружение, влияющее на поведение через стимулы и ограничения",
|
||||
"желание, вызванное стимулом": "непроизвольная тяга к действию, спровоцированному внешним триггером",
|
||||
"аутокаталитический процесс": "процесс, усиливающий себя сам"
|
||||
},
|
||||
"principles": [
|
||||
{
|
||||
"title": "Среда формирует поведение",
|
||||
"description": "Человек не управляет привычками напрямую, а воздействует на окружение, чтобы оно вело его к нужным действиям",
|
||||
"example": "Убрать телефон с рабочего стола, чтобы не отвлекаться на соцсети",
|
||||
"chains": [
|
||||
{
|
||||
"cause": "Человек находится в среде с доступными стимулами для нежелательной привычки",
|
||||
"mechanism": "Стимул активирует уже сформированную привычку, которая запускает автоматическое действие",
|
||||
"result": "Человек повторяет вредную привычку, не осознавая этого"
|
||||
},
|
||||
{
|
||||
"cause": "Изменяется среда, удаляются стимулы, провоцирующие нежелательную привычку",
|
||||
"mechanism": "Отсутствие триггеров снижает вероятность срабатывания привычки",
|
||||
"result": "Человек реже проявляет нежелательное поведение"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Привычки не исчезают, они только временно подавлены",
|
||||
"description": "Даже если человек перестаёт делать что-то, привычка остаётся в мозге и может вернуться при подходящих условиях",
|
||||
"example": "Человек перестаёт курить, но снова начинает после посещения места, где раньше курил",
|
||||
"chains": [
|
||||
{
|
||||
"cause": "Человек прекращает проявлять вредную привычку",
|
||||
"mechanism": "Мозг сохраняет нейронные связи, связанные с этой привычкой",
|
||||
"result": "Привычка может вернуться, если появятся подходящие стимулы"
|
||||
},
|
||||
{
|
||||
"cause": "Окружение меняется, и в нем появляются триггеры, связанные с прошлой привычкой",
|
||||
"mechanism": "Стимулы запускают автоматические паттерны поведения",
|
||||
"result": "Человек снова начинает делать то, что уже перестал"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Самоконтроль — это краткосрочный, а не долгосрочный инструмент",
|
||||
"description": "Противостояние искушению неэффективно на длительном сроке, нужно менять контекст",
|
||||
"example": "Человек отказывается от сладкого, но возвращается к нему после стрессового дня",
|
||||
"chains": [
|
||||
{
|
||||
"cause": "Человек пытается контролировать себя в момент искушения",
|
||||
"mechanism": "Это требует энергии и усилий, которые невозможно поддерживать всегда",
|
||||
"result": "Человек устаёт от борьбы и возвращается к нежелательной привычке"
|
||||
},
|
||||
{
|
||||
"cause": "Человек изменяет окружение, чтобы искушения стали менее доступными",
|
||||
"mechanism": "Стимулы для плохого поведения становятся незаметными или невозможными",
|
||||
"result": "Человек реже сталкивается с искушением"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Дисциплина — это настройка среды, а не внутреннее усилие",
|
||||
"description": "Сильные люди не просто дисциплинированы, а живут в среде, которая поддерживает их цели",
|
||||
"example": "Человек встаёт раньше, потому что спальня тёмная и не имеет гаджетов",
|
||||
"chains": [
|
||||
{
|
||||
"cause": "Человек пытается быть дисциплинированным только силой воли",
|
||||
"mechanism": "Это требует большого количества энергии и часто неудачно",
|
||||
"result": "Человек теряет мотивацию и возвращается к нежелательному поведению"
|
||||
},
|
||||
{
|
||||
"cause": "Человек настраивает окружение так, чтобы хорошее поведение было лёгким",
|
||||
"mechanism": "Стимулы для правильных действий становятся более доступными",
|
||||
"result": "Человек чаще выбирает здоровые привычки"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Негативные эмоции усиливают негативное поведение",
|
||||
"description": "Стресс, тревога и другие негативные чувства провоцируют возвращение к вредным привычкам",
|
||||
"example": "Человек садится на диван и ест шоколад, когда ему плохо",
|
||||
"chains": [
|
||||
{
|
||||
"cause": "Человек испытывает стресс или негативные эмоции",
|
||||
"mechanism": "Это активирует привычку, которая помогает снизить дискомфорт",
|
||||
"result": "Человек снова начинает делать то, что раньше снимало напряжение"
|
||||
},
|
||||
{
|
||||
"cause": "Человек пытается избавиться от вредной привычки, но не меняет среду",
|
||||
"mechanism": "Стресс и негативные эмоции остаются, усиливая желание к действию",
|
||||
"result": "Человек возвращается к нежелательной привычке"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"insights": [
|
||||
{
|
||||
"title": "Среда влияет на привычки больше, чем сила воли",
|
||||
"description": "Чтобы изменить привычку, нужно изменить окружение, а не надеяться только на самоконтроль",
|
||||
"example": "Убрать телефон с рабочего стола, чтобы не отвлекаться на соцсети"
|
||||
},
|
||||
{
|
||||
"title": "Привычки не исчезают, только временно подавляются",
|
||||
"description": "Даже если человек перестаёт курить или есть сладкое, эти привычки остаются в мозге и могут вернуться при подходящих условиях",
|
||||
"example": "После посещения бара человек снова начинает пить, не осознавая этого"
|
||||
},
|
||||
{
|
||||
"title": "Негативные эмоции усиливают вредное поведение",
|
||||
"description": "Стресс, тревога и другие негативные чувства могут спровоцировать возвращение к старым привычкам",
|
||||
"example": "После ссоры человек снова начинает есть вредную пищу, чтобы успокоиться"
|
||||
},
|
||||
{
|
||||
"title": "Сокращение стимулов уменьшает повторение нежелательного поведения",
|
||||
"description": "Удаление триггеров, связанных с вредной привычкой, снижает вероятность её возобновления",
|
||||
"example": "Убрать сигареты из дома, чтобы уменьшить вероятность их употребления"
|
||||
},
|
||||
{
|
||||
"title": "Самоконтроль — это временная стратегия, а не долгосрочное решение",
|
||||
"description": "Постоянно бороться с искушением утомительно и непрочное; нужно настраивать среду так, чтобы искушений не было совсем",
|
||||
"example": "Поставить телефон в другую комнату, чтобы не проверять соцсети во время работы"
|
||||
}
|
||||
],
|
||||
"application": {
|
||||
"techniques": [
|
||||
{
|
||||
"name": "Снижение доступности стимула",
|
||||
"goal": "Уменьшение вероятности повторения нежелательной привычки за счёт удаления её триггеров",
|
||||
"context_example": "Вечер после работы, когда тянет залипнуть в телефон и проверять соцсети",
|
||||
"steps": [
|
||||
"Определите конкретный стимул (например, наличие телефона на столе)",
|
||||
"Уберите объект из зоны видимости или досягаемости (например, оставьте телефон в другой комнате)",
|
||||
"Запишите дату и время изменения (для отслеживания эффективности)"
|
||||
],
|
||||
"client_phrase": "Уберите источник искушения из вашей среды — действие станет менее вероятным",
|
||||
"success_criteria": "Частота использования телефона в моменты, когда это не нужно, снижается с 5 раз/день до 1–2 раз/день за 2 недели"
|
||||
}
|
||||
]
|
||||
},
|
||||
"limitations": [
|
||||
{
|
||||
"description": "Идеи не работают, если триггер (то, что в окружении запускает действие) не устранён или остаётся доступным, так как привычка может вернуться при появлении стимула",
|
||||
"when_relevant": "Когда человек не полностью убирает триггер из своей среды или сталкивается с ним в новой обстановке",
|
||||
"example": "Человек удалил сигареты из дома, но снова начинает курить на работе среди коллег-курильщиков"
|
||||
},
|
||||
{
|
||||
"description": "Техники могут не сработать, если негативные эмоции (стресс, тревога) остаются необратленными и усиливают нежелательное поведение",
|
||||
"when_relevant": "Когда человек продолжает испытывать сильный стресс или эмоциональные трудности, не решая их на уровне среды",
|
||||
"example": "Человек убрал телефон из комнаты, но всё равно переедает перед сном из-за хронической тревоги"
|
||||
},
|
||||
{
|
||||
"description": "Изменения среды могут быть недостаточны, если привычка закреплена на уровне автоматических нейронных паттернов и не сопровождается новыми, здоровыми привычками",
|
||||
"when_relevant": "Когда человек устраняет триггер, но не вводит альтернативное поведение для подкрепления",
|
||||
"example": "Человек убрал телевизор из спальни, но не нашёл замену в виде чтения или медитации и проводит время впустую"
|
||||
}
|
||||
],
|
||||
"tags": {
|
||||
"principle": [
|
||||
{
|
||||
"tag": "среда формирует поведение",
|
||||
"confidence": 0.95
|
||||
},
|
||||
{
|
||||
"tag": "привычки не исчезают",
|
||||
"confidence": 0.92
|
||||
},
|
||||
{
|
||||
"tag": "самоконтроль краткосрочен",
|
||||
"confidence": 0.9
|
||||
},
|
||||
{
|
||||
"tag": "дисциплина через среду",
|
||||
"confidence": 0.9
|
||||
},
|
||||
{
|
||||
"tag": "негативные эмоции усиливают поведение",
|
||||
"confidence": 0.85
|
||||
}
|
||||
],
|
||||
"psychology": [
|
||||
{
|
||||
"tag": "стимул",
|
||||
"confidence": 0.95
|
||||
},
|
||||
{
|
||||
"tag": "привычка",
|
||||
"confidence": 0.95
|
||||
},
|
||||
{
|
||||
"tag": "желание вызванное стимулом",
|
||||
"confidence": 0.9
|
||||
},
|
||||
{
|
||||
"tag": "аутокаталитический процесс",
|
||||
"confidence": 0.85
|
||||
},
|
||||
{
|
||||
"tag": "подкрепление",
|
||||
"confidence": 0.8
|
||||
}
|
||||
],
|
||||
"method": [
|
||||
{
|
||||
"tag": "снижение доступности стимула",
|
||||
"confidence": 0.95
|
||||
},
|
||||
{
|
||||
"tag": "настройка среды",
|
||||
"confidence": 0.92
|
||||
},
|
||||
{
|
||||
"tag": "устранение триггеров",
|
||||
"confidence": 0.9
|
||||
}
|
||||
],
|
||||
"result": [
|
||||
{
|
||||
"tag": "уменьшение вредных привычек",
|
||||
"confidence": 0.95
|
||||
},
|
||||
{
|
||||
"tag": "устойчивое поведение",
|
||||
"confidence": 0.9
|
||||
},
|
||||
{
|
||||
"tag": "снижение искушений",
|
||||
"confidence": 0.85
|
||||
}
|
||||
],
|
||||
"context": [
|
||||
{
|
||||
"tag": "поведенческая психология",
|
||||
"confidence": 0.95
|
||||
},
|
||||
{
|
||||
"tag": "привычки",
|
||||
"confidence": 0.92
|
||||
},
|
||||
{
|
||||
"tag": "атомные привычки",
|
||||
"confidence": 0.9
|
||||
}
|
||||
]
|
||||
},
|
||||
"removed": []
|
||||
}
|
||||
185
2b_финальная_валидация_согласованности/run_consistency_ollama.py
Normal file
185
2b_финальная_валидация_согласованности/run_consistency_ollama.py
Normal file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Финальная валидация согласованности анализа главы через Ollama (шаг 2b).
|
||||
Проверяет связи между блоками: application ↔ framework, insights ↔ framework, limitations ↔ остальное.
|
||||
Вход: merge.json (полный анализ), вход_главы.json (метаданные главы).
|
||||
Выход: один JSON-файл (verdict, score, inconsistencies).
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
OLLAMA_URL = "http://localhost:11434"
|
||||
MODEL = "qwen3:14b"
|
||||
DIR = Path(__file__).resolve().parent
|
||||
DEFAULT_MERGE = DIR.parent / "1_анализ_главы" / "merge.json"
|
||||
DEFAULT_CHAPTER = DIR.parent / "1_анализ_главы" / "вход_главы.json"
|
||||
|
||||
OLLAMA_OPTIONS = {
|
||||
"temperature": 0.2,
|
||||
"num_ctx": 8500,
|
||||
"num_predict": 2048,
|
||||
"repeat_penalty": 1.1,
|
||||
}
|
||||
|
||||
PROMPT_FILE = "validate_consistency.txt"
|
||||
|
||||
|
||||
def load_json(path: Path) -> dict:
|
||||
"""Загружает JSON из файла."""
|
||||
with open(path, encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def load_prompt(filename: str) -> str:
|
||||
"""Загружает шаблон промпта из файла."""
|
||||
with open(DIR / filename, encoding="utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def substitute_prompt(
|
||||
prompt: str,
|
||||
book_title: str,
|
||||
chapter_title: str,
|
||||
full_analysis_json: str,
|
||||
) -> str:
|
||||
"""Подставляет в промпт поля главы и полный JSON анализа."""
|
||||
return (
|
||||
prompt.replace("{book_title}", book_title)
|
||||
.replace("{chapter_title}", chapter_title)
|
||||
.replace("{full_analysis_json}", full_analysis_json)
|
||||
)
|
||||
|
||||
|
||||
def extract_json_from_response(text: str) -> dict:
|
||||
"""Достаёт JSON из ответа модели (может быть обёрнут в ```json ... ```)."""
|
||||
text = text.strip()
|
||||
match = re.search(r"```(?:json)?\s*([\s\S]*?)\s*```", text)
|
||||
if match:
|
||||
text = match.group(1).strip()
|
||||
return json.loads(text)
|
||||
|
||||
|
||||
def call_ollama(prompt: str) -> str:
|
||||
"""Вызывает Ollama /api/chat и возвращает content ответа."""
|
||||
body = json.dumps(
|
||||
{
|
||||
"model": MODEL,
|
||||
"messages": [{"role": "user", "content": prompt}],
|
||||
"stream": False,
|
||||
"format": "json",
|
||||
"options": OLLAMA_OPTIONS,
|
||||
"keep_alive": 0,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
).encode("utf-8")
|
||||
req = urllib.request.Request(
|
||||
f"{OLLAMA_URL}/api/chat",
|
||||
data=body,
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=None) as resp:
|
||||
data = json.load(resp)
|
||||
return data.get("message", {}).get("content", "")
|
||||
except urllib.error.HTTPError as e:
|
||||
body_b = b""
|
||||
if e.fp:
|
||||
try:
|
||||
body_b = e.fp.read()[:1000]
|
||||
except Exception:
|
||||
pass
|
||||
raise RuntimeError(
|
||||
f"Ollama HTTP {e.code}: {e.reason}. Body: {body_b.decode('utf-8', errors='replace')}"
|
||||
) from e
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Загружает данные, вызывает валидатор согласованности, пишет результат в JSON."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Финальная валидация согласованности анализа главы через Ollama (шаг 2b)."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--merge",
|
||||
type=Path,
|
||||
default=DEFAULT_MERGE,
|
||||
help=f"Путь к merge.json (по умолчанию: {DEFAULT_MERGE})",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--chapter",
|
||||
type=Path,
|
||||
default=DEFAULT_CHAPTER,
|
||||
help=f"Путь к вход_главы.json (по умолчанию: {DEFAULT_CHAPTER})",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o",
|
||||
"--output",
|
||||
type=Path,
|
||||
default=DIR / "consistency_result.json",
|
||||
help="Путь к выходному JSON (по умолчанию: consistency_result.json)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.merge.is_file():
|
||||
print(f"Файл не найден: {args.merge}", file=sys.stderr)
|
||||
return 1
|
||||
if not args.chapter.is_file():
|
||||
print(f"Файл не найден: {args.chapter}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print("Загрузка merge.json и вход_главы.json...")
|
||||
merge = load_json(args.merge)
|
||||
chapter = load_json(args.chapter)
|
||||
book_title = chapter.get("book_title", "")
|
||||
chapter_title = chapter.get("chapter_title", "")
|
||||
full_analysis_json = json.dumps(merge, ensure_ascii=False, indent=2)
|
||||
|
||||
prompt_tpl = load_prompt(PROMPT_FILE)
|
||||
prompt = substitute_prompt(
|
||||
prompt_tpl,
|
||||
book_title,
|
||||
chapter_title,
|
||||
full_analysis_json,
|
||||
)
|
||||
|
||||
print(f"Вызов Ollama {MODEL} — валидация согласованности...")
|
||||
t0 = time.monotonic()
|
||||
try:
|
||||
raw = call_ollama(prompt)
|
||||
except Exception as e:
|
||||
print(f"Ошибка вызова Ollama: {e}", file=sys.stderr)
|
||||
return 1
|
||||
elapsed = time.monotonic() - t0
|
||||
print(f"Ответ получен за {elapsed:.1f} сек ({elapsed / 60:.1f} мин)")
|
||||
|
||||
try:
|
||||
result = extract_json_from_response(raw)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Не удалось распарсить JSON ответа: {e}", file=sys.stderr)
|
||||
print("Первые 500 символов ответа:", raw[:500], file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if not isinstance(result, dict):
|
||||
print(
|
||||
f"Ожидался объект JSON, получен: {type(result).__name__}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(args.output, "w", encoding="utf-8") as f:
|
||||
json.dump(result, f, ensure_ascii=False, indent=2)
|
||||
print(f"Записано: {args.output}")
|
||||
verdict = result.get("verdict", "?")
|
||||
print(f"Вердикт: {verdict}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user