'integer', 'total_tokens' => 'integer', 'last_message_at' => 'datetime', ]; /** * 关联用户 */ public function user(): BelongsTo { return $this->belongsTo(User::class); } /** * 关联消息 */ public function messages(): HasMany { return $this->hasMany(AIMessage::class); } /** * 最后一条消息 */ public function lastMessage() { return $this->hasOne(AIMessage::class)->latest(); } /** * 获取对话摘要 */ public function getSummaryAttribute(): string { if ($this->title) { return $this->title; } $firstMessage = $this->messages()->orderBy('created_at', 'asc')->first(); if ($firstMessage && $firstMessage->role === 'user') { $content = $firstMessage->content; return strlen($content) > 50 ? substr($content, 0, 50) . '...' : $content; } return 'AI对话'; } /** * 获取对话时长 */ public function getDurationAttribute(): string { if (!$this->last_message_at) { return '0分钟'; } $duration = $this->last_message_at->diffInMinutes($this->created_at); if ($duration < 60) { return $duration . '分钟'; } elseif ($duration < 1440) { return floor($duration / 60) . '小时'; } else { return floor($duration / 1440) . '天'; } } /** * 获取平均响应时间 */ public function getAvgResponseTimeAttribute(): ?string { $aiMessages = $this->messages()->where('role', 'assistant')->get(); if ($aiMessages->isEmpty()) { return null; } $totalSeconds = 0; $count = 0; foreach ($aiMessages as $message) { $previousMessage = AIMessage::where('conversation_id', $this->id) ->where('created_at', '<', $message->created_at) ->orderBy('created_at', 'desc') ->first(); if ($previousMessage) { $diff = $message->created_at->diffInSeconds($previousMessage->created_at); $totalSeconds += $diff; $count++; } } if ($count === 0) { return null; } $avgSeconds = $totalSeconds / $count; if ($avgSeconds < 60) { return round($avgSeconds) . '秒'; } else { return round($avgSeconds / 60, 1) . '分钟'; } } /** * 获取对话统计 */ public function getStatisticsAttribute(): array { $userMessages = $this->messages()->where('role', 'user')->count(); $aiMessages = $this->messages()->where('role', 'assistant')->count(); $userTokens = $this->messages()->where('role', 'user')->sum('tokens'); $aiTokens = $this->messages()->where('role', 'assistant')->sum('tokens'); return [ 'total_messages' => $userMessages + $aiMessages, 'user_messages' => $userMessages, 'ai_messages' => $aiMessages, 'total_tokens' => $userTokens + $aiTokens, 'user_tokens' => $userTokens, 'ai_tokens' => $aiTokens, 'avg_tokens_per_message' => $this->message_count > 0 ? round(($userTokens + $aiTokens) / $this->message_count, 1) : 0, ]; } /** * 检查对话是否活跃 */ public function getIsActiveAttribute(): bool { if (!$this->last_message_at) { return false; } // 24小时内活跃 return $this->last_message_at->diffInHours(now()) < 24; } /** * 获取对话标签 */ public function getTagsAttribute(): array { $tags = []; if ($this->is_active) { $tags[] = ['label' => '活跃', 'color' => 'success']; } if ($this->message_count > 20) { $tags[] = ['label' => '长篇', 'color' => 'warning']; } if ($this->total_tokens > 10000) { $tags[] = ['label' => '深度', 'color' => 'primary']; } if ($this->status === 'archived') { $tags[] = ['label' => '已归档', 'color' => 'secondary']; } return $tags; } /** * 归档对话 */ public function archive(): void { $this->update(['status' => 'archived']); } /** * 恢复对话 */ public function restore(): void { $this->update(['status' => 'active']); } /** * 获取用户对话统计 */ public static function getUserStatistics($userId) { $conversations = self::where('user_id', $userId)->get(); $totalConversations = $conversations->count(); $activeConversations = $conversations->where('is_active', true)->count(); $totalMessages = $conversations->sum('message_count'); $totalTokens = $conversations->sum('total_tokens'); $avgMessagesPerConversation = $totalConversations > 0 ? round($totalMessages / $totalConversations, 1) : 0; $avgTokensPerConversation = $totalConversations > 0 ? round($totalTokens / $totalConversations, 1) : 0; return [ 'total_conversations' => $totalConversations, 'active_conversations' => $activeConversations, 'total_messages' => $totalMessages, 'total_tokens' => $totalTokens, 'avg_messages_per_conversation' => $avgMessagesPerConversation, 'avg_tokens_per_conversation' => $avgTokensPerConversation, ]; } /** * 清理过期对话 */ public static function cleanupExpired($days = 30) { $expiredDate = now()->subDays($days); $conversations = self::where('last_message_at', '<', $expiredDate) ->where('status', '!=', 'archived') ->get(); $deletedCount = 0; $failedConversations = []; foreach ($conversations as $conversation) { try { // 删除相关消息 $conversation->messages()->delete(); // 删除对话 $conversation->delete(); $deletedCount++; } catch (\Exception $e) { $failedConversations[] = [ 'id' => $conversation->id, 'title' => $conversation->title, 'error' => $e->getMessage(), ]; } } return [ 'deleted_count' => $deletedCount, 'failed_conversations' => $failedConversations, ]; } }