安装AI工具包
安装依赖项
npm install ai @ai-sdk/react zod配置.env
app/api/chat/route.tsimport { convertToModelMessages, streamText, UIMessage } from "ai"; import { createDeepSeek } from "@ai-sdk/deepseek"; // Allow streaming responses up to 30 seconds export const maxDuration = 30; const deepseek = createDeepSeek({ apiKey: process.env.DEEPSEEK_API_KEY ?? "", baseURL: process.env.DEEPSEEK_BASE_URL ?? "", }); export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } = await req.json(); const result = streamText({ model: deepseek("deepseek-chat"), system: "You are a helpful assistant.", messages: await convertToModelMessages(messages), }); return result.toUIMessageStreamResponse(); }页面
page.tsx"use client"; import { useChat } from "@ai-sdk/react"; import { useEffect, useRef, useState } from "react"; import EastIcon from "@mui/icons-material/East"; export default function Page() { const [model, setModel] = useState("deepseek-v3"); const [input, setInput] = useState(""); const { messages, sendMessage } = useChat({}); const handleChangeModel = () => { setModel(model === "deepseek-v3" ? "deepseek-r1" : "deepseek-v3"); }; const handleSubmit = () => { if (input.trim()) { sendMessage({ text: input }); setInput(""); } }; const endRef = useRef<HTMLDivElement>(null); useEffect(() => { if (endRef.current) { endRef?.current?.scrollIntoView({ behavior: "smooth" }); } }, [messages]); return ( <div className="flex flex-col h-screen justify-between items-center"> <div className="flex flex-col w-2/3 gap-8 overflow-y-auto justify-between flex-1"> <div className="h-4"></div> <div className="flex flex-col gap-8 flex-1"> {messages?.map((message) => ( <div key={message.id} className={`rounded-lg flex flex-row ${message?.role === "assistant" ? "justify-start mr-18" : "justify-end ml-10"}`} > <p className={`inline-block p-2 rounded-lg ${message?.role === "assistant" ? "bg-blue-300" : "bg-slate-100"}`} > {message.parts.map((part, index) => part.type === "text" ? ( <span key={index}>{part.text}</span> ) : null, )} </p> </div> ))} </div> <div className="h-4" ref={endRef}></div> </div> {/* 输入框 */} <div className="flex flex-col items-center justify-center mt-4 shadow-lg border-[1px] border-gray-300 h-32 rounded-lg w-2/3"> <textarea className="w-full rounded-lg p-3 h-30 focus:outline-none" value={input} onChange={(e) => setInput(e.target.value)} ></textarea> <div className="flex flex-row items-center justify-between w-full h-12 mb-2"> <div> <div className={`flex flex-row items-center justify-center rounded-lg border-[1px] px-2 py-1 ml-2 cursor-pointer ${model === "deepseek-r1" ? "border-blue-300 bg-blue-200" : "border-gray-300"}`} onClick={handleChangeModel} > <p className="text-sm">深度思考(R1)</p> </div> </div> <div className="flex items-center justify-center border-2 mr-4 border-black p-1 rounded-full" onClick={handleSubmit} > <EastIcon></EastIcon> </div> </div> </div> </div> ); }