промежуточно. Работает все, неверно формируется вчерашний отчет (нет выхода).

This commit is contained in:
2026-07-28 16:41:26 +03:00
parent 522800d317
commit 2603627098
13 changed files with 297 additions and 283 deletions
+34 -35
View File
@@ -2,7 +2,8 @@ import json
from modules.ai_verifier import ask_ollama
from modules.knowledge_base import load_knowledge_base
def generate_markdown_report(merged_df, absent_explained, absent_unexplained, scud_present_but_absent_in_1c, raw_scud_df=None, raw_staff_df=None, date_str="27.07.2026"):
def generate_markdown_report(merged_df, absent_explained, absent_unexplained, scud_present_but_absent_in_1c, anomalies_list=None, raw_scud_df=None, raw_staff_df=None, date_str="28.07.2026"):
kb = load_knowledge_base()
custom_rules = kb.get("rules", [])
custom_rules_str = "\n".join([f"- {r}" for r in custom_rules]) if custom_rules else "Специфических правил компании пока нет."
@@ -25,67 +26,65 @@ def generate_markdown_report(merged_df, absent_explained, absent_unexplained, sc
detailed_cases_for_ai.append({
"fio_clean": fio_clean,
"staff_records_count": len(staff_matches),
"staff_records_1C": staff_matches,
"scud_records_LOGS": scud_matches
})
cols_crit = [c for c in ['Сотрудник', 'Подразделение', 'Должность', 'Вид_отсутствия'] if c in scud_present_but_absent_in_1c.columns]
critical_list = scud_present_but_absent_in_1c[cols_crit].to_dict(orient='records')
# Исходные точные цифры Python
total_staff = len(merged_df)
present_cnt = len(merged_df[merged_df['Пришел'] == True])
is_working_mask = (merged_df['Пришел'] == True) | (
merged_df['Вид_отсутствия'].astype(str).str.lower().str.contains('командировк|удален|дистанцион|разъездн', regex=True, na=False)
)
present_cnt = len(merged_df[is_working_mask])
explained_cnt = len(absent_explained)
unexplained_cnt = len(absent_unexplained)
anomalies_cnt = len(anomalies_list) if anomalies_list else 0
prompt = f"""
Ты — старший аудитор кадровой безопасности и систем СКУД. Проанализируй данные за {date_str} и составь итоговый отчет.
Ты — старший аудитор кадровой безопасности и контроллинга СКУД.
Проанализируй аномалии и пересечения данных за {date_str}.
📌 ДИНАМИЧЕСКИЕ ПРАВИЛА И НАКОПЛЕННЫЙ ОПЫТ ПРЕДПРИЯТИЯ:
📌 НАКОПЛЕННЫЕ ПРАВИЛА ПРЕДПРИЯТИЯ И ИСКЛЮЧЕНИЯ:
{custom_rules_str}
🚨 СТРОГИЕ ПРАВИЛА МАТЕМАТИКИ И КАТЕГОРИЙ:
1. Цифры сводки ДОЛЖНЫ СТРОГО СОВПАДАТЬ с первично посчитанным массивом:
- Всего офисных сотрудников: {total_staff}
- Присутствуют на рабочем месте: {present_cnt}
- Официально отсутствуют: {explained_cnt}
- Неизвестно (истинно неотмеченные): {unexplained_cnt} чел.
2. Заголовок "#### Неизвестные случаи: {unexplained_cnt}" должен иметь ровно ту же цифру {unexplained_cnt}.
3. Нумерованный список ниже ДОЛЖЕН содержать ровно {unexplained_cnt} сотрудников из массива `detailed_cases_for_ai` без пропусков.
🚨 ВХОДНЫЕ МЕТРИКИ:
- Всего сотрудников: {total_staff}
- На работе / Удаленно / Командировка: {present_cnt}
- Официально отсутствуют (1С/Реестры): {explained_cnt}
- Неизвестно (требуют выяснения): {unexplained_cnt}
- Выявлено аномалий и конфликтов реестров: {anomalies_cnt}
---
📊 ВХОДНЫЕ МИКРО-ДАННЫЕ НЕИЗВЕСТНЫХ ({unexplained_cnt} чел):
{json.dumps(detailed_cases_for_ai, ensure_ascii=False, indent=2)}
🚨 ОБНАРУЖЕННЫЕ АНОМАЛИИ И КОНФЛИКТЫ МЕЖДУ СКУД, 1С, СТАТИЧЕСКИМИ РЕЕСТРАМИ И ИСКЛЮЧЕНИЯМИ ({anomalies_cnt} шт.):
{json.dumps(anomalies_list, ensure_ascii=False, indent=2)}
🚨 СПИСОК КРИТИЧЕСКИХ АНОМАЛИЙ:
{json.dumps(critical_list, ensure_ascii=False, indent=2)}
---
📊 СПИСОК НЕИЗВЕСТНЫХ СЛУЧАЕВ ({unexplained_cnt} чел):
{json.dumps(detailed_cases_for_ai, ensure_ascii=False, indent=2)}
СТРОГИЙ ШАБЛОН ОТВЕТА:
**Сводка контроллинга СКУД и 1С:ЗУП на {date_str} в 12:00**
**Сводка контроллинга СКУД и 1С:ЗУП на {date_str}**
- Всего офисных сотрудников: **{total_staff}**
- Присутствуют на рабочем месте: **{present_cnt}**
- Работают (офис / удаленка / командировки): **{present_cnt}**
- Официально отсутствуют: **{explained_cnt}**
- Неизвестно (истинно неотмеченные после проверки ИИ): **{unexplained_cnt}** чел.
- Неизвестно (истинно неотмеченные): **{unexplained_cnt}** чел.
- Выявлено аномалий/конфликтов реестров: **{anomalies_cnt}** шт.
#### ⚠️ Подозрения на ложные срабатывания СКУД / Совмещения:
(Укажи сотрудников с аномалиями/вторыми проходами, например Кондрашову Е.В., если у нее дубликат карты)
#### 🚨 Выявленные ИИ аномалии и конфликты источников ({anomalies_cnt}):
(Подробно разбери каждый конфликт из `anomalies_list`. Опиши суть нарушения. Если аномалий нет — напиши "Аномалий и конфликтов не обнаружено.")
#### Критические аномалии (Работа в отпуске / на больничном):
(Детально опиши сотрудников из списка КРИТИЧЕСКИХ АНОМАЛИЙ. Если их нет — напиши "Критических нарушений не выявлено.")
#### ⚠️ Подозрения на ложные срабатывания / Совмещения:
(Укажи сотрудников с повторными проходами или несколькими картами, если такие есть)
#### Неизвестные случаи: {unexplained_cnt}
(Выведи НУМЕРОВАННЫЙ СПИСОК ВСЕХ {unexplained_cnt} человек строго в формате:
1. ФИО — [Аббревиатура], Должность
2. ФИО — [Аббревиатура], Должность
...
{unexplained_cnt}. ФИО — [Аббревиатура], Должность)
(Выведи НУМЕРОВАННЫЙ СПИСОК ВСЕХ {unexplained_cnt} человек в формате:
1. ФИО — Подразделение, Должность
2. ФИО — Подразделение, Должность)
### Рекомендации:
...
(Сформулируй 2-3 общие системные рекомендации для кадровой службы. КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО перечислять конкретные ФИО сотрудников в скобках или тексте рекомендаций — они уже перечислены выше.)
"""
sys_prompt = "Ты — кадровый аудитор. Выводи ровно то количество людей в списке, которое указано в переменной unexplained_cnt."
sys_prompt = "Ты — эксперт кадрового аудита. Пиши сжато, лаконично, без дублирования ФИО сотрудников в блоке рекомендаций."
return ask_ollama(prompt, system_prompt=sys_prompt)