baseUrl = config('services.knowledge_api.base_url', env('KNOWLEDGE_API_BASE', env('KNOWLEDGE_API_BASE_URL', 'http://localhost:5011'))); $this->baseUrl = rtrim($this->baseUrl, '/'); } /** * 获取知识点列表 */ public function listKnowledgePoints(int $page = 1, int $perPage = 100): array { try { $response = Http::timeout(10) ->withHeaders(['Accept' => 'application/json']) ->get($this->baseUrl . '/knowledge-points/', [ 'page' => $page, 'per_page' => $perPage ]); if ($response->successful()) { $data = $response->json(); $points = $data['data'] ?? $data ?? []; // 格式化知识点数据 return array_map(function($kp) { return [ 'id' => (string)($kp['id'] ?? $kp['kp_id'] ?? uniqid()), 'kp_code' => $kp['kp_code'] ?? $kp['kp_id'] ?? $kp['code'] ?? 'KP_UNKNOWN', 'cn_name' => $kp['cn_name'] ?? $kp['kp_name'] ?? $kp['name'] ?? $kp['kp_code'] ?? '未知知识点', 'category' => $kp['category'] ?? '数学', 'phase' => $kp['phase'] ?? '', 'grade' => $kp['grade'] ?? null, 'importance' => $kp['importance'] ?? 0, ]; }, $points); } Log::warning('知识图谱API调用失败', [ 'status' => $response->status(), 'url' => $this->baseUrl . '/knowledge-points', 'response' => $response->json() ]); } catch (\Exception $e) { Log::error('获取知识点列表失败', [ 'error' => $e->getMessage() ]); } // 返回备用数据 return $this->getFallbackKnowledgePoints(); } /** * 根据知识点代码获取技能列表 */ public function getSkillsByKnowledgePoint(string $kpCode): array { try { $response = Http::timeout(10) ->withHeaders(['Accept' => 'application/json']) ->get($this->baseUrl . "/graph/node/{$kpCode}"); if ($response->successful()) { $data = $response->json(); $skills = $data['skills'] ?? []; return array_map(function($skill) { return [ 'code' => $skill['skill_code'] ?? '', 'name' => $skill['skill_name'] ?? '', 'weight' => $skill['weight'] ?? 0, ]; }, $skills); } Log::warning('获取技能列表失败', [ 'status' => $response->status(), 'kp_code' => $kpCode ]); } catch (\Exception $e) { Log::error('获取技能列表异常', [ 'kp_code' => $kpCode, 'error' => $e->getMessage() ]); } return []; } /** * 获取所有技能列表 */ public function listSkills(int $page = 1, int $perPage = 50): array { // ... (existing code) try { $response = Http::timeout(10) ->get($this->baseUrl . '/skills/', [ 'page' => $page, 'per_page' => $perPage ]); if ($response->successful()) { $data = $response->json(); $skills = $data['data'] ?? $data ?? []; // 格式化技能数据 return array_map(function($skill) { return [ 'id' => (string)($skill['id'] ?? $skill['skill_code'] ?? uniqid()), 'code' => $skill['skill_code'] ?? $skill['code'] ?? 'SK_UNKNOWN', 'name' => $skill['skill_name'] ?? $skill['name'] ?? $skill['skill_code'] ?? '未知技能', 'category' => $skill['skill_type'] ?? $skill['category'] ?? '基础技能' ]; }, $skills); } Log::warning('技能API调用失败', [ 'status' => $response->status() ]); } catch (\Exception $e) { Log::error('获取技能列表失败', [ 'error' => $e->getMessage() ]); } // 返回备用数据 return $this->getFallbackSkills(); } /** * 获取关联关系列表 */ public function listRelations(int $page = 1, int $perPage = 100): array { try { $response = Http::timeout(10) ->get($this->baseUrl . '/graph/relations', [ 'page' => $page, 'per_page' => $perPage ]); if ($response->successful()) { $data = $response->json(); $relations = $data['data'] ?? []; return array_map(function($rel) { return [ 'source_kp' => $rel['source'] ?? $rel['source_kp'] ?? '', 'target_kp' => $rel['target'] ?? $rel['target_kp'] ?? '', 'relation_type' => $rel['relation_type'] ?? 'PREREQUISITE', 'relation_direction' => $rel['relation_direction'] ?? 'DOWNSTREAM', 'weight' => $rel['weight'] ?? 0, 'description' => $rel['description'] ?? '', ]; }, $relations); } Log::warning('获取关联关系列表失败', [ 'status' => $response->status() ]); } catch (\Exception $e) { Log::error('获取关联关系列表异常', [ 'error' => $e->getMessage() ]); } return []; } /** * 导出完整图谱数据 (用于可视化) */ public function exportGraph(): array { try { $response = Http::timeout(30) ->get($this->baseUrl . '/graph/export'); if ($response->successful()) { return $response->json(); } Log::warning('导出图谱数据失败', [ 'status' => $response->status() ]); } catch (\Exception $e) { Log::error('导出图谱数据异常', [ 'error' => $e->getMessage() ]); } return ['nodes' => [], 'edges' => []]; } /** * 检查服务健康状态 */ public function checkHealth(): bool { try { $response = Http::timeout(5) ->get($this->baseUrl . '/health'); return $response->successful(); } catch (\Exception $e) { Log::error('知识图谱服务健康检查失败', [ 'error' => $e->getMessage() ]); return false; } } /** * 获取备用知识点数据 */ private function getFallbackKnowledgePoints(): array { return [ ['id' => 'kp_1', 'code' => 'KP1001', 'name' => '因式分解基础', 'subject' => '数学', 'phase' => '初中', 'importance' => 5], ['id' => 'kp_2', 'code' => 'KP1002', 'name' => '提取公因式', 'subject' => '数学', 'phase' => '初中', 'importance' => 5], ['id' => 'kp_3', 'code' => 'KP1003', 'name' => '平方差公式', 'subject' => '数学', 'phase' => '初中', 'importance' => 5], ['id' => 'kp_4', 'code' => 'KP1004', 'name' => '完全平方公式', 'subject' => '数学', 'phase' => '初中', 'importance' => 5], ['id' => 'kp_5', 'code' => 'KP1005', 'name' => '分组分解法', 'subject' => '数学', 'phase' => '初中', 'importance' => 4], ['id' => 'kp_6', 'code' => 'KP1006', 'name' => '十字相乘法', 'subject' => '数学', 'phase' => '初中', 'importance' => 5], ['id' => 'kp_7', 'code' => 'KP1007', 'name' => '有理数运算', 'subject' => '数学', 'phase' => '初中', 'importance' => 5], ['id' => 'kp_8', 'code' => 'KP1008', 'name' => '一元二次方程', 'subject' => '数学', 'phase' => '初中', 'importance' => 5], ['id' => 'kp_9', 'code' => 'KP1009', 'name' => '不等式', 'subject' => '数学', 'phase' => '初中', 'importance' => 4], ['id' => 'kp_10', 'code' => 'KP1010', 'name' => '函数基础', 'subject' => '数学', 'phase' => '初中', 'importance' => 5], ]; } /** * 获取备用技能数据 */ private function getFallbackSkills(): array { return [ ['id' => 'sk_1', 'code' => 'SK001', 'name' => '计算能力', 'category' => '基础技能'], ['id' => 'sk_2', 'code' => 'SK002', 'name' => '逻辑推理', 'category' => '思维技能'], ['id' => 'sk_3', 'code' => 'SK003', 'name' => '模式识别', 'category' => '认知技能'], ['id' => 'sk_4', 'code' => 'SK004', 'name' => '代数运算', 'category' => '专业技能'], ['id' => 'sk_5', 'code' => 'SK005', 'name' => '解题能力', 'category' => '专业技能'], ['id' => 'sk_6', 'code' => 'SK006', 'name' => '分析能力', 'category' => '思维技能'], ['id' => 'sk_7', 'code' => 'SK007', 'name' => '抽象思维', 'category' => '高级技能'], ['id' => 'sk_8', 'code' => 'SK008', 'name' => '创新思维', 'category' => '高级技能'], ]; } /** * 导入知识图谱数据 */ public function importGraph(array $treeData, array $edgesData): bool { try { $response = Http::timeout(60) // 导入可能耗时较长 ->post($this->baseUrl . '/import/graph', [ 'tree_data' => $treeData, 'edges_data' => $edgesData ]); if ($response->successful()) { Log::info('知识图谱导入成功', [ 'response' => $response->json() ]); return true; } Log::error('知识图谱导入失败', [ 'status' => $response->status(), 'body' => $response->body() ]); } catch (\Exception $e) { Log::error('知识图谱导入异常', [ 'error' => $e->getMessage() ]); } return false; } /** * 获取单个知识点详情 */ public function getKnowledgePoint(string $code): ?array { try { $response = Http::timeout(10) ->get($this->baseUrl . "/knowledge-points/{$code}"); if ($response->successful()) { return $response->json(); } } catch (\Exception $e) { Log::error('获取知识点详情失败', ['error' => $e->getMessage()]); } return null; } /** * 创建知识点 */ public function createKnowledgePoint(array $data): bool { try { $response = Http::timeout(10) ->post($this->baseUrl . '/knowledge-points/', $data); return $response->successful(); } catch (\Exception $e) { Log::error('创建知识点失败', ['error' => $e->getMessage()]); return false; } } /** * 更新知识点 */ public function updateKnowledgePoint(string $code, array $data): bool { try { $response = Http::timeout(10) ->patch($this->baseUrl . "/knowledge-points/{$code}", $data); return $response->successful(); } catch (\Exception $e) { Log::error('更新知识点失败', ['error' => $e->getMessage()]); return false; } } /** * 删除知识点 */ public function deleteKnowledgePoint(string $code): bool { try { $response = Http::timeout(10) ->delete($this->baseUrl . "/knowledge-points/{$code}"); return $response->successful(); } catch (\Exception $e) { Log::error('删除知识点失败', ['error' => $e->getMessage()]); return false; } } }