baseUrl = rtrim($this->baseUrl ?: config('question_bank.api_base', 'http://localhost:5015'), '/'); $this->timeout = (int) config('question_bank.timeout', 10); $this->cacheTtl = (int) config('question_bank.cache_ttl', 300); } /** * 获取所有题目(分页) */ public function listQuestions(int $page = 1, int $perPage = 50, array $filters = []): array { $cacheKey = sprintf( 'questions-list-%d-%d-%s', $page, $perPage, md5(json_encode($filters)) ); return Cache::remember( $cacheKey, now()->addSeconds($this->cacheTtl), function () use ($page, $perPage, $filters): array { $query = array_filter([ 'page' => $page, 'per_page' => $perPage, 'kp_code' => $filters['kp_code'] ?? null, 'difficulty' => $filters['difficulty'] ?? null, 'skill' => $filters['skill'] ?? null, 'search' => $filters['search'] ?? null, ], fn ($value) => filled($value)); $response = $this->request('GET', '/questions', $query); return [ 'data' => $response['data'] ?? [], 'meta' => $response['meta'] ?? [ 'page' => $page, 'per_page' => $perPage, 'total' => is_array($response) ? count($response) : 0, 'total_pages' => 1, ], ]; } ); } /** * 获取题目统计信息 */ public function getStatistics(): array { $cacheKey = 'question-statistics'; return Cache::remember( $cacheKey, now()->addSeconds($this->cacheTtl), function (): array { $response = $this->request('GET', '/questions/statistics'); return $response ?? [ 'total' => 0, 'by_difficulty' => [], 'by_kp' => [], 'by_source' => [], ]; } ); } /** * 根据 kp_code 获取题目 */ public function getQuestionsByKpCode(string $kpCode, int $limit = 100): array { return $this->request('GET', '/questions', [ 'kp_code' => $kpCode, 'limit' => $limit, ]); } /** * 语义搜索题目 */ public function searchQuestions(string $query, int $limit = 20): array { $cacheKey = sprintf('question-search-%s-%d', md5($query), $limit); return Cache::remember( $cacheKey, now()->addSeconds($this->cacheTtl), function () use ($query, $limit): array { try { $response = $this->request('POST', '/questions/search', [ 'query' => $query, 'limit' => $limit, ]); return $response ?? []; } catch (\Exception $e) { \Log::error('Question search failed: ' . $e->getMessage()); return []; } } ); } /** * 获取单个题目详情 */ public function getQuestionById(int $id): ?array { $cacheKey = "question-{$id}"; return Cache::remember( $cacheKey, now()->addSeconds($this->cacheTtl), function () use ($id): ?array { try { $response = $this->request('GET', "/questions/{$id}"); return $response ?: null; } catch (\Exception $e) { \Log::error("Failed to get question {$id}: " . $e->getMessage()); return null; } } ); } /** * 创建题目(通过 AI 生成) */ public function generateQuestions(array $params): array { try { $response = $this->request('POST', '/questions/generate', $params); return $response ?? [ 'success' => false, 'message' => '生成失败', ]; } catch (\Exception $e) { \Log::error('Question generation failed: ' . $e->getMessage()); return [ 'success' => false, 'message' => '生成失败:' . $e->getMessage(), ]; } } /** * 导入题目(JSON 批量导入) */ public function importQuestions(array $questions): array { try { $response = $this->request('POST', '/questions/import', [ 'questions' => $questions, ]); return $response ?? [ 'success' => false, 'message' => '导入失败', ]; } catch (\Exception $e) { \Log::error('Question import failed: ' . $e->getMessage()); return [ 'success' => false, 'message' => '导入失败:' . $e->getMessage(), ]; } } /** * 删除题目 */ public function deleteQuestion(int $id): bool { try { $response = $this->request('DELETE', "/questions/{$id}"); return $response['success'] ?? false; } catch (\Exception $e) { \Log::error("Failed to delete question {$id}: " . $e->getMessage()); return false; } } /** * 获取知识点选项(从知识图谱服务) */ public function getKnowledgePointOptions(): array { try { $knowledgeService = app(KnowledgeServiceApi::class); $points = $knowledgeService->listKnowledgePoints(limit: 1000); return $points->pluck('cn_name', 'kp_code') ->sort() ->all(); } catch (\Exception $e) { \Log::error('Failed to get knowledge points: ' . $e->getMessage()); return []; } } /** * 获取提示词模板列表 */ public function listPrompts(?string $type = null, ?string $active = null): array { $cacheKey = sprintf( 'prompts-list-%s-%s', $type ?: 'all', $active ?: 'all' ); return Cache::remember( $cacheKey, now()->addSeconds($this->cacheTtl), function () use ($type, $active): array { $query = array_filter([ 'type' => $type, 'active' => $active, ], fn ($value) => filled($value)); try { $response = $this->request('GET', '/prompts', $query); return $response ?? []; } catch (\Exception $e) { \Log::error('Failed to get prompts: ' . $e->getMessage()); return []; } } ); } /** * @throws RequestException * @return mixed */ protected function request(string $method, string $path, array $params = []): mixed { $response = $this->http()->send($method, ltrim($path, '/'), [ 'query' => $method === 'GET' ? $params : null, 'json' => $method !== 'GET' ? $params : null, ]); return $response->throw()->json(); } protected function http(): PendingRequest { return Http::baseUrl($this->baseUrl) ->acceptJson() ->timeout($this->timeout) ->retry(2, 200) ->withHeaders([ 'User-Agent' => 'Laravel/' . (app()->version()), 'Accept' => 'application/json', ]); } }