| 1 | import Link from "next/link"; |
| 2 | import { getFacts } from "@/lib/facts"; |
| 3 | import { buildPageMetadata } from "@/lib/page-meta"; |
| 4 | |
| 5 | export const revalidate = 300; |
| 6 | |
| 7 | export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) { |
| 8 | const { locale } = await params; |
| 9 | const isZh = locale === "zh"; |
| 10 | return buildPageMetadata({ |
| 11 | path: "/models", |
| 12 | locale, |
| 13 | title: isZh ? "模型与提供商 · Codewhale" : "Models & providers · Codewhale", |
| 14 | description: isZh |
| 15 | ? "Codewhale 托管与本地提供商路由的配置方式和完整注册表。" |
| 16 | : "Configuration guidance and the full registry for Codewhale's hosted and local provider routes.", |
| 17 | }); |
| 18 | } |
| 19 | |
| 20 | export default async function ModelsPage({ params }: { params: Promise<{ locale: string }> }) { |
| 21 | const { locale } = await params; |
| 22 | const isZh = locale === "zh"; |
| 23 | const p = (path: string) => (isZh ? `/zh${path}` : `/en${path}`); |
| 24 | const facts = await getFacts(); |
| 25 | const providerDocs = "https://github.com/Hmbown/CodeWhale/blob/main/docs/PROVIDERS.md"; |
| 26 | |
| 27 | const setupPatterns = isZh |
| 28 | ? [ |
| 29 | { |
| 30 | title: "DeepSeek", |
| 31 | detail: `新配置默认使用 ${facts.defaultModel ?? "deepseek-v4-pro"}。可以通过 --provider、/provider 或 CODEWHALE_PROVIDER 明确选择其他路由。`, |
| 32 | reference: "DEEPSEEK_API_KEY", |
| 33 | }, |
| 34 | { |
| 35 | title: "本地运行时", |
| 36 | detail: "vLLM、SGLang 和 Ollama 可以直连 localhost。按需配置端点和模型;本地部署通常不需要 API 密钥。", |
| 37 | reference: "vllm · sglang · ollama", |
| 38 | }, |
| 39 | { |
| 40 | title: "OpenRouter", |
| 41 | detail: "OpenRouter 用一个托管端点访问多个模型。提供商和模型仍由你明确选择,不会根据模型名称或提示词自动切换。", |
| 42 | reference: "OPENROUTER_API_KEY", |
| 43 | }, |
| 44 | ] |
| 45 | : [ |
| 46 | { |
| 47 | title: "DeepSeek", |
| 48 | detail: `New configurations default to ${facts.defaultModel ?? "deepseek-v4-pro"}. Select another route explicitly with --provider, /provider, or CODEWHALE_PROVIDER.`, |
| 49 | reference: "DEEPSEEK_API_KEY", |
| 50 | }, |
| 51 | { |
| 52 | title: "Local runtimes", |
| 53 | detail: "vLLM, SGLang, and Ollama can connect directly to localhost. Set an endpoint and model as needed; local deployments usually require no API key.", |
| 54 | reference: "vllm · sglang · ollama", |
| 55 | }, |
| 56 | { |
| 57 | title: "OpenRouter", |
| 58 | detail: "OpenRouter provides one hosted endpoint for many models. You still select the provider and model explicitly; model names and prompts do not switch routes.", |
| 59 | reference: "OPENROUTER_API_KEY", |
| 60 | }, |
| 61 | ]; |
| 62 | |
| 63 | return ( |
| 64 | <div className="models-page"> |
| 65 | <section className="community-welcome"> |
| 66 | <div className="portal-current" aria-hidden="true" /> |
| 67 | <div className="portal-container community-welcome-inner"> |
| 68 | <div className="eyebrow">{isZh ? "模型与提供商" : "Models and providers"}</div> |
| 69 | <h1>{isZh ? "选择模型和提供商。" : "Choose a model and provider."}</h1> |
| 70 | <p> |
| 71 | {isZh |
| 72 | ? `Codewhale 包含 ${facts.providers.length} 条提供商路由。提供商、模型和端点都是明确的配置;每条路由使用同一个本地运行时、工具和审批边界。托管提供商使用你配置的凭据,本地 vLLM、SGLang 和 Ollama 端点通常不需要密钥。` |
| 73 | : `Codewhale includes ${facts.providers.length} provider routes. The provider, model, and endpoint are explicit configuration, and every route uses the same local runtime, tools, and approval boundaries. Hosted providers use credentials you configure; local vLLM, SGLang, and Ollama endpoints usually require no key.`} |
| 74 | </p> |
| 75 | <div className="portal-actions"> |
| 76 | <Link href={providerDocs} className="portal-button portal-button-primary"> |
| 77 | {isZh ? "阅读提供商文档" : "Read the provider docs"} |
| 78 | </Link> |
| 79 | <Link href={p("/install")} className="portal-button portal-button-secondary"> |
| 80 | {isZh ? "安装 Codewhale" : "Install Codewhale"} |
| 81 | </Link> |
| 82 | </div> |
| 83 | </div> |
| 84 | </section> |
| 85 | |
| 86 | <section className="portal-section"> |
| 87 | <div className="portal-container portal-section-grid"> |
| 88 | <div className="portal-section-copy"> |
| 89 | <span>{isZh ? "配置方式" : "Configuration paths"}</span> |
| 90 | <h2>{isZh ? "常用提供商路由" : "Common provider routes"}</h2> |
| 91 | <p> |
| 92 | {isZh |
| 93 | ? "托管提供商的密钥可以通过 codewhale auth set 保存,也可以使用文档中列出的配置项或环境变量。提供商和模型分别选择;模型名称不会隐式改变提供商。" |
| 94 | : "Hosted-provider credentials can be saved with codewhale auth set or supplied through documented configuration and environment variables. Provider and model selection remain separate; a model name never changes the provider implicitly."} |
| 95 | </p> |
| 96 | </div> |
| 97 | <div className="portal-topic-list"> |
| 98 | {setupPatterns.map((pattern) => ( |
| 99 | <Link key={pattern.title} href={p("/docs#providers")}> |
| 100 | <strong>{pattern.title}</strong> |
| 101 | <span>{pattern.detail}</span> |
| 102 | <span className="font-mono break-all">{pattern.reference}</span> |
| 103 | </Link> |
| 104 | ))} |
| 105 | </div> |
| 106 | </div> |
| 107 | </section> |
| 108 | |
| 109 | <section className="portal-section portal-section-muted"> |
| 110 | <div className="portal-container"> |
| 111 | <div className="portal-docs-heading"> |
| 112 | <div> |
| 113 | <span>{isZh ? "仓库数据" : "Repository data"}</span> |
| 114 | <h2>{isZh ? "内置提供商注册表" : "Built-in provider registry"}</h2> |
| 115 | </div> |
| 116 | <Link href={providerDocs}>{isZh ? "打开源文档 ↗" : "Open the source document ↗"}</Link> |
| 117 | </div> |
| 118 | <p className={`mb-6 max-w-3xl text-sm text-ink-soft ${isZh ? "leading-[1.9] tracking-wide" : "leading-relaxed"}`}> |
| 119 | {isZh |
| 120 | ? "下面的列表由仓库中的提供商注册表生成,并随发布更新。这里列出路由 ID 和常用认证环境变量;传输协议、默认端点、模型解析和完整认证优先级以 docs/PROVIDERS.md 为准。" |
| 121 | : "This list is generated from the provider registry in the repository and updated with releases. It shows route IDs and common authentication environment variables; docs/PROVIDERS.md is the source for wire protocols, default endpoints, model resolution, and full authentication precedence."} |
| 122 | </p> |
| 123 | <ul className="grid gap-x-10 sm:grid-cols-2 hairline-t"> |
| 124 | {facts.providers.map((provider) => ( |
| 125 | <li key={provider.id} className="py-4 hairline-b min-w-0"> |
| 126 | <div className="font-display text-base">{provider.label}</div> |
| 127 | <div className="mt-1 font-mono text-[0.68rem] text-indigo break-all">{provider.id}</div> |
| 128 | <div className="mt-1 font-mono text-[0.64rem] text-ink-mute break-all leading-relaxed">{provider.env}</div> |
| 129 | </li> |
| 130 | ))} |
| 131 | </ul> |
| 132 | <p className={`mt-6 max-w-3xl text-sm text-ink-soft ${isZh ? "leading-[1.9] tracking-wide" : "leading-relaxed"}`}> |
| 133 | {isZh ? ( |
| 134 | <> |
| 135 | 如果需要的提供商尚未列出,请先{" "} |
| 136 | <Link href="https://github.com/Hmbown/CodeWhale/issues/new/choose" className="body-link">提交 issue</Link> |
| 137 | ,说明端点、认证方式和模型能力;也欢迎发送包含注册表、文档和测试的 pull request。 |
| 138 | </> |
| 139 | ) : ( |
| 140 | <> |
| 141 | If a provider is missing, please{" "} |
| 142 | <Link href="https://github.com/Hmbown/CodeWhale/issues/new/choose" className="body-link">file an issue</Link> |
| 143 | {" "}with its endpoint, authentication method, and model capabilities. Pull requests that update the registry, documentation, and tests are welcome too. |
| 144 | </> |
| 145 | )} |
| 146 | </p> |
| 147 | </div> |
| 148 | </section> |
| 149 | </div> |
| 150 | ); |
| 151 | } |
| 152 |