智能体列表,全部
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package com.aiosman.ravenow.data
|
||||
|
||||
import com.aiosman.ravenow.AppStore
|
||||
import com.aiosman.ravenow.data.api.ApiClient
|
||||
import com.aiosman.ravenow.entity.AgentEntity
|
||||
import com.aiosman.ravenow.entity.ProfileEntity
|
||||
@@ -22,8 +23,6 @@ data class Agent(
|
||||
val isPublic: Boolean,
|
||||
@SerializedName("openId")
|
||||
val openId: String,
|
||||
@SerializedName("profile")
|
||||
val profile: Profile,
|
||||
@SerializedName("title")
|
||||
val title: String,
|
||||
@SerializedName("updatedAt")
|
||||
@@ -38,13 +37,12 @@ data class Agent(
|
||||
desc = desc,
|
||||
createdAt = createdAt,
|
||||
updatedAt = updatedAt,
|
||||
avatar = "${ApiClient.BASE_SERVER}$avatar",
|
||||
author = author,
|
||||
avatar = "${ApiClient.BASE_API_URL+"/outside"}$avatar"+"?token="+"Bearer ${AppStore.token}",
|
||||
//author = author,
|
||||
isPublic = isPublic,
|
||||
openId = openId,
|
||||
breakMode = breakMode,
|
||||
useCount = useCount,
|
||||
profile = profile.toProfileEntity(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,11 @@ data class AgentMomentRequestBody(
|
||||
val sessionId: String
|
||||
)
|
||||
|
||||
data class SingleChatRequestBody(
|
||||
@SerializedName("agentOpenId")
|
||||
val generateText: String,
|
||||
)
|
||||
|
||||
data class LoginUserRequestBody(
|
||||
@SerializedName("username")
|
||||
val username: String? = null,
|
||||
@@ -470,12 +475,14 @@ interface RaveNowAPI {
|
||||
suspend fun getAgent(
|
||||
@Query("page") page: Int = 1,
|
||||
@Query("pageSize") pageSize: Int = 20,
|
||||
): Response<ListContainer<Agent>>
|
||||
@Query("withWorkflow") withWorkflow: Int = 1,
|
||||
): Response<DataContainer<ListContainer<Agent>>>
|
||||
|
||||
@GET("outside/my/prompts")
|
||||
suspend fun getMyAgent(
|
||||
@Query("page") page: Int = 1,
|
||||
@Query("pageSize") pageSize: Int = 20,
|
||||
@Query("withWorkflow") withWorkflow: Int = 1,
|
||||
): Response<ListContainer<Agent>>
|
||||
|
||||
@Multipart
|
||||
@@ -483,12 +490,25 @@ interface RaveNowAPI {
|
||||
suspend fun createAgent(
|
||||
@Part avatar: MultipartBody.Part?,
|
||||
@Part("title") title: RequestBody?,
|
||||
@Part("value") value: RequestBody?,
|
||||
@Part("desc") desc: RequestBody?,
|
||||
@Part("workflowId") workflowId: RequestBody?,
|
||||
@Part("public") isPublic: RequestBody?,
|
||||
@Part("breakMode") breakMode: RequestBody?,
|
||||
@Part("useWorkflow") useWorkflow: RequestBody?,
|
||||
@Part("workflowInputs") workflowInputs: RequestBody?,
|
||||
): Response<DataContainer<Agent>>
|
||||
|
||||
|
||||
@POST("generate/postText")
|
||||
suspend fun agentMoment(@Body body: AgentMomentRequestBody): Response<DataContainer<String>>
|
||||
|
||||
@POST("outside/rooms/create-single-chat")
|
||||
suspend fun createSingleChat(@Body body: SingleChatRequestBody): Response<DataContainer<Unit>>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,35 +7,48 @@ import com.aiosman.ravenow.data.AgentService
|
||||
import com.aiosman.ravenow.data.ServiceException
|
||||
import com.aiosman.ravenow.data.UploadImage
|
||||
import com.aiosman.ravenow.data.api.ApiClient
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import retrofit2.http.Part
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* 智能体
|
||||
*/
|
||||
|
||||
suspend fun createAgent(
|
||||
title: String,
|
||||
desc: String,
|
||||
avatar: UploadImage? = null,
|
||||
workflowId:Int = 1,
|
||||
isPublic:Boolean = true,
|
||||
breakMode:Boolean = false,
|
||||
useWorkflow:Boolean = true,
|
||||
): AgentEntity {
|
||||
val textTitle = title.toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
val textDesc = desc.toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
val workflowIdRequestBody = workflowId.toString().toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
val isPublicRequestBody = isPublic.toString().toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
val breakModeRequestBody = breakMode.toString().toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
val useWorkflowRequestBody = useWorkflow.toString().toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
val workflowInputsValue = "{\"si\":\"$desc\"}"
|
||||
val workflowInputsRequestBody = workflowInputsValue.toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
|
||||
val avatarField: MultipartBody.Part? = avatar?.let {
|
||||
createMultipartBody(it.file, it.filename, "avatar")
|
||||
}
|
||||
val response = ApiClient.api.createAgent(avatarField, textTitle ,textDesc)
|
||||
val response = ApiClient.api.createAgent(avatarField, textTitle ,textDesc,textDesc,workflowIdRequestBody,isPublicRequestBody,breakModeRequestBody,useWorkflowRequestBody,workflowInputsRequestBody)
|
||||
val body = response.body()?.data ?: throw ServiceException("Failed to create agent")
|
||||
return body.toAgentEntity()
|
||||
|
||||
}
|
||||
|
||||
data class AgentEntity(
|
||||
val author: String,
|
||||
//val author: String,
|
||||
val avatar: String,
|
||||
val breakMode: Boolean,
|
||||
val createdAt: String,
|
||||
@@ -43,7 +56,7 @@ data class AgentEntity(
|
||||
val id: Int,
|
||||
val isPublic: Boolean,
|
||||
val openId: String,
|
||||
val profile: ProfileEntity,
|
||||
//val profile: ProfileEntity,
|
||||
val title: String,
|
||||
val updatedAt: String,
|
||||
val useCount: Int
|
||||
@@ -80,8 +93,8 @@ class AgentLoader : DataLoader<AgentEntity,AgentLoaderExtraArgs>() {
|
||||
)
|
||||
val data = result.body()?.let {
|
||||
ListContainer(
|
||||
list = it.list.map { it.toAgentEntity()},
|
||||
total = it.total,
|
||||
list = it.data.list.map { it.toAgentEntity()},
|
||||
total = it.data.total,
|
||||
page = page,
|
||||
pageSize = pageSize
|
||||
)
|
||||
|
||||
@@ -230,6 +230,8 @@ fun AddAgentScreen() {
|
||||
if (result != null) {
|
||||
println("AddAgent: Agent created successfully, closing page")
|
||||
// 创建成功,关闭页面
|
||||
model.name = ""
|
||||
model.desc = ""
|
||||
navController.popBackStack()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -80,7 +80,7 @@ fun AgentCard(
|
||||
text = agentEntity.title,
|
||||
color = AppColors.text,
|
||||
fontSize = 16.sp,
|
||||
style = TextStyle(fontWeight = FontWeight.Bold)
|
||||
style = TextStyle(fontWeight = FontWeight.W700)
|
||||
)
|
||||
}
|
||||
Row(
|
||||
@@ -93,6 +93,7 @@ fun AgentCard(
|
||||
modifier = Modifier,
|
||||
text = agentEntity.desc,
|
||||
color = AppColors.text,
|
||||
maxLines = 1,
|
||||
fontSize = 12.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.aiosman.ravenow.LocalNavController
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.ui.NavigationRoute
|
||||
import com.aiosman.ravenow.ui.index.tabs.ai.tabs.mine.MineAgent
|
||||
import com.aiosman.ravenow.ui.index.tabs.ai.tabs.hot.HotAgent
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -134,7 +135,7 @@ fun Agent() {
|
||||
Text(
|
||||
text = stringResource(R.string.agent_mine),
|
||||
fontSize = 14.sp,
|
||||
color = if (pagerState.currentPage == 0) AppColors.checkedText else AppColors.text,
|
||||
color = if (pagerState.currentPage == 0) AppColors.mainText else AppColors.checkedBackground,
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(if (pagerState.currentPage == 0) AppColors.checkedBackground else AppColors.unCheckedBackground)
|
||||
@@ -158,7 +159,7 @@ fun Agent() {
|
||||
Text(
|
||||
text = stringResource(R.string.agent_hot),
|
||||
fontSize = 14.sp,
|
||||
color = if (pagerState.currentPage == 1) AppColors.checkedText else AppColors.text,
|
||||
color = if (pagerState.currentPage == 1) AppColors.mainText else AppColors.checkedBackground,
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(if (pagerState.currentPage == 1) AppColors.checkedBackground else AppColors.unCheckedBackground)
|
||||
@@ -182,7 +183,7 @@ fun Agent() {
|
||||
Text(
|
||||
text = stringResource(R.string.agent_recommend),
|
||||
fontSize = 14.sp,
|
||||
color = if (pagerState.currentPage == 2) AppColors.checkedText else AppColors.text,
|
||||
color = if (pagerState.currentPage == 2) AppColors.mainText else AppColors.checkedBackground,
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(if (pagerState.currentPage == 2) AppColors.checkedBackground else AppColors.unCheckedBackground)
|
||||
@@ -206,7 +207,7 @@ fun Agent() {
|
||||
Text(
|
||||
text = stringResource(R.string.agent_other),
|
||||
fontSize = 14.sp,
|
||||
color = if (pagerState.currentPage == 3) AppColors.checkedText else AppColors.text,
|
||||
color = if (pagerState.currentPage == 3) AppColors.mainText else AppColors.checkedBackground,
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(if (pagerState.currentPage == 3) AppColors.checkedBackground else AppColors.unCheckedBackground)
|
||||
@@ -231,7 +232,7 @@ fun Agent() {
|
||||
}
|
||||
|
||||
1 -> {
|
||||
|
||||
HotAgent()
|
||||
}
|
||||
|
||||
2 -> {
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.aiosman.ravenow.ui.index.tabs.ai.tabs.hot
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.ui.composables.AgentCard
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun HotAgent() {
|
||||
val AppColors = LocalAppTheme.current
|
||||
val model = HotAgentViewModel
|
||||
var agentList = model.agentList
|
||||
val scope = rememberCoroutineScope()
|
||||
val state = rememberPullRefreshState(model.refreshing, onRefresh = {
|
||||
model.refreshPager(pullRefresh = true)
|
||||
})
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
// observe list scrolling
|
||||
val reachedBottom by remember {
|
||||
derivedStateOf {
|
||||
val lastVisibleItem = listState.layoutInfo.visibleItemsInfo.lastOrNull()
|
||||
lastVisibleItem?.index != 0 && lastVisibleItem?.index == listState.layoutInfo.totalItemsCount - 2
|
||||
}
|
||||
}
|
||||
|
||||
// load more if scrolled to bottom
|
||||
LaunchedEffect(reachedBottom) {
|
||||
if (reachedBottom && !model.isLoading && model.hasNext) {
|
||||
model.loadMore()
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
model.refreshPager()
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
) {
|
||||
if(agentList.isEmpty() && !model.isLoading) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.rider_pro_following_empty),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(140.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.size(32.dp))
|
||||
Text(
|
||||
text = "您还没有创建任何智能体",
|
||||
color = AppColors.text,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W600
|
||||
)
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
Text(
|
||||
text = "点击开始创建您的第一个智能体",
|
||||
color = AppColors.text,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W400
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Box(Modifier.pullRefresh(state)) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = listState
|
||||
) {
|
||||
items(
|
||||
agentList.size,
|
||||
key = { idx -> idx }
|
||||
) { idx ->
|
||||
val agentItem = agentList[idx]
|
||||
AgentCard(agentEntity = agentItem)
|
||||
}
|
||||
|
||||
// 加载更多指示器
|
||||
if (model.isLoading && agentList.isNotEmpty()) {
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(24.dp),
|
||||
color = AppColors.main
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PullRefreshIndicator(model.refreshing, state, Modifier.align(Alignment.TopCenter))
|
||||
}
|
||||
}
|
||||
|
||||
// 错误信息显示
|
||||
model.error?.let { error ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = error,
|
||||
color = AppColors.error,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.aiosman.ravenow.ui.index.tabs.ai.tabs.hot
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.aiosman.ravenow.data.api.ApiClient
|
||||
import com.aiosman.ravenow.data.ServiceException
|
||||
import com.aiosman.ravenow.entity.AgentEntity
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object HotAgentViewModel : ViewModel() {
|
||||
var agentList by mutableStateOf<List<AgentEntity>>(emptyList())
|
||||
var refreshing by mutableStateOf(false)
|
||||
var isLoading by mutableStateOf(false)
|
||||
var hasNext by mutableStateOf(true)
|
||||
var currentPage by mutableStateOf(1)
|
||||
var error by mutableStateOf<String?>(null)
|
||||
|
||||
private val pageSize = 20
|
||||
|
||||
init {
|
||||
refreshPager()
|
||||
}
|
||||
|
||||
fun refreshPager(pullRefresh: Boolean = false) {
|
||||
if (isLoading && !pullRefresh) return
|
||||
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
isLoading = true
|
||||
refreshing = pullRefresh
|
||||
error = null
|
||||
|
||||
val response = ApiClient.api.getAgent(
|
||||
page = 1,
|
||||
pageSize = pageSize
|
||||
)
|
||||
|
||||
val body = response.body()
|
||||
if (body != null) {
|
||||
val newAgents = body.data.list.map { it.toAgentEntity() }
|
||||
agentList = newAgents
|
||||
currentPage = 1
|
||||
hasNext = newAgents.size == pageSize
|
||||
} else {
|
||||
throw ServiceException("Failed to load agents")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
error = e.message ?: "加载失败"
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
isLoading = false
|
||||
refreshing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun loadMore() {
|
||||
if (isLoading || !hasNext) return
|
||||
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
isLoading = true
|
||||
error = null
|
||||
|
||||
val response = ApiClient.api.getAgent(
|
||||
page = currentPage + 1,
|
||||
pageSize = pageSize
|
||||
)
|
||||
|
||||
val body = response.body()
|
||||
if (body != null) {
|
||||
val newAgents = body.data.list.map { it.toAgentEntity() }
|
||||
agentList = agentList + newAgents
|
||||
currentPage += 1
|
||||
hasNext = newAgents.size == pageSize
|
||||
} else {
|
||||
throw ServiceException("Failed to load more agents")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
error = e.message ?: "加载更多失败"
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,18 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.navigation.NavHostController
|
||||
import com.aiosman.ravenow.data.api.ApiClient
|
||||
import com.aiosman.ravenow.data.ServiceException
|
||||
import com.aiosman.ravenow.data.api.AgentMomentRequestBody
|
||||
import com.aiosman.ravenow.data.api.SingleChatRequestBody
|
||||
import com.aiosman.ravenow.entity.AgentEntity
|
||||
import com.aiosman.ravenow.ui.index.tabs.message.Conversation
|
||||
import com.aiosman.ravenow.ui.index.tabs.message.MessageListViewModel.userService
|
||||
import com.aiosman.ravenow.ui.navigateToChat
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
|
||||
object MineAgentViewModel : ViewModel() {
|
||||
var agentList by mutableStateOf<List<AgentEntity>>(emptyList())
|
||||
@@ -87,4 +95,22 @@ object MineAgentViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun createSingleChat(
|
||||
openId: String,
|
||||
): String {
|
||||
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(generateText = openId))
|
||||
val body = response.body()?.data ?: throw ServiceException("Failed to create single chat")
|
||||
return body.toString()
|
||||
|
||||
}
|
||||
fun goToChat(
|
||||
conversation: Conversation,
|
||||
navController: NavHostController
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val profile = userService.getUserProfileByTrtcUserId(conversation.trtcUserId)
|
||||
navController.navigateToChat(profile.id.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user