90 lines
5.4 KiB
Python
90 lines
5.4 KiB
Python
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, 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 "Специфических правил компании пока нет."
|
|
|
|
detailed_cases_for_ai = []
|
|
unexplained_fios = absent_unexplained['fio_clean'].unique() if 'fio_clean' in absent_unexplained.columns else []
|
|
|
|
for fio_clean in unexplained_fios:
|
|
staff_matches = []
|
|
if raw_staff_df is not None and not raw_staff_df.empty and 'fio_clean' in raw_staff_df.columns:
|
|
st_m = raw_staff_df[raw_staff_df['fio_clean'] == fio_clean]
|
|
cols_staff = [c for c in ['ФИО', 'Подразделение', 'Должность', 'Таб_№'] if c in st_m.columns]
|
|
staff_matches = st_m[cols_staff].to_dict(orient='records')
|
|
|
|
scud_matches = []
|
|
if raw_scud_df is not None and not raw_scud_df.empty and 'fio_clean' in raw_scud_df.columns:
|
|
sc_m = raw_scud_df[raw_scud_df['fio_clean'] == fio_clean]
|
|
cols_scud = [c for c in ['Сотрудник', 'Подразделение', 'Должность', 'Начало_дня', 'Статус'] if c in sc_m.columns]
|
|
scud_matches = sc_m[cols_scud].to_dict(orient='records')
|
|
|
|
detailed_cases_for_ai.append({
|
|
"fio_clean": fio_clean,
|
|
"staff_records_1C": staff_matches,
|
|
"scud_records_LOGS": scud_matches
|
|
})
|
|
|
|
total_staff = len(merged_df)
|
|
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}.
|
|
|
|
📌 НАКОПЛЕННЫЕ ПРАВИЛА ПРЕДПРИЯТИЯ И ИСКЛЮЧЕНИЯ:
|
|
{custom_rules_str}
|
|
|
|
🚨 ВХОДНЫЕ МЕТРИКИ:
|
|
- Всего сотрудников: {total_staff}
|
|
- На работе / Удаленно / Командировка: {present_cnt}
|
|
- Официально отсутствуют (1С/Реестры): {explained_cnt}
|
|
- Неизвестно (требуют выяснения): {unexplained_cnt}
|
|
- Выявлено аномалий и конфликтов реестров: {anomalies_cnt}
|
|
|
|
---
|
|
🚨 ОБНАРУЖЕННЫЕ АНОМАЛИИ И КОНФЛИКТЫ МЕЖДУ СКУД, 1С, СТАТИЧЕСКИМИ РЕЕСТРАМИ И ИСКЛЮЧЕНИЯМИ ({anomalies_cnt} шт.):
|
|
{json.dumps(anomalies_list, ensure_ascii=False, indent=2)}
|
|
|
|
---
|
|
📊 СПИСОК НЕИЗВЕСТНЫХ СЛУЧАЕВ ({unexplained_cnt} чел):
|
|
{json.dumps(detailed_cases_for_ai, ensure_ascii=False, indent=2)}
|
|
|
|
СТРОГИЙ ШАБЛОН ОТВЕТА:
|
|
|
|
**Сводка контроллинга СКУД и 1С:ЗУП на {date_str}**
|
|
|
|
- Всего офисных сотрудников: **{total_staff}**
|
|
- Работают (офис / удаленка / командировки): **{present_cnt}**
|
|
- Официально отсутствуют: **{explained_cnt}**
|
|
- Неизвестно (истинно неотмеченные): **{unexplained_cnt}** чел.
|
|
- Выявлено аномалий/конфликтов реестров: **{anomalies_cnt}** шт.
|
|
|
|
#### 🚨 Выявленные ИИ аномалии и конфликты источников ({anomalies_cnt}):
|
|
(Подробно разбери каждый конфликт из `anomalies_list`. Опиши суть нарушения. Если аномалий нет — напиши "Аномалий и конфликтов не обнаружено.")
|
|
|
|
#### ⚠️ Подозрения на ложные срабатывания / Совмещения:
|
|
(Укажи сотрудников с повторными проходами или несколькими картами, если такие есть)
|
|
|
|
#### Неизвестные случаи: {unexplained_cnt}
|
|
(Выведи НУМЕРОВАННЫЙ СПИСОК ВСЕХ {unexplained_cnt} человек в формате:
|
|
1. ФИО — Подразделение, Должность
|
|
2. ФИО — Подразделение, Должность)
|
|
|
|
### Рекомендации:
|
|
(Сформулируй 2-3 общие системные рекомендации для кадровой службы. КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО перечислять конкретные ФИО сотрудников в скобках или тексте рекомендаций — они уже перечислены выше.)
|
|
"""
|
|
|
|
sys_prompt = "Ты — эксперт кадрового аудита. Пиши сжато, лаконично, без дублирования ФИО сотрудников в блоке рекомендаций."
|
|
return ask_ollama(prompt, system_prompt=sys_prompt) |