Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,16 @@ GEMINI_API_KEY=
#
# 常用厂商模板(任选其一复制到 .env;完整说明见 docs/llm-providers.md)
#
# aimlapi.com(OpenAI Compatible 聚合平台)
# 来源:官方模型库 https://docs.aimlapi.com/api-references/model-database
# 模型名填 /v1/models 返回的 alias;带 anthropic/、gemini/、xai/ 前缀的 id 会被 LiteLLM 当作直连 provider,不再走本渠道 Base URL。
# LLM_CHANNELS=aimlapi
# LLM_AIMLAPI_PROTOCOL=openai
# LLM_AIMLAPI_BASE_URL=https://api.aimlapi.com/v1
# LLM_AIMLAPI_API_KEY=sk-xxx
# LLM_AIMLAPI_MODELS=gpt-5.5-2026-04-23,claude-sonnet-4.6,deepseek-v4-flash
# LITELLM_MODEL=openai/claude-sonnet-4.6
#
# Anspire Open(共享搜索与 LLM Key,OpenAI Compatible)
# LLM_CHANNELS=anspire
# LLM_ANSPIRE_PROTOCOL=openai
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/00-daily-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,15 @@ jobs:
LLM_AIHUBMIX_ENABLED: ${{ vars.LLM_AIHUBMIX_ENABLED || secrets.LLM_AIHUBMIX_ENABLED }}
LLM_AIHUBMIX_EXTRA_HEADERS: ${{ vars.LLM_AIHUBMIX_EXTRA_HEADERS || secrets.LLM_AIHUBMIX_EXTRA_HEADERS }}

LLM_AIMLAPI_PROTOCOL: ${{ vars.LLM_AIMLAPI_PROTOCOL || secrets.LLM_AIMLAPI_PROTOCOL }}
LLM_AIMLAPI_API_SURFACE: ${{ vars.LLM_AIMLAPI_API_SURFACE || secrets.LLM_AIMLAPI_API_SURFACE }}
LLM_AIMLAPI_BASE_URL: ${{ vars.LLM_AIMLAPI_BASE_URL || secrets.LLM_AIMLAPI_BASE_URL }}
LLM_AIMLAPI_API_KEY: ${{ secrets.LLM_AIMLAPI_API_KEY }}
LLM_AIMLAPI_API_KEYS: ${{ secrets.LLM_AIMLAPI_API_KEYS }}
LLM_AIMLAPI_MODELS: ${{ vars.LLM_AIMLAPI_MODELS || secrets.LLM_AIMLAPI_MODELS }}
LLM_AIMLAPI_ENABLED: ${{ vars.LLM_AIMLAPI_ENABLED || secrets.LLM_AIMLAPI_ENABLED }}
LLM_AIMLAPI_EXTRA_HEADERS: ${{ vars.LLM_AIMLAPI_EXTRA_HEADERS || secrets.LLM_AIMLAPI_EXTRA_HEADERS }}

LLM_ANSPIRE_PROTOCOL: ${{ vars.LLM_ANSPIRE_PROTOCOL || secrets.LLM_ANSPIRE_PROTOCOL }}
LLM_ANSPIRE_API_SURFACE: ${{ vars.LLM_ANSPIRE_API_SURFACE || secrets.LLM_ANSPIRE_API_SURFACE }}
LLM_ANSPIRE_BASE_URL: ${{ vars.LLM_ANSPIRE_BASE_URL || secrets.LLM_ANSPIRE_BASE_URL }}
Expand Down
2 changes: 1 addition & 1 deletion apps/dsa-web/src/components/settings/LLMChannelEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1666,7 +1666,7 @@ export const LLMChannelEditor: React.FC<LLMChannelEditorProps> = ({
const [capabilityStates, setCapabilityStates] = useState<Record<string, ChannelCapabilityState>>({});
const [expandedRows, setExpandedRows] = useState<Record<number, boolean>>({});
const [isCollapsed, setIsCollapsed] = useState(false);
const [addPreset, setAddPreset] = useState('aihubmix');
const [addPreset, setAddPreset] = useState(LLM_PROVIDER_TEMPLATES[0].channelId);
const addChannelIdRef = useRef(0);
const lastDraftFingerprintRef = useRef<string | null>(null);
const onDraftItemsChangeRef = useRef(onDraftItemsChange);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
describe('llmProviderTemplates', () => {
it('keeps provider template order aligned with the existing preset dropdown order', () => {
expect(LLM_PROVIDER_TEMPLATES.map((template) => template.channelId)).toEqual([
'aimlapi',
'aihubmix',
'anspire',
'deepseek',
Expand Down Expand Up @@ -91,6 +92,18 @@ describe('llmProviderTemplates', () => {
});
});

it('keeps the aimlapi preset on the OpenAI-compatible chat completions entry', () => {
expect(LLM_PROVIDER_TEMPLATE_BY_ID.aimlapi).toMatchObject({
label: 'aimlapi.com',
protocol: 'openai',
baseUrl: 'https://api.aimlapi.com/v1',
placeholderModels: 'gpt-5.5-2026-04-23,claude-sonnet-4.6,deepseek-v4-flash',
});
// /v1/completions does not exist on this gateway; the Base URL must stop at /v1.
expect(LLM_PROVIDER_TEMPLATE_BY_ID.aimlapi.baseUrl.endsWith('/v1')).toBe(true);
expect(LLM_PROVIDER_TEMPLATE_BY_ID.aimlapi.configHint).toContain('anthropic/');
});

it('keeps basic metadata on non-custom provider templates', () => {
for (const template of LLM_PROVIDER_TEMPLATES.filter((item) => item.channelId !== 'custom')) {
expect(template.capabilities.length).toBeGreaterThan(0);
Expand Down
14 changes: 14 additions & 0 deletions apps/dsa-web/src/components/settings/llmProviderTemplates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ export const LLM_PROVIDER_CAPABILITY_LABELS: Record<LLMProviderCapability, { lab
};

export const LLM_PROVIDER_TEMPLATES: LLMProviderTemplate[] = [
{
channelId: 'aimlapi',
label: 'aimlapi.com',
protocol: 'openai',
baseUrl: 'https://api.aimlapi.com/v1',
placeholderModels: 'gpt-5.5-2026-04-23,claude-sonnet-4.6,deepseek-v4-flash',
capabilities: ['openai-compatible', 'aggregator', 'model-discovery'],
configHint:
'模型名填平台 /v1/models 返回的 alias(例如 claude-sonnet-4.6,注意是点号);不要填带 anthropic/、gemini/、xai/ 前缀的 id,这些前缀会被 LiteLLM 当作直连 provider,不再走本渠道 Base URL。',
officialSources: [
{ label: 'AI/ML API Model Database', url: 'https://docs.aimlapi.com/api-references/model-database' },
{ label: 'AI/ML API Quickstart', url: 'https://docs.aimlapi.com/quickstart/setting-up' },
],
},
{
channelId: 'aihubmix',
label: 'AIHubmix(聚合平台)',
Expand Down
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
> For user-friendly release highlights, see the [GitHub Releases](https://github.com/ZhuLinsen/daily_stock_analysis/releases) page.

## [Unreleased]
- [新功能] 新增 aimlapi.com 渠道预设(渠道名 `aimlapi`,OpenAI Compatible,Base URL `https://api.aimlapi.com/v1`),同步补齐 Web 设置页预设、`.env.example` 模板、`00-daily-analysis.yml` 的 `LLM_AIMLAPI_*` 映射与中英文档;请求发往 `api.aimlapi.com` 时按既有 AIHubmix 赞助头的同一机制附加合作归因请求头,渠道自身 `LLM_<NAME>_EXTRA_HEADERS` 同名字段仍然优先
- [修复] 将 litellm 依赖窗口上界收敛到 `<1.99.0`:1.99.0 起把 `prompt_cache_key` 透传给 OpenAI provider,破坏 provider 缓存测试对不透传行为的既有断言(CI backend-tests 3/3 与 backend-gate 失败);保留历史最低版本与 `!=1.82.7`/`!=1.82.8` 事故排除,同时同步更新各 LLM 兼容文档中写死的依赖约束表述,避免文档与 requirements.txt 漂移

- [新功能] 新增 `SEARXNG_TIMEOUT_SECONDS` 配置自建 SearXNG 单次搜索超时(默认 10 秒),已接线全部 SearchService 构造入口(含题材搜索子进程重建)与默认 GitHub Actions 工作流
Expand Down
2 changes: 1 addition & 1 deletion docs/LLM_CONFIG_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ model_list:

- 运行时选择:`GENERATION_BACKEND`、`GENERATION_FALLBACK_BACKEND`、`GENERATION_BACKEND_TIMEOUT_SECONDS`、`GENERATION_BACKEND_MAX_OUTPUT_BYTES`、`GENERATION_BACKEND_MAX_CONCURRENCY`、`LOCAL_CLI_BACKEND_MAX_CONCURRENCY`、`AGENT_GENERATION_BACKEND`、`LLM_CHANNELS`、`LITELLM_MODEL`、`LITELLM_FALLBACK_MODELS`、`AGENT_LITELLM_MODEL`、`VISION_MODEL`、`VISION_PROVIDER_PRIORITY`、`LLM_TEMPERATURE`、`LLM_USAGE_HMAC_SECRET`、`LLM_USAGE_HMAC_KEY_VERSION`、`LLM_PROMPT_CACHE_TELEMETRY_ENABLED`、`LLM_PROMPT_CACHE_HINTS_ENABLED`、`LLM_PROMPT_CACHE_DIAGNOSTICS_LEVEL`
- 多 Key:`GEMINI_API_KEYS`、`ANTHROPIC_API_KEYS`、`OPENAI_API_KEYS`、`DEEPSEEK_API_KEYS`(当前 workflow 仅从 repository secrets 导入,不会读取同名 Variables)
- 常用渠道名:`primary`、`secondary`、`aihubmix`、`deepseek`、`dashscope`、`zhipu`、`moonshot`、`minimax`、`volcengine`、`siliconflow`、`openrouter`、`gemini`、`anthropic`、`openai`、`ollama`
- 常用渠道名:`primary`、`secondary`、`aihubmix`、`aimlapi`、`deepseek`、`dashscope`、`zhipu`、`moonshot`、`minimax`、`volcengine`、`siliconflow`、`openrouter`、`gemini`、`anthropic`、`openai`、`ollama`

例如在 GitHub Actions 中配置 `LLM_CHANNELS=primary,deepseek` 时,需同步配置 `LLM_PRIMARY_*` / `LLM_DEEPSEEK_*`。其中 `LLM_<NAME>_API_KEY` / `LLM_<NAME>_API_KEYS` 当前也仅从 repository secrets 导入;如果你把这些值放在 Variables,运行时不会生效。若使用自定义渠道名(如 `my_proxy`),GitHub Actions 还必须在 workflow `env:` 中显式新增对应的 `LLM_MY_PROXY_*` 映射;本地 `.env` 和 Docker 不受这个限制。

Expand Down
2 changes: 1 addition & 1 deletion docs/LLM_CONFIG_GUIDE_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ The bundled `00-daily-analysis.yml` explicitly passes the common LLM runtime fie

- Runtime selection: `GENERATION_BACKEND`, `GENERATION_FALLBACK_BACKEND`, `GENERATION_BACKEND_TIMEOUT_SECONDS`, `GENERATION_BACKEND_MAX_OUTPUT_BYTES`, `GENERATION_BACKEND_MAX_CONCURRENCY`, `LOCAL_CLI_BACKEND_MAX_CONCURRENCY`, `AGENT_GENERATION_BACKEND`, `LLM_CHANNELS`, `LITELLM_MODEL`, `LITELLM_FALLBACK_MODELS`, `AGENT_LITELLM_MODEL`, `VISION_MODEL`, `VISION_PROVIDER_PRIORITY`, `LLM_TEMPERATURE`, `LLM_USAGE_HMAC_SECRET`, `LLM_USAGE_HMAC_KEY_VERSION`, `LLM_PROMPT_CACHE_TELEMETRY_ENABLED`, `LLM_PROMPT_CACHE_HINTS_ENABLED`, `LLM_PROMPT_CACHE_DIAGNOSTICS_LEVEL`
- Multiple keys: `GEMINI_API_KEYS`, `ANTHROPIC_API_KEYS`, `OPENAI_API_KEYS`, `DEEPSEEK_API_KEYS` (the current workflow imports these from repository Secrets only, not from same-named Variables)
- Common channel names: `primary`, `secondary`, `aihubmix`, `deepseek`, `dashscope`, `zhipu`, `moonshot`, `minimax`, `volcengine`, `siliconflow`, `openrouter`, `gemini`, `anthropic`, `openai`, `ollama`
- Common channel names: `primary`, `secondary`, `aihubmix`, `aimlapi`, `deepseek`, `dashscope`, `zhipu`, `moonshot`, `minimax`, `volcengine`, `siliconflow`, `openrouter`, `gemini`, `anthropic`, `openai`, `ollama`

For example, if you set `LLM_CHANNELS=primary,deepseek` in GitHub Actions, also configure the corresponding `LLM_PRIMARY_*` and `LLM_DEEPSEEK_*` entries. The `LLM_<NAME>_API_KEY` / `LLM_<NAME>_API_KEYS` fields are also imported from repository Secrets only right now, so storing them in Variables will not work at runtime. If you use a custom channel name such as `my_proxy`, GitHub Actions must explicitly add matching `LLM_MY_PROXY_*` mappings in the workflow `env:` block. Local `.env` and Docker runs do not have this limitation.

Expand Down
4 changes: 3 additions & 1 deletion docs/llm-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ LITELLM_FALLBACK_MODELS=openai/gpt-5.6-terra,openai/gpt-5.6-luna

| 服务商 | 渠道名 | 协议 | Base URL | 模型示例 |
| --- | --- | --- | --- | --- |
| aimlapi.com | `aimlapi` | `openai` | `https://api.aimlapi.com/v1` | `gpt-5.5-2026-04-23,claude-sonnet-4.6,deepseek-v4-flash` |
| AIHubmix | `aihubmix` | `openai` | `https://aihubmix.com/v1` | `gpt-5.5,claude-sonnet-4-6,gemini-3.1-pro-preview` |
| Anspire Open | `anspire` | `openai` | `https://open-gateway.anspire.cn/v6`(示例) | `Doubao-Seed-2.0-lite,Doubao-Seed-2.0-pro,qwen3.5-flash,MiniMax-M2.7`(示例) |
| OpenAI | `openai` | `openai` | `https://api.openai.com/v1` | `gpt-5.5,gpt-5.4-mini` |
Expand Down Expand Up @@ -139,6 +140,7 @@ LITELLM_FALLBACK_MODELS=openai/gpt-5.6-terra,openai/gpt-5.6-luna
| 火山方舟 / 豆包 | [在线推理(常规)](https://www.volcengine.com/docs/82379/2121998)、[模型列表](https://www.volcengine.com/docs/82379/1949118) | 官方示例使用 `https://ark.cn-beijing.volces.com/api/v3` 与 `doubao-seed-1-6-251015`;如使用 Coding Plan,请改用其专用 Base URL 和模型名,不要套用本表的在线推理模板。 |
| SiliconFlow | [模型列表](https://docs.siliconflow.cn/quickstart/models)、[获取模型列表 API](https://docs.siliconflow.cn/cn/api-reference/models/get-model-list) | 平台模型实时更新且 `/models` 需要 API Key;模板只给常见新模型示例,保存前建议在 Web 设置页点击「获取模型」确认账号可见性。 |
| OpenRouter | [Models API](https://openrouter.ai/docs/api/api-reference/models/get-models) | OpenRouter 支持 `~anthropic/claude-sonnet-latest`、`~openai/gpt-latest` 等 latest router alias;2026-05-03 的一次手动 live smoke 以 Claude Sonnet latest 作为默认示例通过,GPT latest 保留为可按账号权限切换的备选。 |
| aimlapi.com | [Model Database](https://docs.aimlapi.com/api-references/model-database)、[Quickstart](https://docs.aimlapi.com/quickstart/setting-up) | OpenAI-compatible Base URL 为 `https://api.aimlapi.com/v1`,只提供 `/chat/completions` 与 `/responses`,没有 `/v1/completions`。`/v1/models` 返回 `{"object":"list","data":[...]}`,可以用「获取模型」拉取;但它对任意 Key 都返回 200,不能作为 Key 有效性判据,请以「测试连接」的实际推理结果为准。模型请填返回的 alias(例如 `claude-sonnet-4.6`——该网关同时提供点号与横杠两种拼写,只有点号形式在 `?include=all` 中声明了 `tools` / `vision` / `structured_output` 等能力,横杠形式只声明 `streaming`),不要填带 `anthropic/`、`gemini/`、`xai/` 前缀的 id,否则 LiteLLM 会按直连 provider 路由而不再走本渠道 Base URL。该网关还对 `temperature` / `top_p` / `seed` / `tools` / `tool_choice` / `response_format` / `stream` / `max_tokens` 等字段的 JSON `null` 返回 400(未设置的可选参数正好会被序列化成 `null`),因此请求参数应整键省略而不是传 `None`;本仓库现有实现已满足,回归见 `tests/test_llm_channel_config.py::AimlapiRequestParamsTestCase`。与 AIHubmix 的赞助头同一机制:请求发往 `api.aimlapi.com` 时会附加合作归因请求头(`X-AIMLAPI-Partner-ID` / `X-AIMLAPI-Source` / `HTTP-Referer` / `X-Title`),渠道自身的 `LLM_AIMLAPI_EXTRA_HEADERS` 同名字段优先,其他 Base URL 不会被注入。 |
| LiteLLM | [OpenAI-Compatible Endpoints](https://docs.litellm.ai/docs/providers/openai_compatible) | OpenAI-compatible 端点需要把运行时模型写成 `openai/<model>`,Base URL 只填到服务商兼容入口,不额外拼接 `/chat/completions`。 |

本页预设只保证配置形状与当前依赖的 OpenAI-compatible 路由规则一致;实际连通性仍取决于服务商账号权限、地域、额度和模型开通状态。当前 LiteLLM 版本约束为 `litellm>=1.80.10,!=1.82.7,!=1.82.8,<1.99.0`(见 `requirements.txt`),保留历史最低版本、显式排除 PyPI 事故版本,并将上界收敛到已验证的 `<1.99.0`,避免未来大版本自动进入。
Expand Down Expand Up @@ -172,7 +174,7 @@ LITELLM_FALLBACK_MODELS=openai/gpt-5.6-terra,openai/gpt-5.6-luna
| `LLM_USAGE_HMAC_SECRET` | Secrets | 可选;只有需要跨部署比较 usage message HMAC 时才配置同一个高熵随机密钥,例如 `openssl rand -hex 32`;不要放 Variables 或提交到版本控制。 |
| `LLM_USAGE_HMAC_KEY_VERSION` | Variables 或 Secrets | 可选;轮换 `LLM_USAGE_HMAC_SECRET` 时同步更新版本标签,避免误比较不同密钥生成的 HMAC。 |

默认 workflow 已显式映射 `primary`、`secondary`、`aihubmix`、`anspire`、`deepseek`、`dashscope`、`zhipu`、`moonshot`、`minimax`、`volcengine`、`siliconflow`、`openrouter`、`gemini`、`anthropic`、`openai`、`ollama`、`hermes`;`mimo` 未在默认 workflow 中映射。若使用 `mimo`(或任何未列渠道名),除了在 Variables/Secrets 配置同名 `LLM_<CHANNEL>_*` 外,还需在 workflow 中同步补齐对应 env 映射;本地 `.env`、Docker 和自托管脚本不受这个限制。
默认 workflow 已显式映射 `primary`、`secondary`、`aihubmix`、`aimlapi`、`anspire`、`deepseek`、`dashscope`、`zhipu`、`moonshot`、`minimax`、`volcengine`、`siliconflow`、`openrouter`、`gemini`、`anthropic`、`openai`、`ollama`、`hermes`;`mimo` 未在默认 workflow 中映射。若使用 `mimo`(或任何未列渠道名),除了在 Variables/Secrets 配置同名 `LLM_<CHANNEL>_*` 外,还需在 workflow 中同步补齐对应 env 映射;本地 `.env`、Docker 和自托管脚本不受这个限制。

回滚 HMAC 遥测显式配置时,可移除 `LLM_USAGE_HMAC_SECRET` 并恢复或删除 `LLM_USAGE_HMAC_KEY_VERSION`;留空后系统会回到本地生成 `.llm_usage_hmac_secret` 的默认行为。

Expand Down
51 changes: 43 additions & 8 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,41 @@ def __str__(self) -> str: # noqa: D105
ANSPIRE_LLM_BASE_URL_DEFAULT = "https://open-gateway.anspire.cn/v6"
ANSPIRE_LLM_MODEL_DEFAULT = "Doubao-Seed-2.0-lite"

# 聚合平台的赞助 / 归因请求头。
# 仅在请求确实发往对应服务商时注入,避免被带到其他渠道或中转代理上;
# 渠道自身的 LLM_<CHANNEL>_EXTRA_HEADERS 始终优先,不会被这里覆盖。
AIHUBMIX_SPONSORED_HEADERS: Dict[str, str] = {"APP-Code": "GPIJ3886"}
AIMLAPI_API_HOST = "api.aimlapi.com"
AIMLAPI_ATTRIBUTION_HEADERS: Dict[str, str] = {
"HTTP-Referer": "https://github.com/ZhuLinsen/daily_stock_analysis",
"X-Title": "Daily Stock Analysis",
"X-AIMLAPI-Partner-ID": "part_ZBzsnhYW8aO7HueEfvKZM4je",
"X-AIMLAPI-Source": "agent/daily-stock-analysis",
}


def build_provider_extra_headers(
base_url: Optional[str],
extra_headers: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
"""按 base_url 合并服务商赞助 / 归因请求头。

每次调用都返回新的 dict:既不修改模块级常量,也不覆盖调用方已经配置的同名
header。aihubmix 沿用既有的 base_url 子串匹配;aimlapi 按主机名精确匹配,
确保归因头不会跟着请求发到其他服务商或中转代理。
"""
headers: Dict[str, Any] = dict(extra_headers or {})
raw_base_url = (base_url or "").strip()
if not raw_base_url:
return headers
if "aihubmix.com" in raw_base_url:
for header_name, header_value in AIHUBMIX_SPONSORED_HEADERS.items():
headers.setdefault(header_name, header_value)
if (urlparse(raw_base_url).hostname or "").lower() == AIMLAPI_API_HOST:
for header_name, header_value in AIMLAPI_ATTRIBUTION_HEADERS.items():
headers.setdefault(header_name, header_value)
return headers


def _has_ntfy_topic_endpoint(value: Optional[str]) -> bool:
"""Return whether an ntfy URL points at a concrete topic endpoint."""
Expand Down Expand Up @@ -2624,10 +2659,8 @@ def _channels_to_model_list(cls, channels: List[Dict[str, Any]]) -> List[Dict[st
litellm_params['api_key'] = api_key
if ch['base_url']:
litellm_params['api_base'] = ch['base_url']
# Auto-inject aihubmix sponsored header
headers = dict(ch.get('extra_headers') or {})
if ch['base_url'] and 'aihubmix.com' in ch['base_url']:
headers.setdefault('APP-Code', 'GPIJ3886')
# Auto-inject provider sponsored / attribution headers
headers = build_provider_extra_headers(ch['base_url'], ch.get('extra_headers'))
if headers:
litellm_params['extra_headers'] = headers

Expand Down Expand Up @@ -2689,8 +2722,9 @@ def _legacy_keys_to_model_list(
params: Dict[str, Any] = {'model': '__legacy_openai__', 'api_key': k}
if openai_base_url:
params['api_base'] = openai_base_url
if openai_base_url and 'aihubmix.com' in openai_base_url:
params['extra_headers'] = {'APP-Code': 'GPIJ3886'}
legacy_headers = build_provider_extra_headers(openai_base_url)
if legacy_headers:
params['extra_headers'] = legacy_headers
model_list.append({
'model_name': '__legacy_openai__',
'litellm_params': params,
Expand Down Expand Up @@ -3733,8 +3767,9 @@ def extra_litellm_params(model: str, config: Config) -> Dict[str, Any]:
if model.startswith("openai/") or "/" not in model:
if config.openai_base_url:
params["api_base"] = config.openai_base_url
if config.openai_base_url and "aihubmix.com" in config.openai_base_url:
params["extra_headers"] = {"APP-Code": "GPIJ3886"}
provider_headers = build_provider_extra_headers(config.openai_base_url)
if provider_headers:
params["extra_headers"] = provider_headers
return params


Expand Down
Loading
Loading