aiService = new \App\Services\AIService(); } /** * AI对话 */ public function chat(AIChatRequest $request) { try { $message = $request->input('message'); $conversationId = $request->input('conversation_id'); $context = $request->input('context', []); // 获取或创建对话 if ($conversationId) { $conversation = AIConversation::where('id', $conversationId) ->where('user_id', auth()->id()) ->firstOrFail(); } else { $conversation = AIConversation::create([ 'user_id' => auth()->id(), 'title' => substr($message, 0, 50) . '...', 'model' => $this->config['model'], 'status' => 'active', ]); } // 添加上下文到消息 $messages = $this->buildMessages($message, $context, $conversation); // 调用AI API $response = $this->callAIAPI($messages); if (!$response['success']) { return response()->json([ 'code' => 500, 'message' => 'AI服务暂时不可用: ' . $response['error'] ], 500); } $aiResponse = $response['data']; // 保存消息记录 $userMessage = AIMessage::create([ 'conversation_id' => $conversation->id, 'role' => 'user', 'content' => $message, 'tokens' => $this->estimateTokens($message), ]); $aiMessage = AIMessage::create([ 'conversation_id' => $conversation->id, 'role' => 'assistant', 'content' => $aiResponse, 'tokens' => $this->estimateTokens($aiResponse), ]); // 更新对话统计 $conversation->increment('message_count', 2); $conversation->increment('total_tokens', $userMessage->tokens + $aiMessage->tokens); $conversation->last_message_at = now(); $conversation->save(); return response()->json([ 'code' => 200, 'data' => [ 'conversation_id' => $conversation->id, 'response' => $aiResponse, 'message_id' => $aiMessage->id, 'tokens_used' => $userMessage->tokens + $aiMessage->tokens, ], 'message' => 'success' ]); } catch (\Exception $e) { Log::error('AI对话失败: ' . $e->getMessage()); return response()->json([ 'code' => 500, 'message' => 'AI对话失败: ' . $e->getMessage() ], 500); } } /** * 构建消息数组 */ private function buildMessages(string $message, array $context, AIConversation $conversation): array { $messages = []; // 系统提示词 $systemPrompt = $this->getSystemPrompt($context); $messages[] = ['role' => 'system', 'content' => $systemPrompt]; // 添加上下文消息 if (!empty($context)) { foreach ($context as $ctx) { if (isset($ctx['role']) && isset($ctx['content'])) { $messages[] = ['role' => $ctx['role'], 'content' => $ctx['content']]; } } } // 添加历史消息(最近10条) $historyMessages = AIMessage::where('conversation_id', $conversation->id) ->orderBy('created_at', 'desc') ->limit(10) ->get() ->reverse(); foreach ($historyMessages as $history) { $messages[] = ['role' => $history->role, 'content' => $history->content]; } // 添加当前消息 $messages[] = ['role' => 'user', 'content' => $message]; return $messages; } /** * 获取系统提示词 */ private function getSystemPrompt(array $context): string { $basePrompt = "你是一个专业的ERP系统AI助手,专门帮助用户处理企业资源管理相关的问题。"; // 根据上下文添加特定提示 if (isset($context['module'])) { switch ($context['module']) { case 'goods': $basePrompt .= "你现在正在处理商品管理模块的问题。"; break; case 'orders': $basePrompt .= "你现在正在处理订单管理模块的问题。"; break; case 'purchase': $basePrompt .= "你现在正在处理采购管理模块的问题。"; break; case 'inventory': $basePrompt .= "你现在正在处理库存管理模块的问题。"; break; case 'finance': $basePrompt .= "你现在正在处理财务管理模块的问题。"; break; } } $basePrompt .= "\n\n请用专业、准确、简洁的语言回答用户的问题。如果涉及具体操作,请提供清晰的步骤说明。"; return $basePrompt; } /** * 调用AI API */ private function callAIAPI(array $messages): array { try { // 这里使用模拟响应,实际项目中需要配置真实的API密钥 $apiKey = config('services.ai.api_key', ''); if (empty($apiKey)) { // 模拟AI响应(开发环境) return $this->mockAIResponse($messages); } $response = Http::withHeaders([ 'Authorization' => 'Bearer ' . $apiKey, 'Content-Type' => 'application/json', ])->timeout(30)->post($this->config['api_url'], [ 'model' => $this->config['model'], 'messages' => $messages, 'max_tokens' => $this->config['max_tokens'], 'temperature' => $this->config['temperature'], ]); if ($response->successful()) { $data = $response->json(); $content = $data['choices'][0]['message']['content'] ?? ''; $tokens = $data['usage']['total_tokens'] ?? 0; return [ 'success' => true, 'data' => $content, 'tokens' => $tokens, ]; } else { Log::error('AI API调用失败: ' . $response->body()); return [ 'success' => false, 'error' => 'API调用失败: ' . $response->status(), ]; } } catch (\Exception $e) { Log::error('AI API异常: ' . $e->getMessage()); return [ 'success' => false, 'error' => $e->getMessage(), ]; } } /** * 模拟AI响应(开发环境使用) */ private function mockAIResponse(array $messages): array { $lastMessage = end($messages); $userMessage = $lastMessage['content'] ?? ''; // 根据用户消息生成模拟响应 $responses = [ '商品' => "关于商品管理,我可以帮你:\n1. 查询商品信息\n2. 添加新商品\n3. 更新商品库存\n4. 设置商品价格\n5. 管理商品分类\n\n请告诉我具体需要什么帮助?", '订单' => "关于订单管理,我可以帮你:\n1. 查看订单状态\n2. 处理新订单\n3. 发货操作\n4. 订单统计\n5. 退款处理\n\n请提供订单号或具体问题。", '采购' => "关于采购管理,我可以帮你:\n1. 创建采购单\n2. 供应商管理\n3. 采购审批流程\n4. 收货入库\n5. 采购统计\n\n请告诉我你的具体需求。", '库存' => "关于库存管理,我可以帮你:\n1. 库存查询\n2. 库存预警\n3. 盘点管理\n4. 出入库记录\n5. 库存调拨\n\n请提供仓库或商品信息。", '财务' => "关于财务管理,我可以帮你:\n1. 收支记录\n2. 财务报表\n3. 发票管理\n4. 对账处理\n5. 预算控制\n\n请告诉我具体财务问题。", 'default' => "我是ERP系统AI助手,可以帮你处理:\n• 商品管理\n• 订单处理\n• 采购管理\n• 库存控制\n• 财务统计\n• 系统操作指导\n\n请详细描述你的问题,我会尽力提供帮助。" ]; $response = $responses['default']; foreach ($responses as $key => $value) { if (strpos($userMessage, $key) !== false) { $response = $value; break; } } // 添加个性化问候 if (strpos(strtolower($userMessage), '你好') !== false || strpos(strtolower($userMessage), 'hi') !== false || strpos(strtolower($userMessage), 'hello') !== false) { $response = "你好!我是ERP系统AI助手。我可以帮你处理企业资源管理的各种问题,包括商品、订单、采购、库存、财务等模块的操作和咨询。有什么可以帮你的吗?"; } return [ 'success' => true, 'data' => $response, 'tokens' => $this->estimateTokens($response), ]; } /** * 执行AI任务 */ public function executeTask(AITaskRequest $request) { try { $task = $request->input('task'); $parameters = $request->input('parameters', []); // 根据任务类型处理 $result = $this->processTask($task, $parameters); // 记录任务执行 \App\Models\OperationLog::log([ 'module' => 'AI助手', 'action' => '执行任务', 'method' => 'POST', 'path' => 'api/ai/tasks/execute', 'request_data' => ['task' => $task, 'parameters' => $parameters], 'response_data' => $result, 'remark' => 'AI任务执行', ]); return response()->json([ 'code' => 200, 'data' => $result, 'message' => '任务执行成功' ]); } catch (\Exception $e) { Log::error('AI任务执行失败: ' . $e->getMessage()); return response()->json([ 'code' => 500, 'message' => '任务执行失败: ' . $e->getMessage() ], 500); } } /** * 处理具体任务 */ private function processTask(string $task, array $parameters): array { switch ($task) { case 'data_analysis': return $this->analyzeData($parameters); case 'report_generation': return $this->generateReport($parameters); case 'prediction': return $this->makePrediction($parameters); case 'recommendation': return $this->provideRecommendation($parameters); case 'document_summary': return $this->summarizeDocument($parameters); default: return [ 'success' => false, 'error' => '不支持的任务类型', 'task' => $task, ]; } } /** * 数据分析 */ private function analyzeData(array $parameters): array { $type = $parameters['type'] ?? 'sales'; $period = $parameters['period'] ?? 'month'; // 模拟数据分析结果 $analysis = [ 'type' => $type, 'period' => $period, 'summary' => "根据{$period}数据,发现以下趋势:", 'insights' => [ '销售额增长15%', '最畅销商品:商品A', '客户复购率:45%', '库存周转率:2.5次', ], 'recommendations' => [ '增加商品A的库存', '优化营销策略提高复购率', '关注库存周转率提升', ], ]; return [ 'success' => true, 'analysis' => $analysis, 'generated_at' => now()->toDateTimeString(), ]; } /** * 生成报告 */ private function generateReport(array $parameters): array { $reportType = $parameters['report_type'] ?? 'sales'; $startDate = $parameters['start_date'] ?? now()->subMonth()->toDateString(); $endDate = $parameters['end_date'] ?? now()->toDateString(); // 模拟报告生成 $report = [ 'type' => $reportType, 'period' => $startDate . ' 至 ' . $endDate, 'title' => ucfirst($reportType) . '分析报告', 'sections' => [ 'executive_summary' => '报告摘要内容...', 'data_analysis' => '数据分析内容...', 'key_findings' => '主要发现...', 'recommendations' => '建议措施...', ], 'metrics' => [ 'total_sales' => '¥125,000', 'order_count' => 156, 'average_order_value' => '¥801', 'growth_rate' => '15%', ], ]; return [ 'success' => true, 'report' => $report, 'download_url' => '/api/reports/download/' . uniqid(), 'generated_at' => now()->toDateTimeString(), ]; } /** * 预测分析 */ private function makePrediction(array $parameters): array { $target = $parameters['target'] ?? 'sales'; $periods = $parameters['periods'] ?? 3; // 模拟预测结果 $predictions = []; $current = 100000; // 基准值 for ($i = 1; $i <= $periods; $i++) { $growth = rand(5, 15) / 100; // 5-15%增长 $predicted = $current * (1 + $growth); $predictions[] = [ 'period' => "第{$i}期", 'value' => number_format($predicted, 2), 'growth' => number_format($growth * 100, 1) . '%', 'confidence' => rand(70, 95) . '%', ]; $current = $predicted; } return [ 'success' => true, 'target' => $target, 'predictions' => $predictions, 'notes' => '基于历史数据的趋势预测,实际结果可能因市场变化而有所不同。', ]; } /** * 提供建议 */ private function provideRecommendation(array $parameters): array { $area = $parameters['area'] ?? 'inventory'; $recommendations = [ 'inventory' => [ '优化库存水平,减少积压', '建立安全库存机制', '实施ABC分类管理', '定期盘点,确保账实相符', ], 'sales' => [ '加强客户关系管理', '优化产品定价策略', '拓展销售渠道', '提升客户服务质量', ], 'purchase' => [ '建立供应商评估体系', '优化采购审批流程', '实施集中采购降低成本', '加强采购合同管理', ], 'finance' => [ '加强现金流管理', '优化成本控制', '完善财务报告体系', '加强预算执行监控', ], ]; $areaRecommendations = $recommendations[$area] ?? $recommendations['inventory']; return [ 'success' => true, 'area' => $area, 'recommendations' => $areaRecommendations, 'priority' => '根据当前业务状况,建议优先实施前两项。', ]; } /** * 文档摘要 */ private function summarizeDocument(array $parameters): array { $content = $parameters['content'] ?? ''; $maxLength = $parameters['max_length'] ?? 200; if (empty($content)) { return [ 'success' => false, 'error' => '文档内容不能为空', ]; } // 简单摘要算法(实际应使用AI) $sentences = preg_split('/[。!?.!?]/', $content); $sentences = array_filter($sentences, function($sentence) { return strlen(trim($sentence)) > 10; }); $summary = ''; $count = 0; foreach ($sentences as $sentence) { if (strlen($summary) + strlen($sentence) < $maxLength) { $summary .= trim($sentence) . '。'; $count++; } if ($count >= 3) { break; } } if (empty($summary)) { $summary = substr($content, 0, $maxLength) . '...'; } $keywords = $this->extractKeywords($content); return [ 'success' => true, 'original_length' => strlen($content), 'summary_length' => strlen($summary), 'summary' => $summary, 'keywords' => $keywords, 'compression_rate' => round((1 - strlen($summary) / strlen($content)) * 100, 1) . '%', ]; } /** * 提取关键词 */ private function extractKeywords(string $content): array { // 简单关键词提取(实际应使用更复杂的算法) $words = preg_split('/\s+/', $content); $wordCount = array_count_values($words); arsort($wordCount); $keywords = array_slice(array_keys($wordCount), 0, 10); // 过滤常见词 $commonWords = ['的', '了', '在', '是', '和', '与', '或', '等', '这个', '那个']; $keywords = array_diff($keywords, $commonWords); return array_values($keywords); } /** * 估算Token数量 */ private function estimateTokens(string $text): int { // 简单估算:英文约4字符=1token,中文约1.5字符=1token $chineseChars = preg_match_all('/[\x{4e00}-\x{9fa5}]/u', $text); $otherChars = strlen($text) - $chineseChars * 3; // 中文字符占3字节 $tokens = ceil($chineseChars / 1.5 + $otherChars / 4); return max(1, $tokens); } /** * 获取对话列表 */ public function getConversations(Request $request) { $query = AIConversation::where('user_id', auth()->id()) ->orderBy('last_message_at', 'desc'); if ($request->filled('status')) { $query->where('status', $request->status); } if ($request->filled('keyword')) { $keyword = $request->keyword; $query->where(function ($q) use ($keyword) { $q->where('title', 'like', "%{$keyword}%") ->orWhereHas('messages', function ($q) use ($keyword) { $q->where('content', 'like', "%{$keyword}%"); }); }); } $perPage = $request->input('limit', 20); $conversations = $query->paginate($perPage); // 加载最后一条消息 $conversations->load(['lastMessage']); return response()->json([ 'code' => 200, 'data' => [ 'list' => $conversations->items(), 'total' => $conversations->total(), 'current_page' => $conversations->currentPage(), 'last_page' => $conversations->lastPage(), ], 'message' => 'success' ]); } /** * 获取对话详情 */ public function getConversation(string $id) { $conversation = AIConversation::with(['messages' => function ($query) { $query->orderBy('created_at', 'asc'); }])->where('id', $id) ->where('user_id', auth()->id()) ->firstOrFail(); return response()->json([ 'code' => 200, 'data' => $conversation, 'message' => 'success' ]); } /** * 删除对话 */ public function deleteConversation(string $id) { $conversation = AIConversation::where('id', $id) ->where('user_id', auth()->id()) ->firstOrFail(); try { // 删除相关消息 AIMessage::where('conversation_id', $id)->delete(); // 删除对话 $conversation->delete(); return response()->json([ 'code' => 200, 'message' => '对话删除成功' ]); } catch (\Exception $e) { Log::error('删除对话失败: ' . $e->getMessage()); return response()->json([ 'code' => 500, 'message' => '删除失败: ' . $e->getMessage() ], 500); } } /** * 清空对话消息 */ public function clearConversation(string $id) { $conversation = AIConversation::where('id', $id) ->where('user_id', auth()->id()) ->firstOrFail(); try { // 删除所有消息 AIMessage::where('conversation_id', $id)->delete(); // 重置对话统计 $conversation->update([ 'message_count' => 0, 'total_tokens' => 0, 'last_message_at' => null, ]); return response()->json([ 'code' => 200, 'message' => '对话消息已清空' ]); } catch (\Exception $e) { Log::error('清空对话失败: ' . $e->getMessage()); return response()->json([ 'code' => 500, 'message' => '清空失败: ' . $e->getMessage() ], 500); } } /** * 获取AI能力列表 */ public function getCapabilities() { $capabilities = [ 'chat' => [ 'name' => '智能对话', 'description' => '回答ERP系统相关问题,提供操作指导', 'examples' => [ '如何创建采购单?', '查看商品库存', '订单处理流程', ], ], 'data_analysis' => [ 'name' => '数据分析', 'description' => '分析销售、库存、财务等数据', 'examples' => [ '分析本月销售趋势', '库存周转率分析', '客户购买行为分析', ], ], 'report_generation' => [ 'name' => '报告生成', 'description' => '自动生成各类业务报告', 'examples' => [ '生成销售日报', '制作库存月报', '财务季度分析报告', ], ], 'prediction' => [ 'name' => '趋势预测', 'description' => '基于历史数据预测未来趋势', 'examples' => [ '预测下月销售额', '库存需求预测', '客户增长预测', ], ], 'recommendation' => [ 'name' => '智能建议', 'description' => '提供业务优化建议', 'examples' => [ '库存优化建议', '销售策略建议', '成本控制建议', ], ], 'document_summary' => [ 'name' => '文档摘要', 'description' => '自动提取文档关键信息', 'examples' => [ '合同摘要', '会议纪要整理', '报告要点提取', ], ], ]; return response()->json([ 'code' => 200, 'data' => $capabilities, 'message' => 'success' ]); } /** * 获取使用统计 */ public function getUsageStatistics(Request $request) { $userId = auth()->id(); // 今日使用统计 $todayStart = now()->startOfDay(); $todayEnd = now()->endOfDay(); $todayConversations = AIConversation::where('user_id', $userId) ->whereBetween('created_at', [$todayStart, $todayEnd]) ->count(); $todayMessages = AIMessage::whereHas('conversation', function ($query) use ($userId) { $query->where('user_id', $userId); })->whereBetween('created_at', [$todayStart, $todayEnd]) ->count(); $todayTokens = AIMessage::whereHas('conversation', function ($query) use ($userId) { $query->where('user_id', $userId); })->whereBetween('created_at', [$todayStart, $todayEnd]) ->sum('tokens'); // 月度统计 $monthStart = now()->startOfMonth(); $monthEnd = now()->endOfMonth(); $monthConversations = AIConversation::where('user_id', $userId) ->whereBetween('created_at', [$monthStart, $monthEnd]) ->count(); $monthMessages = AIMessage::whereHas('conversation', function ($query) use ($userId) { $query->where('user_id', $userId); })->whereBetween('created_at', [$monthStart, $monthEnd]) ->count(); $monthTokens = AIMessage::whereHas('conversation', function ($query) use ($userId) { $query->where('user_id', $userId); })->whereBetween('created_at', [$monthStart, $monthEnd]) ->sum('tokens'); // 总体统计 $totalConversations = AIConversation::where('user_id', $userId)->count(); $totalMessages = AIMessage::whereHas('conversation', function ($query) use ($userId) { $query->where('user_id', $userId); })->count(); $totalTokens = AIMessage::whereHas('conversation', function ($query) use ($userId) { $query->where('user_id', $userId); })->sum('tokens'); $statistics = [ 'today' => [ 'conversations' => $todayConversations, 'messages' => $todayMessages, 'tokens' => $todayTokens, ], 'month' => [ 'conversations' => $monthConversations, 'messages' => $monthMessages, 'tokens' => $monthTokens, ], 'total' => [ 'conversations' => $totalConversations, 'messages' => $totalMessages, 'tokens' => $totalTokens, ], ]; return response()->json([ 'code' => 200, 'data' => $statistics, 'message' => 'success' ]); } /** * 测试AI连接 */ public function testConnection() { try { $testMessage = '你好,请回复"AI服务正常"以确认连接成功。'; $messages = [ ['role' => 'system', 'content' => '你是一个测试助手,只需要按照要求回复。'], ['role' => 'user', 'content' => $testMessage], ]; $response = $this->callAIAPI($messages); if ($response['success']) { return response()->json([ 'code' => 200, 'data' => [ 'status' => 'connected', 'response' => $response['data'], 'response_time' => '正常', ], 'message' => 'AI服务连接正常' ]); } else { return response()->json([ 'code' => 503, 'data' => [ 'status' => 'disconnected', 'error' => $response['error'], ], 'message' => 'AI服务连接失败' ], 503); } } catch (\Exception $e) { return response()->json([ 'code' => 500, 'data' => [ 'status' => 'error', 'error' => $e->getMessage(), ], 'message' => '测试过程中发生错误' ], 500); } } }