Initial server source import
This commit is contained in:
@@ -0,0 +1,572 @@
|
||||
import sys
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
import argparse
|
||||
import re
|
||||
from itertools import cycle
|
||||
import time
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from keycheck_common import (
|
||||
commit_status_transaction,
|
||||
default_input_file,
|
||||
default_proxy_file,
|
||||
ensure_output_files as ensure_private_output_files,
|
||||
iter_findings,
|
||||
iter_bounded_text_lines,
|
||||
keycheck_input_mode,
|
||||
load_known_statuses,
|
||||
private_atomic_writer,
|
||||
record_cached_keycheck_occurrence,
|
||||
record_validation_result,
|
||||
recover_status_transaction,
|
||||
require_provider_authority,
|
||||
service_output_dir,
|
||||
should_skip_key,
|
||||
write_keycheck_event,
|
||||
)
|
||||
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
sys.stderr.reconfigure(encoding='utf-8', errors='replace')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# --- Конфигурация ---
|
||||
SERVICE = "openai"
|
||||
OUTPUT_DIR = os.getenv("KEYCHECK_OUTPUT_DIR") or service_output_dir(SERVICE)
|
||||
INPUT_FILE = os.getenv("KEYCHECK_INPUT_FILE") or default_input_file()
|
||||
ALIVE_FILE = os.path.join(OUTPUT_DIR, "openaiAlive.txt")
|
||||
DEAD_FILE = os.path.join(OUTPUT_DIR, "openaiDead.txt")
|
||||
NETWORK_FILE = os.path.join(OUTPUT_DIR, "openaiNetwork.txt")
|
||||
LIMITED_FILE = os.path.join(OUTPUT_DIR, "openaiLimited.txt")
|
||||
RESTRICTED_FILE = os.path.join(OUTPUT_DIR, "openaiRestricted.txt")
|
||||
UNKNOWN_FILE = os.path.join(OUTPUT_DIR, "openaiUnknown.txt")
|
||||
NO_TARGET_FILE = os.path.join(OUTPUT_DIR, "openaiNoTarget.txt")
|
||||
CHECKED_FILE = os.path.join(OUTPUT_DIR, "openaiChecked.txt")
|
||||
RESULTS_FILE = os.path.join(OUTPUT_DIR, "openaiResults.jsonl")
|
||||
PROXY_FILE = os.getenv("KEYCHECK_PROXY_FILE") or default_proxy_file()
|
||||
|
||||
MODEL_PRIORITY_FOR_TEST = (
|
||||
'gpt-5.6-sol',
|
||||
'gpt-5.6',
|
||||
'gpt-5.6-luna',
|
||||
'gpt-5.6-terra',
|
||||
'gpt-5',
|
||||
'o3-pro',
|
||||
'o3',
|
||||
)
|
||||
TARGET_MODELS = {'gpt-5', 'o3-pro', 'o3'}
|
||||
NON_CHAT_MODEL_MARKERS = (
|
||||
'embedding', 'image', 'audio', 'tts', 'transcribe', 'realtime', 'search', 'moderation',
|
||||
)
|
||||
PROBE_MAX_COMPLETION_TOKENS = 16
|
||||
STATUS_FILES = [ALIVE_FILE, DEAD_FILE, NETWORK_FILE, LIMITED_FILE, RESTRICTED_FILE, UNKNOWN_FILE, NO_TARGET_FILE]
|
||||
STATUS_BY_FILE = {
|
||||
ALIVE_FILE: 'ALIVE',
|
||||
DEAD_FILE: 'DEAD',
|
||||
NETWORK_FILE: 'NETWORK',
|
||||
LIMITED_FILE: 'LIMITED',
|
||||
RESTRICTED_FILE: 'RESTRICTED',
|
||||
UNKNOWN_FILE: 'UNKNOWN',
|
||||
NO_TARGET_FILE: 'NO_TARGET_MODELS',
|
||||
}
|
||||
OPENAI_KEY_REGEX = re.compile(r'sk-[A-Za-z0-9_-]{20,}')
|
||||
|
||||
# --- Вспомогательные функции ---
|
||||
def key_from_line(line):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
return None
|
||||
if '\t' in line:
|
||||
return line.split('\t', 1)[0].strip()
|
||||
if ':[' in line:
|
||||
return line.split(':[', 1)[0].strip()
|
||||
match = OPENAI_KEY_REGEX.search(line)
|
||||
if match:
|
||||
return match.group(0)
|
||||
return line.split()[0].strip()
|
||||
|
||||
def load_set_from_file(filepath):
|
||||
if keycheck_input_mode() == 'postgres':
|
||||
return set()
|
||||
if not os.path.exists(filepath): return set()
|
||||
return {key for key in (key_from_line(line) for line in iter_bounded_text_lines(filepath)) if key}
|
||||
|
||||
|
||||
def iter_plain_openai_keys(paths):
|
||||
if keycheck_input_mode() == 'postgres':
|
||||
return
|
||||
seen = set()
|
||||
items = []
|
||||
for path in paths or []:
|
||||
if not path or not os.path.exists(path):
|
||||
continue
|
||||
for line in iter_bounded_text_lines(path):
|
||||
key = key_from_line(line)
|
||||
if not key or key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
items.append({'key': key, 'source': path, 'finding': {}})
|
||||
for item in items:
|
||||
yield item
|
||||
|
||||
|
||||
def retry_plain_files(args):
|
||||
if keycheck_input_mode() == 'postgres':
|
||||
return []
|
||||
files = list(args.plain or [])
|
||||
if args.recheck_all:
|
||||
files.extend(STATUS_FILES)
|
||||
else:
|
||||
if args.retry_limited:
|
||||
files.append(LIMITED_FILE)
|
||||
if args.retry_network:
|
||||
files.append(NETWORK_FILE)
|
||||
if args.retry_unknown:
|
||||
files.append(UNKNOWN_FILE)
|
||||
if args.retry_restricted:
|
||||
files.append(RESTRICTED_FILE)
|
||||
if args.retry_no_balance:
|
||||
files.append(LIMITED_FILE)
|
||||
out = []
|
||||
seen = set()
|
||||
for path in files:
|
||||
if path and path not in seen:
|
||||
seen.add(path)
|
||||
out.append(path)
|
||||
return out
|
||||
|
||||
def load_checked_statuses():
|
||||
if keycheck_input_mode() == 'postgres':
|
||||
return {}
|
||||
statuses = {}
|
||||
if not os.path.exists(CHECKED_FILE):
|
||||
return statuses
|
||||
for line in iter_bounded_text_lines(CHECKED_FILE):
|
||||
parts = line.rstrip('\n').split('\t')
|
||||
if parts and parts[0]:
|
||||
statuses[parts[0]] = parts[1] if len(parts) > 1 else 'UNKNOWN'
|
||||
return statuses
|
||||
|
||||
def load_known_keys():
|
||||
if keycheck_input_mode() == 'postgres':
|
||||
return set()
|
||||
known = set(load_checked_statuses().keys())
|
||||
for path in STATUS_FILES:
|
||||
known.update(load_set_from_file(path))
|
||||
return known
|
||||
|
||||
def ensure_output_files():
|
||||
ensure_private_output_files([CHECKED_FILE, RESULTS_FILE, *STATUS_FILES])
|
||||
recover_status_transaction(CHECKED_FILE, STATUS_BY_FILE)
|
||||
|
||||
def compact_status_file(path):
|
||||
if keycheck_input_mode() == 'postgres':
|
||||
return
|
||||
if not os.path.exists(path):
|
||||
return
|
||||
last_by_key = {}
|
||||
order = []
|
||||
for line in iter_bounded_text_lines(path):
|
||||
key = key_from_line(line)
|
||||
if not key:
|
||||
continue
|
||||
if key not in last_by_key:
|
||||
order.append(key)
|
||||
last_by_key[key] = line
|
||||
for attempt in range(6):
|
||||
try:
|
||||
with private_atomic_writer(path) as f:
|
||||
for key in order:
|
||||
f.write(last_by_key[key])
|
||||
except PermissionError:
|
||||
if attempt == 5:
|
||||
print(f"Warning: unable to compact {path}; leaving existing file as-is")
|
||||
return
|
||||
time.sleep(0.1 * (attempt + 1))
|
||||
else:
|
||||
return
|
||||
|
||||
def compact_all_status_files():
|
||||
for path in [CHECKED_FILE, *STATUS_FILES]:
|
||||
compact_status_file(path)
|
||||
|
||||
def backfill_checked_file():
|
||||
if keycheck_input_mode() == 'postgres':
|
||||
return
|
||||
checked = load_checked_statuses()
|
||||
changed = False
|
||||
for path, status in STATUS_BY_FILE.items():
|
||||
for key in load_set_from_file(path):
|
||||
if key not in checked:
|
||||
checked[key] = status
|
||||
changed = True
|
||||
if not changed:
|
||||
return
|
||||
with private_atomic_writer(CHECKED_FILE) as f:
|
||||
for key, status in sorted(checked.items()):
|
||||
f.write(f"{key}\t{status}\tbackfilled\n")
|
||||
|
||||
def load_proxies(proxy_file=None):
|
||||
proxy_file = proxy_file or PROXY_FILE
|
||||
if not os.path.exists(proxy_file): return None
|
||||
proxies = []
|
||||
with open(proxy_file, 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line: continue
|
||||
try:
|
||||
ip, port, login, password = line.split(':')
|
||||
proxy_url = f"http://{login}:{password}@{ip}:{port}"
|
||||
proxies.append({"http": proxy_url, "https": proxy_url})
|
||||
except ValueError:
|
||||
print(f"⚠️ Неверный формат прокси: '{line}'. Пропускаем.")
|
||||
if not proxies:
|
||||
print("⚠️ Файл proxy.txt пуст. Запросы будут идти напрямую.")
|
||||
return None
|
||||
print(f"✅ Загружено {len(proxies)} прокси.")
|
||||
return cycle(proxies)
|
||||
|
||||
def move_key_to_alive(
|
||||
key, available_target_models, service_tier, source='', finding=None,
|
||||
model_inventory=None, probe_model='',
|
||||
):
|
||||
"""
|
||||
Перемещает ключ из DEAD_FILE в ALIVE_FILE, записывая модели и service_tier.
|
||||
"""
|
||||
models_str = ",".join(sorted(list(available_target_models)))
|
||||
tier_str = str(service_tier or 'unknown').replace('\r', ' ').replace('\n', ' ')[:1000]
|
||||
print(f" -> ✅ Ключ рабочий! Модели: {models_str}, Тир: {tier_str}. Перемещаем в {ALIVE_FILE}")
|
||||
|
||||
model_inventory = sorted(set(model_inventory or available_target_models))
|
||||
result = {
|
||||
'status': 'ALIVE',
|
||||
'models': sorted(list(available_target_models)),
|
||||
'model_inventory': model_inventory,
|
||||
'model_count': len(model_inventory),
|
||||
'llm_probe_model': probe_model,
|
||||
'llm_probe_status': 'GENERATION_OK',
|
||||
'service_tier': service_tier,
|
||||
'message': f'chat ping ok; model={probe_model}; models={len(model_inventory)}',
|
||||
}
|
||||
write_keycheck_event(SERVICE, RESULTS_FILE, key, result, source, finding, 'OpenAI')
|
||||
commit_status_transaction(
|
||||
CHECKED_FILE,
|
||||
STATUS_BY_FILE,
|
||||
key,
|
||||
'ALIVE',
|
||||
status_line=f"{key}:[{models_str}]:{tier_str}\n",
|
||||
checked_line=f"{key}\tALIVE\t{time.strftime('%Y-%m-%dT%H:%M:%S')}\n",
|
||||
)
|
||||
record_validation_result(SERVICE, key, result, source, finding, 'OpenAI')
|
||||
|
||||
def redact_message(message, key):
|
||||
message = str(message).replace('\r', ' ').replace('\n', ' ')[:1000]
|
||||
if key:
|
||||
message = message.replace(key, '***REDACTED***')
|
||||
return OPENAI_KEY_REGEX.sub('***REDACTED***', message)
|
||||
|
||||
def write_key_status(key, path, status, message='', source='', finding=None, metadata=None):
|
||||
status_upper = status.upper()
|
||||
projection_status = STATUS_BY_FILE.get(path)
|
||||
if not projection_status:
|
||||
raise ValueError(f'unknown OpenAI status projection: {path}')
|
||||
message = redact_message(message, key)
|
||||
result = {**(metadata or {}), 'status': status_upper, 'message': message}
|
||||
write_keycheck_event(SERVICE, RESULTS_FILE, key, result, source, finding, 'OpenAI')
|
||||
commit_status_transaction(
|
||||
CHECKED_FILE,
|
||||
STATUS_BY_FILE,
|
||||
key,
|
||||
projection_status,
|
||||
message,
|
||||
source,
|
||||
status_line=f"{key}\t{status}\t{message}\n",
|
||||
checked_line=f"{key}\t{projection_status}\t{time.strftime('%Y-%m-%dT%H:%M:%S')}\n",
|
||||
)
|
||||
record_validation_result(SERVICE, key, result, source, finding, 'OpenAI')
|
||||
|
||||
def extract_openai_key(data):
|
||||
if data.get("DetectorName") == "OpenAI":
|
||||
return data.get("Raw") or data.get("RawV2")
|
||||
if data.get("detector") == "OpenAI":
|
||||
return data.get("raw") or data.get("raw_v2")
|
||||
finding = data.get("finding")
|
||||
if isinstance(finding, dict) and finding.get("DetectorName") == "OpenAI":
|
||||
return finding.get("Raw") or finding.get("RawV2")
|
||||
return None
|
||||
|
||||
# --- Функции проверки ---
|
||||
def check_authentication(key, proxy):
|
||||
print(f" [1/2] Проверка аутентификации...")
|
||||
url = "https://api.openai.com/v1/models"
|
||||
headers = {"Authorization": f"Bearer {key}"}
|
||||
try:
|
||||
response = requests.get(url, headers=headers, proxies=proxy, timeout=15)
|
||||
if response.status_code == 200:
|
||||
print(" -> Аутентификация пройдена.")
|
||||
return 'valid', response.json().get('data', [])
|
||||
elif response.status_code == 401:
|
||||
print(" -> Ошибка 401: Ключ недействителен или отозван.")
|
||||
return 'dead', response.text
|
||||
elif response.status_code == 403:
|
||||
print(f" -> Ошибка 403: ключ ограничен/заблокирован: {response.text[:300]}")
|
||||
return 'restricted', response.text
|
||||
elif response.status_code == 429:
|
||||
print(f" -> Ошибка 429: rate limit / quota: {response.text[:300]}")
|
||||
return 'limited', response.text
|
||||
else:
|
||||
print(f" -> Ошибка {response.status_code}: {response.text}")
|
||||
return 'unknown', response.text
|
||||
except requests.RequestException as e:
|
||||
print(f" -> Ошибка сети: {e}")
|
||||
return 'network', str(e)
|
||||
|
||||
def reportable_target_models(model_ids):
|
||||
return {
|
||||
model for model in model_ids
|
||||
if model in TARGET_MODELS or model.startswith('gpt-5.6-') or model == 'gpt-5.6'
|
||||
}
|
||||
|
||||
|
||||
def choose_probe_model(model_ids):
|
||||
models = [str(model or '') for model in model_ids if model]
|
||||
by_lower = {model.lower(): model for model in models}
|
||||
for model in MODEL_PRIORITY_FOR_TEST:
|
||||
if model.lower() in by_lower:
|
||||
return by_lower[model.lower()]
|
||||
for model in models:
|
||||
lowered = model.lower()
|
||||
if lowered.startswith(('gpt-', 'o')) and not any(
|
||||
marker in lowered for marker in NON_CHAT_MODEL_MARKERS
|
||||
):
|
||||
return model
|
||||
return ''
|
||||
|
||||
|
||||
def check_balance_and_tier(key, model_to_test, proxy):
|
||||
"""
|
||||
Проверяет баланс и возвращает service_tier в случае успеха.
|
||||
"""
|
||||
print(f" [2/2] Проверка баланса и тира...")
|
||||
if not model_to_test:
|
||||
print(" -> Не найдено подходящих моделей для теста баланса.")
|
||||
return 'unknown', 'no chat-capable model from /models'
|
||||
|
||||
print(f" -> Используем модель для теста: {model_to_test}")
|
||||
url = "https://api.openai.com/v1/chat/completions"
|
||||
headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}
|
||||
payload = {
|
||||
"model": model_to_test,
|
||||
"messages": [{"role": "user", "content": "Reply with one digit."}],
|
||||
"max_completion_tokens": PROBE_MAX_COMPLETION_TOKENS,
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=payload, proxies=proxy, timeout=20)
|
||||
if response.status_code == 200:
|
||||
# Успех, извлекаем service_tier
|
||||
response_data = response.json()
|
||||
service_tier = response_data.get('service_tier')
|
||||
return 'ok', service_tier
|
||||
elif response.status_code == 429:
|
||||
print(f" -> Ошибка 429: Нет баланса или превышен лимит.")
|
||||
return 'limited', response.text
|
||||
elif response.status_code == 401:
|
||||
print(f" -> Ошибка 401: ключ недействителен или отозван.")
|
||||
return 'dead', response.text
|
||||
elif response.status_code == 403:
|
||||
print(f" -> Ошибка 403: ключ ограничен/заблокирован: {response.text[:300]}")
|
||||
return 'restricted', response.text
|
||||
else:
|
||||
print(f" -> Ошибка {response.status_code}: {response.text}")
|
||||
return 'unknown', response.text
|
||||
except requests.RequestException as e:
|
||||
print(f" -> Ошибка сети: {e}")
|
||||
return 'network', str(e)
|
||||
|
||||
# --- Основной процесс ---
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='OpenAI key checker')
|
||||
parser.add_argument('--input', default=INPUT_FILE)
|
||||
parser.add_argument('--plain', action='append', default=[])
|
||||
parser.add_argument('--proxy-file', default=PROXY_FILE)
|
||||
parser.add_argument('--max-keys', type=int, default=0)
|
||||
parser.add_argument('--retry-network', action='store_true')
|
||||
parser.add_argument('--retry-limited', action='store_true')
|
||||
parser.add_argument('--retry-unknown', action='store_true')
|
||||
parser.add_argument('--retry-restricted', action='store_true')
|
||||
parser.add_argument('--retry-no-balance', action='store_true')
|
||||
parser.add_argument('--recheck-all', action='store_true')
|
||||
return parser.parse_args()
|
||||
|
||||
def main():
|
||||
require_provider_authority(SERVICE)
|
||||
args = parse_args()
|
||||
ensure_output_files()
|
||||
compact_all_status_files()
|
||||
backfill_checked_file()
|
||||
print("--- 🚀 Запуск чекера ключей OpenAI 🚀 ---")
|
||||
proxy_cycler = load_proxies(args.proxy_file)
|
||||
checked_statuses = load_checked_statuses()
|
||||
known_statuses = load_known_statuses(CHECKED_FILE, STATUS_BY_FILE)
|
||||
known_keys = set(known_statuses)
|
||||
alive_keys = load_set_from_file(ALIVE_FILE)
|
||||
retry_statuses = set()
|
||||
if args.retry_network:
|
||||
retry_statuses.add('NETWORK')
|
||||
if args.retry_limited:
|
||||
retry_statuses.update(('LIMITED', 'LIMITED_OR_NO_BALANCE', 'LIMITED_OR_QUOTA'))
|
||||
if args.retry_unknown:
|
||||
retry_statuses.add('UNKNOWN')
|
||||
if args.retry_restricted:
|
||||
retry_statuses.add('RESTRICTED')
|
||||
if args.retry_no_balance:
|
||||
retry_statuses.update(('NO_BALANCE', 'NO_QUOTA', 'LIMITED_OR_NO_BALANCE', 'LIMITED_OR_QUOTA'))
|
||||
print(f"📖 Загружено: {len(alive_keys)} живых ключей, {len(known_keys)} уже классифицированных ключей, {len(checked_statuses)} checked.")
|
||||
|
||||
if keycheck_input_mode() == 'jsonl' and not os.path.exists(args.input):
|
||||
print(f"❌ Файл с секретами {args.input} не найден. Завершение.")
|
||||
return
|
||||
|
||||
processed = 0
|
||||
skipped = 0
|
||||
seen_this_run = set()
|
||||
def candidates():
|
||||
for item in iter_findings(args.input, ['OpenAI']):
|
||||
data = item.get('finding') or {}
|
||||
key = item.get('raw') or extract_openai_key(data)
|
||||
if key:
|
||||
yield {'key': key, 'source': item.get('source') or args.input, 'finding': data}
|
||||
seen_plain = set()
|
||||
for item in iter_plain_openai_keys(retry_plain_files(args)):
|
||||
key = item.get('key')
|
||||
if key and key not in seen_plain:
|
||||
seen_plain.add(key)
|
||||
yield item
|
||||
|
||||
for item in candidates():
|
||||
data = item.get('finding') or {}
|
||||
source_line = item.get('source') or args.input
|
||||
key = item.get('key')
|
||||
if not key:
|
||||
continue
|
||||
if keycheck_input_mode() != 'postgres' and key in seen_this_run:
|
||||
cached_status = checked_statuses.get(key) or known_statuses.get(key) or 'UNKNOWN'
|
||||
record_cached_keycheck_occurrence(SERVICE, key, cached_status, source_line, data, 'OpenAI')
|
||||
skipped += 1
|
||||
continue
|
||||
seen_this_run.add(key)
|
||||
if should_skip_key(
|
||||
key, checked_statuses, known_keys, args, retry_statuses,
|
||||
service=SERVICE, source=source_line, finding=data, detector='OpenAI',
|
||||
known_statuses=known_statuses,
|
||||
):
|
||||
skipped += 1
|
||||
continue
|
||||
if args.max_keys and processed >= args.max_keys:
|
||||
break
|
||||
processed += 1
|
||||
|
||||
print(f"\n[{processed}] 🎯 Новый кандидат: {key[:8]}...{key[-4:]} from {source_line}")
|
||||
|
||||
current_proxy = next(proxy_cycler) if proxy_cycler else None
|
||||
|
||||
auth_status, auth_data = check_authentication(key, current_proxy)
|
||||
|
||||
if auth_status == 'valid' and auth_data:
|
||||
all_available_models_data = auth_data
|
||||
all_model_ids = sorted({
|
||||
str(model.get('id') or '') for model in all_available_models_data
|
||||
if isinstance(model, dict) and model.get('id')
|
||||
})
|
||||
found_target_models = reportable_target_models(all_model_ids)
|
||||
model_to_test = choose_probe_model(all_model_ids)
|
||||
|
||||
if not model_to_test:
|
||||
print(" -> Ключ валиден, но не имеет подходящей chat-модели. Пропускаем.")
|
||||
write_key_status(
|
||||
key, NO_TARGET_FILE, 'no_target_models', ','.join(all_model_ids)[:500],
|
||||
source_line, data, {
|
||||
'models': sorted(found_target_models),
|
||||
'model_inventory': all_model_ids,
|
||||
'model_count': len(all_model_ids),
|
||||
'llm_probe_status': 'NO_CONTEXT',
|
||||
},
|
||||
)
|
||||
known_keys.add(key)
|
||||
checked_statuses[key] = 'NO_TARGET_MODELS'
|
||||
continue
|
||||
|
||||
balance_status, balance_data = check_balance_and_tier(key, model_to_test, current_proxy)
|
||||
probe_metadata = {
|
||||
'models': sorted(found_target_models or {model_to_test}),
|
||||
'model_inventory': all_model_ids,
|
||||
'model_count': len(all_model_ids),
|
||||
'llm_probe_model': model_to_test,
|
||||
'llm_probe_status': {
|
||||
'ok': 'GENERATION_OK',
|
||||
'limited': 'LIMITED',
|
||||
'network': 'NETWORK',
|
||||
'restricted': 'RESTRICTED',
|
||||
'dead': 'DEAD',
|
||||
}.get(balance_status, 'UNKNOWN'),
|
||||
}
|
||||
|
||||
# Проверяем, что результат не None (успешная проверка баланса)
|
||||
if balance_status == 'ok':
|
||||
move_key_to_alive(
|
||||
key, found_target_models or {model_to_test}, balance_data, source_line, data,
|
||||
model_inventory=all_model_ids, probe_model=model_to_test,
|
||||
)
|
||||
alive_keys.add(key)
|
||||
final_status = 'ALIVE'
|
||||
elif balance_status == 'limited':
|
||||
write_key_status(key, LIMITED_FILE, 'limited_or_no_balance', balance_data, source_line, data, probe_metadata)
|
||||
final_status = 'LIMITED_OR_NO_BALANCE'
|
||||
elif balance_status == 'network':
|
||||
write_key_status(key, NETWORK_FILE, 'network_error', balance_data, source_line, data, probe_metadata)
|
||||
final_status = 'NETWORK'
|
||||
elif balance_status == 'restricted':
|
||||
write_key_status(key, RESTRICTED_FILE, 'restricted', balance_data, source_line, data, probe_metadata)
|
||||
final_status = 'RESTRICTED'
|
||||
elif balance_status == 'dead':
|
||||
write_key_status(key, DEAD_FILE, 'invalid_or_revoked', balance_data, source_line, data, probe_metadata)
|
||||
final_status = 'DEAD'
|
||||
else:
|
||||
write_key_status(key, UNKNOWN_FILE, 'unknown', balance_data, source_line, data, probe_metadata)
|
||||
final_status = 'UNKNOWN'
|
||||
known_keys.add(key)
|
||||
checked_statuses[key] = final_status
|
||||
elif auth_status == 'network':
|
||||
write_key_status(key, NETWORK_FILE, 'network_error', auth_data, source_line, data)
|
||||
known_keys.add(key)
|
||||
checked_statuses[key] = 'NETWORK'
|
||||
elif auth_status == 'limited':
|
||||
write_key_status(key, LIMITED_FILE, 'limited_or_quota', auth_data, source_line, data)
|
||||
known_keys.add(key)
|
||||
checked_statuses[key] = 'LIMITED'
|
||||
elif auth_status == 'restricted':
|
||||
write_key_status(key, RESTRICTED_FILE, 'restricted', auth_data, source_line, data)
|
||||
known_keys.add(key)
|
||||
checked_statuses[key] = 'RESTRICTED'
|
||||
elif auth_status == 'dead':
|
||||
write_key_status(key, DEAD_FILE, 'invalid_or_revoked', auth_data, source_line, data)
|
||||
known_keys.add(key)
|
||||
checked_statuses[key] = 'DEAD'
|
||||
else:
|
||||
write_key_status(key, UNKNOWN_FILE, 'unknown', auth_data, source_line, data)
|
||||
known_keys.add(key)
|
||||
checked_statuses[key] = 'UNKNOWN'
|
||||
|
||||
print("\n--- ✅ Проверка завершена. ---")
|
||||
print(f"Processed={processed}, skipped={skipped}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user