use std::str::FromStr; use base64::{Engine, prelude::BASE64_STANDARD}; use reqwest::header; use serde_json::json; use tracing::error; use crate::{ pojo::common::ApiResult, vo::vo::{LoginReq, LoginResp}, }; #[derive(Debug)] pub struct ImRequestClient { client: reqwest::Client, base_url: String, pub token: Option, pub refresh_token: Option, } impl ImRequestClient { pub fn new(base_url: String) -> Result { let mut headers = header::HeaderMap::new(); headers.insert( header::CONTENT_TYPE, header::HeaderValue::from_static("application/json"), ); let basic_auth = BASE64_STANDARD.encode("luohuo_web_pro:luohuo_web_pro_secret"); let basic_auth_value = header::HeaderValue::from_str(&basic_auth) .map_err(|e| anyhow::anyhow!("Failed to create HTTP client: {}", e))?; headers.insert(header::AUTHORIZATION, basic_auth_value); let client = reqwest::Client::builder() .default_headers(headers) .build() .map_err(|e| anyhow::anyhow!("Failed to create HTTP client: {}", e))?; Ok(Self { client: client, base_url: base_url, token: None, refresh_token: None, }) } pub fn set_base_url(&mut self, base_url: String) { self.base_url = base_url; } /// 构建请求的公共方法(不发送请求) /// /// 提取了 URL 构建、token 添加、body/params 处理等公共逻辑 /// /// # 参数 /// - `method`: HTTP 方法 /// - `path`: API 路径 /// - `body`: 请求体(可选) /// - `params`: 查询参数(可选) /// - `extra_headers`: 额外的请求头(可选) fn build_request( &self, method: http::Method, path: &str, body: &Option, params: &Option, extra_headers: Option>, ) -> reqwest::RequestBuilder { let url = format!("{}/{}", self.base_url, path); let mut request_builder = self.client.request(method, &url); // 设置 token 请求头 if let Some(token) = &self.token { request_builder = request_builder.header("token", token); } // 添加额外的请求头 if let Some(headers) = extra_headers { for (key, value) in headers { request_builder = request_builder.header(key, value); } } // 设置请求体 if let Some(body) = body { request_builder = request_builder.json(body); } else { request_builder = request_builder.json(&serde_json::json!({})); } // 设置查询参数 if let Some(params) = params { request_builder = request_builder.query(params); } request_builder } pub async fn request< T: serde::de::DeserializeOwned, B: serde::Serialize, C: serde::Serialize, >( &mut self, method: http::Method, path: &str, body: Option, params: Option, ) -> Result, anyhow::Error> { let mut retry_count = 0; const MAX_RETRY_COUNT: u8 = 2; let is_logout = path == ImUrl::Logout.get_url().1; loop { // 使用 build_request 构建请求 let request_builder = self.build_request(method.clone(), path, &body, ¶ms, None); // 发送请求,区分网络错误和业务错误 let response = request_builder .send() .await .map_err(|e| anyhow::anyhow!("network_error: {}", e))?; let result: ApiResult = response .json() .await .map_err(|e| anyhow::anyhow!("network_error: {}", e))?; let url = format!("{}/{}", self.base_url, path); match result.code { Some(406) => { if is_logout { return Ok(result); } if retry_count >= MAX_RETRY_COUNT { return Err(anyhow::anyhow!("token过期,刷新token失败")); } self.start_refresh_token().await?; retry_count += 1; continue; } Some(401) => { if is_logout { return Ok(result); } error!( "{}; 方法: {}; 失败信息: {}", &url, method, result.msg.clone().unwrap_or_default() ); return Err(anyhow::anyhow!("请重新登录")); } Some(200) => { return Ok(result); } _ => { error!( "{}; 方法: {}; 失败信息: {}", &url, method, result.msg.clone().unwrap_or_default() ); return Err(anyhow::anyhow!( "{}", result.msg.clone().unwrap_or_default() )); } } } } /// 流式请求方法(用于 SSE 等流式响应) /// /// 与 `request` 方法的区别: /// 1. 添加 `Accept: text/event-stream` 请求头 /// 2. 返回 `reqwest::Response` 而不是解析 JSON /// 3. 不支持自动 token 刷新重试(因为流式响应无法中断重试) /// /// # 参数 /// - `method`: HTTP 方法 /// - `path`: API 路径 /// - `body`: 请求体(可选) /// - `params`: 查询参数(可选) /// /// # 返回 /// - `Ok(Response)`: 成功返回响应对象,可用于读取流式数据 /// - `Err`: 请求失败或状态码非 2xx pub async fn request_stream( &mut self, method: http::Method, path: &str, body: Option, params: Option, ) -> Result { // 添加流式请求头 let extra_headers = Some(vec![("Accept", "text/event-stream")]); // 使用 build_request 构建请求 let request_builder = self.build_request(method.clone(), path, &body, ¶ms, extra_headers); // 发送请求 let response = request_builder.send().await?; // 检查响应状态(但不解析 JSON) let status = response.status(); if !status.is_success() { let url = format!("{}/{}", self.base_url, path); error!("流式请求失败,URL: {}, 状态码: {}", url, status); // 根据状态码返回不同的错误信息 match status.as_u16() { 406 => { error!("Token expired in stream request"); return Err(anyhow::anyhow!("token过期,请刷新后重试")); } 401 => { error!("Unauthorized in stream request"); return Err(anyhow::anyhow!("请重新登录")); } _ => { return Err(anyhow::anyhow!("请求失败,状态码: {}", status)); } } } Ok(response) } pub async fn start_refresh_token(&mut self) -> Result<(), anyhow::Error> { let url = format!("{}/{}", self.base_url, ImUrl::RefreshToken.get_url().1); let refresh_token = match self.refresh_token.clone() { Some(token) if !token.is_empty() => token, _ => return Err(anyhow::anyhow!("请重新登录")), }; let old_refresh_token = refresh_token.clone(); let body = json!({ "refreshToken": refresh_token }); let request_builder = self.client.request(http::Method::POST, &url); let response = request_builder .json(&body) .send() .await .map_err(|e| anyhow::anyhow!("network_error: {}", e))?; let result: ApiResult = response .json() .await .map_err(|e| anyhow::anyhow!("network_error: {}", e))?; if !result.success { // 服务器明确拒绝 refresh token,需要重新登录 return Err(anyhow::anyhow!("请重新登录")); } let data = match result.data { Some(data) => data, None => { error!("刷新token失败: 响应缺少 data 字段"); return Err(anyhow::anyhow!("请重新登录")); } }; let token = match data.get("token").and_then(|value| value.as_str()) { Some(value) => value, None => { error!("刷新token失败: 响应缺少 token 字段"); return Err(anyhow::anyhow!("请重新登录")); } }; self.token = Some(token.to_owned()); let refresh_token = match data.get("refreshToken").and_then(|value| value.as_str()) { Some(value) if !value.is_empty() => value.to_owned(), _ => old_refresh_token, }; self.refresh_token = Some(refresh_token); Ok(()) } pub async fn im_request< T: serde::de::DeserializeOwned, B: serde::Serialize, C: serde::Serialize, >( &mut self, url: ImUrl, body: Option, params: Option, ) -> Result, anyhow::Error> { let (method, path) = url.get_url(); let result: ApiResult = self.request(method, path, body, params).await?; Ok(result.data) } } impl ImRequest for ImRequestClient { async fn login(&mut self, login_req: LoginReq) -> Result, anyhow::Error> { let result: Option = self .im_request(ImUrl::Login, Some(login_req), None::) .await?; if let Some(data) = result.clone() { self.token = Some(data.token.clone()); self.refresh_token = Some(data.refresh_token.clone()); } Ok(result) } } pub enum ImUrl { Login, RefreshToken, ForgetPassword, CheckToken, Logout, Register, GetQiniuToken, InitConfig, StorageProvider, MapCoordTranslate, MapReverseGeocode, MapStatic, GetAssistantModelList, SendCaptcha, GetCaptcha, Announcement, EditAnnouncement, DeleteAnnouncement, PushAnnouncement, GetAnnouncementList, ApplyGroup, SearchGroup, UpdateMyRoomInfo, UpdateRoomInfo, GroupList, GroupListMember, GroupDetail, GroupInfo, RevokeAdmin, AddAdmin, ExitGroup, AcceptInvite, InviteList, InviteGroupMember, RemoveGroupMember, CreateGroup, Shield, Notification, DeleteSession, SetSessionTop, SessionDetailWithFriends, SessionDetail, GetMsgReadCount, GetMsgReadList, ModifyFriendRemark, DeleteFriend, SendAddFriendRequest, HandleInvite, NoticeUnReadCount, RequestNoticePage, GetContactList, SearchFriend, ChangeUserState, GetAllUserState, UploadAvatar, GetEmoji, DeleteEmoji, AddEmoji, RecallMsg, BlockUser, MarkMsg, SetUserBadge, ModifyUserInfo, GetUserInfoDetail, GetMsgList, GetMsgPage, GetAllUserBaseInfo, GetBadgesBatch, GetMemberStatistic, GetBadgeList, FeedDetail, FeedList, PushFeed, DelFeed, EditFeed, GetFeedPermission, // 朋友圈点赞相关 FeedLikeToggle, FeedLikeList, FeedLikeCount, FeedLikeHasLiked, // 朋友圈评论相关 FeedCommentAdd, FeedCommentDelete, FeedCommentList, FeedCommentAll, FeedCommentCount, SendMsg, SetHide, GetFriendPage, MarkMsgRead, CheckEmail, MergeMsg, GetUserByIds, GenerateQRCode, CheckQRStatus, ScanQRCode, ConfirmQRCode, MessageSend, MessageSendStream, MessageListByConversationId, MessageDelete, MessageDeleteByConversationId, MessagePage, MessageDeleteByAdmin, MessageSaveGeneratedContent, ConversationCreateMy, ConversationUpdateMy, ConversationMyList, ConversationGetMy, ConversationDeleteMy, ConversationDeleteByUnpinned, ConversationPage, ConversationDeleteByAdmin, ModelCreate, ModelUpdate, ModelDelete, ModelGet, ModelRemainingUsage, ModelPage, ModelSimpleList, ChatRoleMyPage, ChatRoleGetMy, ChatRoleCreateMy, ChatRoleUpdateMy, ChatRoleDeleteMy, ChatRoleCategoryList, ChatRoleCreate, ChatRoleUpdate, ChatRoleDelete, ChatRoleGet, ChatRolePage, ApiKeyCreate, ApiKeyUpdate, ApiKeyDelete, ApiKeyGet, ApiKeyPage, ApiKeySimpleList, ApiKeyBalance, PlatformList, PlatformAddModel, ToolCreate, ToolUpdate, ToolDelete, ToolGet, ToolPage, ToolSimpleList, ImageMyPage, ImagePublicPage, ImageGetMy, ImageMyListByIds, ImageDraw, ImageDeleteMy, ImageMidjourneyImagine, ImageMidjourneyNotify, ImageMidjourneyAction, ImagePage, ImageUpdate, ImageDelete, VideoMyPage, VideoGet, VideoMyListByIds, VideoGenerate, VideoDeleteMy, AudioMyPage, AudioGetMy, AudioMyListByIds, AudioGenerate, AudioDeleteMy, AudioVoices, KnowledgePage, KnowledgeGet, KnowledgeCreate, KnowledgeUpdate, KnowledgeDelete, KnowledgeSimpleList, KnowledgeDocumentPage, KnowledgeDocumentGet, KnowledgeDocumentCreate, KnowledgeDocumentCreateList, KnowledgeDocumentUpdate, KnowledgeDocumentUpdateStatus, KnowledgeDocumentDelete, KnowledgeSegmentGet, KnowledgeSegmentPage, KnowledgeSegmentCreate, KnowledgeSegmentUpdate, KnowledgeSegmentUpdateStatus, KnowledgeSegmentSplit, KnowledgeSegmentGetProcessList, KnowledgeSegmentSearch, MindMapGenerateStream, MindMapDelete, MindMapPage, MusicMyPage, MusicGenerate, MusicDeleteMy, MusicGetMy, MusicUpdateMy, MusicPage, MusicDelete, MusicUpdate, WorkflowCreate, WorkflowUpdate, WorkflowDelete, WorkflowGet, WorkflowPage, WorkflowTest, WriteGenerateStream, WriteDelete, WritePage, } impl ImUrl { pub fn get_url(&self) -> (http::Method, &str) { match self { // Token 相关 ImUrl::Login => (http::Method::POST, "oauth/anyTenant/login"), ImUrl::RefreshToken => (http::Method::POST, "oauth/anyTenant/refresh"), ImUrl::ForgetPassword => (http::Method::PUT, "oauth/anyTenant/password"), ImUrl::CheckToken => (http::Method::POST, "oauth/check"), ImUrl::Logout => (http::Method::POST, "oauth/anyUser/logout"), ImUrl::Register => (http::Method::POST, "oauth/anyTenant/registerByEmail"), // 系统相关 ImUrl::GetQiniuToken => (http::Method::GET, "system/anyTenant/ossToken"), ImUrl::InitConfig => (http::Method::GET, "system/anyTenant/config/init"), ImUrl::StorageProvider => (http::Method::GET, "system/anyTenant/storage/provider"), ImUrl::MapCoordTranslate => (http::Method::GET, "system/anyTenant/map/coord/translate"), ImUrl::MapReverseGeocode => { (http::Method::GET, "system/anyTenant/map/geocoder/reverse") } ImUrl::MapStatic => (http::Method::GET, "system/anyTenant/map/static"), ImUrl::GetAssistantModelList => (http::Method::GET, "system/model/list"), // 验证码相关 ImUrl::SendCaptcha => (http::Method::POST, "oauth/anyTenant/sendEmailCode"), ImUrl::GetCaptcha => (http::Method::GET, "oauth/anyTenant/captcha"), // 群公告相关 ImUrl::Announcement => (http::Method::GET, "im/room/announcement"), ImUrl::EditAnnouncement => (http::Method::POST, "im/room/announcement/edit"), ImUrl::DeleteAnnouncement => (http::Method::POST, "im/room/announcement/delete"), ImUrl::PushAnnouncement => (http::Method::POST, "im/room/announcement/push"), ImUrl::GetAnnouncementList => (http::Method::GET, "im/room/announcement/list"), // 群聊申请相关 ImUrl::ApplyGroup => (http::Method::POST, "im/room/apply/group"), // 群聊搜索和管理 ImUrl::SearchGroup => (http::Method::GET, "im/room/search"), ImUrl::UpdateMyRoomInfo => (http::Method::POST, "im/room/updateMyRoomInfo"), ImUrl::UpdateRoomInfo => (http::Method::POST, "im/room/updateRoomInfo"), ImUrl::GroupList => (http::Method::GET, "im/room/group/list"), ImUrl::GroupListMember => (http::Method::GET, "im/room/group/listMember"), ImUrl::GroupDetail => (http::Method::GET, "im/room/group/detail"), ImUrl::GroupInfo => (http::Method::GET, "im/room/group/info"), // 群聊管理员 ImUrl::RevokeAdmin => (http::Method::DELETE, "im/room/group/admin"), ImUrl::AddAdmin => (http::Method::PUT, "im/room/group/admin"), // 群聊成员管理 ImUrl::ExitGroup => (http::Method::DELETE, "im/room/group/member/exit"), ImUrl::AcceptInvite => (http::Method::POST, "im/room/group/invite/accept"), ImUrl::InviteList => (http::Method::GET, "im/room/group/invite/list"), ImUrl::InviteGroupMember => (http::Method::POST, "im/room/group/member"), ImUrl::RemoveGroupMember => (http::Method::DELETE, "im/room/group/member"), ImUrl::CreateGroup => (http::Method::POST, "im/room/group"), // 聊天会话相关 ImUrl::Shield => (http::Method::POST, "im/chat/setShield"), ImUrl::Notification => (http::Method::POST, "im/chat/notification"), ImUrl::DeleteSession => (http::Method::DELETE, "im/chat/delete"), ImUrl::SetSessionTop => (http::Method::POST, "im/chat/setTop"), ImUrl::SessionDetailWithFriends => (http::Method::GET, "im/chat/contact/detail/friend"), ImUrl::SessionDetail => (http::Method::GET, "im/chat/contact/detail"), ImUrl::SetHide => (http::Method::POST, "im/chat/setHide"), // 消息已读未读 ImUrl::GetMsgReadCount => (http::Method::GET, "im/chat/msg/read"), ImUrl::MarkMsgRead => (http::Method::PUT, "im/chat/msg/read"), ImUrl::SendMsg => (http::Method::POST, "im/chat/msg"), ImUrl::GetMsgReadList => (http::Method::GET, "im/chat/msg/read/page"), // 好友相关 ImUrl::ModifyFriendRemark => (http::Method::POST, "im/user/friend/updateRemark"), ImUrl::DeleteFriend => (http::Method::DELETE, "im/user/friend"), ImUrl::SendAddFriendRequest => (http::Method::POST, "im/room/apply/apply"), ImUrl::HandleInvite => (http::Method::POST, "im/room/apply/handler/apply"), ImUrl::NoticeUnReadCount => (http::Method::GET, "im/room/notice/unread"), ImUrl::RequestNoticePage => (http::Method::GET, "im/room/notice/page"), ImUrl::GetFriendPage => (http::Method::GET, "im/user/friend/page"), ImUrl::GetContactList => (http::Method::GET, "im/chat/contact/list"), ImUrl::SearchFriend => (http::Method::GET, "im/user/friend/search"), // 用户状态相关 ImUrl::ChangeUserState => (http::Method::POST, "im/user/state/changeState"), ImUrl::GetAllUserState => (http::Method::GET, "im/user/state/list"), // 用户信息相关 ImUrl::UploadAvatar => (http::Method::POST, "im/user/avatar"), ImUrl::GetEmoji => (http::Method::GET, "im/user/emoji/list"), ImUrl::DeleteEmoji => (http::Method::DELETE, "im/user/emoji"), ImUrl::AddEmoji => (http::Method::POST, "im/user/emoji"), ImUrl::SetUserBadge => (http::Method::PUT, "im/user/badge"), ImUrl::ModifyUserInfo => (http::Method::PUT, "im/user/info"), ImUrl::GetUserInfoDetail => (http::Method::GET, "im/user/userInfo"), ImUrl::GetBadgesBatch => (http::Method::POST, "im/user/badges/batch"), ImUrl::GetBadgeList => (http::Method::GET, "im/user/badges"), ImUrl::BlockUser => (http::Method::PUT, "im/user/black"), // 扫码登录相关 ImUrl::GenerateQRCode => (http::Method::GET, "oauth/anyTenant/qr/generate"), ImUrl::CheckQRStatus => (http::Method::GET, "oauth/anyTenant/qr/status/query"), ImUrl::ScanQRCode => (http::Method::POST, "oauth/qrcode/scan"), ImUrl::ConfirmQRCode => (http::Method::POST, "oauth/qrcode/confirm"), // 消息相关 ImUrl::RecallMsg => (http::Method::PUT, "im/chat/msg/recall"), ImUrl::MarkMsg => (http::Method::PUT, "im/chat/msg/mark"), ImUrl::GetMsgPage => (http::Method::GET, "im/chat/msg/page"), ImUrl::GetMsgList => (http::Method::POST, "im/chat/msg/list"), ImUrl::GetMemberStatistic => (http::Method::GET, "im/chat/member/statistic"), // 朋友圈相关 ImUrl::FeedList => (http::Method::POST, "im/feed/list"), ImUrl::PushFeed => (http::Method::POST, "im/feed/pushFeed"), ImUrl::GetFeedPermission => (http::Method::GET, "im/feed/getFeedPermission"), ImUrl::EditFeed => (http::Method::POST, "im/feed/edit"), ImUrl::DelFeed => (http::Method::POST, "im/feed/del"), ImUrl::FeedDetail => (http::Method::GET, "im/feed/detail"), // 朋友圈点赞相关 ImUrl::FeedLikeToggle => (http::Method::POST, "im/feed/like/toggle"), ImUrl::FeedLikeList => (http::Method::GET, "im/feed/like/list"), ImUrl::FeedLikeCount => (http::Method::GET, "im/feed/like/count"), ImUrl::FeedLikeHasLiked => (http::Method::GET, "im/feed/like/hasLiked"), // 朋友圈评论相关 ImUrl::FeedCommentAdd => (http::Method::POST, "im/feed/comment/add"), ImUrl::FeedCommentDelete => (http::Method::POST, "im/feed/comment/delete"), ImUrl::FeedCommentList => (http::Method::POST, "im/feed/comment/list"), ImUrl::FeedCommentAll => (http::Method::GET, "im/feed/comment/all"), ImUrl::FeedCommentCount => (http::Method::GET, "im/feed/comment/count"), // ai相关 - 聊天消息 ImUrl::MessageSend => (http::Method::POST, "ai/chat/message/send"), ImUrl::MessageSendStream => (http::Method::POST, "ai/chat/message/send-stream"), ImUrl::MessageListByConversationId => { (http::Method::GET, "ai/chat/message/list-by-conversation-id") } ImUrl::MessageDelete => (http::Method::DELETE, "ai/chat/message/delete"), ImUrl::MessageDeleteByConversationId => ( http::Method::DELETE, "ai/chat/message/delete-by-conversation-id", ), ImUrl::MessagePage => (http::Method::GET, "ai/chat/message/page"), ImUrl::MessageDeleteByAdmin => { (http::Method::DELETE, "ai/chat/message/delete-by-admin") } ImUrl::MessageSaveGeneratedContent => { (http::Method::POST, "ai/chat/message/save-generated-content") } // AI 聊天对话 ImUrl::ConversationCreateMy => (http::Method::POST, "ai/chat/conversation/create-my"), ImUrl::ConversationUpdateMy => (http::Method::PUT, "ai/chat/conversation/update-my"), ImUrl::ConversationMyList => (http::Method::GET, "ai/chat/conversation/my-list"), ImUrl::ConversationGetMy => (http::Method::GET, "ai/chat/conversation/get-my"), ImUrl::ConversationDeleteMy => (http::Method::DELETE, "ai/chat/conversation/delete-my"), ImUrl::ConversationDeleteByUnpinned => ( http::Method::DELETE, "ai/chat/conversation/delete-by-unpinned", ), ImUrl::ConversationPage => (http::Method::GET, "ai/chat/conversation/page"), ImUrl::ConversationDeleteByAdmin => { (http::Method::DELETE, "ai/chat/conversation/delete-by-admin") } // AI 模型相关接口 ImUrl::ModelCreate => (http::Method::POST, "ai/model/create"), ImUrl::ModelUpdate => (http::Method::PUT, "ai/model/update"), ImUrl::ModelDelete => (http::Method::DELETE, "ai/model/delete"), ImUrl::ModelGet => (http::Method::GET, "ai/model/get"), ImUrl::ModelRemainingUsage => (http::Method::GET, "ai/model/get-remaining-usage"), ImUrl::ModelPage => (http::Method::GET, "ai/model/page"), ImUrl::ModelSimpleList => (http::Method::GET, "ai/model/simple-list"), // 聊天角色相关接口 ImUrl::ChatRoleMyPage => (http::Method::GET, "ai/chat-role/my-page"), ImUrl::ChatRoleGetMy => (http::Method::GET, "ai/chat-role/get-my"), ImUrl::ChatRoleCreateMy => (http::Method::POST, "ai/chat-role/create-my"), ImUrl::ChatRoleUpdateMy => (http::Method::PUT, "ai/chat-role/update-my"), ImUrl::ChatRoleDeleteMy => (http::Method::DELETE, "ai/chat-role/delete-my"), ImUrl::ChatRoleCategoryList => (http::Method::GET, "ai/chat-role/category-list"), ImUrl::ChatRoleCreate => (http::Method::POST, "ai/chat-role/create"), ImUrl::ChatRoleUpdate => (http::Method::PUT, "ai/chat-role/update"), ImUrl::ChatRoleDelete => (http::Method::DELETE, "ai/chat-role/delete"), ImUrl::ChatRoleGet => (http::Method::GET, "ai/chat-role/get"), ImUrl::ChatRolePage => (http::Method::GET, "ai/chat-role/page"), // API 密钥相关接口 ImUrl::ApiKeyCreate => (http::Method::POST, "ai/api-key/create"), ImUrl::ApiKeyUpdate => (http::Method::PUT, "ai/api-key/update"), ImUrl::ApiKeyDelete => (http::Method::DELETE, "ai/api-key/delete"), ImUrl::ApiKeyGet => (http::Method::GET, "ai/api-key/get"), ImUrl::ApiKeyPage => (http::Method::GET, "ai/api-key/page"), ImUrl::ApiKeySimpleList => (http::Method::GET, "ai/api-key/simple-list"), ImUrl::ApiKeyBalance => (http::Method::GET, "ai/api-key/balance"), // 平台相关接口 ImUrl::PlatformList => (http::Method::GET, "ai/platform/list"), ImUrl::PlatformAddModel => (http::Method::POST, "ai/platform/add-model"), // AI 工具相关接口 ImUrl::ToolCreate => (http::Method::POST, "ai/tool/create"), ImUrl::ToolUpdate => (http::Method::PUT, "ai/tool/update"), ImUrl::ToolDelete => (http::Method::DELETE, "ai/tool/delete"), ImUrl::ToolGet => (http::Method::GET, "ai/tool/get"), ImUrl::ToolPage => (http::Method::GET, "ai/tool/page"), ImUrl::ToolSimpleList => (http::Method::GET, "ai/tool/simple-list"), // AI 绘画 ImUrl::ImageMyPage => (http::Method::GET, "ai/image/my-page"), ImUrl::ImagePublicPage => (http::Method::GET, "ai/image/public-page"), ImUrl::ImageGetMy => (http::Method::GET, "ai/image/get-my"), ImUrl::ImageMyListByIds => (http::Method::GET, "ai/image/my-list-by-ids"), ImUrl::ImageDraw => (http::Method::POST, "ai/image/draw"), ImUrl::ImageDeleteMy => (http::Method::DELETE, "ai/image/delete-my"), ImUrl::ImageMidjourneyImagine => (http::Method::POST, "ai/image/midjourney/imagine"), ImUrl::ImageMidjourneyNotify => (http::Method::POST, "ai/image/midjourney/notify"), ImUrl::ImageMidjourneyAction => (http::Method::POST, "ai/image/midjourney/action"), ImUrl::ImagePage => (http::Method::GET, "ai/image/page"), ImUrl::ImageUpdate => (http::Method::PUT, "ai/image/update"), ImUrl::ImageDelete => (http::Method::DELETE, "ai/image/delete"), // AI 视频生成 ImUrl::VideoMyPage => (http::Method::GET, "ai/video/my-page"), ImUrl::VideoGet => (http::Method::GET, "ai/video/get"), ImUrl::VideoMyListByIds => (http::Method::GET, "ai/video/my-list-by-ids"), ImUrl::VideoGenerate => (http::Method::POST, "ai/video/generate"), ImUrl::VideoDeleteMy => (http::Method::DELETE, "ai/video/delete-my"), // AI 音频生成 ImUrl::AudioMyPage => (http::Method::GET, "ai/audio/my-page"), ImUrl::AudioGetMy => (http::Method::GET, "ai/audio/get-my"), ImUrl::AudioMyListByIds => (http::Method::GET, "ai/audio/my-list-by-ids"), ImUrl::AudioGenerate => (http::Method::POST, "ai/audio/generate"), ImUrl::AudioDeleteMy => (http::Method::DELETE, "ai/audio/delete-my"), ImUrl::AudioVoices => (http::Method::GET, "ai/audio/voices"), // 知识库相关接口 ImUrl::KnowledgePage => (http::Method::GET, "ai/knowledge/page"), ImUrl::KnowledgeGet => (http::Method::GET, "ai/knowledge/get"), ImUrl::KnowledgeCreate => (http::Method::POST, "ai/knowledge/create"), ImUrl::KnowledgeUpdate => (http::Method::PUT, "ai/knowledge/update"), ImUrl::KnowledgeDelete => (http::Method::DELETE, "ai/knowledge/delete"), ImUrl::KnowledgeSimpleList => (http::Method::GET, "ai/knowledge/simple-list"), // 知识库文档相关接口 ImUrl::KnowledgeDocumentPage => (http::Method::GET, "ai/knowledge/document/page"), ImUrl::KnowledgeDocumentGet => (http::Method::GET, "ai/knowledge/document/get"), ImUrl::KnowledgeDocumentCreate => (http::Method::POST, "ai/knowledge/document/create"), ImUrl::KnowledgeDocumentCreateList => { (http::Method::POST, "ai/knowledge/document/create-list") } ImUrl::KnowledgeDocumentUpdate => (http::Method::PUT, "ai/knowledge/document/update"), ImUrl::KnowledgeDocumentUpdateStatus => { (http::Method::PUT, "ai/knowledge/document/update-status") } ImUrl::KnowledgeDocumentDelete => { (http::Method::DELETE, "ai/knowledge/document/delete") } // 知识库文档片段相关接口 ImUrl::KnowledgeSegmentGet => (http::Method::GET, "ai/knowledge/segment/get"), ImUrl::KnowledgeSegmentPage => (http::Method::GET, "ai/knowledge/segment/page"), ImUrl::KnowledgeSegmentCreate => (http::Method::POST, "ai/knowledge/segment/create"), ImUrl::KnowledgeSegmentUpdate => (http::Method::PUT, "ai/knowledge/segment/update"), ImUrl::KnowledgeSegmentUpdateStatus => { (http::Method::PUT, "ai/knowledge/segment/update-status") } ImUrl::KnowledgeSegmentSplit => (http::Method::GET, "ai/knowledge/segment/split"), ImUrl::KnowledgeSegmentGetProcessList => { (http::Method::GET, "ai/knowledge/segment/get-process-list") } ImUrl::KnowledgeSegmentSearch => (http::Method::GET, "ai/knowledge/segment/search"), // AI 思维导图相关接口 ImUrl::MindMapGenerateStream => (http::Method::POST, "ai/mind-map/generate-stream"), ImUrl::MindMapDelete => (http::Method::DELETE, "ai/mind-map/delete"), ImUrl::MindMapPage => (http::Method::GET, "ai/mind-map/page"), // 音乐 ImUrl::MusicMyPage => (http::Method::GET, "ai/music/my-page"), ImUrl::MusicGenerate => (http::Method::POST, "ai/music/generate"), ImUrl::MusicDeleteMy => (http::Method::DELETE, "ai/music/delete-my"), ImUrl::MusicGetMy => (http::Method::GET, "ai/music/get-my"), ImUrl::MusicUpdateMy => (http::Method::POST, "ai/music/update-my"), ImUrl::MusicPage => (http::Method::GET, "ai/music/page"), ImUrl::MusicDelete => (http::Method::DELETE, "ai/music/delete"), ImUrl::MusicUpdate => (http::Method::PUT, "ai/music/update"), // 工作流 ImUrl::WorkflowCreate => (http::Method::POST, "ai/workflow/create"), ImUrl::WorkflowUpdate => (http::Method::PUT, "ai/workflow/update"), ImUrl::WorkflowDelete => (http::Method::DELETE, "ai/workflow/delete"), ImUrl::WorkflowGet => (http::Method::GET, "ai/workflow/get"), ImUrl::WorkflowPage => (http::Method::GET, "ai/workflow/page"), ImUrl::WorkflowTest => (http::Method::POST, "ai/workflow/test"), // 写作 ImUrl::WriteGenerateStream => (http::Method::POST, "ai/write/generate-stream"), ImUrl::WriteDelete => (http::Method::DELETE, "ai/write/delete"), ImUrl::WritePage => (http::Method::GET, "ai/write/page"), // 群成员信息 ImUrl::GetAllUserBaseInfo => (http::Method::GET, "im/room/group/member/list"), ImUrl::CheckEmail => (http::Method::GET, "oauth/anyTenant/checkEmail"), ImUrl::MergeMsg => (http::Method::POST, "im/room/mergeMessage"), ImUrl::GetUserByIds => (http::Method::POST, "im/user/getUserByIds"), } } fn from_str(s: &str) -> Result { match s { // Token 相关 "login" => Ok(ImUrl::Login), "refreshToken" => Ok(ImUrl::RefreshToken), "forgetPassword" => Ok(ImUrl::ForgetPassword), "checkToken" => Ok(ImUrl::CheckToken), "logout" => Ok(ImUrl::Logout), "register" => Ok(ImUrl::Register), // 系统相关 "getQiniuToken" => Ok(ImUrl::GetQiniuToken), "initConfig" => Ok(ImUrl::InitConfig), "storageProvider" => Ok(ImUrl::StorageProvider), "mapCoordTranslate" => Ok(ImUrl::MapCoordTranslate), "mapReverseGeocode" => Ok(ImUrl::MapReverseGeocode), "mapStatic" => Ok(ImUrl::MapStatic), "getAssistantModelList" => Ok(ImUrl::GetAssistantModelList), // 验证码相关 "sendCaptcha" => Ok(ImUrl::SendCaptcha), "getCaptcha" => Ok(ImUrl::GetCaptcha), // 群公告相关 "announcement" => Ok(ImUrl::Announcement), "editAnnouncement" => Ok(ImUrl::EditAnnouncement), "deleteAnnouncement" => Ok(ImUrl::DeleteAnnouncement), "pushAnnouncement" => Ok(ImUrl::PushAnnouncement), "getAnnouncementList" => Ok(ImUrl::GetAnnouncementList), // 群聊申请相关 "applyGroup" => Ok(ImUrl::ApplyGroup), // 群聊搜索和管理 "searchGroup" => Ok(ImUrl::SearchGroup), "updateMyRoomInfo" => Ok(ImUrl::UpdateMyRoomInfo), "updateRoomInfo" => Ok(ImUrl::UpdateRoomInfo), "groupList" => Ok(ImUrl::GroupList), "groupDetail" => Ok(ImUrl::GroupDetail), "groupInfo" => Ok(ImUrl::GroupInfo), // 群聊管理员 "revokeAdmin" => Ok(ImUrl::RevokeAdmin), "addAdmin" => Ok(ImUrl::AddAdmin), // 群聊成员管理 "exitGroup" => Ok(ImUrl::ExitGroup), "acceptInvite" => Ok(ImUrl::AcceptInvite), "inviteList" => Ok(ImUrl::InviteList), "inviteGroupMember" => Ok(ImUrl::InviteGroupMember), "removeGroupMember" => Ok(ImUrl::RemoveGroupMember), "createGroup" => Ok(ImUrl::CreateGroup), // 聊天会话相关 "shield" => Ok(ImUrl::Shield), "notification" => Ok(ImUrl::Notification), "deleteSession" => Ok(ImUrl::DeleteSession), "setSessionTop" => Ok(ImUrl::SetSessionTop), "sessionDetailWithFriends" => Ok(ImUrl::SessionDetailWithFriends), "sessionDetail" => Ok(ImUrl::SessionDetail), // 消息已读未读 "getMsgReadCount" => Ok(ImUrl::GetMsgReadCount), "getMsgReadList" => Ok(ImUrl::GetMsgReadList), // 好友相关 "modifyFriendRemark" => Ok(ImUrl::ModifyFriendRemark), "deleteFriend" => Ok(ImUrl::DeleteFriend), "sendAddFriendRequest" => Ok(ImUrl::SendAddFriendRequest), "handleInvite" => Ok(ImUrl::HandleInvite), "noticeUnReadCount" => Ok(ImUrl::NoticeUnReadCount), "requestNoticePage" => Ok(ImUrl::RequestNoticePage), "getContactList" => Ok(ImUrl::GetContactList), "searchFriend" => Ok(ImUrl::SearchFriend), // 用户状态相关 "changeUserState" => Ok(ImUrl::ChangeUserState), "getAllUserState" => Ok(ImUrl::GetAllUserState), // 用户信息相关 "uploadAvatar" => Ok(ImUrl::UploadAvatar), "getEmoji" => Ok(ImUrl::GetEmoji), "deleteEmoji" => Ok(ImUrl::DeleteEmoji), "addEmoji" => Ok(ImUrl::AddEmoji), "setUserBadge" => Ok(ImUrl::SetUserBadge), "ModifyUserInfo" => Ok(ImUrl::ModifyUserInfo), "getUserInfoDetail" => Ok(ImUrl::GetUserInfoDetail), "getBadgesBatch" => Ok(ImUrl::GetBadgesBatch), "getBadgeList" => Ok(ImUrl::GetBadgeList), "blockUser" => Ok(ImUrl::BlockUser), // 消息相关 "recallMsg" => Ok(ImUrl::RecallMsg), "markMsg" => Ok(ImUrl::MarkMsg), "getMsgList" => Ok(ImUrl::GetMsgList), "getMsgPage" => Ok(ImUrl::GetMsgPage), "getMemberStatistic" => Ok(ImUrl::GetMemberStatistic), // 朋友圈相关 "feedDetail" => Ok(ImUrl::FeedDetail), "feedList" => Ok(ImUrl::FeedList), "pushFeed" => Ok(ImUrl::PushFeed), "delFeed" => Ok(ImUrl::DelFeed), "editFeed" => Ok(ImUrl::EditFeed), "getFeedPermission" => Ok(ImUrl::GetFeedPermission), // 朋友圈点赞相关 "feedLikeToggle" => Ok(ImUrl::FeedLikeToggle), "feedLikeList" => Ok(ImUrl::FeedLikeList), "feedLikeCount" => Ok(ImUrl::FeedLikeCount), "feedLikeHasLiked" => Ok(ImUrl::FeedLikeHasLiked), // 朋友圈评论相关 "feedCommentAdd" => Ok(ImUrl::FeedCommentAdd), "feedCommentDelete" => Ok(ImUrl::FeedCommentDelete), "feedCommentList" => Ok(ImUrl::FeedCommentList), "feedCommentAll" => Ok(ImUrl::FeedCommentAll), "feedCommentCount" => Ok(ImUrl::FeedCommentCount), // 群成员信息 "getAllUserBaseInfo" => Ok(ImUrl::GetAllUserBaseInfo), "sendMsg" => Ok(ImUrl::SendMsg), "setHide" => Ok(ImUrl::SetHide), "getFriendPage" => Ok(ImUrl::GetFriendPage), "markMsgRead" => Ok(ImUrl::MarkMsgRead), "groupListMember" => Ok(ImUrl::GroupListMember), "checkEmail" => Ok(ImUrl::CheckEmail), "mergeMsg" => Ok(ImUrl::MergeMsg), "getUserByIds" => Ok(ImUrl::GetUserByIds), "generateQRCode" => Ok(ImUrl::GenerateQRCode), "checkQRStatus" => Ok(ImUrl::CheckQRStatus), "scanQRCode" => Ok(ImUrl::ScanQRCode), "confirmQRCode" => Ok(ImUrl::ConfirmQRCode), // ================ AI 聊天消息 ================ "messageSend" => Ok(ImUrl::MessageSend), "messageSendStream" => Ok(ImUrl::MessageSendStream), "messageListByConversationId" => Ok(ImUrl::MessageListByConversationId), "messageDelete" => Ok(ImUrl::MessageDelete), "messageDeleteByConversationId" => Ok(ImUrl::MessageDeleteByConversationId), "messagePage" => Ok(ImUrl::MessagePage), "messageDeleteByAdmin" => Ok(ImUrl::MessageDeleteByAdmin), "messageSaveGeneratedContent" => Ok(ImUrl::MessageSaveGeneratedContent), // ================ AI 聊天对话 ================ "conversationCreateMy" => Ok(ImUrl::ConversationCreateMy), "conversationUpdateMy" => Ok(ImUrl::ConversationUpdateMy), "conversationMyList" => Ok(ImUrl::ConversationMyList), "conversationGetMy" => Ok(ImUrl::ConversationGetMy), "conversationDeleteMy" => Ok(ImUrl::ConversationDeleteMy), "conversationDeleteByUnpinned" => Ok(ImUrl::ConversationDeleteByUnpinned), "conversationPage" => Ok(ImUrl::ConversationPage), "conversationDeleteByAdmin" => Ok(ImUrl::ConversationDeleteByAdmin), // ================ AI 模型 ================ "modelCreate" => Ok(ImUrl::ModelCreate), "modelUpdate" => Ok(ImUrl::ModelUpdate), "modelDelete" => Ok(ImUrl::ModelDelete), "modelGet" => Ok(ImUrl::ModelGet), "modelRemainingUsage" => Ok(ImUrl::ModelRemainingUsage), "modelPage" => Ok(ImUrl::ModelPage), "modelSimpleList" => Ok(ImUrl::ModelSimpleList), // ================ AI 聊天角色 ================ "chatRoleMyPage" => Ok(ImUrl::ChatRoleMyPage), "chatRoleGetMy" => Ok(ImUrl::ChatRoleGetMy), "chatRoleCreateMy" => Ok(ImUrl::ChatRoleCreateMy), "chatRoleUpdateMy" => Ok(ImUrl::ChatRoleUpdateMy), "chatRoleDeleteMy" => Ok(ImUrl::ChatRoleDeleteMy), "chatRoleCategoryList" => Ok(ImUrl::ChatRoleCategoryList), "chatRoleCreate" => Ok(ImUrl::ChatRoleCreate), "chatRoleUpdate" => Ok(ImUrl::ChatRoleUpdate), "chatRoleDelete" => Ok(ImUrl::ChatRoleDelete), "chatRoleGet" => Ok(ImUrl::ChatRoleGet), "chatRolePage" => Ok(ImUrl::ChatRolePage), // ================ API 密钥 ================ "apiKeyCreate" => Ok(ImUrl::ApiKeyCreate), "apiKeyUpdate" => Ok(ImUrl::ApiKeyUpdate), "apiKeyDelete" => Ok(ImUrl::ApiKeyDelete), "apiKeyGet" => Ok(ImUrl::ApiKeyGet), "apiKeyPage" => Ok(ImUrl::ApiKeyPage), "apiKeySimpleList" => Ok(ImUrl::ApiKeySimpleList), "apiKeyBalance" => Ok(ImUrl::ApiKeyBalance), // ================ 平台配置 ================ "platformList" => Ok(ImUrl::PlatformList), "platformAddModel" => Ok(ImUrl::PlatformAddModel), // ================ AI 工具 ================ "toolCreate" => Ok(ImUrl::ToolCreate), "toolUpdate" => Ok(ImUrl::ToolUpdate), "toolDelete" => Ok(ImUrl::ToolDelete), "toolGet" => Ok(ImUrl::ToolGet), "toolPage" => Ok(ImUrl::ToolPage), "toolSimpleList" => Ok(ImUrl::ToolSimpleList), // ================ AI 图像 ================ "imageMyPage" => Ok(ImUrl::ImageMyPage), "imagePublicPage" => Ok(ImUrl::ImagePublicPage), "imageGetMy" => Ok(ImUrl::ImageGetMy), "imageMyListByIds" => Ok(ImUrl::ImageMyListByIds), "imageDraw" => Ok(ImUrl::ImageDraw), "imageDeleteMy" => Ok(ImUrl::ImageDeleteMy), "imageMidjourneyImagine" => Ok(ImUrl::ImageMidjourneyImagine), "imageMidjourneyNotify" => Ok(ImUrl::ImageMidjourneyNotify), "imageMidjourneyAction" => Ok(ImUrl::ImageMidjourneyAction), "imagePage" => Ok(ImUrl::ImagePage), "imageUpdate" => Ok(ImUrl::ImageUpdate), "imageDelete" => Ok(ImUrl::ImageDelete), // ================ AI 视频生成 ================ "videoMyPage" => Ok(ImUrl::VideoMyPage), "videoGet" => Ok(ImUrl::VideoGet), "videoMyListByIds" => Ok(ImUrl::VideoMyListByIds), "videoGenerate" => Ok(ImUrl::VideoGenerate), "videoDeleteMy" => Ok(ImUrl::VideoDeleteMy), // ================ AI 音频生成 ================ "audioMyPage" => Ok(ImUrl::AudioMyPage), "audioGetMy" => Ok(ImUrl::AudioGetMy), "audioMyListByIds" => Ok(ImUrl::AudioMyListByIds), "audioGenerate" => Ok(ImUrl::AudioGenerate), "audioDeleteMy" => Ok(ImUrl::AudioDeleteMy), "audioVoices" => Ok(ImUrl::AudioVoices), // ================ AI 知识库 ================ "knowledgePage" => Ok(ImUrl::KnowledgePage), "knowledgeGet" => Ok(ImUrl::KnowledgeGet), "knowledgeCreate" => Ok(ImUrl::KnowledgeCreate), "knowledgeUpdate" => Ok(ImUrl::KnowledgeUpdate), "knowledgeDelete" => Ok(ImUrl::KnowledgeDelete), "knowledgeSimpleList" => Ok(ImUrl::KnowledgeSimpleList), // ================ AI 知识库文档 ================ "knowledgeDocumentPage" => Ok(ImUrl::KnowledgeDocumentPage), "knowledgeDocumentGet" => Ok(ImUrl::KnowledgeDocumentGet), "knowledgeDocumentCreate" => Ok(ImUrl::KnowledgeDocumentCreate), "knowledgeDocumentCreateList" => Ok(ImUrl::KnowledgeDocumentCreateList), "knowledgeDocumentUpdate" => Ok(ImUrl::KnowledgeDocumentUpdate), "knowledgeDocumentUpdateStatus" => Ok(ImUrl::KnowledgeDocumentUpdateStatus), "knowledgeDocumentDelete" => Ok(ImUrl::KnowledgeDocumentDelete), // ================ AI 知识库段落 ================ "knowledgeSegmentGet" => Ok(ImUrl::KnowledgeSegmentGet), "knowledgeSegmentPage" => Ok(ImUrl::KnowledgeSegmentPage), "knowledgeSegmentCreate" => Ok(ImUrl::KnowledgeSegmentCreate), "knowledgeSegmentUpdate" => Ok(ImUrl::KnowledgeSegmentUpdate), "knowledgeSegmentUpdateStatus" => Ok(ImUrl::KnowledgeSegmentUpdateStatus), "KnowledgeSegmentSplit" => Ok(ImUrl::KnowledgeSegmentSplit), "KnowledgeSegmentGetProcessList" => Ok(ImUrl::KnowledgeSegmentGetProcessList), "KnowledgeSegmentSearch" => Ok(ImUrl::KnowledgeSegmentSearch), // ================ AI 思维导图 ================ "mindMapGenerateStream" => Ok(ImUrl::MindMapGenerateStream), "mindMapDelete" => Ok(ImUrl::MindMapDelete), "mindMapPage" => Ok(ImUrl::MindMapPage), // ================ AI 音乐 ================ "musicMyPage" => Ok(ImUrl::MusicMyPage), "musicGenerate" => Ok(ImUrl::MusicGenerate), "musicDeleteMy" => Ok(ImUrl::MusicDeleteMy), "musicGetMy" => Ok(ImUrl::MusicGetMy), "musicUpdateMy" => Ok(ImUrl::MusicUpdateMy), "musicPage" => Ok(ImUrl::MusicPage), "musicDelete" => Ok(ImUrl::MusicDelete), "musicUpdate" => Ok(ImUrl::MusicUpdate), // ================ AI 工作流 ================ "workflowCreate" => Ok(ImUrl::WorkflowCreate), "workflowUpdate" => Ok(ImUrl::WorkflowUpdate), "workflowDelete" => Ok(ImUrl::WorkflowDelete), "workflowGet" => Ok(ImUrl::WorkflowGet), "workflowPage" => Ok(ImUrl::WorkflowPage), "workflowTest" => Ok(ImUrl::WorkflowTest), // ================ AI 写作 ================ "WriteGenerateStream" => Ok(ImUrl::WriteGenerateStream), "WriteDelete" => Ok(ImUrl::WriteDelete), "WritePage" => Ok(ImUrl::WritePage), // 未匹配的字符串 _ => Err(anyhow::anyhow!("未知的URL类型: {}", s)), } } } impl FromStr for ImUrl { type Err = anyhow::Error; fn from_str(s: &str) -> Result { Self::from_str(s) } } pub trait ImRequest { async fn login(&mut self, login_req: LoginReq) -> Result, anyhow::Error>; }