added proxy
This commit is contained in:
@@ -0,0 +1,65 @@
|
|||||||
|
# ── LLM (OpenRouter / любой совместимый провайдер) ────────────
|
||||||
|
# Базовый URL и ключ:
|
||||||
|
# - по умолчанию: OpenRouter
|
||||||
|
# - можно переопределить под другой API, если он совместим по формату
|
||||||
|
LLM_BASE_URL=https://openrouter.ai/api/v1/chat/completions
|
||||||
|
LLM_API_KEY=sk-or-v1-...
|
||||||
|
# Для обратной совместимости с текущей конфигурацией:
|
||||||
|
ROUTER_KEY=${LLM_API_KEY}
|
||||||
|
|
||||||
|
# Авторизационный заголовок и префикс (опционально):
|
||||||
|
#LLM_AUTH_HEADER=Authorization
|
||||||
|
#LLM_AUTH_PREFIX=Bearer
|
||||||
|
|
||||||
|
# Прокси: HTTP или SOCKS5, например:
|
||||||
|
# socks5://user:pass@127.0.0.1:1080
|
||||||
|
# http://127.0.0.1:8080
|
||||||
|
# Любая из переменных может использоваться (берётся первая непустая):
|
||||||
|
#LLM_PROXY=
|
||||||
|
#LLM_SOCKS5=
|
||||||
|
#LLM_SOCKS5_PROXY=
|
||||||
|
|
||||||
|
# ── Model routing ─────────────────────────────────────────────
|
||||||
|
CHAT_MODEL=deepseek/deepseek-v4-flash
|
||||||
|
SYSTEM_MODEL=deepseek/deepseek-chat-v3
|
||||||
|
LLM_FALLBACK_MODEL=mistralai/mistral-nemo
|
||||||
|
|
||||||
|
RPG_PLOT_MODEL=deepseek/deepseek-chat-v3
|
||||||
|
RPG_NARRATOR_MODEL=deepseek/deepseek-chat-v3
|
||||||
|
RPG_FACTS_MODEL=deepseek/deepseek-chat-v3
|
||||||
|
SD_PROMPT_MODEL=deepseek/deepseek-chat-v3
|
||||||
|
|
||||||
|
FACTS_STORE_LIMIT=100
|
||||||
|
|
||||||
|
# ── Comfy / SD ────────────────────────────────────────────────
|
||||||
|
# Comfy на том же хосте, что и docker compose (Linux):
|
||||||
|
# вариант A — LAN-IP сервера (часто работает сразу)
|
||||||
|
SD_BASE_URL=http://192.168.1.109:8188
|
||||||
|
# вариант B — host.docker.internal (нужен extra_hosts в compose, уже добавлен)
|
||||||
|
# SD_BASE_URL=http://host.docker.internal:8188
|
||||||
|
# Comfy на другой машине в сети:
|
||||||
|
# SD_BASE_URL=http://84.50.156.15:8188
|
||||||
|
|
||||||
|
SD_COMFY_TOKEN=
|
||||||
|
SD_CHECKPOINT=
|
||||||
|
SD_UNET=anima-preview3-base.safetensors
|
||||||
|
SD_CLIP=qwen_3_06b_base.safetensors
|
||||||
|
SD_VAE=qwen_image_vae.safetensors
|
||||||
|
SD_STYLE_LORA=anima-preview-3-masterpieces-v5.safetensors
|
||||||
|
SD_STYLE_LORA_WEIGHT=0.7
|
||||||
|
|
||||||
|
SD_AUTO_GENERATE=true
|
||||||
|
SD_STEPS=30
|
||||||
|
SD_CFG=4
|
||||||
|
SD_SAMPLER=er_sde
|
||||||
|
SD_SCHEDULER=simple
|
||||||
|
SD_ANIMA_DUAL_COMPARE=false
|
||||||
|
|
||||||
|
# ── LibreTranslate ────────────────────────────────────────────
|
||||||
|
# Тот же хост: LAN-IP или host.docker.internal:5100
|
||||||
|
LIBRETRANSLATE_URL=http://192.168.1.109:5100
|
||||||
|
|
||||||
|
# Порт веб-UI и API (по умолчанию 8201)
|
||||||
|
APP_PORT=8201
|
||||||
|
|
||||||
|
# DB_PATH и IMAGES_DIR заданы в docker-compose.yml — в .env не нужны
|
||||||
+27
-10
@@ -8,16 +8,33 @@ load_dotenv()
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
OPENROUTER_KEY = os.getenv("ROUTER_KEY")
|
# ── Provider / transport configuration ─────────────────────────────
|
||||||
OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions"
|
# По умолчанию работаем через OpenRouter, но базовый URL и ключ
|
||||||
|
# можно переопределить для любого совместимого провайдера.
|
||||||
|
LLM_BASE_URL = (
|
||||||
|
os.getenv("LLM_BASE_URL")
|
||||||
|
or "https://openrouter.ai/api/v1/chat/completions"
|
||||||
|
)
|
||||||
|
LLM_API_KEY = os.getenv("LLM_API_KEY") or os.getenv("ROUTER_KEY")
|
||||||
|
LLM_AUTH_HEADER = os.getenv("LLM_AUTH_HEADER", "Authorization")
|
||||||
|
LLM_AUTH_PREFIX = os.getenv("LLM_AUTH_PREFIX", "Bearer ")
|
||||||
|
|
||||||
|
# SOCKS5 / HTTP‑прокси (например: socks5://user:pass@host:1080)
|
||||||
|
LLM_PROXY_URL = (
|
||||||
|
os.getenv("LLM_PROXY")
|
||||||
|
or os.getenv("LLM_SOCKS5")
|
||||||
|
or os.getenv("LLM_SOCKS5_PROXY")
|
||||||
|
)
|
||||||
|
PROXIES = {"all": LLM_PROXY_URL} if LLM_PROXY_URL else None
|
||||||
|
|
||||||
|
# ── Модели ─────────────────────────────────────────────────────────
|
||||||
CHAT_MODEL = os.getenv("CHAT_MODEL", "mistralai/mistral-nemo")
|
CHAT_MODEL = os.getenv("CHAT_MODEL", "mistralai/mistral-nemo")
|
||||||
SYSTEM_MODEL = os.getenv("SYSTEM_MODEL", "google/gemini-2.5-flash")
|
SYSTEM_MODEL = os.getenv("SYSTEM_MODEL", "google/gemini-2.5-flash")
|
||||||
# Softer model when primary returns content_filter / empty / API errors (default: CHAT_MODEL).
|
# Softer model when primary returns content_filter / empty / API errors (default: CHAT_MODEL).
|
||||||
LLM_FALLBACK_MODEL = (os.getenv("LLM_FALLBACK_MODEL") or "").strip() or CHAT_MODEL
|
LLM_FALLBACK_MODEL = (os.getenv("LLM_FALLBACK_MODEL") or "").strip() or CHAT_MODEL
|
||||||
|
|
||||||
HEADERS = {
|
HEADERS = {
|
||||||
"Authorization": f"Bearer {OPENROUTER_KEY}",
|
LLM_AUTH_HEADER: f"{LLM_AUTH_PREFIX}{LLM_API_KEY}" if LLM_API_KEY else "",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"HTTP-Referer": "http://localhost:8000",
|
"HTTP-Referer": "http://localhost:8000",
|
||||||
}
|
}
|
||||||
@@ -86,12 +103,12 @@ def _clean(messages: list) -> list:
|
|||||||
|
|
||||||
|
|
||||||
async def _post_once(model: str, messages: list, extra: dict | None = None) -> str:
|
async def _post_once(model: str, messages: list, extra: dict | None = None) -> str:
|
||||||
if not OPENROUTER_KEY:
|
if not LLM_API_KEY:
|
||||||
raise LLMError("ROUTER_KEY is not set in environment")
|
raise LLMError("LLM_API_KEY / ROUTER_KEY is not set in environment")
|
||||||
|
|
||||||
payload = {"model": model, "messages": _clean(messages), **(extra or {})}
|
payload = {"model": model, "messages": _clean(messages), **(extra or {})}
|
||||||
async with httpx.AsyncClient(timeout=90) as client:
|
async with httpx.AsyncClient(timeout=90, proxies=PROXIES) as client:
|
||||||
r = await client.post(OPENROUTER_URL, headers=HEADERS, json=payload)
|
r = await client.post(LLM_BASE_URL, headers=HEADERS, json=payload)
|
||||||
try:
|
try:
|
||||||
data = r.json()
|
data = r.json()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -108,7 +125,7 @@ async def _post_once(model: str, messages: list, extra: dict | None = None) -> s
|
|||||||
return _parse_completion_body(data)
|
return _parse_completion_body(data)
|
||||||
except LLMError:
|
except LLMError:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"OpenRouter completion failed model=%s status=%s body=%.500s",
|
"LLM completion failed model=%s status=%s body=%.500s",
|
||||||
model,
|
model,
|
||||||
r.status_code,
|
r.status_code,
|
||||||
data,
|
data,
|
||||||
@@ -157,9 +174,9 @@ async def stream_message(messages: list):
|
|||||||
}
|
}
|
||||||
timeout = httpx.Timeout(connect=10, read=120, write=10, pool=5)
|
timeout = httpx.Timeout(connect=10, read=120, write=10, pool=5)
|
||||||
chunk_count = 0
|
chunk_count = 0
|
||||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
async with httpx.AsyncClient(timeout=timeout, proxies=PROXIES) as client:
|
||||||
try:
|
try:
|
||||||
async with client.stream("POST", OPENROUTER_URL, headers=HEADERS, json=payload) as response:
|
async with client.stream("POST", LLM_BASE_URL, headers=HEADERS, json=payload) as response:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
buf = ""
|
buf = ""
|
||||||
async for raw in response.aiter_bytes():
|
async for raw in response.aiter_bytes():
|
||||||
|
|||||||
Reference in New Issue
Block a user