Next.js+ai npm包调用OpenAI API,流式响应无换行如何格式化?
解决流式返回内容不换行的问题
前端渲染层处理
HTML默认会将文本中的换行符(\n)合并为空格,可通过以下两种方式修复:
- CSS样式快速处理
给消息容器添加white-space: pre-line样式,该样式会保留换行符并自动合并连续空格,适合纯文本格式的内容:
// 修改page.js中的消息渲染部分 {messages.map(m => ( <div key={m.id} style={{ whiteSpace: 'pre-line' }}> {m.role}: {m.content} </div> ))}
- 转换为HTML标签精确控制
如果需要区分单换行和段落分隔的双换行,可以将文本中的换行符替换为<br>标签,通过dangerouslySetInnerHTML渲染:
{messages.map(m => ( <div key={m.id}> <span>{m.role}: </span> <span dangerouslySetInnerHTML={{ __html: m.content.replace(/\n\n/g, '<br><br>').replace(/\n/g, '<br>') }} /> </div> ))}
注意:使用
dangerouslySetInnerHTML时需确保内容可信,避免XSS风险。
借助OpenAI的格式化输出
可以通过以下方式让OpenAI返回结构化的格式化内容:
- Prompt指定输出格式
在对话消息中明确要求模型返回Markdown格式,例如在系统消息中添加:
请使用Markdown格式回复,段落之间用空行分隔。
之后前端使用react-markdown库渲染Markdown内容:
// 先安装依赖:npm install react-markdown import ReactMarkdown from 'react-markdown'; // 渲染消息时 {messages.map(m => ( <div key={m.id}> {m.role}: <ReactMarkdown>{m.content}</ReactMarkdown> </div> ))}
- 使用Response Format参数(GPT-4-1106-preview+)
对于支持的模型,可通过response_format参数指定输出为JSON结构,再由前端解析渲染:
// 修改API路由中的调用逻辑 const response = await openai.chat.completions.create({ model: 'gpt-4-1106-preview', stream: true, messages: [ { role: 'system', content: '请返回包含paragraphs数组的JSON,每个元素是一段文本。' }, ...messages ], response_format: { type: 'json_object' }, });
修改后的完整示例代码
API路由(app/api/chat/route.js)
import OpenAI from 'openai'; import { OpenAIStream, StreamingTextResponse } from 'ai'; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); export const runtime = 'edge'; export async function POST(req) { const { messages } = await req.json(); const formattedMessages = [ { role: 'system', content: '请使用Markdown格式回复,段落之间用空行分隔。' }, ...messages ]; const response = await openai.chat.completions.create({ model: 'gpt-4', stream: true, messages: formattedMessages, }); const stream = OpenAIStream(response); return new StreamingTextResponse(stream); }
前端页面(app/page.js)
'use client'; import { useChat } from 'ai/react'; import ReactMarkdown from 'react-markdown'; export default function Chat() { const { messages, input, handleInputChange, handleSubmit } = useChat(); return ( <div> {messages.map(m => ( <div key={m.id} style={{ margin: '1rem 0' }}> <strong>{m.role}:</strong> <ReactMarkdown style={{ marginTop: '0.5rem' }}>{m.content}</ReactMarkdown> </div> ))} <form onSubmit={handleSubmit} style={{ marginTop: '2rem' }}> <input value={input} placeholder="Say something..." onChange={handleInputChange} style={{ padding: '0.5rem', width: '300px' }} /> <button type="submit" style={{ marginLeft: '0.5rem', padding: '0.5rem 1rem' }}>发送</button> </form> </div> ); }
内容的提问来源于stack exchange,提问作者Starfs
相关产品推荐
相关产品推荐

