diff --git a/app/src/main/java/com/stand/standapp/ui/chat/repo/AiChatRepository.kt b/app/src/main/java/com/stand/standapp/ui/chat/repo/AiChatRepository.kt new file mode 100644 index 0000000..713d531 --- /dev/null +++ b/app/src/main/java/com/stand/standapp/ui/chat/repo/AiChatRepository.kt @@ -0,0 +1,55 @@ +package com.stand.standapp.ui.chat.repo + +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.Response +import okhttp3.sse.EventSource +import okhttp3.sse.EventSourceListener +import okhttp3.sse.EventSources +import timber.log.Timber +import java.util.concurrent.TimeUnit + +class AiChatRepository { + // 根据后端实际情况修改,模拟器访问本地后端用 10.0.2.2 + private val backendUrl = "http://10.0.2.2:8080/api/chat/stream" + + private val client = OkHttpClient.Builder() + .readTimeout(0, TimeUnit.MILLISECONDS) // SSE 需要关闭读取超时 + .build() + + fun streamChat(message: String): Flow = callbackFlow { + val json = """{"message": "$message"}""" + val request = Request.Builder() + .url(backendUrl) + .post(json.toRequestBody("application/json".toMediaType())) + .header("Accept", "text/event-stream") + .build() + + val listener = object : EventSourceListener() { + override fun onEvent(eventSource: EventSource, id: String?, type: String?, data: String) { + // 收到后端推送的数据块 + trySend(data) + } + + override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) { + Timber.e(t, "SSE Connection failed") + close(t) // 结束流 + } + + override fun onClosed(eventSource: EventSource) { + close() // 正常结束 + } + } + + val eventSource = EventSources.createFactory(client).newEventSource(request, listener) + + awaitClose { + eventSource.cancel() + } + } +}