feat: 扩展网络层API和WebSocket消息处理
- 扩展ApiService添加回忆录状态和任务状态接口 - 优化WebSocketClient连接管理 - 增强WebSocketMessage消息类型支持 - 更新MemoirModels数据模型
This commit is contained in:
@@ -95,7 +95,6 @@ class ApiService(
|
|||||||
return try {
|
return try {
|
||||||
val response = client.get("$BASE_URL/api/chapters") {
|
val response = client.get("$BASE_URL/api/chapters") {
|
||||||
contentType(ContentType.Application.Json)
|
contentType(ContentType.Application.Json)
|
||||||
parameter("user_id", userId)
|
|
||||||
}
|
}
|
||||||
Result.success(response.body())
|
Result.success(response.body())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -261,5 +260,46 @@ class ApiService(
|
|||||||
Result.success(Unit)
|
Result.success(Unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 回忆录状态相关API ====================
|
||||||
|
|
||||||
|
suspend fun getMemoirState(): Result<com.huaga.life_echo.network.models.MemoirStateDto> {
|
||||||
|
return try {
|
||||||
|
val response = client.get("$BASE_URL/api/memoir-state") {
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
|
}
|
||||||
|
Result.success(response.body())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Result.failure(Exception("获取回忆录状态失败: ${e.message}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 任务状态相关API ====================
|
||||||
|
|
||||||
|
suspend fun getTasksStatus(): Result<com.huaga.life_echo.network.models.TasksStatusDto> {
|
||||||
|
return try {
|
||||||
|
val response = client.get("$BASE_URL/api/tasks/status") {
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
|
}
|
||||||
|
Result.success(response.body())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Result.failure(Exception("获取任务状态失败: ${e.message}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun clearTasks(): Result<Unit> {
|
||||||
|
return try {
|
||||||
|
val response = client.delete("$BASE_URL/api/tasks/clear") {
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
|
}
|
||||||
|
if (response.status.isSuccess()) {
|
||||||
|
Result.success(Unit)
|
||||||
|
} else {
|
||||||
|
Result.failure(Exception("清除任务失败: ${response.status}"))
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Result.failure(Exception("清除任务失败: ${e.message}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ import io.ktor.http.*
|
|||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
import kotlinx.serialization.json.put
|
||||||
|
import kotlinx.serialization.json.putJsonObject
|
||||||
|
|
||||||
class WebSocketClient {
|
class WebSocketClient {
|
||||||
private val client = HttpClient(Android) {
|
private val client = HttpClient(Android) {
|
||||||
@@ -74,7 +78,7 @@ class WebSocketClient {
|
|||||||
sendMessage(WebSocketMessage(
|
sendMessage(WebSocketMessage(
|
||||||
type = MessageType.connect,
|
type = MessageType.connect,
|
||||||
conversation_id = conversationId,
|
conversation_id = conversationId,
|
||||||
data = mapOf("status" to "connected")
|
data = buildJsonObject { put("status", JsonPrimitive("connected")) }
|
||||||
))
|
))
|
||||||
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -118,7 +122,7 @@ class WebSocketClient {
|
|||||||
sendMessage(WebSocketMessage(
|
sendMessage(WebSocketMessage(
|
||||||
type = MessageType.audio_chunk,
|
type = MessageType.audio_chunk,
|
||||||
conversation_id = conversationId,
|
conversation_id = conversationId,
|
||||||
data = mapOf("audio_base64" to base64Audio)
|
data = buildJsonObject { put("audio_base64", JsonPrimitive(base64Audio)) }
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,14 +130,15 @@ class WebSocketClient {
|
|||||||
sendMessage(WebSocketMessage(
|
sendMessage(WebSocketMessage(
|
||||||
type = MessageType.text,
|
type = MessageType.text,
|
||||||
conversation_id = conversationId,
|
conversation_id = conversationId,
|
||||||
data = mapOf("text" to text)
|
data = buildJsonObject { put("text", JsonPrimitive(text)) }
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun sendEndConversation(conversationId: String) {
|
suspend fun sendEndConversation(conversationId: String) {
|
||||||
sendMessage(WebSocketMessage(
|
sendMessage(WebSocketMessage(
|
||||||
type = MessageType.end_conversation,
|
type = MessageType.end_conversation,
|
||||||
conversation_id = conversationId
|
conversation_id = conversationId,
|
||||||
|
data = buildJsonObject { }
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +151,7 @@ class WebSocketClient {
|
|||||||
sendMessage(WebSocketMessage(
|
sendMessage(WebSocketMessage(
|
||||||
type = MessageType.cancel_generation,
|
type = MessageType.cancel_generation,
|
||||||
conversation_id = conversationId,
|
conversation_id = conversationId,
|
||||||
data = mapOf("action" to "cancel")
|
data = buildJsonObject { put("action", JsonPrimitive("cancel")) }
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.huaga.life_echo.network
|
package com.huaga.life_echo.network
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
enum class MessageType {
|
enum class MessageType {
|
||||||
@@ -23,7 +26,58 @@ enum class MessageType {
|
|||||||
data class WebSocketMessage(
|
data class WebSocketMessage(
|
||||||
val type: MessageType,
|
val type: MessageType,
|
||||||
val conversation_id: String? = null,
|
val conversation_id: String? = null,
|
||||||
val data: Map<String, String> = emptyMap(),
|
val data: JsonObject = buildJsonObject { },
|
||||||
val timestamp: String? = null
|
val timestamp: String? = null
|
||||||
)
|
) {
|
||||||
|
/**
|
||||||
|
* 获取data中的字符串值
|
||||||
|
*/
|
||||||
|
fun getString(key: String): String? {
|
||||||
|
return data[key]?.let {
|
||||||
|
if (it is JsonPrimitive) {
|
||||||
|
try {
|
||||||
|
it.content
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取data中的整数值
|
||||||
|
*/
|
||||||
|
fun getInt(key: String): Int? {
|
||||||
|
return data[key]?.let {
|
||||||
|
if (it is JsonPrimitive) {
|
||||||
|
try {
|
||||||
|
it.content.toIntOrNull()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取data中的布尔值
|
||||||
|
*/
|
||||||
|
fun getBoolean(key: String): Boolean? {
|
||||||
|
return data[key]?.let {
|
||||||
|
if (it is JsonPrimitive) {
|
||||||
|
try {
|
||||||
|
it.content.toBooleanStrictOrNull()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,30 +6,31 @@ import kotlinx.serialization.Serializable
|
|||||||
* 回忆录相关的数据模型
|
* 回忆录相关的数据模型
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// 书籍信息DTO(扩展版)
|
// 书籍信息DTO(匹配服务器格式)
|
||||||
@Serializable
|
@Serializable
|
||||||
data class BookDto(
|
data class BookDto(
|
||||||
val id: String,
|
val id: String,
|
||||||
val userId: String,
|
|
||||||
val title: String,
|
val title: String,
|
||||||
val subtitle: String? = null,
|
val total_pages: Int? = null,
|
||||||
val totalPages: Int,
|
val total_words: Int? = null,
|
||||||
val totalWords: Int,
|
val cover_image_url: String? = null,
|
||||||
val updatedAt: Long,
|
val has_update: Boolean = false,
|
||||||
val lastUpdatedAt: Long? = null
|
val last_update_chapter_id: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
// 章节信息DTO(扩展版)
|
// 章节信息DTO(匹配服务器格式)
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ChapterDto(
|
data class ChapterDto(
|
||||||
val id: String,
|
val id: String,
|
||||||
val title: String,
|
val title: String,
|
||||||
val content: String,
|
val content: String,
|
||||||
val orderIndex: Int,
|
val order_index: Int,
|
||||||
val status: String, // "draft", "partial", "completed"
|
val status: String, // "draft", "partial", "completed"
|
||||||
val category: String,
|
val category: String,
|
||||||
val pageCount: Int? = null,
|
val images: List<String> = emptyList(),
|
||||||
val updatedAt: Long? = null
|
val updated_at: String? = null,
|
||||||
|
val is_new: Boolean = false,
|
||||||
|
val source_segments: List<String> = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
// 章节内容详情DTO
|
// 章节内容详情DTO
|
||||||
@@ -45,3 +46,39 @@ data class ChapterContentDto(
|
|||||||
val updatedAt: Long,
|
val updatedAt: Long,
|
||||||
val quotes: List<String> = emptyList() // 引用内容列表
|
val quotes: List<String> = emptyList() // 引用内容列表
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 回忆录状态DTO
|
||||||
|
@Serializable
|
||||||
|
data class MemoirStateDto(
|
||||||
|
val current_stage: String,
|
||||||
|
val covered_stages: List<String> = emptyList(),
|
||||||
|
val slots: Map<String, Map<String, SlotInfo>> = emptyMap()
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SlotInfo(
|
||||||
|
val snippet: String? = null,
|
||||||
|
val filled: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
|
// 任务状态DTO
|
||||||
|
@Serializable
|
||||||
|
data class TasksStatusDto(
|
||||||
|
val total: Int,
|
||||||
|
val pending: Int,
|
||||||
|
val running: Int,
|
||||||
|
val success: Int,
|
||||||
|
val failure: Int,
|
||||||
|
val all_completed: Boolean,
|
||||||
|
val tasks: List<TaskInfoDto> = emptyList()
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class TaskInfoDto(
|
||||||
|
val task_id: String,
|
||||||
|
val task_type: String = "memoir",
|
||||||
|
val status: String, // "pending", "running", "success", "failure"
|
||||||
|
val created_at: String? = null,
|
||||||
|
val updated_at: String? = null,
|
||||||
|
val result: Map<String, String>? = null
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user