Section 8/151 menit
8. Streaming Response
8. Streaming Response
Untuk UI yang responsif, gunakan streaming agar teks muncul secara progresif — persis seperti ChatGPT atau Writing Tools Apple.
Streaming Dasar
swift
func streamResponse(to prompt: String) async throws {
let session = LanguageModelSession()
let stream = session.streamResponse(to: prompt)
for try await partial in stream {
// partial.content berisi akumulasi teks hingga saat ini
print(partial.content, terminator: "")
}
print() // newline di akhir
}
Streaming dengan Structured Output
Streaming juga bekerja dengan @Generable — field akan terisi secara progresif:
swift
@Generable
struct StoryOutline {
@Guide(description: "Judul cerita")
var title: String
@Guide(description: "Paragraf pembuka")
var opening: String
@Guide(description: "Tiga poin plot utama")
var plotPoints: [String]
@Guide(description: "Kalimat penutup")
var conclusion: String
}
func streamStoryOutline(topic: String) async throws {
let session = LanguageModelSession()
let stream = session.streamResponse(
to: "Buat outline cerita pendek tentang: \(topic)",
generating: StoryOutline.self
)
for try await partial in stream {
// partial.content adalah StoryOutline parsial
// Field yang sudah lengkap sudah bisa diakses
if let title = partial.content.title {
print("Judul:", title)
}
}
}
Streaming di SwiftUI dengan @Observable
swift
import FoundationModels
import SwiftUI
@Observable
class StreamingViewModel {
var displayedText = ""
var isStreaming = false
private let session = LanguageModelSession()
func sendMessage(_ prompt: String) async {
displayedText = ""
isStreaming = true
defer { isStreaming = false }
do {
let stream = session.streamResponse(to: prompt)
for try await partial in stream {
displayedText = partial.content
}
} catch {
displayedText = "Error: \(error.localizedDescription)"
}
}
}
struct StreamingChatView: View {
@State private var viewModel = StreamingViewModel()
@State private var inputText = ""
var body: some View {
VStack {
ScrollView {
Text(viewModel.displayedText)
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
}
if viewModel.isStreaming {
ProgressView()
}
HStack {
TextField("Ketik pesan...", text: $inputText)
.textFieldStyle(.roundedBorder)
Button("Kirim") {
let text = inputText
inputText = ""
Task {
await viewModel.sendMessage(text)
}
}
.disabled(viewModel.isStreaming || inputText.isEmpty)
}
.padding()
}
}
}