Akış

Akıcı okunan yapay zeka yanıtları akıtın. Modelden gelen patlamalı parçalar, yetişmek için hızlanan sabit bir hızla gösterilir; yeni kelimelerde yumuşak bir solma ve yazarken bir imleç vardır.

Modeller metni patlamalar halinde gönderir: birkaç kelime, bir duraklama, sonra bir cümle birden. Her parçayı geldiği gibi yazdırmak yanıtı kekeme gösterir. Streaming, aldıklarınızı gösterdiklerinizden ayrı tutar ve saniyede sabit 90 karakterle gösterir.

Parçalar biriktiğinde hız, aradaki farkı yaklaşık 0,3 saniyede kapatacak şekilde yükselir ve akış bittiğinde geri kalan yaklaşık 0,12 saniyede boşaltılır; böylece metin modelin çok gerisinde kalmaz. Emoji ve diğer çok parçalı karakterler gösterim ortasında asla bölünmez ve metin eklenmek yerine, yeniden oluşturmadaki gibi değiştirilirse gösterim iki sürümün ortak olduğu yerden yeniden başlar.

Akmayan metin ilk karede tam olarak render edilir; böylece geçmiş ve sunucu render'ları asla animasyonlanmaz. StreamingText en yeni kelimelere yumuşak bir solma ve yazarken bir imleç ekler. useSmoothText, Markdown dahil herhangi bir renderer'ın önüne koymanız için yalnızca hızlandırmayı verir.

  1. Pro registry'yi components.json dosyasına ekleyin

    components.json
    {
      "registries": {
        "@hextaui-pro": {
          "url": "https://hextaui.com/r/pro/{name}.json",
          "headers": {
            "Authorization": "Bearer ${HEXTAUI_PRO_TOKEN}"
          }
        }
      }
    }
  2. Token'ınızı ekleyin

    Hesap sayfanızda bir token oluşturun ve .env.local dosyasına HEXTAUI_PRO_TOKEN olarak ekleyin.

  3. Bloğu ekleyin

    pnpm dlx shadcn@latest add @hextaui-pro/streaming

AI SDK ile

Bir useChat mesajının her metin parçasını render edin. Parçanın kendi durumu StreamingText'e modelin hâlâ yazıp yazmadığını söyler; bu yüzden tamamlanmış mesajlar ve geçmiş anında görünür.

"use client"

import * as React from "react"
import { useChat } from "@ai-sdk/react"

import { StreamingText } from "@/components/blocks/streaming/streaming-text"

export function Chat() {
  const { messages, sendMessage, status } = useChat()
  const [input, setInput] = React.useState("")

  return (
    <div className="flex flex-col gap-4">
      {messages.map((message) => (
        <div key={message.id} className="flex flex-col gap-2">
          {message.parts.map((part, index) =>
            part.type === "text" ? (
              <StreamingText
                key={index}
                text={part.text}
                streaming={part.state === "streaming"}
              />
            ) : null
          )}
        </div>
      ))}
      <form
        onSubmit={(event) => {
          event.preventDefault()
          sendMessage({ text: input })
          setInput("")
        }}
      >
        <input
          value={input}
          disabled={status !== "ready"}
          onChange={(event) => setInput(event.target.value)}
        />
      </form>
    </div>
  )
}

Markdown ile

Metni herhangi bir renderer'dan önce yumuşatmak için hook'u tek başına kullanın. Streamdown akarken tamamlanmamış Markdown'ı ele alır; react-markdown da aynı şekilde çalışır.

"use client"

import { Streamdown } from "streamdown"

import { useSmoothText } from "@/components/blocks/streaming/use-smooth-text"

export function MarkdownAnswer({
  text,
  streaming,
}: {
  text: string
  streaming: boolean
}) {
  const smooth = useSmoothText(text, { streaming })

  return (
    <Streamdown mode="streaming" isAnimating={streaming || smooth.animating}>
      {smooth.text}
    </Streamdown>
  )
}

Herhangi bir akışla

Her parçayı bir dizeye ekleyin ve iletin. Bu, fetch, OpenAI ya da Anthropic delta'ları veya server-sent events için aynı şekilde çalışır.

"use client"

import * as React from "react"

import { StreamingText } from "@/components/blocks/streaming/streaming-text"

export function Answer({ prompt }: { prompt: string }) {
  const [text, setText] = React.useState("")
  const [streaming, setStreaming] = React.useState(false)

  const ask = async () => {
    setText("")
    setStreaming(true)
    const response = await fetch("/api/chat", {
      method: "POST",
      body: JSON.stringify({ prompt }),
    })
    const reader = response
      .body!.pipeThrough(new TextDecoderStream())
      .getReader()
    for (;;) {
      const { done, value } = await reader.read()
      if (done) break
      setText((current) => current + value)
    }
    setStreaming(false)
  }

  return (
    <div className="flex flex-col gap-3">
      <button onClick={ask}>Ask</button>
      <StreamingText text={text} streaming={streaming} />
    </div>
  )
}

Yapı

Dıştan içe doğru birleştirdiğiniz parçalar.

ParçaAçıklama
StreamingTextHızlandıran, solduran ve imleci gösteren hazır bir metin öğesi. Düz metin yanıtları için kullanın.
useSmoothTextTek başına hızlandırma. Şu an gösterilecek metni ve hâlâ yetişip yetişmediğini döndürür.

StreamingText

Ayrıca children dışındaki her div prop'unu kabul eder.

PropTürVarsayılan
textŞimdiye kadar alınan her şey. Parçalar geldikçe ekleyin.
string–
streamingDaha fazla metin gelip gelmeyeceği. İmleci gösterir ve yetişme penceresini açık tutar.
booleanfalse
smoothMetni alındığı gibi render etmek için hızlandırmayı kapatın.
booleantrue
charsPerSecondHerhangi bir yetişmeden önceki temel okuma hızı.
number90

useSmoothText(text, options)

{ text, animating } döndürür. animating, gösterilen metin tam metne ulaşana kadar true kalır.

PropTürVarsayılan
textŞimdiye kadar alınan tam metin.
string–
options.streamingKaynağın hâlâ gönderip göndermediği.
booleanfalse
options.enabledfalse iken hook metni değiştirmeden döndürür.
booleantrue
options.charsPerSecondTemel okuma hızı.
number90
  • Metin kapsayıcısı, akarken aria-busy içeren polite bir live region'dır; böylece ekran okuyucular her karakter yerine yanıt oturduktan sonra duyurur.
  • İmleç dekoratiftir ve yardımcı teknolojilerden gizlenir.
  • Azaltılmış harekette kelimeler solmadan belirir ve imleç atmayı bırakır. Hızlandırma kalır; çünkü bu hareketle değil okuma hızıyla ilgilidir.

Şunlarla geliştirildi

Streaming bloğunun yapıldığı ücretsiz HextaUI bileşenleri. Her biri tek başına yüklenir.

Kod

3 dosya, components/blocks/streaming konumuna eklendi.