Android 仿 DeepSeek 思考效果:逐字显示 AI 生成内容,支持加粗、颜色,复制内容

最近特别火的非AI莫属了,对我们高级搬运工太友好了,不管是网页端还是APP端,输入你要问的问题,都会逐字给你显示出来,有的还会加粗,这种效果看着不错,今天就带大家一起来实现。有啥更好的建议请在评论区留言。

首先我们要了解,这种数据不像平常调用接口返的,一下子都给你返了,这里会用到接口返回 EventStream 结构的数据(即接收读取 stream 流)

HTTP 的 EventStream 格式(也称为 Server-Sent Events,SSE)

是一种服务器向客户端推送实时数据的轻量级协议,基于 HTTP 长连接实现。以下是其核心特点和格式解析:

基本原理 使用 HTTP/1.1 长连接,默认保持连接状态 服务器主动向客户端发送数据,客户端单向接收 基于文本流传输,内容类型为text/event-stream 数据格式 每条消息由多个字段组成,字段间用空行分隔,示例:

cpp 复制代码
id: 123          // 事件ID
event: message   // 事件类型(可选)
data: Hello World// 数据内容
retry: 10000     // 重连时间(毫秒)

核心优势 简单易用:基于标准 HTTP 协议,无需复杂握手 自动重连:客户端支持自动恢复连接 低开销:文本格式传输,比 WebSocket 更轻量 支持持久连接:默认保持连接状态 与 WebSocket 对比

特性 EventStream (SSE) WebSocket
方向 单向(服务器→客户端) 全双工
协议 HTTP ws/wss
数据格式 文本流 二进制 / 文本
浏览器支持 原生支持 需 JS 实现

典型应用场景 实时通知(新闻推送、消息提醒) 股票行情更新 日志监控系统 在线协作编辑 注意事项 处理连接中断:需实现重连机制 内存管理:避免长时间占用资源 数据解析:注意处理分块传输编码 线程安全:确保 UI 更新在主线程 在 Android 开发中,建议使用okhttp或Retrofit库处理 EventStream,配合协程或 RxJava 进行异步处理,保证主线程不阻塞。对于复杂场景,可封装 SSE 客户端类,实现自动重连、事件分发等功能。

EventStream 的关键点

基于 HTTP,使用 text/event-stream 媒体类型,每个事件由多个字段组成,如 id、event、data 等,支持分块传输,适合实时更新。同时,要提到与 WebSocket 的区别,比如 SSE 是单向的,而 WebSocket 是全双工的,这样用户能更好地理解适用场景。

效果图

网页版 APP端

开始实现

一、自定义TextView

kotlin 复制代码
package com.example.testdemo

import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.Typeface
import android.net.Uri
import android.text.*
import android.text.style.AlignmentSpan
import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.StyleSpan
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.widget.ScrollView
import android.os.Handler
import android.os.Looper
import android.text.method.ScrollingMovementMethod
import androidx.appcompat.widget.AppCompatTextView

class DeepSeekTextView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AppCompatTextView(context, attrs, defStyleAttr) {

    private val mainHandler = Handler(Looper.getMainLooper())
    private val contentBuilder = SpannableStringBuilder()
    private val tempContentList = mutableListOf<String>()
    private var currentLineStart = 0
    private val normalTextColor = Color.parseColor("#8A9098") // 非加粗文本颜色

    init {
        movementMethod = ScrollingMovementMethod()
        highlightColor = resources.getColor(android.R.color.transparent, null)
        isClickable = true
        isFocusable = true
        isLongClickable = false
    }

    fun appendContent(content: String) {
        mainHandler.post {
            tempContentList.add(content)
            val combinedContent = tempContentList.joinToString("")
            processContent(combinedContent)
        }
    }

    private fun processContent(content: String) {
        contentBuilder.clear()
        var isBold = false
        var startIndex = 0
        for (i in content.indices) {
            if (i <= content.length - 2 && content[i] == '*' && content[i + 1] == '*') {
                if (isBold) {
                    // 结束加粗
                    val boldText = content.substring(startIndex, i)
                    addTextWithStyle(boldText, true)
                    isBold = false
                    startIndex = i + 2
                } else {
                    // 开始加粗
                    val normalText = content.substring(startIndex, i)
                    addTextWithStyle(normalText, false)
                    isBold = true
                    startIndex = i + 2
                }
            }
        }
        // 处理最后一段文本
        val lastText = content.substring(startIndex)
        addTextWithStyle(lastText, isBold)

        // 处理 Markdown 链接
        handleMarkdownLinks()

        // 处理换行
        if (content.contains("\n")) {
            handleNewLine()
        }

        text = contentBuilder
        (parent as? ScrollView)?.let { scrollView ->
            scrollView.post {
                scrollView.fullScroll(ScrollView.FOCUS_DOWN)
            }
        }
    }

    private fun addTextWithStyle(text: String, isBold: Boolean) {
        if (text.isNotEmpty()) {
            val start = contentBuilder.length
            contentBuilder.append(text)
            if (isBold) {
                contentBuilder.setSpan(
                    BoldAndBlackSpan(),
                    start,
                    contentBuilder.length,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                )
            } else {
                contentBuilder.setSpan(
                    ForegroundColorSpan(normalTextColor),
                    start,
                    contentBuilder.length,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                )
            }
        }
    }

    private fun handleMarkdownLinks() {
        val text = contentBuilder.toString()
        val linkPattern = "\\[(.*?)\\]\\((.*?)\\)".toRegex()
        val matches = linkPattern.findAll(text)
        for (match in matches) {
            val linkText = match.groupValues[1]
            val linkUrl = match.groupValues[2]
            val start = match.range.first
            val end = match.range.last + 1

            // 删除原 Markdown 格式
            contentBuilder.delete(start, end)

            // 插入链接文本
            contentBuilder.insert(start, linkText)

            // 设置点击事件
            contentBuilder.setSpan(
                object : ClickableSpan() {
                    override fun onClick(widget: View) {
                        val intent = Intent(Intent.ACTION_VIEW)
                        intent.data = Uri.parse(linkUrl)
                        context.startActivity(intent)
                    }

                    override fun updateDrawState(ds: android.text.TextPaint) {
                        super.updateDrawState(ds)
                        ds.color = Color.BLUE
                        ds.isUnderlineText = true
                    }
                },
                start,
                start + linkText.length,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
            )
        }
    }

    private fun handleNewLine() {
        val lineBreaks = contentBuilder.toString().split("\n").size - 1
        if (lineBreaks > 0) {
            currentLineStart = contentBuilder.length - lineBreaks
            contentBuilder.setSpan(
                AlignmentSpan.Standard(android.text.Layout.Alignment.ALIGN_NORMAL),
                currentLineStart,
                contentBuilder.length,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
            )
        }
    }

    fun clear() {
        mainHandler.post {
            contentBuilder.clear()
            tempContentList.clear()
            text = ""
        }
    }

    private class BoldAndBlackSpan : StyleSpan(Typeface.BOLD) {
        override fun updateDrawState(ds: TextPaint) {
            super.updateDrawState(ds)
            ds.color = Color.BLACK
            ds.typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
        }
    }

    // 重写 onTouchEvent 方法,确保点击事件传递到 ClickableSpan
    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                // 处理点击按下事件
                val x = event.x.toInt()
                val y = event.y.toInt()
                val layout = layout
                val line = layout.getLineForVertical(y)
                val offset = layout.getOffsetForHorizontal(line, x.toFloat())
                val spans = contentBuilder.getSpans(offset, offset, ClickableSpan::class.java)
                if (spans.isNotEmpty()) {
                    spans[0].onClick(this)
                    return true
                }
            }
            else -> {
                // 其他事件由父类处理
            }
        }
        return super.onTouchEvent(event)
    }

    // 重写 performLongClick 方法,禁止长按
    override fun performLongClick(): Boolean {
        return false
    }
}

二、事件流的处理(写死的数据)

cpp 复制代码
package com.example.testdemo

import android.os.Handler
import android.os.Looper
import org.json.JSONObject
 /**
  * @author: Created by J
  * @desc: 事件流的处理
  */
class MockEventStreamProcessor(private val textView: DeepSeekTextView) {

    private val handler = Handler(Looper.getMainLooper())
    private val mockData = MockData.data

    private var typingSpeed = 100L // 默认打字速度,单位为毫秒

    fun startProcessing() {
        var index = 0

        val runnable = object : Runnable {
            override fun run() {
                if (index < mockData.size) {
                    val dataLine = mockData[index]
                    handleData(dataLine)
                    index++
                    handler.postDelayed(this, typingSpeed)
                } else {
                    // 处理完成事件
                    textView.appendContent("")
                }
            }
        }

        handler.post(runnable)
    }

    private fun handleData(data: String) {
        try {
            val lines = data.split("\n")
            if (lines.size == 2 && lines[0].startsWith("event:") && lines[1].startsWith("data:")) {
                val eventType = lines[0].substring(6)
                val dataJson = JSONObject(lines[1].substring(5))
                val content = dataJson.getString("content")

                when (eventType) {
                    "thinkingProcess" -> textView.appendContent(content)
                    "finalResult" -> textView.appendContent(content)
                    "done" -> handler.removeCallbacksAndMessages(null)
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    // 设置打字速度的方法
    fun setTypingSpeed(speed: Long) {
        this.typingSpeed = speed
    }
}

三、布局

cpp 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:orientation="vertical"
    android:padding="10dp"
    tools:context=".MainActivity">

    <androidx.core.widget.NestedScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:descendantFocusability="beforeDescendants"
        android:fillViewport="true">

        <com.example.testdemo.DeepSeekTextView
            android:id="@+id/deepSeekTv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:lineSpacingExtra="4sp"
            android:paddingBottom="32dp"
            android:scrollbars="vertical"
            android:textSize="13sp" />

    </androidx.core.widget.NestedScrollView>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/black" />

    <Button
        android:id="@+id/startButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="点击开始思考"
        android:textSize="16sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/clearButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="清空内容"
            android:textSize="16sp" />

        <Button
            android:id="@+id/copyButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_weight="1"
            android:text="复制内容"
            android:textSize="16sp" />

    </LinearLayout>

</LinearLayout>

四、调用,包括 开始思考,清空内容插入新内容,复制内容

cpp 复制代码
package com.example.testdemo

import android.annotation.SuppressLint
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.widget.Button
import android.widget.Toast

class MainActivity : AppCompatActivity() {
    @SuppressLint("MissingInflatedId")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val deepSeekTv = findViewById<DeepSeekTextView>(R.id.deepSeekTv)

        val startButton = findViewById<Button>(R.id.startButton)
        val copyButton = findViewById<Button>(R.id.copyButton)
        val clearButton = findViewById<Button>(R.id.clearButton)
        val mockProcessor = MockEventStreamProcessor(deepSeekTv)

        startButton.setOnClickListener {

            // 设置打字速度(可选)
//         mockProcessor.setTypingSpeed(150)

            mockProcessor.startProcessing()
            // 开启点击监听
            deepSeekTv.movementMethod = LinkMovementMethod.getInstance()
        }
        clearButton.setOnClickListener {
            deepSeekTv.clear()
            val newContent = "这是新的文本内容..."
            deepSeekTv.appendContent(newContent)
        }


        copyButton.setOnClickListener {

            val textToCopy = deepSeekTv.text.toString()
            if (textToCopy.isEmpty()) {
                Toast.makeText(this, "没有可复制的内容", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }

            val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
            val clip = ClipData.newPlainText("Copied Text", textToCopy)
            clipboard.setPrimaryClip(clip)
            Toast.makeText(this, "已复制到剪贴板", Toast.LENGTH_SHORT).show()

        }


    }

}

五、模拟数据

cpp 复制代码
package com.example.testdemo

/** 模拟数据 */
object MockData {
    val data = listOf(
        "event:thinkingProcess\ndata:{\"content\":\"好的\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"用户\"}",
        "event:thinkingProcess\ndata:{\"content\":\"之前\"}",
        "event:thinkingProcess\ndata:{\"content\":\"问\"}",
        "event:thinkingProcess\ndata:{\"content\":\"今天\"}",
        "event:thinkingProcess\ndata:{\"content\":\"火星\"}",
        "event:thinkingProcess\ndata:{\"content\":\"的\"}",
        "event:thinkingProcess\ndata:{\"content\":\"天气\"}",
        "event:thinkingProcess\ndata:{\"content\":\"怎么样\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"我\"}",
        "event:thinkingProcess\ndata:{\"content\":\"回答\"}",
        "event:thinkingProcess\ndata:{\"content\":\"不会\"}",
        "event:thinkingProcess\ndata:{\"content\":\"。\"}",
        "event:thinkingProcess\ndata:{\"content\":\"现在\"}",
        "event:thinkingProcess\ndata:{\"content\":\"用户\"}",
        "event:thinkingProcess\ndata:{\"content\":\"输入\"}",
        "event:thinkingProcess\ndata:{\"content\":\""\"}",
        "event:thinkingProcess\ndata:{\"content\":\"al\"}",
        "event:thinkingProcess\ndata:{\"content\":\"",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"可能是\"}",
        "event:thinkingProcess\ndata:{\"content\":\""\"}",
        "event:thinkingProcess\ndata:{\"content\":\"请\"}",
        "event:thinkingProcess\ndata:{\"content\":\"详细\"}",
        "event:thinkingProcess\ndata:{\"content\":\"说明\"}",
        "event:thinkingProcess\ndata:{\"content\":\""\"}",
        "event:thinkingProcess\ndata:{\"content\":\"或者\"}",
        "event:thinkingProcess\ndata:{\"content\":\"拼\"}",
        "event:thinkingProcess\ndata:{\"content\":\"写\"}",
        "event:thinkingProcess\ndata:{\"content\":\"错误\"}",
        "event:thinkingProcess\ndata:{\"content\":\"。\"}",
        "event:thinkingProcess\ndata:{\"content\":\"首先\"}",
        "event:thinkingProcess\ndata:{\"content\":\"需要\"}",
        "event:thinkingProcess\ndata:{\"content\":\"判断\"}",
        "event:thinkingProcess\ndata:{\"content\":\"用户\"}",
        "event:thinkingProcess\ndata:{\"content\":\"意图\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"可能\"}",
        "event:thinkingProcess\ndata:{\"content\":\"想\"}",
        "event:thinkingProcess\ndata:{\"content\":\"让我\"}",
        "event:thinkingProcess\ndata:{\"content\":\"进一步\"}",
        "event:thinkingProcess\ndata:{\"content\":\"解释\"}",
        "event:thinkingProcess\ndata:{\"content\":\"为什么\"}",
        "event:thinkingProcess\ndata:{\"content\":\"无法\"}",
        "event:thinkingProcess\ndata:{\"content\":\"回答\"}",
        "event:thinkingProcess\ndata:{\"content\":\"火星\"}",
        "event:thinkingProcess\ndata:{\"content\":\"天气\"}",
        "event:thinkingProcess\ndata:{\"content\":\"的问题\"}",
        "event:thinkingProcess\ndata:{\"content\":\"。\"}",
        "event:thinkingProcess\ndata:{\"content\":\"\\n\\n\"}",
        "event:thinkingProcess\ndata:{\"content\":\"然后\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"我应该\"}",
        "event:thinkingProcess\ndata:{\"content\":\"考虑\"}",
        "event:thinkingProcess\ndata:{\"content\":\"用户\"}",
        "event:thinkingProcess\ndata:{\"content\":\"可能的\"}",
        "event:thinkingProcess\ndata:{\"content\":\"真实\"}",
        "event:thinkingProcess\ndata:{\"content\":\"需求\"}",
        "event:thinkingProcess\ndata:{\"content\":\"。\"}",
        "event:thinkingProcess\ndata:{\"content\":\"他们\"}",
        "event:thinkingProcess\ndata:{\"content\":\"可能\"}",
        "event:thinkingProcess\ndata:{\"content\":\"对\"}",
        "event:thinkingProcess\ndata:{\"content\":\"火星\"}",
        "event:thinkingProcess\ndata:{\"content\":\"感兴趣\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"或者\"}",
        "event:thinkingProcess\ndata:{\"content\":\"需要\"}",
        "event:thinkingProcess\ndata:{\"content\":\"了解\"}",
        "event:thinkingProcess\ndata:{\"content\":\"如何\"}",
        "event:thinkingProcess\ndata:{\"content\":\"获取\"}",
        "event:thinkingProcess\ndata:{\"content\":\"火星\"}",
        "event:thinkingProcess\ndata:{\"content\":\"天气\"}",
        "event:thinkingProcess\ndata:{\"content\":\"数据\"}",
        "event:thinkingProcess\ndata:{\"content\":\"的方法\"}",
        "event:thinkingProcess\ndata:{\"content\":\"。\"}",
        "event:thinkingProcess\ndata:{\"content\":\"因此\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"我需要\"}",
        "event:thinkingProcess\ndata:{\"content\":\"解释\"}",
        "event:thinkingProcess\ndata:{\"content\":\"当前\"}",
        "event:thinkingProcess\ndata:{\"content\":\"的技术\"}",
        "event:thinkingProcess\ndata:{\"content\":\"限制\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"比如\"}",
        "event:thinkingProcess\ndata:{\"content\":\"火星\"}",
        "event:thinkingProcess\ndata:{\"content\":\"探测器\"}",
        "event:thinkingProcess\ndata:{\"content\":\"的作用\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"以及\"}",
        "event:thinkingProcess\ndata:{\"content\":\"相关\"}",
        "event:thinkingProcess\ndata:{\"content\":\"数据的\"}",
        "event:thinkingProcess\ndata:{\"content\":\"来源\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"比如\"}",
        "event:thinkingProcess\ndata:{\"content\":\"NASA\"}",
        "event:thinkingProcess\ndata:{\"content\":\"的\"}",
        "event:thinkingProcess\ndata:{\"content\":\"网站\"}",
        "event:thinkingProcess\ndata:{\"content\":\"。\\n\\n\"}",
        "event:thinkingProcess\ndata:{\"content\":\"还要\"}",
        "event:thinkingProcess\ndata:{\"content\":\"确保\"}",
        "event:thinkingProcess\ndata:{\"content\":\"回答\"}",
        "event:thinkingProcess\ndata:{\"content\":\"有帮助\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"可能\"}",
        "event:thinkingProcess\ndata:{\"content\":\"建议\"}",
        "event:thinkingProcess\ndata:{\"content\":\"用户\"}",
        "event:thinkingProcess\ndata:{\"content\":\"访问\"}",
        "event:thinkingProcess\ndata:{\"content\":\"NASA\"}",
        "event:thinkingProcess\ndata:{\"content\":\"官网\"}",
        "event:thinkingProcess\ndata:{\"content\":\"获取\"}",
        "event:thinkingProcess\ndata:{\"content\":\"最新\"}",
        "event:thinkingProcess\ndata:{\"content\":\"信息\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"或者\"}",
        "event:thinkingProcess\ndata:{\"content\":\"解释\"}",
        "event:thinkingProcess\ndata:{\"content\":\"火星\"}",
        "event:thinkingProcess\ndata:{\"content\":\"天气\"}",
        "event:thinkingProcess\ndata:{\"content\":\"监测\"}",
        "event:thinkingProcess\ndata:{\"content\":\"的\"}",
        "event:thinkingProcess\ndata:{\"content\":\"现状\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"比如\"}",
        "event:thinkingProcess\ndata:{\"content\":\"毅力\"}",
        "event:thinkingProcess\ndata:{\"content\":\"号\"}",
        "event:thinkingProcess\ndata:{\"content\":\"探测\"}",
        "event:thinkingProcess\ndata:{\"content\":\"器的\"}",
        "event:thinkingProcess\ndata:{\"content\":\"实时\"}",
        "event:thinkingProcess\ndata:{\"content\":\"数据\"}",
        "event:thinkingProcess\ndata:{\"content\":\"更新\"}",
        "event:thinkingProcess\ndata:{\"content\":\"情况\"}",
        "event:thinkingProcess\ndata:{\"content\":\"。\"}",
        "event:thinkingProcess\ndata:{\"content\":\"同时\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"保持\"}",
        "event:thinkingProcess\ndata:{\"content\":\"回答\"}",
        "event:thinkingProcess\ndata:{\"content\":\"简洁\"}",
        "event:thinkingProcess\ndata:{\"content\":\"易懂\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"避免\"}",
        "event:thinkingProcess\ndata:{\"content\":\"使用\"}",
        "event:thinkingProcess\ndata:{\"content\":\"太\"}",
        "event:thinkingProcess\ndata:{\"content\":\"专业的\"}",
        "event:thinkingProcess\ndata:{\"content\":\"术语\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"让\"}",
        "event:thinkingProcess\ndata:{\"content\":\"用户\"}",
        "event:thinkingProcess\ndata:{\"content\":\"明白\"}",
        "event:thinkingProcess\ndata:{\"content\":\"虽然\"}",
        "event:thinkingProcess\ndata:{\"content\":\"现在\"}",
        "event:thinkingProcess\ndata:{\"content\":\"不能\"}",
        "event:thinkingProcess\ndata:{\"content\":\"实时\"}",
        "event:thinkingProcess\ndata:{\"content\":\"提供\"}",
        "event:thinkingProcess\ndata:{\"content\":\",\"}",
        "event:thinkingProcess\ndata:{\"content\":\"但有\"}",
        "event:thinkingProcess\ndata:{\"content\":\"途径\"}",
        "event:thinkingProcess\ndata:{\"content\":\"可以\"}",
        "event:thinkingProcess\ndata:{\"content\":\"获取\"}",
        "event:thinkingProcess\ndata:{\"content\":\"这些\"}",
        "event:thinkingProcess\ndata:{\"content\":\"信息\"}",
        "event:thinkingProcess\ndata:{\"content\":\"。\\n\"}",
        "event:finalResult\ndata:{\"content\":\"\\n\\n\"}",
        "event:finalResult\ndata:{\"content\":\"目前\"}",
        "event:finalResult\ndata:{\"content\":\",\"}",
        "event:finalResult\ndata:{\"content\":\"我\"}",
        "event:finalResult\ndata:{\"content\":\"无法\"}",
        "event:finalResult\ndata:{\"content\":\"实时\"}",
        "event:finalResult\ndata:{\"content\":\"获取\"}",
        "event:finalResult\ndata:{\"content\":\"火星\"}",
        "event:finalResult\ndata:{\"content\":\"的\"}",
        "event:finalResult\ndata:{\"content\":\"天气\"}",
        "event:finalResult\ndata:{\"content\":\"数据\"}",
        "event:finalResult\ndata:{\"content\":\",\"}",
        "event:finalResult\ndata:{\"content\":\"但\"}",
        "event:finalResult\ndata:{\"content\":\"可以通过\"}",
        "event:finalResult\ndata:{\"content\":\"以下\"}",
        "event:finalResult\ndata:{\"content\":\"信息\"}",
        "event:finalResult\ndata:{\"content\":\"帮助你\"}",
        "event:finalResult\ndata:{\"content\":\"了解\"}",
        "event:finalResult\ndata:{\"content\":\"火星\"}",
        "event:finalResult\ndata:{\"content\":\"天气\"}",
        "event:finalResult\ndata:{\"content\":\"相关的\"}",
        "event:finalResult\ndata:{\"content\":\"知识\"}",
        "event:finalResult\ndata:{\"content\":\":\\n\\n\"}",
        "event:finalResult\ndata:{\"content\":\"1\"}",
        "event:finalResult\ndata:{\"content\":\"。\"}",
        "event:finalResult\ndata:{\"content\":\" **\"}",
        "event:finalResult\ndata:{\"content\":\"火星\"}",
        "event:finalResult\ndata:{\"content\":\"天气\"}",
        "event:finalResult\ndata:{\"content\":\"特点\"}",
        "event:finalResult\ndata:{\"content\":\"**\"}",
        "event:finalResult\ndata:{\"content\":\":\"}",
        "event:finalResult\ndata:{\"content\":\"  \\n\"}",
        "event:finalResult\ndata:{\"content\":\"   \"}",
        "event:finalResult\ndata:{\"content\":\"火星\"}",
        "event:finalResult\ndata:{\"content\":\"大气\"}",
        "event:finalResult\ndata:{\"content\":\"稀\"}",
        "event:finalResult\ndata:{\"content\":\"薄\"}",
        "event:finalResult\ndata:{\"content\":\"(\"}",
        "event:finalResult\ndata:{\"content\":\"主要\"}",
        "event:finalResult\ndata:{\"content\":\"成\"}",
        "event:finalResult\ndata:{\"content\":\"分为\"}",
        "event:finalResult\ndata:{\"content\":\"二氧化碳\"}",
        "event:finalResult\ndata:{\"content\":\"),\"}",
        "event:finalResult\ndata:{\"content\":\"平均\"}",
        "event:finalResult\ndata:{\"content\":\"温度\"}",
        "event:finalResult\ndata:{\"content\":\"约\"}",
        "event:finalResult\ndata:{\"content\":\"-\"}",
        "event:finalResult\ndata:{\"content\":\"63\"}",
        "event:finalResult\ndata:{\"content\":\"℃,\"}",
        "event:finalResult\ndata:{\"content\":\"昼夜\"}",
        "event:finalResult\ndata:{\"content\":\"温差\"}",
        "event:finalResult\ndata:{\"content\":\"极大\"}",
        "event:finalResult\ndata:{\"content\":\"(\"}",
        "event:finalResult\ndata:{\"content\":\"白天\"}",
        "event:finalResult\ndata:{\"content\":\"可能\"}",
        "event:finalResult\ndata:{\"content\":\"接近\"}",
        "event:finalResult\ndata:{\"content\":\"0\"}",
        "event:finalResult\ndata:{\"content\":\"℃,\"}",
        "event:finalResult\ndata:{\"content\":\"夜晚\"}",
        "event:finalResult\ndata:{\"content\":\"降至\"}",
        "event:finalResult\ndata:{\"content\":\"-\"}",
        "event:finalResult\ndata:{\"content\":\"80\"}",
        "event:finalResult\ndata:{\"content\":\"℃\"}",
        "event:finalResult\ndata:{\"content\":\"以下\"}",
        "event:finalResult\ndata:{\"content\":\")。\"}",
        "event:finalResult\ndata:{\"content\":\"常\"}",
        "event:finalResult\ndata:{\"content\":\"发生\"}",
        "event:finalResult\ndata:{\"content\":\"区域性\"}",
        "event:finalResult\ndata:{\"content\":\"沙\"}",
        "event:finalResult\ndata:{\"content\":\"尘\"}",
        "event:finalResult\ndata:{\"content\":\"暴\"}",
        "event:finalResult\ndata:{\"content\":\",\"}",
        "event:finalResult\ndata:{\"content\":\"可能\"}",
        "event:finalResult\ndata:{\"content\":\"持续\"}",
        "event:finalResult\ndata:{\"content\":\"数\"}",
        "event:finalResult\ndata:{\"content\":\"周\"}",
        "event:finalResult\ndata:{\"content\":\"甚至\"}",
        "event:finalResult\ndata:{\"content\":\"覆盖\"}",
        "event:finalResult\ndata:{\"content\":\"整个\"}",
        "event:finalResult\ndata:{\"content\":\"星球\"}",
        "event:finalResult\ndata:{\"content\":\"。\\n\\n\"}",
        "event:finalResult\ndata:{\"content\":\"2\"}",
        "event:finalResult\ndata:{\"content\":\"。\"}",
        "event:finalResult\ndata:{\"content\":\" **\"}",
        "event:finalResult\ndata:{\"content\":\"数据\"}",
        "event:finalResult\ndata:{\"content\":\"来源\"}",
        "event:finalResult\ndata:{\"content\":\"**\"}",
        "event:finalResult\ndata:{\"content\":\":\"}",
        "event:finalResult\ndata:{\"content\":\"  \\n\"}",
        "event:finalResult\ndata:{\"content\":\"   \"}",
        "event:finalResult\ndata:{\"content\":\"火星\"}",
        "event:finalResult\ndata:{\"content\":\"探测器\"}",
        "event:finalResult\ndata:{\"content\":\"(\"}",
        "event:finalResult\ndata:{\"content\":\"如\"}",
        "event:finalResult\ndata:{\"content\":\""\"}",
        "event:finalResult\ndata:{\"content\":\"毅力\"}",
        "event:finalResult\ndata:{\"content\":\"号\"}",
        "event:finalResult\ndata:{\"content\":\"""\"}",
        "event:finalResult\ndata:{\"content\":\"好奇\"}",
        "event:finalResult\ndata:{\"content\":\"号\"}",
        "event:finalResult\ndata:{\"content\":\"")\"}",
        "event:finalResult\ndata:{\"content\":\"会\"}",
        "event:finalResult\ndata:{\"content\":\"传\"}",
        "event:finalResult\ndata:{\"content\":\"回\"}",
        "event:finalResult\ndata:{\"content\":\"局部\"}",
        "event:finalResult\ndata:{\"content\":\"气象\"}",
        "event:finalResult\ndata:{\"content\":\"数据\"}",
        "event:finalResult\ndata:{\"content\":\",\"}",
        "event:finalResult\ndata:{\"content\":\"包括\"}",
        "event:finalResult\ndata:{\"content\":\"温度\"}",
        "event:finalResult\ndata:{\"content\":\"、\"}",
        "event:finalResult\ndata:{\"content\":\"风速\"}",
        "event:finalResult\ndata:{\"content\":\"、\"}",
        "event:finalResult\ndata:{\"content\":\"气压\"}",
        "event:finalResult\ndata:{\"content\":\"等\"}",
        "event:finalResult\ndata:{\"content\":\"。\"}",
        "event:finalResult\ndata:{\"content\":\"例如\"}",
        "event:finalResult\ndata:{\"content\":\",\"}",
        "event:finalResult\ndata:{\"content\":\"毅力\"}",
        "event:finalResult\ndata:{\"content\":\"号\"}",
        "event:finalResult\ndata:{\"content\":\"所在的\"}",
        "event:finalResult\ndata:{\"content\":\"**\"}",
        "event:finalResult\ndata:{\"content\":\"J\"}",
        "event:finalResult\ndata:{\"content\":\"ez\"}",
        "event:finalResult\ndata:{\"content\":\"ero\"}",
        "event:finalResult\ndata:{\"content\":\"陨\"}",
        "event:finalResult\ndata:{\"content\":\"石\"}",
        "event:finalResult\ndata:{\"content\":\"坑\"}",
        "event:finalResult\ndata:{\"content\":\"**\"}",
        "event:finalResult\ndata:{\"content\":\"近期\"}",
        "event:finalResult\ndata:{\"content\":\"记录\"}",
        "event:finalResult\ndata:{\"content\":\"到\"}",
        "event:finalResult\ndata:{\"content\":\"白天\"}",
        "event:finalResult\ndata:{\"content\":\"-\"}",
        "event:finalResult\ndata:{\"content\":\"20\"}",
        "event:finalResult\ndata:{\"content\":\"℃\"}",
        "event:finalResult\ndata:{\"content\":\"至\"}",
        "event:finalResult\ndata:{\"content\":\"夜间\"}",
        "event:finalResult\ndata:{\"content\":\"-\"}",
        "event:finalResult\ndata:{\"content\":\"80\"}",
        "event:finalResult\ndata:{\"content\":\"℃\"}",
        "event:finalResult\ndata:{\"content\":\"的温度\"}",
        "event:finalResult\ndata:{\"content\":\"波动\"}",
        "event:finalResult\ndata:{\"content\":\"。\\n\\n\"}",
        "event:finalResult\ndata:{\"content\":\"3\"}",
        "event:finalResult\ndata:{\"content\":\"。\"}",
        "event:finalResult\ndata:{\"content\":\" **\"}",
        "event:finalResult\ndata:{\"content\":\"实时\"}",
        "event:finalResult\ndata:{\"content\":\"查询\"}",
        "event:finalResult\ndata:{\"content\":\"建议\"}",
        "event:finalResult\ndata:{\"content\":\"**\"}",
        "event:finalResult\ndata:{\"content\":\":\"}",
        "event:finalResult\ndata:{\"content\":\"  \\n\"}",
        "event:finalResult\ndata:{\"content\":\"   \"}",
        "event:finalResult\ndata:{\"content\":\"可\"}",
        "event:finalResult\ndata:{\"content\":\"访问\"}",
        "event:finalResult\ndata:{\"content\":\"**\"}",
        "event:finalResult\ndata:{\"content\":\"NASA\"}",
        "event:finalResult\ndata:{\"content\":\"官网\"}",
        "event:finalResult\ndata:{\"content\":\"**\"}",
        "event:finalResult\ndata:{\"content\":\"(\"}",
        "event:finalResult\ndata:{\"content\":\"例如\"}",
        "event:finalResult\ndata:{\"content\":\"[\"}",
        "event:finalResult\ndata:{\"content\":\"火星\"}",
        "event:finalResult\ndata:{\"content\":\"探测\"}",
        "event:finalResult\ndata:{\"content\":\"任务\"}",
        "event:finalResult\ndata:{\"content\":\"页面\"}",
        "event:finalResult\ndata:{\"content\":\"](\"}",
        "event:finalResult\ndata:{\"content\":\"https\"}",
        "event:finalResult\ndata:{\"content\":\"://\"}",
        "event:finalResult\ndata:{\"content\":\"mars\"}",
        "event:finalResult\ndata:{\"content\":\".nasa\"}",
        "event:finalResult\ndata:{\"content\":\".gov\"}",
        "event:finalResult\ndata:{\"content\":\"/)\"}",
        "event:finalResult\ndata:{\"content\":\")\"}",
        "event:finalResult\ndata:{\"content\":\"或\"}",
        "event:finalResult\ndata:{\"content\":\"关注\"}",
        "event:finalResult\ndata:{\"content\":\""\"}",
        "event:finalResult\ndata:{\"content\":\"好奇\"}",
        "event:finalResult\ndata:{\"content\":\"号\"}",
        "event:finalResult\ndata:{\"content\":\""\"}",
        "event:finalResult\ndata:{\"content\":\"等\"}",
        "event:finalResult\ndata:{\"content\":\"探测\"}",
        "event:finalResult\ndata:{\"content\":\"器的\"}",
        "event:finalResult\ndata:{\"content\":\"社交媒体\"}",
        "event:finalResult\ndata:{\"content\":\"账号\"}",
        "event:finalResult\ndata:{\"content\":\",\"}",
        "event:finalResult\ndata:{\"content\":\"这些\"}",
        "event:finalResult\ndata:{\"content\":\"平台\"}",
        "event:finalResult\ndata:{\"content\":\"会\"}",
        "event:finalResult\ndata:{\"content\":\"定期\"}",
        "event:finalResult\ndata:{\"content\":\"更新\"}",
        "event:finalResult\ndata:{\"content\":\"火星\"}",
        "event:finalResult\ndata:{\"content\":\"天气\"}",
        "event:finalResult\ndata:{\"content\":\"报告\"}",
        "event:finalResult\ndata:{\"content\":\"。\\n\\n\"}",
        "event:finalResult\ndata:{\"content\":\"需要\"}",
        "event:finalResult\ndata:{\"content\":\"其他\"}",
        "event:finalResult\ndata:{\"content\":\"帮助\"}",
        "event:finalResult\ndata:{\"content\":\"(\"}",
        "event:finalResult\ndata:{\"content\":\"例如\"}",
        "event:finalResult\ndata:{\"content\":\"具体\"}",
        "event:finalResult\ndata:{\"content\":\"日期\"}",
        "event:finalResult\ndata:{\"content\":\"的历史\"}",
        "event:finalResult\ndata:{\"content\":\"数据\"}",
        "event:finalResult\ndata:{\"content\":\"或\"}",
        "event:finalResult\ndata:{\"content\":\"科学\"}",
        "event:finalResult\ndata:{\"content\":\"分析\"}",
        "event:finalResult\ndata:{\"content\":\")\"}",
        "event:finalResult\ndata:{\"content\":\"可以\"}",
        "event:finalResult\ndata:{\"content\":\"告诉我\"}",
        "event:finalResult\ndata:{\"content\":\",\"}",
        "event:finalResult\ndata:{\"content\":\"我会\"}",
        "event:finalResult\ndata:{\"content\":\"尽力\"}",
        "event:finalResult\ndata:{\"content\":\"提供\"}",
        "event:finalResult\ndata:{\"content\":\"参考资料\"}",
        "event:finalResult\ndata:{\"content\":\"!\"}",
        "event:done\ndata:done"
    )

}

毕竟模拟数据写死的,后台返的数据是这样的

相关推荐
禅思院13 分钟前
AI对话前端从入门到崩溃:一个长对话引发的五层优化战争【引子】
前端·面试·架构
TrisighT41 分钟前
Electron 鸿蒙 PC 上点外链唤醒应用,我试了 6 种写法只有 1 种能跑
前端·electron·harmonyos
天才熊猫君2 小时前
配置与数据分离:一种可视化搭建的属性编辑方案
前端·javascript
林希_Rachel_傻希希2 小时前
web性能之相关路径——AI总结
前端·javascript·面试
竹林8182 小时前
用 wagmi v2 踩坑两天,我终于搞懂了多链钱包切换在 DeFi 前端中的正确姿势
前端·javascript
用户2136610035722 小时前
Vue项目搜索功能与面包屑导航
前端·javascript
星栈2 小时前
LiveView 的实时通信,爽是爽,但 PubSub 和广播也最容易把自己绕晕
前端·前端框架·elixir
用户2930750976692 小时前
告别关键词匹配,拥抱向量语义 —— RAG 搜索从零到一
前端
独孤留白2 小时前
从C到Rust:告别 C 的"指针 + 长度"手动模式
前端·rust
掘金安东尼3 小时前
中小厂前端候选人简历面试拆解:从 HR 面、技术面到主管面的双赢提问法
前端·面试