9ade3115d1
EXA за Cloudflare режет российские IP, федеральный канал возвращал пусто с боевого. Добавлен services.exa.proxy (env EXA_PROXY) → Guzzle proxy option в findSite/findSites. Пусто → напрямую (dev). Тест: с proxy цепочка не ломается, домен извлекается (8/8). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
203 lines
13 KiB
PHP
203 lines
13 KiB
PHP
<?php
|
||
|
||
return [
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Third Party Services
|
||
|--------------------------------------------------------------------------
|
||
|
|
||
| This file is for storing the credentials for third party services such
|
||
| as Mailgun, Postmark, AWS and more. This file provides the de facto
|
||
| location for this type of information, allowing packages to have
|
||
| a conventional file to locate the various service credentials.
|
||
|
|
||
*/
|
||
|
||
'postmark' => [
|
||
'key' => env('POSTMARK_API_KEY'),
|
||
],
|
||
|
||
'resend' => [
|
||
'key' => env('RESEND_API_KEY'),
|
||
],
|
||
|
||
'ses' => [
|
||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||
],
|
||
|
||
'slack' => [
|
||
'notifications' => [
|
||
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
|
||
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
|
||
],
|
||
],
|
||
|
||
// Капча самозаписи (G1/SP1). driver=null → NullCaptchaVerifier (dev/test).
|
||
// Реальный Yandex SmartCaptcha подключается позже (SP3/ops).
|
||
'captcha' => [
|
||
'driver' => env('CAPTCHA_DRIVER', 'null'),
|
||
'fake_passes' => filter_var(env('CAPTCHA_FAKE_PASSES', true), FILTER_VALIDATE_BOOL),
|
||
'yandex_server_key' => env('YANDEX_SMARTCAPTCHA_SERVER_KEY'),
|
||
'yandex_validate_url' => env('YANDEX_SMARTCAPTCHA_VALIDATE_URL', 'https://smartcaptcha.cloud.yandex.ru/validate'),
|
||
],
|
||
|
||
'supplier' => [
|
||
'login' => env('SUPPLIER_LOGIN'),
|
||
'password' => env('SUPPLIER_PASSWORD'),
|
||
'portal_url' => env('SUPPLIER_PORTAL_URL', 'https://crm.bp-gr.ru'),
|
||
'alert_email' => env('SUPPLIER_ALERT_EMAIL', 'ops@liderra.ru'),
|
||
// Плитка балансов (28.06): у кабинета поставщика НЕ денежный баланс, а остаток
|
||
// НОМЕРОВ («Баланс ГЦК» в выпадашке). Деньги = номера × number_price_rub (20 ₽/шт,
|
||
// подтверждено владельцем 28.06). avg_lead_price_rub=0 → расход/день неизвестен.
|
||
'number_price_rub' => (float) env('SUPPLIER_NUMBER_PRICE_RUB', 20),
|
||
'avg_lead_price_rub' => (float) env('SUPPLIER_AVG_LEAD_PRICE_RUB', 0),
|
||
'red_floor_rub' => (int) env('SUPPLIER_RED_FLOOR_RUB', 5000),
|
||
'amber_floor_rub' => (int) env('SUPPLIER_AMBER_FLOOR_RUB', 15000),
|
||
'topup_url' => env('SUPPLIER_TOPUP_URL', env('SUPPLIER_PORTAL_URL', 'https://crm.bp-gr.ru')),
|
||
],
|
||
|
||
// DaData phone cleaner — резолв региона лида по телефону (lead region resolution).
|
||
// Ключи → YC Lockbox на проде; на dev/staging — .env. enabled=false до раскатки.
|
||
'dadata' => [
|
||
'api_key' => env('DADATA_API_KEY'),
|
||
'secret' => env('DADATA_SECRET'),
|
||
'timeout_ms' => (int) env('DADATA_TIMEOUT_MS', 2000),
|
||
'retries' => (int) env('DADATA_RETRIES', 1),
|
||
'daily_cap_rub' => (int) env('DADATA_DAILY_CAP_RUB', 10000),
|
||
'call_cost_kopecks' => (int) env('DADATA_CALL_COST_KOPECKS', 60), // ≈0.60 ₽/вызов, откалибровать по тарифу
|
||
'enabled' => filter_var(env('LEAD_REGION_RESOLVER_ENABLED', false), FILTER_VALIDATE_BOOL),
|
||
'cache_ttl_days' => (int) env('PHONE_REGION_CACHE_TTL_DAYS', 30),
|
||
// G1/SP2: подтяжка организации по ИНН (suggestions findById/party). Тот же api_key
|
||
// (Token), secret не нужен. Default false → NullPartyLookup (dev/тесты не ходят в сеть).
|
||
'party_enabled' => filter_var(env('DADATA_PARTY_ENABLED', false), FILTER_VALIDATE_BOOL),
|
||
// Плитка балансов (28.06): чтение баланса профиля + пороги светофора + ссылка пополнения.
|
||
'balance_url' => env('DADATA_BALANCE_URL', 'https://dadata.ru/api/v2/profile/balance'),
|
||
'red_floor_rub' => (int) env('DADATA_RED_FLOOR_RUB', 500),
|
||
'amber_floor_rub' => (int) env('DADATA_AMBER_FLOOR_RUB', 2000),
|
||
'topup_url' => env('DADATA_TOPUP_URL', 'https://dadata.ru/profile/#billing'),
|
||
],
|
||
|
||
// AITUNNEL (OpenAI-совместимый) для автоподбора: эмбеддинги (похожесть конкурента на
|
||
// профиль клиента) + LLM-классификатор «поставщик услуги или площадка-агрегатор?».
|
||
// Ключ — только в .env/окружении, НИКОГДА в гит. Пусто → движок отдаёт сырой список
|
||
// (без % и без авто-отсева площадок).
|
||
'aitunnel' => [
|
||
'key' => env('AITUNNEL_API_KEY'),
|
||
'base_url' => env('AITUNNEL_BASE_URL', 'https://api.aitunnel.ru/v1'),
|
||
'embed_model' => env('AITUNNEL_EMBED_MODEL', 'text-embedding-3-small'),
|
||
'chat_model' => env('AITUNNEL_CHAT_MODEL', 'gpt-4o-mini'),
|
||
// Модель отсева агрегаторов (вариант А — точнее, чтобы не терять живых конкурентов вроде
|
||
// «ГорЗайм»). Пусто → фолбэк на chat_model. Пример: AITUNNEL_AGGREGATOR_MODEL=gpt-4o.
|
||
'aggregator_model' => env('AITUNNEL_AGGREGATOR_MODEL'),
|
||
// ИИ-вызовы (анализ рубрик, эмбеддинги) — с ЗАПАСОМ: латентность модели плавает
|
||
// (один и тот же запрос то 8с, то 30-40с), а сбор асинхронный и клиент ждёт — режем
|
||
// медленный-но-настоящий ответ таймаутом ХУЖЕ, чем ждём. Потому большие таймауты.
|
||
'timeout_sec' => (int) env('AITUNNEL_TIMEOUT_SEC', 120),
|
||
// Батч отсева агрегаторов: список фирм режем на порции по aggregator_batch_size (иначе
|
||
// один запрос на ~100 фирм долгий и рискует не успеть) + отдельный долгий таймаут на порцию.
|
||
'aggregator_batch_size' => (int) env('AITUNNEL_AGGREGATOR_BATCH_SIZE', 40),
|
||
'aggregator_timeout_sec' => (int) env('AITUNNEL_AGGREGATOR_TIMEOUT_SEC', 240),
|
||
// Канал В — генератор имён (ZAFIKSIROVANO §0-БИС): одна рассуждающая модель sonar-reasoning-pro,
|
||
// в реальном прогоне ~30-70 с/вызов и плавает вверх; 2 прохода. Большой таймаут с запасом —
|
||
// лучше дождаться, чем прислать пусто (сбор асинхронный, клиент всё равно ждёт результат).
|
||
'research_model' => env('AITUNNEL_RESEARCH_MODEL', 'sonar-reasoning-pro'),
|
||
'research_timeout_sec' => (int) env('AITUNNEL_RESEARCH_TIMEOUT_SEC', 300),
|
||
],
|
||
|
||
// EXA — поиск САЙТА по имени для канала В (федералы): у федерала нет карточки в 2ГИС/Яндексе
|
||
// на регион, а нам нужен сайт (ZAFIKSIROVANO / §11.5). Ключ только в .env. Пусто → канал В без сайтов.
|
||
'exa' => [
|
||
'key' => env('EXA_API_KEY'),
|
||
'base_url' => env('EXA_BASE_URL', 'https://api.exa.ai'),
|
||
'timeout_sec' => (int) env('EXA_TIMEOUT_SEC', 90),
|
||
// Сколько запросов сайта-федерала слать ОДНОВРЕМЕННО (пул EXA). Лимит EXA — на КЛЮЧ,
|
||
// общий на всех клиентов, поэтому бережно; глобальный потолок между клиентами — очередь.
|
||
'concurrency' => (int) env('EXA_CONCURRENCY', 5),
|
||
// Прокси для EXA (Guzzle proxy option). EXA за Cloudflare режет российские IP, поэтому
|
||
// федеральный канал ходит наружу через зарубежный выход. Формат socks5h://host:port или
|
||
// http://host:port. Пусто → напрямую.
|
||
'proxy' => env('EXA_PROXY'),
|
||
],
|
||
|
||
// Плитка балансов (28.06): Yandex Cloud биллинг (серверы + Managed PG ~18к/мес).
|
||
// OAuth владельца (interim) → IAM-токен → billing API. SA billing-reader создан,
|
||
// миграция на него — follow-up (только источник токена сменится). console_billing_url
|
||
// + billing_account_id строят прямую ссылку «Пополнить» в дашборде.
|
||
'yandex_cloud' => [
|
||
'oauth_token' => env('YC_OAUTH_TOKEN'),
|
||
'billing_account_id' => env('YC_BILLING_ACCOUNT_ID'),
|
||
'iam_url' => env('YC_IAM_URL', 'https://iam.api.cloud.yandex.net/iam/v1/tokens'),
|
||
'billing_url' => env('YC_BILLING_URL', 'https://billing.api.cloud.yandex.net/billing/v1/billingAccounts'),
|
||
'console_billing_url' => env('YC_CONSOLE_BILLING_URL', 'https://console.yandex.cloud/billing/accounts'),
|
||
'daily_spend_rub' => (int) env('YC_DAILY_SPEND_RUB', 600), // оценка ~18к/мес; откалибровать
|
||
'red_floor_rub' => (int) env('YC_RED_FLOOR_RUB', 1000),
|
||
'amber_floor_rub' => (int) env('YC_AMBER_FLOOR_RUB', 5000),
|
||
],
|
||
|
||
// G7-A: клиентская «Помощь».
|
||
'support' => [
|
||
'email' => env('SUPPORT_EMAIL', 'support@liderra.ru'),
|
||
],
|
||
'jivosite' => [
|
||
'widget_id' => env('JIVO_WIDGET_ID'),
|
||
'widget_url_template' => env('JIVO_WIDGET_URL_TEMPLATE', 'https://code.jivo.ru/widget/{id}'),
|
||
],
|
||
|
||
// Платёжный шлюз ЮKassa. webhook_ip_allowlist — CSV IP/CIDR из env (defense-in-depth
|
||
// на /api/webhook/payment). Пусто → fail-open (поток не ломается). На проде заполнить
|
||
// опубликованными ЮKassa подсетями: 185.71.76.0/27,185.71.77.0/27,77.75.153.0/25,
|
||
// 77.75.154.128/25,77.75.156.11,77.75.156.35,2a02:5180::/32.
|
||
'yookassa' => [
|
||
'shop_id' => env('YOOKASSA_SHOP_ID'),
|
||
'secret_key' => env('YOOKASSA_SECRET_KEY'),
|
||
'api_url' => env('YOOKASSA_API_URL', 'https://api.yookassa.ru/v3'),
|
||
'webhook_ip_allowlist' => array_values(array_filter(array_map(
|
||
'trim',
|
||
explode(',', (string) env('YOOKASSA_WEBHOOK_IPS', '')),
|
||
))),
|
||
],
|
||
|
||
// Автоподбор шаг 2: сервис обхода антибота справочников (2ГИС/Яндекс) — xfetch.ru.
|
||
// Ключ — ТОЛЬКО в .env (gitignored), в код/гит не попадает. Без ключа загрузчик
|
||
// молча возвращает пусто (поток не падает).
|
||
'xfetch' => [
|
||
'key' => env('XFETCH_API_KEY'),
|
||
// Несколько ключей через запятую (round-robin) — суммарная параллельность = ключи × concurrency.
|
||
// Пусто → берётся одиночный XFETCH_API_KEY. Ключи — ТОЛЬКО в .env, в код/гит не попадают.
|
||
'keys' => array_values(array_filter(
|
||
array_map('trim', explode(',', (string) env('XFETCH_API_KEYS', ''))),
|
||
static fn (string $v): bool => $v !== '',
|
||
)),
|
||
'endpoint' => env('XFETCH_ENDPOINT', 'https://xf4.ru/fetch'),
|
||
// Параллельность НА КЛЮЧ. Эмпирический предел xf4.ru — ~3 одновременных на ключ
|
||
// (выше идут 429 Too Many Requests; замер 01.07.2026). Меняется без деплоя через .env.
|
||
'concurrency' => (int) env('XFETCH_CONCURRENCY', 3),
|
||
],
|
||
|
||
// Автоподбор self-render: свой рендер-сервис на виртуалке (замена xf4, за флагом autopodbor.self_render).
|
||
// Секрет портал↔виртуалка и адрес — ТОЛЬКО в .env. Без них SelfRenderClient молча пусто (деградация).
|
||
'self_render' => [
|
||
'endpoint' => env('SELF_RENDER_ENDPOINT', ''),
|
||
'key' => env('SELF_RENDER_KEY', ''),
|
||
// Параллельность запросов к виртуалке (браузерная параллельность — внутри виртуалки, §12).
|
||
'concurrency' => (int) env('SELF_RENDER_CONCURRENCY', 8),
|
||
],
|
||
|
||
// Куда слать алерты о недоступности/исходе денег внешних сервисов.
|
||
'monitoring' => [
|
||
'alert_email' => env('MONITORING_ALERT_EMAIL', env('SUPPLIER_ALERT_EMAIL', 'ops@liderra.ru')),
|
||
],
|
||
|
||
// Баланс Яндекс 360 (почта) — РУЧНОЙ ввод (см. Yandex360BalanceProvider). Пороги
|
||
// светофора — как у dadata; topup_url — страница «Оплата и тариф» в кабинете Яндекс 360.
|
||
'yandex360' => [
|
||
'red_floor_rub' => (int) env('YANDEX360_RED_FLOOR_RUB', 500),
|
||
'amber_floor_rub' => (int) env('YANDEX360_AMBER_FLOOR_RUB', 2000),
|
||
'topup_url' => env('YANDEX360_TOPUP_URL', 'https://admin.yandex.ru/products'),
|
||
],
|
||
|
||
];
|