今天我們要教大家如何讓之前做的ChatBox工具能夠連上OpenAI API。
不論你手上的key是舊的sk-xxxxx或新的sk-proj-xxxxx,都能順利運作。
我們會同時建立:
.env設定
# .env
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
OPENAI_PROJECT_ID=proj_xxxxxxxxxxxxxxxxxxxxx # 若你是 project key 才需要
PORT=3001
然後建立一個server.js
// server.js
import express from "express"
import fetch from "node-fetch"
import cors from "cors"
import dotenv from "dotenv"
dotenv.config()
const app = express()
app.use(cors())
app.use(express.json())
app.get("/", (req, res) => {
res.send("✅ ChatGPT Proxy Server 正常運作中!")
})
app.post("/api/chat", async (req, res) => {
try {
const apiKey = process.env.OPENAI_API_KEY
const projectId = process.env.OPENAI_PROJECT_ID
if (!apiKey) {
return res.status(400).json({ error: "❌ 缺少 OPENAI_API_KEY,請確認 .env 是否正確" })
}
// 根據 key 類型選擇正確 header
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
}
// 若為 project key(sk-proj 開頭),必須額外加上 project id
if (apiKey.startsWith("sk-proj") && projectId) {
headers["OpenAI-Project"] = projectId
}
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers,
body: JSON.stringify({
model: "gpt-4o-mini",
messages: req.body.messages,
}),
})
const data = await response.json()
res.status(response.status).json(data)
} catch (error) {
console.error("❌ Proxy error:", error)
res.status(500).json({ error: "Proxy server error" })
}
})
const PORT = process.env.PORT || 3001
app.listen(PORT, () => console.log(`🚀 Server running on http://localhost:${PORT}`))
讓server.js判斷你是用哪一種的api key
最後改動一下原本的chatbox
// src/pages/Chatbox.jsx
import { useState } from "react"
export default function Chatbox() {
const [input, setInput] = useState("")
const [messages, setMessages] = useState([
{ role: "assistant", content: "你好!我是 ChatGPT 助手 😊" },
])
const [loading, setLoading] = useState(false)
const [error, setError] = useState("")
const handleSend = async () => {
if (!input.trim()) return
const newMsg = { role: "user", content: input }
setMessages((prev) => [...prev, newMsg])
setInput("")
setError("")
setLoading(true)
try {
const res = await fetch("http://localhost:3001/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages: [...messages, newMsg] }),
})
if (!res.ok) {
const err = await res.json()
throw new Error(err.error?.message || `API 錯誤:${res.status}`)
}
const data = await res.json()
const reply = data.choices?.[0]?.message?.content || "⚠️ 沒有回應內容"
setMessages((prev) => [...prev, { role: "assistant", content: reply }])
} catch (err) {
setError(`⚠️ 聊天失敗:${err.message}`)
console.error(err)
} finally {
setLoading(false)
}
}
return (
<div className="space-y-4">
<h2 className="text-xl font-bold">💬 ChatGPT 聊天工具</h2>
<div className="bg-white p-4 rounded shadow space-y-2">
{messages.map((m, i) => (
<div
key={i}
className={`p-2 rounded ${
m.role === "user"
? "bg-blue-100 text-right"
: "bg-gray-100 text-left"
}`}
>
{m.content}
</div>
))}
{error && <p className="text-red-500">{error}</p>}
<div className="flex space-x-2 mt-3">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="輸入訊息..."
className="flex-1 border px-3 py-2 rounded"
/>
<button
onClick={handleSend}
disabled={loading}
className="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700 disabled:opacity-50"
>
{loading ? "發送中..." : "發送"}
</button>
</div>
</div>
</div>
)
}
今天我們讓ChatBox成功接上了OpenAI API。
為了支援兩種不同的金鑰(user key與project key),
我們在server.js中做了自動判斷:
若金鑰開頭是sk-proj→ 自動加上OpenAI-Project header。
若是一般的sk-→正常通過。
這樣無論是舊版或新版金鑰,都能讓你的chatbox變成真正能聊天的chatbox!