Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/aetik-yue_chinasoft-project-group23.json

1 line
14 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "aetik-yue/chinasoft-project-group23", "files": {"backend/src/main/java/com/chinasoft/smokesensor/client/LlmClient.java": {"128cbf1d8783403458e26c8850562e3b58b8810f": {"t": 1785745685.3527782, "n": 4232, "h": "299e0af72cb474b2", "c": "package com.chinasoft.smokesensor.client;\n\nimport com.chinasoft.smokesensor.config.LlmProperties;\nimport com.chinasoft.smokesensor.config.ApiKeyEncryptor;\nimport com.chinasoft.smokesensor.entity.SystemSetting;\nimport com.chinasoft.smokesensor.repository.SystemSettingRepository;\nimport jakarta.annotation.PostConstruct;\nimport java.util.List;\nimport java.util.Map;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.client.RestClient;\n\n/**\n * DeepSeek(OpenAI 兼容)大模型客户端,封装 chat completions + function calling 调用。\n *\n * <p>调用 {@code POST {base-url}/v1/chat/completions},请求体含 {@code model / messages / tools / tool_choice},\n * 响应 {@code choices[0].message}(含 {@code content} 或 {@code tool_calls})。\n *\n * <p>本类只负责 HTTP 调用与响应解析,工具执行与多轮编排由 {@code AgentToolService} 完成。\n *\n * <p>降级:{@code qq.llm.enabled=false} 或未配置 api-key 时 {@link #isEnabled} 返回 false,\n * 调用方走规则回退。调用失败只 warn 不抛异常,返回 null。\n */\n@Slf4j\n@Component\n@RequiredArgsConstructor\npublic class LlmClient {\n\n private final LlmProperties properties;\n private final SystemSettingRepository systemSettingRepository;\n private final ApiKeyEncryptor apiKeyEncryptor;\n\n private RestClient restClient;\n\n @PostConstruct\n void init() {\n if (properties.getBaseUrl() != null && !properties.getBaseUrl().isBlank()) {\n this.restClient = RestClient.builder()\n .baseUrl(properties.getBaseUrl())\n .build();\n }\n }\n\n /**\n * 是否启用(已 enabled 且 api-key 非空且 restClient 已初始化)。\n */\n public boolean isEnabled() {\n String apiKey = getApiKey();\n return properties.isEnabled()\n && restClient != null\n && apiKey != null\n && !apiKey.isBlank();\n }\n\n private String getApiKey() {\n String dbKey = systemSettingRepository.findBySettingKey(\"deepseek_api_key\")\n .map(SystemSetting::getSettingValue)\n .orElse(null);\n if (dbKey != null && !dbKey.isBlank()) {\n return apiKeyEncryptor.decrypt(dbKey);\n }\n return properties.getApiKey();\n }\n\n /**\n * 调用 chat completions,返回 assistant 消息(含 content 或 tool_calls)。\n *\n * @param messages 对话消息列表(含历史 + 上一轮 assistant tool_calls + tool 结果)\n * @param tools 工具 schema 列表(OpenAI function 格式),为空则不传 tools\n * @return assistant 消息 Map,或 null(调用失败 / 无响应)\n */\n @SuppressWarnings(\"unchecked\")\n public Map<String, Object> chat(List<Map<String, Object>> messages, List<Map<String, Object>> tools) {\n if (!isEnabled()) {\n return null;\n }\n try {\n Map<String, Object> body = new java.util.LinkedHashMap<>();\n body.put(\"model\", properties.getModel());\n body.put(\"messages\", messages);\n if (tools != null && !tools.isEmpty()) {\n body.put(\"tools\", tools);\n body.put(\"tool_choice\", \"auto\");\n }\n\n Map<String, Object> response = restClient.post()\n .uri(\"/v1/chat/completions\")\n .header(\"Authorization\", \"Bearer \" + getApiKey())\n .contentType(MediaType.APPLICATION_JSON)\n .body(body)\n .retrieve()\n .body(Map.class);\n return extractMessage(response);\n } catch (Exception e) {\n log.warn(\"DeepSeek 调用失败: reason={}\", e.getMessage());\n return null;\n }\n }\n\n /**\n * 从响应中提取 choices[0].message。\n */\n @SuppressWarnings(\"unchecked\")\n private Map<String, Object> extractMessage(Map<String, Object> response) {\n if (response == null) {\n return null;\n }\n Object choices = response.get(\"choices\");\n if (choices instanceof List<?> list && !list.isEmpty() && list.get(0) instanceof Map<?, ?> first) {\n Object message = first.get(\"message\");\n if (message instanceof Map<?, ?> msg) {\n return (Map<String, Object>) msg;\n }\n }\n log.warn(\"DeepSeek 响应格式异常: {}\", response);\n return null;\n }\n}\n"}, "a101dd944b079def1d8450a4b94b00df32d52e1e": {"t": 1785755705.9064398, "n": 4232, "h": "299e0af72cb474b2", "c": "package com.chinasoft.smokesensor.client;\n\nimport com.chinasoft.smokesensor.config.LlmProperties;\nimport com.chinasoft.smokesensor.config.ApiKeyEncryptor;\nimport com.chinasoft.smokesensor.entity.SystemSetting;\nimport com.chinasoft.smokesensor.repository.SystemSettingRepository;\nimport jakarta.annotation.PostConstruct;\nimport java.util.List;\nimport java.util.Map;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.client.RestClient;\n\n/**\n * DeepSeek(OpenAI 兼容)大模型客户端,封装 chat completions + function calling 调用。\n *\n * <p>调用 {@code POST {base-url}/v1/chat/completions},请求体含 {@code model / messages / tools / tool_choice},\n * 响应 {@code choices[0].message}(含 {@code content} 或 {@code tool_calls})。\n *\n * <p>本类只负责 HTTP 调用与响应解析,工具执行与多轮编排由 {@code AgentToolService} 完成。\n *\n * <p>降级:{@code qq.llm.enabled=false} 或未配置 api-key 时 {@link #isEnabled} 返回 false,\n * 调用方走规则回退。调用失败只 warn 不抛异常,返回 null。\n */\n@Slf4j\n@Component\n@RequiredArgsConstructor\npublic class LlmClient {\n\n private final LlmProperties properties;\n private final SystemSettingRepository systemSettingRepository;\n private final ApiKeyEncryptor apiKeyEncryptor;\n\n private RestClient restClient;\n\n @PostConstruct\n void init() {\n if (properties.getBaseUrl() != null && !properties.getBaseUrl().isBlank()) {\n this.restClient = RestClient.builder()\n .baseUrl(properties.getBaseUrl())\n .build();\n }\n }\n\n /**\n * 是否启用(已 enabled 且 api-key 非空且 restClient 已初始化)。\n */\n public boolean isEnabled() {\n String apiKey = getApiKey();\n return properties.isEnabled()\n && restClient != null\n && apiKey != null\n && !apiKey.isBlank();\n }\n\n private String getApiKey() {\n String dbKey = systemSettingRepository.findBySettingKey(\"deepseek_api_key\")\n .map(SystemSetting::getSettingValue)\n .orElse(null);\n if (dbKey != null && !dbKey.isBlank()) {\n return apiKeyEncryptor.decrypt(dbKey);\n }\n return properties.getApiKey();\n }\n\n /**\n * 调用 chat completions,返回 assistant 消息(含 content 或 tool_calls)。\n *\n * @param messages 对话消息列表(含历史 + 上一轮 assistant tool_calls + tool 结果)\n * @param tools 工具 schema 列表(OpenAI function 格式),为空则不传 tools\n * @return assistant 消息 Map,或 null(调用失败 / 无响应)\n */\n @SuppressWarnings(\"unchecked\")\n public Map<String, Object> chat(List<Map<String, Object>> messages, List<Map<String, Object>> tools) {\n if (!isEnabled()) {\n return null;\n }\n try {\n Map<String, Object> body = new java.util.LinkedHashMap<>();\n body.put(\"model\", properties.getModel());\n body.put(\"messages\", messages);\n if (tools != null && !tools.isEmpty()) {\n body.put(\"tools\", tools);\n body.put(\"tool_choice\", \"auto\");\n }\n\n Map<String, Object> response = restClient.post()\n .uri(\"/v1/chat/completions\")\n .header(\"Authorization\", \"Bearer \" + getApiKey())\n .contentType(MediaType.APPLICATION_JSON)\n .body(body)\n .retrieve()\n .body(Map.class);\n return extractMessage(response);\n } catch (Exception e) {\n log.warn(\"DeepSeek 调用失败: reason={}\", e.getMessage());\n return null;\n }\n }\n\n /**\n * 从响应中提取 choices[0].message。\n */\n @SuppressWarnings(\"unchecked\")\n private Map<String, Object> extractMessage(Map<String, Object> response) {\n if (response == null) {\n return null;\n }\n Object choices = response.get(\"choices\");\n if (choices instanceof List<?> list && !list.isEmpty() && list.get(0) instanceof Map<?, ?> first) {\n Object message = first.get(\"message\");\n if (message instanceof Map<?, ?> msg) {\n return (Map<String, Object>) msg;\n }\n }\n log.warn(\"DeepSeek 响应格式异常: {}\", response);\n return null;\n }\n}\n"}, "ff85f054131b21bbc73583bdb7acd20d5a4cdcf4": {"t": 1785755707.230306, "n": 3582, "h": "bbf28979088082ea", "c": "package com.chinasoft.smokesensor.client;\n\nimport com.chinasoft.smokesensor.config.LlmProperties;\nimport jakarta.annotation.PostConstruct;\nimport java.util.List;\nimport java.util.Map;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.client.RestClient;\n\n/**\n * DeepSeek(OpenAI 兼容)大模型客户端,封装 chat completions + function calling 调用。\n *\n * <p>调用 {@code POST {base-url}/v1/chat/completions},请求体含 {@code model / messages / tools / tool_choice},\n * 响应 {@code choices[0].message}(含 {@code content} 或 {@code tool_calls})。\n *\n * <p>本类只负责 HTTP 调用与响应解析,工具执行与多轮编排由 {@code AgentToolService} 完成。\n *\n * <p>降级:{@code qq.llm.enabled=false} 或未配置 api-key 时 {@link #isEnabled} 返回 false,\n * 调用方走规则回退。调用失败只 warn 不抛异常,返回 null。\n */\n@Slf4j\n@Component\n@RequiredArgsConstructor\npublic class LlmClient {\n\n private final LlmProperties properties;\n\n private RestClient restClient;\n\n @PostConstruct\n void init() {\n if (properties.getBaseUrl() != null && !properties.getBaseUrl().isBlank()) {\n this.restClient = RestClient.builder()\n .baseUrl(properties.getBaseUrl())\n .build();\n }\n }\n\n /**\n * 是否启用(已 enabled 且 api-key 非空且 restClient 已初始化)。\n */\n public boolean isEnabled() {\n return properties.isEnabled()\n && restClient != null\n && properties.getApiKey() != null\n && !properties.getApiKey().isBlank();\n }\n\n /**\n * 调用 chat completions,返回 assistant 消息(含 content 或 tool_calls)。\n *\n * @param messages 对话消息列表(含历史 + 上一轮 assistant tool_calls + tool 结果)\n * @param tools 工具 schema 列表(OpenAI function 格式),为空则不传 tools\n * @return assistant 消息 Map,或 null(调用失败 / 无响应)\n */\n @SuppressWarnings(\"unchecked\")\n public Map<String, Object> chat(List<Map<String, Object>> messages, List<Map<String, Object>> tools) {\n if (!isEnabled()) {\n return null;\n }\n try {\n Map<String, Object> body = new java.util.LinkedHashMap<>();\n body.put(\"model\", properties.getModel());\n body.put(\"messages\", messages);\n if (tools != null && !tools.isEmpty()) {\n body.put(\"tools\", tools);\n body.put(\"tool_choice\", \"auto\");\n }\n\n Map<String, Object> response = restClient.post()\n .uri(\"/v1/chat/completions\")\n .header(\"Authorization\", \"Bearer \" + properties.getApiKey())\n .contentType(MediaType.APPLICATION_JSON)\n .body(body)\n .retrieve()\n .body(Map.class);\n return extractMessage(response);\n } catch (Exception e) {\n log.warn(\"DeepSeek 调用失败: reason={}\", e.getMessage());\n return null;\n }\n }\n\n /**\n * 从响应中提取 choices[0].message。\n */\n @SuppressWarnings(\"unchecked\")\n private Map<String, Object> extractMessage(Map<String, Object> response) {\n if (response == null) {\n return null;\n }\n Object choices = response.get(\"choices\");\n if (choices instanceof List<?> list && !list.isEmpty() && list.get(0) instanceof Map<?, ?> first) {\n Object message = first.get(\"message\");\n if (message instanceof Map<?, ?> msg) {\n return (Map<String, Object>) msg;\n }\n }\n log.warn(\"DeepSeek 响应格式异常: {}\", response);\n return null;\n }\n}\n"}}}}