BazaarLink 文件
BazaarLink 是台灣的統一 AI API 閘道器 — 透過單一、與 OpenAI 相容的 API 端點,提供對 OpenAI、Anthropic、Google、Meta 等數百個模型的存取。
美元計費・統一發票・中文支援。企業財務零障礙,政府採購資格。
快速入門
五分鐘內開始使用。BazaarLink 與 OpenAI SDK 完全相容 — 只需更改
基礎 URL
https://bazaarlink.ai/api/v1
使用 OpenAI SDK
BazaarLink 與 OpenAI SDK 完全相容。只需更改 base URL 和 API 金鑰 — 所有其他程式碼保持不變。
from openai import OpenAI
client = OpenAI(
base_url="https://bazaarlink.ai/api/v1",
api_key="sk-bl-YOUR_API_KEY",
)
completion = client.chat.completions.create(
model="openai/gpt-4.1",
messages=[
{"role": "user", "content": "What is the meaning of life?"}
],
)
print(completion.choices[0].message.content)sk-bl-.✗ gpt-4.1 claude-sonnet-4-6 gemini-2.0-flash-001
身份驗證
所有 API 請求都需要在 Authorization 標頭中提供您的 API 金鑰。
Authorization: Bearer sk-bl-YOUR_API_KEY
從 儀表板取得您的 API 金鑰。請妥善保管金鑰 — 請勿在用戶端程式碼中暴露它。
選填標頭
設計原則
BazaarLink 圍繞三個核心原則設計:
1. 統一介面
一個 API、一個 SDK、數百個模型。只需更改模型 ID,無需修改程式碼,即可在 OpenAI、Anthropic、Google Gemini、Meta Llama 等之間切換。
2. 價格優化
BazaarLink 自動路由到您所選模型最具成本效益的供應商。您只需為實際使用量付費,以美元計費並提供完整發票支援。
3. 高可用性
自動故障轉移意味著若供應商服務中斷,您的請求會無縫重新路由。無需修改程式碼,無需停機。
多模態
BazaarLink 支援多模態輸入 — 將圖片、音訊和檔案與文字一起傳送至支援的模型。內容會直接傳送至上游供應商。
支援的模態
傳送圖片
使用 content 陣列格式搭配 image_url 部分。支援格式:PNG、JPEG、WebP 及 GIF(包含動態 GIF)。單一訊息可包含多張圖片,每張為獨立的 image_url 部分:
response = client.chat.completions.create(
model="openai/gpt-4.1",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What's in this image?"},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/photo.jpg",
"detail": "auto" # "low", "high", or "auto"
}
}
]
}
],
)
print(response.choices[0].message.content)圖片生成
使用 DALL·E、GPT-4o 等模型透過文字提示生成圖片。使用 `modalities` 參數透過 chat completions 端點請求圖片輸出。
支援的模型
| Model | Note |
|---|---|
| google/gemini-2.5-flash-image | 文字 + 圖片輸出(modalities: ["image", "text"]) |
| google/gemini-3-pro-image-preview | 高品質文字 + 圖片輸出 |
| black-forest-labs/flux.2-pro | 僅圖片 — 頂級品質 |
| black-forest-labs/flux.2-flex | 僅圖片 — 彈性比例 |
| sourceful/riverflow-v2-fast | 支援 font_inputs 和 super_resolution_references |
| openai/dall-e-3 | 透過 OpenAI 直接上游 |
使用 modalities 參數
傳入 `modalities: ["image"]` 或 `["image", "text"]` 即可請求圖片輸出。生成的圖片回傳於 `choices[0].message.images[]`,為 base64 資料 URI。
response = client.chat.completions.create(
model="google/gemini-2.5-flash-image",
messages=[{"role": "user", "content": "A serene mountain lake at sunrise"}],
modalities=["image", "text"], # ["image"] only for Flux / DALL-E
image_config={
"aspect_ratio": "16:9",
"image_size": "2K",
},
)
# Generated images are in message.images[], NOT in message.content
for img in response.choices[0].message.images:
data_uri = img["image_url"]["url"] # "data:image/png;base64,..."
# Text caption (when modalities includes "text")
print(response.choices[0].message.content)image_config 選項
透過選用的 image_config 參數精細調整圖片生成:
PDF 輸入
直接在訊息中傳送 PDF 文件,讓模型分析、摘要或回答問題。BazaarLink 會將檔案內容透傳至支援的上游供應商。
支援的格式
- PDF 文件(含文字、圖片、表格、掃描件)
- Base64 資料 URL(`data:application/pdf;base64,...`)
- 多頁文件
- 僅限無密碼保護的 PDF
import base64
with open("document.pdf", "rb") as f:
pdf_data = base64.b64encode(f.read()).decode()
response = client.chat.completions.create(
model="anthropic/claude-sonnet-4.6",
messages=[{
"role": "user",
"content": [
{
"type": "file",
"file": {
"filename": "document.pdf",
"file_data": f"data:application/pdf;base64,{pdf_data}",
},
},
{"type": "text", "text": "Summarize this document."},
],
}],
)處理引擎
選擇處理引擎
傳入 `plugins` 陣列可選擇 PDF 解析引擎。解析後的內容會自動注入模型上下文 — 適用於任何模型,不限 PDF 原生支援的模型。
import base64
with open("document.pdf", "rb") as f:
pdf_data = base64.b64encode(f.read()).decode()
response = client.chat.completions.create(
model="openai/gpt-4o", # any model — parser injects text into context
messages=[{
"role": "user",
"content": [
{
"type": "file",
"file": {
"filename": "report.pdf",
"file_data": f"data:application/pdf;base64,{pdf_data}",
},
},
{"type": "text", "text": "Summarize this document."},
],
}],
plugins=[{
"id": "file-parser",
"pdf": {"engine": "mistral-ocr"}, # or "pdf-text" (free), "native"
}],
)音訊輸入
傳送音訊內容讓模型轉錄、翻譯或分析。音訊必須以 base64 編碼資料形式放入訊息 content 陣列中傳送。
支援的格式
WAVMP3AIFFAACOGG(Opus / Vorbis)FLACM4APCM16(原始)PCM24(原始)import base64
with open("audio.wav", "rb") as f:
audio_b64 = base64.b64encode(f.read()).decode()
# audio_b64 is a raw base64 string — do NOT add data: prefix
response = client.chat.completions.create(
model="openai/gpt-4o-audio-preview",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Transcribe this audio:"},
{
"type": "input_audio",
"input_audio": {
"data": audio_b64, # raw base64, no "data:audio/...;base64," prefix
"format": "wav", # wav, mp3, flac, ogg, m4a, aac
},
},
],
}],
)
print(response.choices[0].message.content)影片輸入
傳送影片讓模型分析視覺內容、生成說明或回答場景與事件相關問題。目前透過 Gemini 模型提供支援。
支援的格式
MP4(H.264)MPEGMOVWebM供應商差異
- Google AI(gemini-*):支援 YouTube URL 和 Google Cloud Storage(gs://)URI。檔案大小限制:~1 GB / 最長 1 小時(Gemini 1.5 Pro);~50 MB / 5 分鐘(Gemini 1.5 Flash、2.0 Flash)。
- Vertex AI(gemini-* via vertex):支援 base64 編碼影片資料和 GCS URI。適合私有或企業儲存環境。
- 其他供應商:透過 URL 或 base64 傳送 MP4、MPEG、MOV、WebM(依模型而異)。
# Video analysis via Gemini (Google AI — direct video URL)
response = client.chat.completions.create(
model="google/gemini-2.5-flash",
messages=[{
"role": "user",
"content": [
{
"type": "video_url",
"video_url": {"url": "https://example.com/video.mp4"},
},
{"type": "text", "text": "What is happening in this video?"},
],
}],
)
# Via base64 — local file upload
import base64
with open("video.mp4", "rb") as f:
vid_b64 = base64.b64encode(f.read()).decode()
response = client.chat.completions.create(
model="google/gemini-2.5-flash",
messages=[{
"role": "user",
"content": [
{
"type": "video_url",
"video_url": {"url": f"data:video/mp4;base64,{vid_b64}"},
},
{"type": "text", "text": "Describe the key scenes."},
],
}],
)最佳實踐
- 僅保留必要片段 — 較短的影片可降低成本和延遲。
- 使用 720p 或更低解析度 — 更高解析度通常不會提升模型理解能力。
- 使用 H.264 編解碼器壓縮,以獲得最佳相容性。
- 對於長影片,請提供相關時間段的文字說明。
管理 API 金鑰
管理金鑰(Management Key)專用於程式化管理 API 金鑰:可建立、列出、更新、停用與刪除標準金鑰,但無法呼叫 AI 模型。
建立管理金鑰
在「API 金鑰」頁面建立金鑰時,選擇類型「Management」即可。
列出金鑰
GET https://bazaarlink.ai/api/v1/keys
Authorization: Bearer sk-bl-YOUR_MGMT_KEY
# Response
{
"keys": [
{
"id": "clxyz123...",
"name": "Production Key",
"keyType": "standard",
"keyPrefix": "sk-bl-abc1",
"keySuffix": "XyZ9",
"enabled": true,
"spendLimitUsd": 10.00,
"spendLimitPeriod": "month",
"expiresAt": null,
"createdAt": "2026-01-01T00:00:00.000Z",
"lastUsed": "2026-03-01T12:34:56.000Z",
"requestCount": 1234,
"totalTokens": 5678901
}
]
}建立子金鑰
POST https://bazaarlink.ai/api/v1/keys
Authorization: Bearer sk-bl-YOUR_MGMT_KEY
Content-Type: application/json
{
"name": "Agent Key",
"limit": 10.00,
"limit_reset": "monthly",
"expires_at": "2026-12-31T23:59:59Z"
}
# limit_reset: daily | weekly | monthly
# expires_at: ISO 8601 datetime (optional)
# Response — save the key value, it won't be shown again
{
"id": "clxyz789...",
"name": "Agent Key",
"key": "sk-bl-xyz789abcdef...",
"keyType": "standard",
"spendLimitUsd": 10.00,
"spendLimitPeriod": "month",
"expiresAt": "2026-12-31T23:59:59.000Z",
"enabled": true,
"createdAt": "2026-03-01T00:00:00.000Z"
}更新金鑰
PATCH https://bazaarlink.ai/api/v1/keys/:id
Authorization: Bearer sk-bl-YOUR_MGMT_KEY
Content-Type: application/json
{"enabled": false} # disable key
{"spendLimitUsd": 5, "spendLimitPeriod": "week"} # set spend limit
{"spendLimitUsd": null} # remove spend limit
# Response: {"updated": true}撤銷金鑰
DELETE https://bazaarlink.ai/api/v1/keys/:id Authorization: Bearer sk-bl-YOUR_MGMT_KEY # Returns 204 No Content on success
查詢餘額
GET https://bazaarlink.ai/api/v1/credits
Authorization: Bearer sk-bl-YOUR_MGMT_KEY
# Response
{
"data": {
"total_credits": 12.345,
"total_usage": 3.210
}
}查詢用量
GET https://bazaarlink.ai/api/v1/usage?period=month Authorization: Bearer sk-bl-YOUR_MGMT_KEY # period: day | week | month | year
應用程式識別
透過請求標頭識別您的應用程式,讓系統追蹤使用量、顯示在儀表板上,並在未來提供更細緻的分析。
可用標頭
| Header | Description |
|---|---|
| HTTP-Referer | 您的網站 URL,用於排行和分析(選填) |
| X-Title | 您的應用程式名稱,顯示在儀表板中(選填) |
from openai import OpenAI
client = OpenAI(
base_url="https://bazaarlink.ai/api/v1",
api_key="sk-bl-YOUR_KEY",
default_headers={
"HTTP-Referer": "https://yourapp.com", # Optional: your site URL
"X-Title": "My Application", # Optional: your app name
},
)
response = client.chat.completions.create(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
)回報問題
透過回報問題、錯誤或建議幫助我們改善 BazaarLink。我們積極監控所有回饋管道。
如何回報
應包含的資訊
- 請求 ID(來自回應 id 欄位)
- 使用的模型和傳送的參數
- 預期行為與實際行為
- 時間戳記和問題頻率
- 錯誤訊息或 HTTP 狀態碼
錯誤代碼
BazaarLink 使用標準 HTTP 狀態碼。錯誤回應遵循 OpenAI 格式:
{
"error": {
"message": "Invalid or disabled API key.",
"type": "invalid_request_error",
"code": 401
}
}錯誤處理
from openai import OpenAI, APIError, RateLimitError
client = OpenAI(
base_url="https://bazaarlink.ai/api/v1",
api_key="sk-bl-YOUR_API_KEY",
)
try:
response = client.chat.completions.create(
model="openai/gpt-4.1",
messages=[{"role": "user", "content": "Hello!"}],
)
except RateLimitError:
print("Rate limited — waiting before retry...")
except APIError as e:
print(f"API error {e.status_code}: {e.message}")串流錯誤格式
在任何 token 串流之前發生的錯誤,會以標準 HTTP 錯誤回應(JSON body)回傳。
串流過程中發生的錯誤,會以 SSE 事件形式傳送,finish_reason 為 "error"。請解析 delta 中的 error 欄位。
// Error chunk sent mid-stream (finish_reason: "error")
type MidStreamError = {
choices: [
{
index: 0;
finish_reason: "error";
delta: { content: "" };
native_finish_reason: null;
error: {
code: number;
message: string;
metadata?: {
provider_name?: string;
raw?: unknown;
};
};
}
];
};除錯
設定 debug.echo_upstream_body: true 可檢視實際傳送給上游 provider 的請求 body。轉換後的請求會作為第一個 SSE chunk 回傳。僅供開發與除錯使用,請勿在正式環境使用。
// Request with debug enabled (streaming only)
{
"model": "openai/gpt-4.1",
"messages": [{ "role": "user", "content": "Hello" }],
"stream": true,
"debug": { "echo_upstream_body": true }
}速率限制
速率限制以使用者為單位(非金鑰),以每分鐘請求數(RPM)計算。無每日上限。等級由帳戶點數餘額自動決定。
超過速率限制時,您會收到附有 Retry-After 標頭的 429 回應。重試時請使用指數退避策略。
Response Headers
Every successful response includes rate limit headers for client-side tracking:
X-RateLimit-Limit: 200 # Max requests per minute for your tier X-RateLimit-Remaining: 198 # Remaining requests in current window X-RateLimit-Reset: 1740000060 # Unix timestamp when the window resets X-Provider: anthropic # Which upstream provider served this request X-Request-Id: chatcmpl-abc123 # Unique request ID for debugging
常見問題
API 金鑰輪換
定期輪換 API 金鑰是安全最佳實踐。BazaarLink 支援零停機的金鑰輪換 — 先建立新金鑰並部署至應用程式,確認正常後再刪除舊金鑰,整個過程不中斷服務。
輪換步驟
- 建立新的 API 金鑰
- 更新您的應用程式或環境變數使用新金鑰
- 確認新金鑰正常運作
- 停用或刪除舊金鑰
# Step 1: Create new key
POST https://bazaarlink.ai/api/v1/keys
Authorization: Bearer sk-bl-OLD_KEY
{"name": "Production v2"}
# → saves new key: sk-bl-NEW_KEY_VALUE
# Step 2: Update your application
# export BAZAARLINK_API_KEY=sk-bl-NEW_KEY_VALUE
# Step 3: Verify new key works
curl https://bazaarlink.ai/api/v1/models \
-H "Authorization: Bearer sk-bl-NEW_KEY_VALUE"
# Step 4: Revoke old key
DELETE https://bazaarlink.ai/api/v1/keys/:old_key_id
Authorization: Bearer sk-bl-NEW_KEY_VALUE活動匯出
將完整 API 使用歷史下載為 CSV,用於財務審計、成本分析或合規報告。
CSV 匯出
登入後前往「使用記錄」頁面,點擊右上角的「Export CSV」按鈕,即可下載完整歷史記錄為 CSV 檔案。無需呼叫 API。
CSV 欄位
JSON 用量查詢(API)
如需程式化存取,可透過 API 查詢按期間、模型或金鑰分組的聚合統計:
# Query usage data (grouped / aggregated)
GET https://bazaarlink.ai/api/v1/usage
Authorization: Bearer sk-bl-YOUR_KEY
# With period filtering (day | week | month | year)
GET https://bazaarlink.ai/api/v1/usage?period=month
# Response
{
"period": "month",
"since": "2025-01-01T00:00:00.000Z",
"credits": 10.5000,
"totals": {
"spend": 0.1812,
"requests": 309,
"tokens": 161200,
"promptTokens": 95000,
"completionTokens": 66200
},
"byModel": [{ "model": "openai/gpt-4.1", "spend": 0.0028, "tokens": 1200, "requests": 5 }],
"byKey": [{ "keyName": "My Agent", "spend": 0.0028, "tokens": 1200, "requests": 5 }],
"byApp": [{ "appName": "MyApp", "spend": 0.0015, "tokens": 600, "requests": 3 }],
"timeSeries": [{ "date": "2025-01-15", "model": "openai/gpt-4.1", "cost": 0.0012, "tokens": 500, "requests": 2 }]
}用量統計
透過 API 查詢詳細的使用量統計,包括 token 消耗、成本分析和請求歷史記錄。
回應欄位說明
| Field | Type | Description |
|---|---|---|
| model | string | Model ID used (e.g., openai/gpt-4.1) |
| provider | string | Upstream provider name |
| prompt_tokens | number | Input tokens consumed |
| completion_tokens | number | Output tokens generated |
| total_tokens | number | Total tokens (prompt + completion) |
| reasoning_tokens | number | Reasoning tokens (for thinking models) |
| cached_tokens | number | Prompt tokens served from cache |
| cost | number | Total cost in NTD |
| duration_ms | number | End-to-end latency in milliseconds |
| throughput | number | Generation speed in tokens/sec |
| finish_reason | string | stop | length | content_filter | error |
| status | number | HTTP status code from upstream |
| app_name | string | null | Application name (X-Title header) |
| key_name | string | API key name used for the request |
import httpx
# Aggregated stats (Bearer token — period: day | week | month | year)
response = httpx.get(
"https://bazaarlink.ai/api/v1/usage",
headers={"Authorization": "Bearer sk-bl-YOUR_KEY"},
params={"period": "month"},
)
data = response.json()
totals = data["totals"]
print("This month: NT$%.4f (%d requests)" % (totals["spend"], totals["requests"]))
# Cost breakdown by model
for m in data["byModel"]:
print(" %s: NT$%.4f (%d reqs, %d tokens)" % (m["model"], m["spend"], m["requests"], m["tokens"]))OAuth PKCE BETA
OAuth 2.0 PKCE(Proof Key for Code Exchange)讓公開用戶端應用程式(瀏覽器 SPA、行動 App)能夠代表個別用戶呼叫 API,無需在用戶端儲存長效的伺服器密鑰。
何時使用 OAuth PKCE
- 建構需要每位用戶計費的瀏覽器 SPA 或行動 App
- 多租戶 SaaS — 每位終端用戶支付自己的 API 使用費用
- 無法在用戶端儲存共用密鑰(公開用戶端)
- 需要短效的、可撤銷的每用戶 Token,而非單一共用 API 金鑰
規劃中的流程(即將推出)
授權碼 + PKCE 流程(公開用戶端應用程式) · 每用戶差異化計費(各用戶僅為自己消耗的 Token 付費) · 每用戶速率限制,獨立於共用 API 金鑰 · 儀表板中的用戶級別使用量分析
步驟 1 — 發起認證
產生隨機的 code_verifier(長隨機字串)及其 SHA-256 雜湊值作為 code_challenge,然後將用戶重新導向至 BazaarLink 認證頁面。
// Generate PKCE code_verifier + code_challenge (Web Crypto API)
async function createCodeChallenge(verifier: string): Promise<string> {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const hash = await crypto.subtle.digest("SHA-256", data);
return btoa(String.fromCharCode(...new Uint8Array(hash)))
.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
}
// Generate a cryptographically random verifier (min 43 chars)
const codeVerifier = crypto.randomUUID().replace(/-/g, "") + crypto.randomUUID().replace(/-/g, "");
const codeChallenge = await createCodeChallenge(codeVerifier);
// Redirect user to BazaarLink auth page (planned endpoint)
const authUrl = new URL("https://bazaarlink.ai/api/oauth/authorize");
authUrl.searchParams.set("callback_url", "https://yourapp.com/callback");
authUrl.searchParams.set("code_challenge", codeChallenge);
authUrl.searchParams.set("code_challenge_method", "S256");
window.location.href = authUrl.toString();步驟 2 — 交換授權碼取得 API 金鑰
用戶授權後,BazaarLink 會將用戶重新導向至您的 callback_url 並附上一次性授權碼。將此授權碼與原始 code_verifier 一同 POST 送出,即可取得用戶專屬 API 金鑰。
// On your callback page — exchange the one-time code for an API key
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");
// Planned exchange endpoint (POST)
const response = await fetch("https://bazaarlink.ai/api/v1/oauth/token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
code,
code_verifier: codeVerifier, // saved from Step 1
code_challenge_method: "S256",
}),
});
const { key } = await response.json();
// key = "sk-bl-user-..." — store securely (e.g. encrypted localStorage)步驟 3 — 使用用戶專屬金鑰
回傳的金鑰與一般 BazaarLink API 金鑰相同,但範圍限定於個別用戶帳戶 — 使用量按用戶計費與限速。
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://bazaarlink.ai/api/v1",
apiKey: key, // user-scoped key from Step 2
});
const response = await client.chat.completions.create({
model: "openai/gpt-4.1",
messages: [{ role: "user", content: "Hello!" }],
});
// Usage is billed and rate-limited per individual user目前的替代方案
// Use a server-side API key until OAuth PKCE is available
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://bazaarlink.ai/api/v1",
apiKey: process.env.BAZAARLINK_API_KEY, // ⚠️ server-side only — never expose to the browser
});企業方案 BETA
BazaarLink 企業方案提供專用基礎設施、自訂 SLA 和進階支援,適用於高流量 AI 工作負載的組織。
企業功能
政府採購
BazaarLink 符合台灣政府採購資格。我們提供:
- 統一編號開立發票
- 政府格式報價單及合約
- 符合台灣資料常駐要求
- 支援政府採購招標流程
組織管理 BETA
組織管理功能讓企業客戶能夠管理多個團隊成員、設定存取權限、追蹤各部門的使用量,並統一管理帳單。
計畫功能
- 成員邀請與角色管理(管理員/開發者/只讀)
- 各成員的獨立 API 金鑰和使用量配額
- 部門級別的成本分攤
- 統一帳單和發票管理
- SSO(單一登入)整合
使用者追蹤 BETA
透過在請求中傳送使用者識別碼,追蹤各個終端用戶的使用量,實現細粒度的成本分配和用量限制。
計畫功能
- 依用戶 ID 追蹤 token 消耗
- 每用戶的速率限制和配額
- 用戶級別的費用報告
- 異常使用量警告
# Future: per-user tracking (coming soon)
# Pass a user identifier in requests to track per-user usage:
response = client.chat.completions.create(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
user="user-12345", # Your end-user's unique ID
)
# BazaarLink will track usage per user_id
# You'll be able to query per-user stats:
# GET /api/v1/usage?user_id=user-12345模型蒸餾 BETA
模型蒸餾讓您可以使用大型模型(教師模型)生成高品質的訓練資料,然後用這些資料微調較小的模型(學生模型),達到接近的效能但大幅降低成本。
計畫蒸餾工作流程
- 步驟 1:使用大型模型(GPT-4、Claude 3.5)生成高品質回應
- 步驟 2:BazaarLink 自動收集輸入/輸出對到資料集
- 步驟 3:觸發微調工作,使用收集的資料訓練小型模型
- 步驟 4:評估微調模型的品質並部署
# Current workflow: collect training data via BazaarLink, fine-tune elsewhere
import json
import httpx
# Step 1: Collect high-quality examples from a large model
examples = []
for prompt in your_prompts:
response = client.chat.completions.create(
model="openai/gpt-4o",
messages=[{"role": "user", "content": prompt}],
)
examples.append({
"messages": [
{"role": "user", "content": prompt},
{"role": "assistant", "content": response.choices[0].message.content},
]
})
# Step 2: Save as JSONL for fine-tuning
with open("training_data.jsonl", "w") as f:
for ex in examples:
f.write(json.dumps(ex) + "\n")
# Step 3: Fine-tune with OpenAI (or another provider)
# openai.fine_tuning.jobs.create(
# training_file="training_data.jsonl",
# model="gpt-4o-mini",
# )