- api_settings: убраны реальные API-ключи из кода (env/файл) — 1.1 - verify: промт ИИ для проверки реквизитов больше не ссылается на 187-ФЗ как на закон о ПДн («юрист по ПДн (187-ФЗ)» → специалист по реквизитам) - ui: дата ПП РФ №127 исправлена 08.02.2019 → 08.02.2018 (3 места) - help_docs: группа B переименована «187-ФЗ (персональные данные)» → «187-ФЗ (критическая информационная инфраструктура)» - generator: убран дубль хвоста параграфа в _highlight_unmatched - importer: «магия дат» (числа 10001-79999 → дата Excel) теперь только для полей-дат (as_date), финансовые поля не ломаются - ui (_collect_is): убраны дубли пар маппинга attacker_level/attacker_types - ui (импорт): убрано наследие 152-ФЗ ispdnPosition/ispdnFio из маппинга - test_generator: переписан под модель 187-ФЗ (category/sphere/object_type вместо pd_count/threat_type/defence_level) - criteria_justifications: п.9 для здравоохранения согласован с кодом (убран «критерий неприменим» — противоречие с «применим ко всем») - criteria_applicability: Транспорт (добавлены п.1, п.2; убран п.10), Банковская сфера (добавлены п.8, п.9) — требуется экспертная сверка - ui: Бусредн вынесен в константу DEFAULT_BUDGET_AVG (данные Минфина, обновлять ежегодно); автозаполнение п.9 унифицировано с авторасчётом (ΔБ = ΔНП+ΔНДПИ+ΔДИВ+ΔВСО+ΔНС) - ui: п.8 — предупреждение при неполных данных (менее 5 лет доходов) - models: поля ndpi/div/vso/ns для п.9; комментарий income_loss уточнён - .gitignore: api_settings.json/.env не попадают в git
77 lines
3.1 KiB
Python
77 lines
3.1 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""DokoGen — настройки API для внешних сервисов проверки.
|
||
|
||
Хранятся в JSON рядом с программой (api_settings.json).
|
||
Поля:
|
||
- dadata_token — API-ключ DaData (проверка организации по ИНН)
|
||
- ai_api_key — API-ключ ИИ (OpenAI-совместимый: DeepSeek, ChatGPT и др.)
|
||
- ai_model — модель ИИ (deepseek-chat, gpt-4o-mini, gpt-4o и т.п.)
|
||
- ai_base_url — адрес API ИИ (по умолчанию DeepSeek)
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import json
|
||
|
||
# ВНИМАНИЕ: реальные ключи НЕ хранятся в коде (утечка в git-историю — см. аудит).
|
||
# Источники ключей (по приоритету):
|
||
# 1) переменные окружения DADATA_TOKEN / DEEPSEEK_API_KEY / DEEPSEEK_MODEL / DEEPSEEK_BASE_URL
|
||
# 2) файл api_settings.json рядом с программой
|
||
# 3) DEFAULT_SETTINGS ниже (пустые значения)
|
||
|
||
DEFAULT_SETTINGS = {
|
||
'dadata_token': os.environ.get('DADATA_TOKEN', ''),
|
||
'ai_api_key': os.environ.get('DEEPSEEK_API_KEY', ''),
|
||
'ai_model': os.environ.get('DEEPSEEK_MODEL', 'deepseek-chat'),
|
||
'ai_base_url': os.environ.get('DEEPSEEK_BASE_URL', 'https://api.deepseek.com'),
|
||
}
|
||
|
||
# Старые ключи (для совместимости со старым файлом api_settings.json)
|
||
_LEGACY_KEYS = {
|
||
'deepseek_api_key': 'ai_api_key',
|
||
'deepseek_model': 'ai_model',
|
||
}
|
||
|
||
|
||
def default_api_settings_path():
|
||
"""Путь к файлу настроек: рядом с exe (frozen) или рядом с модулем."""
|
||
if getattr(sys, 'frozen', False):
|
||
base = os.path.dirname(sys.executable)
|
||
else:
|
||
base = os.path.dirname(os.path.abspath(__file__))
|
||
return os.path.join(base, 'api_settings.json')
|
||
|
||
|
||
def load_api_settings(path=None):
|
||
"""Загрузка настроек API из JSON-файла. Если файла нет — дефолт."""
|
||
if path is None:
|
||
path = default_api_settings_path()
|
||
if not path or not os.path.exists(path):
|
||
return dict(DEFAULT_SETTINGS)
|
||
try:
|
||
with open(path, encoding='utf-8-sig') as f:
|
||
loaded = json.load(f)
|
||
merged = dict(DEFAULT_SETTINGS)
|
||
for k, v in loaded.items():
|
||
# переносим старые ключи в новые
|
||
if k in _LEGACY_KEYS and not loaded.get(_LEGACY_KEYS[k]):
|
||
merged[_LEGACY_KEYS[k]] = v
|
||
elif k in merged:
|
||
merged[k] = v
|
||
return merged
|
||
except Exception:
|
||
return dict(DEFAULT_SETTINGS)
|
||
|
||
|
||
def save_api_settings(settings, path=None):
|
||
"""Сохранение настроек API. Возвращает True/False."""
|
||
if path is None:
|
||
path = default_api_settings_path()
|
||
try:
|
||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||
with open(path, 'w', encoding='utf-8') as f:
|
||
json.dump(settings, f, ensure_ascii=False, indent=2)
|
||
return True
|
||
except Exception:
|
||
return False
|