山东大学软件学院创新实训 易学探索助手开发记录

性能优化:修改古文句读功能和翻译功能为流式输出

一、问题说明

在实现古籍处理功能时,为进一步优化用户体验,缩短用户等待时间,我将古文句读功能和翻译功能修改为流式输出,替换了不能关闭思考功能的api,使用支持流式输出的deepseek api。


二、核心实现方案

1. 技术架构图

[前端] --(EventSource)--> [Spring Boot SSE端点] --(HTTP流)--> [Deepseek API]

2. 后端关键实现(Java)

关键点解析:

  1. 编码强制指定

    • 请求头显式声明UTF-8
    .header("Content-Type", "application/json; charset=UTF-8")
    
    • 请求体使用UTF-8编码
    HttpRequest.BodyPublishers.ofString(requestBody, StandardCharsets.UTF_8)
    
  2. 响应流处理

    • 使用ofLines()按行处理响应数据
    HttpResponse.BodyHandlers.ofLines()
    
    • 过滤心跳包与结束标记
    if(line.trim().isEmpty() || line.contains("[DONE]")) return;
    
  3. SSE数据推送

    • 二进制方式发送UTF-8数据
    byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
    emitter.send(SseEmitter.event().data(contentBytes, MediaType.TEXT_EVENT_STREAM));
    

3. 前端关键实现(Vue3)

const startSse = (taskId) => {
  const eventSource = new EventSource(`/api/sentenceStream/${taskId}`);

  eventSource.onmessage = (event) => {
    const processedContent = event.data.replace(/<br\s*\/?>/gi, '\n');
    segmentedText.value += processedContent;
  };
}

关键点解析:

  1. 换行符处理
    使用正则表达式替换HTML换行标记

    replace(/<br\s*\/?>/gi, '\n')
    
  2. 连接生命周期管理

    • onopen:连接建立日志
    • onerror:异常处理
    • onclose:状态重置

三、踩坑与解决方案

1. 中文字符乱码问题

现象:返回内容出现乱码,传送到前端的内容全部显示为问号(?)。
原因排查

  • HTTP请求未显式指定编码格式
  • SSE数据传输未使用二进制方式

解决方案

// 关键修正代码
byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
emitter.send(SseEmitter.event().data(contentBytes, MediaType.TEXT_EVENT_STREAM));

2. 流式响应中断问题

现象:长文本响应中途断开
优化方案

  • 设置Long.MAX_VALUE超时时间
SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);

3. 换行符渲染问题

现象\n在HTML中不换行
解决方案
前端替换为<br/>后,再通过CSS控制渲染:

.white-space-pre {
  white-space: pre-wrap;
}

四、总结

通过本次实践我们得出以下结论:

  1. 字符编码问题需要全链路统一处理
  2. SSE非常适合实时显示场景
  3. Spring Boot的SseEmitter提供了简洁的API
posted @ 2025-05-24 21:37  htekye  阅读(104)  评论(0)    收藏  举报