diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionCreateAndUpdateInput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionCreateAndUpdateInput.cs index c41d956f..cf1ffe89 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionCreateAndUpdateInput.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionCreateAndUpdateInput.cs @@ -1,8 +1,15 @@ -namespace Yi.Framework.AiHub.Application.Contracts.Dtos; +using Yi.Framework.AiHub.Domain.Shared.Enums; + +namespace Yi.Framework.AiHub.Application.Contracts.Dtos; public class SessionCreateAndUpdateInput { public string SessionTitle { get; set; } public string SessionContent { get; set; } public string? Remark { get; set; } + + /// + /// 会话类型 + /// + public SessionTypeEnum SessionType { get; set; } = SessionTypeEnum.Chat; } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionDto.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionDto.cs index a4162aa0..0616f214 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionDto.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionDto.cs @@ -1,4 +1,5 @@ using Volo.Abp.Application.Dtos; +using Yi.Framework.AiHub.Domain.Shared.Enums; namespace Yi.Framework.AiHub.Application.Contracts.Dtos; @@ -7,4 +8,9 @@ public class SessionDto : FullAuditedEntityDto public string SessionTitle { get; set; } public string SessionContent { get; set; } public string Remark { get; set; } + + /// + /// 会话类型 + /// + public SessionTypeEnum SessionType { get; set; } } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionGetListInput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionGetListInput.cs index c4dd072a..1b85c460 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionGetListInput.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/SessionGetListInput.cs @@ -1,8 +1,14 @@ -using Yi.Framework.Ddd.Application.Contracts; +using Yi.Framework.AiHub.Domain.Shared.Enums; +using Yi.Framework.Ddd.Application.Contracts; namespace Yi.Framework.AiHub.Application.Contracts.Dtos; -public class SessionGetListInput:PagedAllResultRequestDto +public class SessionGetListInput : PagedAllResultRequestDto { public string? SessionTitle { get; set; } + + /// + /// 会话类型 + /// + public SessionTypeEnum? SessionType { get; set; } } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/SessionService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/SessionService.cs index 1a7cb4f0..4099883a 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/SessionService.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/SessionService.cs @@ -84,7 +84,8 @@ public class SessionService : CrudAppService total = 0; var userId = CurrentUser.GetId(); var entities = await _repository._DbQueryable - .Where(x=>x.UserId == userId) + .Where(x => x.UserId == userId) + .WhereIF(input.SessionType.HasValue, x => x.SessionType == input.SessionType!.Value) .OrderByDescending(x => x.Id) .ToPageListAsync(input.SkipCount, input.MaxResultCount, total); return new PagedResultDto(total, entities.Adapt>()); diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/SessionTypeEnum.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/SessionTypeEnum.cs new file mode 100644 index 00000000..adbf7041 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/SessionTypeEnum.cs @@ -0,0 +1,17 @@ +namespace Yi.Framework.AiHub.Domain.Shared.Enums; + +/// +/// 会话类型枚举 +/// +public enum SessionTypeEnum +{ + /// + /// 普通聊天 + /// + Chat = 0, + + /// + /// Agent智能体 + /// + Agent = 1 +} diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/Impl/ThorClaude/Chats/AnthropicChatCompletionsService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/Impl/ThorClaude/Chats/AnthropicChatCompletionsService.cs index 983deee6..dbd7de1c 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/Impl/ThorClaude/Chats/AnthropicChatCompletionsService.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/Impl/ThorClaude/Chats/AnthropicChatCompletionsService.cs @@ -75,10 +75,7 @@ public class AnthropicChatCompletionsService( { Guid errorId = Guid.NewGuid(); var error = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); - logger.LogError("Anthropic非流式对话异常 请求地址:{Address},ErrorId:{errorId}, StatusCode: {StatusCode.GetHashCode()} Response: {Response}", - options.Endpoint, - errorId, - response.StatusCode, error); + logger.LogError($"Anthropic非流式对话异常 请求地址:{options.Endpoint},ErrorId:{errorId}, StatusCode: {response.StatusCode.GetHashCode()}, Response: {error}"); throw new Exception( $"恭喜你运气爆棚遇到了错误,尊享包对话异常:StatusCode【{response.StatusCode.GetHashCode()}】,ErrorId【{errorId}】"); } @@ -125,10 +122,7 @@ public class AnthropicChatCompletionsService( { Guid errorId = Guid.NewGuid(); var error = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); - logger.LogError("Anthropic流式对话异常 请求地址:{Address},ErrorId:{errorId}, StatusCode: {StatusCode.GetHashCode()} Response: {Response}", - options.Endpoint, - errorId, - response.StatusCode, error); + logger.LogError($"Anthropic流式对话异常 请求地址:{options.Endpoint},ErrorId:{errorId}, StatusCode: {response.StatusCode.GetHashCode()}, Response: {error}"); throw new Exception( $"恭喜你运气爆棚遇到了错误,尊享包对话异常:StatusCode【{response.StatusCode.GetHashCode()}】,ErrorId【{errorId}】"); } diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/SessionAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/SessionAggregateRoot.cs index 8a25d8da..47614c0f 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/SessionAggregateRoot.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/SessionAggregateRoot.cs @@ -1,5 +1,6 @@ using SqlSugar; using Volo.Abp.Domain.Entities.Auditing; +using Yi.Framework.AiHub.Domain.Shared.Enums; namespace Yi.Framework.AiHub.Domain.Entities.Chat; @@ -9,8 +10,13 @@ public class SessionAggregateRoot : FullAuditedAggregateRoot { public Guid UserId { get; set; } public string SessionTitle { get; set; } - + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString)] public string SessionContent { get; set; } public string? Remark { get; set; } + + /// + /// 会话类型:0-普通聊天,1-Agent智能体 + /// + public SessionTypeEnum SessionType { get; set; } = SessionTypeEnum.Chat; } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Mcp/OnlineSearchTool.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Mcp/OnlineSearchTool.cs index 7935e221..6aebde0a 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Mcp/OnlineSearchTool.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Mcp/OnlineSearchTool.cs @@ -1,16 +1,199 @@ using System.ComponentModel; -using ModelContextProtocol.Server; +using System.Net.Http.Json; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; using Volo.Abp.DependencyInjection; using Yi.Framework.AiHub.Domain.Shared.Attributes; namespace Yi.Framework.AiHub.Domain.Mcp; [YiAgentTool] -public class OnlineSearchTool:ISingletonDependency +public class OnlineSearchTool : ISingletonDependency { - [YiAgentTool("联网搜索"),DisplayName("OnlineSearch"), Description("进行在线搜索")] - public string OnlineSearch(string keyword) + private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; + private readonly string _baiduApiKey; + private const string BaiduSearchUrl = "https://qianfan.baidubce.com/v2/ai_search/web_search"; + + public OnlineSearchTool( + IHttpClientFactory httpClientFactory, + ILogger logger, + IConfiguration configuration) { - return "奥德赛第一中学学生会会长是:郭老板"; + _httpClientFactory = httpClientFactory; + _logger = logger; + _baiduApiKey = configuration["BaiduSearch:ApiKey"] ?? ""; } -} \ No newline at end of file + + [YiAgentTool("联网搜索"), DisplayName("OnlineSearch"), Description("进行在线搜索,获取最新的网络信息")] + public async Task OnlineSearch(string keyword) + { + if (string.IsNullOrWhiteSpace(keyword)) + { + return "搜索关键词不能为空"; + } + + try + { + var client = _httpClientFactory.CreateClient(); + + // 构建请求体 + var requestBody = new BaiduSearchRequest + { + Messages = new List + { + new() { Role = "user", Content = keyword } + } + }; + + var jsonContent = JsonSerializer.Serialize(requestBody, BaiduJsonContext.Default.BaiduSearchRequest); + var content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); + + // 设置请求头 + var request = new HttpRequestMessage(HttpMethod.Post, BaiduSearchUrl) + { + Content = content + }; + request.Headers.Add("Authorization", $"Bearer {_baiduApiKey}"); + + // 发送请求 + var response = await client.SendAsync(request); + + if (!response.IsSuccessStatusCode) + { + var errorContent = await response.Content.ReadAsStringAsync(); + _logger.LogError("百度搜索接口调用失败: {StatusCode}, {Error}", response.StatusCode, errorContent); + return $"搜索失败: {response.StatusCode}"; + } + + var responseJson = await response.Content.ReadAsStringAsync(); + var searchResult = JsonSerializer.Deserialize(responseJson, BaiduJsonContext.Default.BaiduSearchResponse); + + if (searchResult?.References == null || searchResult.References.Count == 0) + { + return "未找到相关搜索结果"; + } + + // 格式化搜索结果返回给AI + return FormatSearchResults(searchResult.References); + } + catch (HttpRequestException ex) + { + _logger.LogError(ex, "百度搜索网络请求异常"); + return "搜索服务暂时不可用,请稍后重试"; + } + catch (TaskCanceledException ex) + { + _logger.LogError(ex, "百度搜索请求超时"); + return "搜索请求超时,请稍后重试"; + } + catch (JsonException ex) + { + _logger.LogError(ex, "百度搜索结果解析失败"); + return "搜索结果解析失败"; + } + catch (Exception ex) + { + _logger.LogError(ex, "百度搜索发生未知异常"); + return "搜索发生异常,请稍后重试"; + } + } + + /// + /// 格式化搜索结果 + /// + private string FormatSearchResults(List references) + { + var sb = new StringBuilder(); + sb.AppendLine("搜索结果:"); + sb.AppendLine(); + + var count = 0; + foreach (var item in references.Take(10)) // 最多返回10条 + { + count++; + sb.AppendLine($"【{count}】{item.Title}"); + sb.AppendLine($"来源:{item.Website} | 时间:{item.Date}"); + sb.AppendLine($"摘要:{item.Snippet}"); + sb.AppendLine($"链接:{item.Url}"); + sb.AppendLine(); + } + + return sb.ToString(); + } +} + +#region 百度搜索 DTO + +/// +/// 百度搜索请求 +/// +public class BaiduSearchRequest +{ + [JsonPropertyName("messages")] + public List Messages { get; set; } = new(); +} + +/// +/// 百度搜索消息 +/// +public class BaiduSearchMessage +{ + [JsonPropertyName("role")] + public string Role { get; set; } = "user"; + + [JsonPropertyName("content")] + public string Content { get; set; } = ""; +} + +/// +/// 百度搜索响应 +/// +public class BaiduSearchResponse +{ + [JsonPropertyName("request_id")] + public string? RequestId { get; set; } + + [JsonPropertyName("references")] + public List? References { get; set; } +} + +/// +/// 百度搜索结果项 +/// +public class BaiduSearchReference +{ + [JsonPropertyName("id")] + public int Id { get; set; } + + [JsonPropertyName("url")] + public string? Url { get; set; } + + [JsonPropertyName("title")] + public string? Title { get; set; } + + [JsonPropertyName("date")] + public string? Date { get; set; } + + [JsonPropertyName("snippet")] + public string? Snippet { get; set; } + + [JsonPropertyName("website")] + public string? Website { get; set; } +} + +#endregion + +#region JSON 序列化上下文 + +[JsonSerializable(typeof(BaiduSearchRequest))] +[JsonSerializable(typeof(BaiduSearchResponse))] +[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] +internal partial class BaiduJsonContext : JsonSerializerContext +{ +} + +#endregion \ No newline at end of file diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs index 33e89ad6..2caadf6c 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs @@ -360,7 +360,7 @@ namespace Yi.Abp.Web var app = context.GetApplicationBuilder(); app.UseRouting(); - //app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); + //app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); // app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); // app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); diff --git a/Yi.Ai.Vue3/src/api/agent/index.ts b/Yi.Ai.Vue3/src/api/agent/index.ts new file mode 100644 index 00000000..02a4952a --- /dev/null +++ b/Yi.Ai.Vue3/src/api/agent/index.ts @@ -0,0 +1,25 @@ +import type { AgentSendInput, AgentToolOutput } from './types'; +import { get, post } from '@/utils/request'; + +/** + * Agent 发送消息 + */ +export function agentSend(data: AgentSendInput) { + return post('/ai-chat/agent/send', data); +} + +/** + * 获取 Agent 工具列表 + */ +export function getAgentTools() { + return post('/ai-chat/agent/tool').json(); +} + +/** + * 获取 Agent 上下文 + */ +export function getAgentContext(sessionId: string) { + return post(`/ai-chat/agent/context/${sessionId}`).json(); +} + +export * from './types'; diff --git a/Yi.Ai.Vue3/src/api/agent/types.ts b/Yi.Ai.Vue3/src/api/agent/types.ts new file mode 100644 index 00000000..146ffae4 --- /dev/null +++ b/Yi.Ai.Vue3/src/api/agent/types.ts @@ -0,0 +1,51 @@ +/** + * Agent 发送消息输入 + */ +export interface AgentSendInput { + /** 会话id */ + sessionId: string; + /** 用户内容 */ + content: string; + /** api密钥Id */ + tokenId: string; + /** 模型id */ + modelId: string; + /** 已选择工具 */ + tools: string[]; +} + +/** + * Agent 工具输出 + */ +export interface AgentToolOutput { + /** 工具代码 */ + code: string; + /** 工具名称 */ + name: string; +} + +/** + * Agent 结果类型 + */ +export type AgentResultType = 'text' | 'toolCalling' | 'toolCalled' | 'usage' | 'toolCallUsage'; + +/** + * Agent 流式结果输出 + */ +export interface AgentResultOutput { + /** 类型 */ + type: AgentResultType; + /** 内容载体 */ + content: any; +} + +/** + * Agent 用量信息 + */ +export interface AgentUsage { + input_tokens?: number; + output_tokens?: number; + total_tokens?: number; + prompt_tokens?: number; + completion_tokens?: number; +} diff --git a/Yi.Ai.Vue3/src/api/index.ts b/Yi.Ai.Vue3/src/api/index.ts index b165d819..c798162f 100644 --- a/Yi.Ai.Vue3/src/api/index.ts +++ b/Yi.Ai.Vue3/src/api/index.ts @@ -1,4 +1,5 @@ export * from './announcement' +export * from './agent'; export * from './auth'; export * from './chat'; export * from './file'; diff --git a/Yi.Ai.Vue3/src/api/session/types.ts b/Yi.Ai.Vue3/src/api/session/types.ts index e8af8b63..31ac7ebe 100644 --- a/Yi.Ai.Vue3/src/api/session/types.ts +++ b/Yi.Ai.Vue3/src/api/session/types.ts @@ -1,5 +1,15 @@ import type { Component } from 'vue'; +/** + * 会话类型枚举 + */ +export enum SessionTypeEnum { + /** 普通聊天 */ + Chat = 0, + /** Agent智能体 */ + Agent = 1, +} + export interface GetSessionListParams { /** * 创建者 @@ -61,6 +71,10 @@ export interface GetSessionListParams { * 用户id */ userId: number; + /** + * 会话类型 + */ + sessionType?: SessionTypeEnum; } /** @@ -96,6 +110,10 @@ export interface ChatSessionVo { * 自定义的消息前缀图标字段 */ prefixIcon?: Component; + /** + * 会话类型 + */ + sessionType?: SessionTypeEnum; } /** @@ -147,6 +165,10 @@ export interface CreateSessionDTO { * 用户id */ userId: number; + /** + * 会话类型 + */ + sessionType?: SessionTypeEnum; } // export interface CreateSessionVO { diff --git a/Yi.Ai.Vue3/src/assets/images/czld.png b/Yi.Ai.Vue3/src/assets/images/czld.png new file mode 100644 index 00000000..f0c18d45 Binary files /dev/null and b/Yi.Ai.Vue3/src/assets/images/czld.png differ diff --git a/Yi.Ai.Vue3/src/pages/chat/agent/index.vue b/Yi.Ai.Vue3/src/pages/chat/agent/index.vue index a465c672..b4d5f2bd 100644 --- a/Yi.Ai.Vue3/src/pages/chat/agent/index.vue +++ b/Yi.Ai.Vue3/src/pages/chat/agent/index.vue @@ -1,26 +1,939 @@ diff --git a/Yi.Ai.Vue3/src/stores/modules/agentSession.ts b/Yi.Ai.Vue3/src/stores/modules/agentSession.ts new file mode 100644 index 00000000..cdd9f4b7 --- /dev/null +++ b/Yi.Ai.Vue3/src/stores/modules/agentSession.ts @@ -0,0 +1,202 @@ +import type { ChatSessionVo, CreateSessionDTO, GetSessionListParams } from '@/api/session/types'; +import { SessionTypeEnum } from '@/api/session/types'; +import { Monitor } from '@element-plus/icons-vue'; +import { defineStore } from 'pinia'; +import { markRaw, ref } from 'vue'; +import { + create_session, + delete_session, + get_session, + get_session_list, + update_session, +} from '@/api'; +import { useUserStore } from './user'; + +export const useAgentSessionStore = defineStore('agentSession', () => { + const userStore = useUserStore(); + + // 当前选中的会话信息 + const currentSession = ref(null); + + // 设置当前会话 + const setCurrentSession = (session: ChatSessionVo | null) => { + currentSession.value = session; + }; + + // 会话列表核心状态 + const sessionList = ref([]); + const currentPage = ref(1); + const pageSize = ref(25); + const hasMore = ref(true); + const isLoading = ref(false); + const isLoadingMore = ref(false); + + // 获取会话列表 + const requestSessionList = async (page: number = currentPage.value, force: boolean = false) => { + if (!userStore.token) { + sessionList.value = []; + return; + } + + if (!force && ((page > 1 && !hasMore.value) || isLoading.value || isLoadingMore.value)) + return; + + isLoading.value = page === 1; + isLoadingMore.value = page > 1; + + try { + const params: GetSessionListParams = { + userId: userStore.userInfo?.userId as number, + skipCount: page, + maxResultCount: pageSize.value, + isAsc: 'desc', + orderByColumn: 'createTime', + sessionType: SessionTypeEnum.Agent, // 只查询Agent类型 + }; + + const resArr = await get_session_list(params); + const res = processSessions(resArr.data.items); + + const allSessions = new Map(sessionList.value.map(item => [item.id, item])); + res.forEach(item => allSessions.set(item.id, { ...item })); + + if (page === 1) { + sessionList.value = [ + ...res, + ...Array.from(allSessions.values()).filter(item => !res.some(r => r.id === item.id)), + ]; + } + else { + sessionList.value = [ + ...sessionList.value.filter(item => !res.some(r => r.id === item.id)), + ...res, + ]; + } + + if (!force) + hasMore.value = (res?.length || 0) === pageSize.value; + if (!force) + currentPage.value = page; + } + catch (error) { + console.error('requestSessionList错误:', error); + } + finally { + isLoading.value = false; + isLoadingMore.value = false; + } + }; + + // 创建新会话 + const createSession = async (data: Omit) => { + if (!userStore.token) { + return null; + } + + try { + const res = await create_session({ + ...data, + sessionType: SessionTypeEnum.Agent, + }); + + await requestSessionList(1, true); + + const newSessionRes = await get_session(`${res.data.id}`); + setCurrentSession(newSessionRes.data); + + return newSessionRes.data; + } + catch (error) { + console.error('createSession错误:', error); + return null; + } + }; + + // 加载更多会话 + const loadMoreSessions = async () => { + if (hasMore.value) + await requestSessionList(currentPage.value + 1); + }; + + // 更新会话 + const updateSession = async (item: ChatSessionVo) => { + try { + await update_session(item); + const targetIndex = sessionList.value.findIndex(session => session.id === item.id); + const targetPage = targetIndex >= 0 + ? Math.floor(targetIndex / pageSize.value) + 1 + : 1; + await requestSessionList(targetPage, true); + } + catch (error) { + console.error('updateSession错误:', error); + } + }; + + // 删除会话 + const deleteSession = async (ids: string[]) => { + try { + await delete_session(ids); + const targetIndex = sessionList.value.findIndex(session => session.id === ids[0]); + const targetPage = targetIndex >= 0 + ? Math.floor(targetIndex / pageSize.value) + 1 + : 1; + await requestSessionList(targetPage, true); + + // 如果删除的是当前会话,清空当前会话 + if (currentSession.value && ids.includes(currentSession.value.id!)) { + setCurrentSession(null); + } + } + catch (error) { + console.error('deleteSession错误:', error); + } + }; + + // 预处理会话 + function processSessions(sessions: ChatSessionVo[]) { + const currentDate = new Date(); + + return sessions.map((session) => { + const createDate = new Date(session.creationTime!); + const diffDays = Math.floor( + (currentDate.getTime() - createDate.getTime()) / (1000 * 60 * 60 * 24), + ); + + let group: string; + if (diffDays < 7) { + group = '7 天内'; + } + else if (diffDays < 30) { + group = '30 天内'; + } + else { + const year = createDate.getFullYear(); + const month = String(createDate.getMonth() + 1).padStart(2, '0'); + group = `${year}-${month}`; + } + + return { + ...session, + group, + prefixIcon: markRaw(Monitor), + }; + }); + } + + return { + currentSession, + setCurrentSession, + sessionList, + currentPage, + pageSize, + hasMore, + isLoading, + isLoadingMore, + createSession, + requestSessionList, + loadMoreSessions, + updateSession, + deleteSession, + }; +}); diff --git a/Yi.Ai.Vue3/src/stores/modules/session.ts b/Yi.Ai.Vue3/src/stores/modules/session.ts index 84ffc750..d026e6df 100644 --- a/Yi.Ai.Vue3/src/stores/modules/session.ts +++ b/Yi.Ai.Vue3/src/stores/modules/session.ts @@ -1,4 +1,5 @@ import type { ChatSessionVo, CreateSessionDTO, GetSessionListParams } from '@/api/session/types'; +import { SessionTypeEnum } from '@/api/session/types'; import { ChatLineRound } from '@element-plus/icons-vue'; import { defineStore } from 'pinia'; import { markRaw } from 'vue'; @@ -64,6 +65,7 @@ export const useSessionStore = defineStore('session', () => { maxResultCount: pageSize.value, isAsc: 'desc', orderByColumn: 'createTime', + sessionType: SessionTypeEnum.Chat, }; const resArr = await get_session_list(params); diff --git a/Yi.Ai.Vue3/types/components.d.ts b/Yi.Ai.Vue3/types/components.d.ts index de4cbd56..b66d66bd 100644 --- a/Yi.Ai.Vue3/types/components.d.ts +++ b/Yi.Ai.Vue3/types/components.d.ts @@ -23,6 +23,7 @@ declare module 'vue' { ElCol: typeof import('element-plus/es')['ElCol'] ElCollapse: typeof import('element-plus/es')['ElCollapse'] ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem'] + ElCollapseTransition: typeof import('element-plus/es')['ElCollapseTransition'] ElContainer: typeof import('element-plus/es')['ElContainer'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] diff --git a/Yi.Ai.Vue3/types/import_meta.d.ts b/Yi.Ai.Vue3/types/import_meta.d.ts index c98d612e..8f2a798b 100644 --- a/Yi.Ai.Vue3/types/import_meta.d.ts +++ b/Yi.Ai.Vue3/types/import_meta.d.ts @@ -7,7 +7,6 @@ interface ImportMetaEnv { readonly VITE_WEB_BASE_API: string; readonly VITE_API_URL: string; readonly VITE_FILE_UPLOAD_API: string; - readonly VITE_BUILD_COMPRESS: string; readonly VITE_SSO_SEVER_URL: string; readonly VITE_APP_VERSION: string; }