icebear0828
refactor: migrate electron from branch to npm workspace
178e38e
raw
history blame
7.8 kB
import { useState, useMemo, useCallback } from "preact/hooks";
import { useT } from "@shared/i18n/context";
import { CopyButton } from "./CopyButton";
type Protocol = "openai" | "anthropic" | "gemini";
type CodeLang = "python" | "node" | "curl";
const protocols: { id: Protocol; label: string }[] = [
{ id: "openai", label: "OpenAI" },
{ id: "anthropic", label: "Anthropic" },
{ id: "gemini", label: "Gemini" },
];
const langs: { id: CodeLang; label: string }[] = [
{ id: "python", label: "Python" },
{ id: "node", label: "Node.js" },
{ id: "curl", label: "cURL" },
];
function buildExamples(
baseUrl: string,
apiKey: string,
model: string,
origin: string,
reasoningEffort: string
): Record<string, string> {
const effortLine = reasoningEffort && reasoningEffort !== "medium"
? `\n reasoning_effort="${reasoningEffort}",`
: "";
const effortJson = reasoningEffort && reasoningEffort !== "medium"
? `,\n "reasoning_effort": "${reasoningEffort}"`
: "";
const effortJs = reasoningEffort && reasoningEffort !== "medium"
? `\n reasoning_effort: "${reasoningEffort}",`
: "";
return {
"openai-python": `from openai import OpenAI
client = OpenAI(
base_url="${baseUrl}",
api_key="${apiKey}",
)
response = client.chat.completions.create(
model="${model}",
messages=[{"role": "user", "content": "Hello"}],${effortLine}
)
print(response.choices[0].message.content)`,
"openai-curl": `curl ${baseUrl}/chat/completions \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer ${apiKey}" \\
-d '{
"model": "${model}",
"messages": [{"role": "user", "content": "Hello"}]${effortJson}
}'`,
"openai-node": `import OpenAI from "openai";
const client = new OpenAI({
baseURL: "${baseUrl}",
apiKey: "${apiKey}",
});
const stream = await client.chat.completions.create({
model: "${model}",
messages: [{ role: "user", content: "Hello" }],${effortJs}
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content || "");
}`,
"anthropic-python": `import anthropic
client = anthropic.Anthropic(
base_url="${origin}/v1",
api_key="${apiKey}",
)
message = client.messages.create(
model="${model}",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
print(message.content[0].text)`,
"anthropic-curl": `curl ${origin}/v1/messages \\
-H "Content-Type: application/json" \\
-H "x-api-key: ${apiKey}" \\
-H "anthropic-version: 2023-06-01" \\
-d '{
"model": "${model}",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello"}]
}'`,
"anthropic-node": `import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
baseURL: "${origin}/v1",
apiKey: "${apiKey}",
});
const message = await client.messages.create({
model: "${model}",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello" }],
});
console.log(message.content[0].text);`,
"gemini-python": `from google import genai
client = genai.Client(
api_key="${apiKey}",
http_options={"base_url": "${origin}/v1beta"},
)
response = client.models.generate_content(
model="${model}",
contents="Hello",
)
print(response.text)`,
"gemini-curl": `curl "${origin}/v1beta/models/${model}:generateContent?key=${apiKey}" \\
-H "Content-Type: application/json" \\
-d '{
"contents": [{"role": "user", "parts": [{"text": "Hello"}]}]
}'`,
"gemini-node": `import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({
apiKey: "${apiKey}",
httpOptions: { baseUrl: "${origin}/v1beta" },
});
const response = await ai.models.generateContent({
model: "${model}",
contents: "Hello",
});
console.log(response.text);`,
};
}
interface CodeExamplesProps {
baseUrl: string;
apiKey: string;
model: string;
reasoningEffort: string;
serviceTier: string | null;
}
export function CodeExamples({ baseUrl, apiKey, model, reasoningEffort, serviceTier }: CodeExamplesProps) {
const t = useT();
const [protocol, setProtocol] = useState<Protocol>("openai");
const [codeLang, setCodeLang] = useState<CodeLang>("python");
const origin = typeof window !== "undefined" ? window.location.origin : "";
// Build compound model name with suffixes for CLI users
const displayModel = useMemo(() => {
let name = model;
if (reasoningEffort && reasoningEffort !== "medium") name += `-${reasoningEffort}`;
if (serviceTier === "fast") name += "-fast";
return name;
}, [model, reasoningEffort, serviceTier]);
// When effort/speed are embedded as suffixes, don't also show separate reasoning_effort param
const explicitEffort = displayModel === model ? reasoningEffort : "medium";
const examples = useMemo(
() => buildExamples(baseUrl, apiKey, displayModel, origin, explicitEffort),
[baseUrl, apiKey, displayModel, origin, explicitEffort]
);
const currentCode = examples[`${protocol}-${codeLang}`] || "Loading...";
const getCode = useCallback(() => currentCode, [currentCode]);
const protoActive =
"px-6 py-3 text-[0.82rem] font-semibold text-primary border-b-2 border-primary bg-white dark:bg-card-dark transition-colors";
const protoInactive =
"px-6 py-3 text-[0.82rem] font-medium text-slate-500 dark:text-text-dim hover:text-slate-700 dark:hover:text-text-main hover:bg-slate-50 dark:hover:bg-[#21262d] border-b-2 border-transparent transition-colors";
const langActive =
"px-3 py-1.5 text-xs font-semibold rounded bg-white dark:bg-[#21262d] text-slate-800 dark:text-text-main shadow-sm border border-transparent dark:border-border-dark transition-all";
const langInactive =
"px-3 py-1.5 text-xs font-medium rounded text-slate-500 dark:text-text-dim hover:text-slate-700 dark:hover:text-text-main hover:bg-white/50 dark:hover:bg-[#21262d] border border-transparent transition-all";
return (
<section class="flex flex-col gap-4">
<h2 class="text-[0.95rem] font-bold">{t("integrationExamples")}</h2>
<div class="bg-white dark:bg-card-dark border border-gray-200 dark:border-border-dark rounded-xl overflow-hidden shadow-sm transition-colors">
{/* Protocol Tabs */}
<div class="flex border-b border-gray-200 dark:border-border-dark bg-slate-50/50 dark:bg-bg-dark/30">
{protocols.map((p) => (
<button
key={p.id}
onClick={() => setProtocol(p.id)}
class={protocol === p.id ? protoActive : protoInactive}
>
{p.label}
</button>
))}
</div>
{/* Language Tabs & Code */}
<div class="p-5">
<div class="flex items-center justify-between mb-4">
<div class="flex gap-2 p-1 bg-slate-100 dark:bg-bg-dark dark:border dark:border-border-dark rounded-lg">
{langs.map((l) => (
<button
key={l.id}
onClick={() => setCodeLang(l.id)}
class={codeLang === l.id ? langActive : langInactive}
>
{l.label}
</button>
))}
</div>
</div>
{/* Code Block */}
<div class="relative group rounded-lg overflow-hidden bg-[#0d1117] text-slate-300 font-mono text-xs border border-slate-800 dark:border-border-dark">
<div class="absolute right-2 top-2 z-10 opacity-0 group-hover:opacity-100 transition-opacity">
<CopyButton getText={getCode} variant="label" />
</div>
<div class="p-4 overflow-x-auto">
<pre class="m-0"><code>{currentCode}</code></pre>
</div>
</div>
</div>
</div>
</section>
);
}