Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/airtimelcj-commits_situapuzzlegame-server.json
T

1 line
6.6 KiB
JSON

{"repo": "airtimelcj-commits/situapuzzlegame-server", "files": {"src/services/deepseek.service.js": {"ee02c4eff27508afdf5d2ffa8ffa215cd8a3efe1": {"t": 1785746697.2183855, "n": 6212, "h": "02728bc357a9706d", "c": "const logger = require(\"../utils/logger\");\n\nconst DEFAULT_BASE_URL = \"https://api.deepseek.com\";\nconst DEFAULT_MODEL = \"deepseek-chat\";\nconst MAX_ATTEMPTS = 3;\nconst MAX_LOG_BODY_CHARS = 1200;\n\nfunction truncate(value, maxChars) {\n if (value == null) return value;\n const s = typeof value === \"string\" ? value : JSON.stringify(value);\n if (s.length <= maxChars) return s;\n return s.slice(0, maxChars) + `…(${s.length - maxChars} chars more)`;\n}\n\nfunction sleep(ms) {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction shouldRetry(status, err) {\n if (err && err.name === \"AbortError\") return false;\n if (err && err.code === \"ETIMEDOUT\") return true;\n if (status == null) return true;\n if (status === 429) return true;\n if (status >= 500 && status < 600) return true;\n if (status >= 400 && status < 500) return false;\n return false;\n}\n\n/**\n * Call DeepSeek chat completions (OpenAI-compatible).\n * @param {string} apiKey\n * @param {{ role: string, content: string }[]} messages\n * @param {{ request_id?: string }=} meta\n * @returns {Promise<{ content: string, raw: object }>}\n */\nasync function chatCompletion(apiKey, messages, meta = {}) {\n const base = (process.env.DEEPSEEK_API_BASE_URL || DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n const url = `${base}/chat/completions`;\n const model = process.env.DEEPSEEK_MODEL || DEFAULT_MODEL;\n\n const body = {\n model,\n messages,\n temperature: 0,\n max_tokens: 10, // 只需要返回一个词,限制 token 数量\n };\n\n //console.log(`body ${JSON.stringify(body)}`);\n\n let lastErr;\n let lastStatus;\n\n const requestTimeoutMs = Number(process.env.DEEPSEEK_TIMEOUT_MS) || 30000;\n const overallStarted = Date.now();\n\n logger.info(\"deepseek.request_start\", {\n request_id: meta.request_id,\n url,\n model,\n timeout_ms: requestTimeoutMs,\n attempts_max: MAX_ATTEMPTS,\n messages_count: Array.isArray(messages) ? messages.length : undefined,\n messages_chars: Array.isArray(messages)\n ? messages.reduce((sum, m) => sum + (typeof m?.content === \"string\" ? m.content.length : 0), 0)\n : undefined,\n });\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), requestTimeoutMs);\n const started = Date.now();\n\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n lastStatus = res.status;\n const text = await res.text();\n\n console.log(`text ${text}`);\n\n let json;\n try {\n json = text ? JSON.parse(text) : {};\n } catch {\n json = { raw: text };\n }\n\n if (!res.ok) {\n const errMsg = json?.error?.message || json?.message || text || `HTTP ${res.status}`;\n lastErr = new Error(errMsg);\n lastErr.statusCode = res.status >= 400 && res.status < 600 ? res.status : 502;\n lastErr.body = json;\n\n logger.warn(\"deepseek.request_failed\", {\n request_id: meta.request_id,\n attempt,\n status: res.status,\n duration_ms: Date.now() - started,\n message: errMsg,\n response_body_preview: truncate(json, MAX_LOG_BODY_CHARS),\n });\n\n if (shouldRetry(res.status, null) && attempt < MAX_ATTEMPTS) {\n logger.info(\"deepseek.retry_scheduled\", {\n request_id: meta.request_id,\n attempt,\n reason: `HTTP_${res.status}`,\n backoff_ms: 200 * attempt,\n });\n await sleep(200 * attempt);\n continue;\n }\n\n throw lastErr;\n }\n\n const content =\n json?.choices?.[0]?.message?.content ??\n json?.choices?.[0]?.delta?.content ??\n \"\";\n\n if (typeof content !== \"string\" || !content.trim()) {\n const e = new Error(\"Empty or invalid completion from DeepSeek\");\n e.statusCode = 503;\n e.body = json;\n throw e;\n }\n\n logger.info(\"deepseek.request_ok\", {\n request_id: meta.request_id,\n attempt,\n duration_ms: Date.now() - started,\n model: json?.model || model,\n });\n\n logger.info(\"deepseek.request_complete\", {\n request_id: meta.request_id,\n status: 200,\n attempts_used: attempt,\n total_duration_ms: Date.now() - overallStarted,\n });\n\n return { content: content.trim(), raw: json };\n } catch (e) {\n lastErr = e;\n if (e.name === \"AbortError\") {\n e.statusCode = 504;\n e.code = \"UPSTREAM_TIMEOUT\";\n logger.warn(\"deepseek.timeout\", {\n request_id: meta.request_id,\n attempt,\n duration_ms: Date.now() - started,\n timeout_ms: requestTimeoutMs,\n });\n } else if (!e.statusCode) {\n e.statusCode = 503;\n e.code = \"NETWORK_ERROR\";\n logger.error(\"deepseek.network_error\", {\n request_id: meta.request_id,\n attempt,\n message: e.message,\n stack: e.stack,\n });\n } else {\n logger.warn(\"deepseek.request_exception\", {\n request_id: meta.request_id,\n attempt,\n status: e.statusCode,\n code: e.code,\n message: e.message,\n });\n }\n\n if (shouldRetry(lastStatus, e) && attempt < MAX_ATTEMPTS) {\n logger.info(\"deepseek.retry_scheduled\", {\n request_id: meta.request_id,\n attempt,\n reason: e.code || (lastStatus ? `HTTP_${lastStatus}` : \"UNKNOWN\"),\n backoff_ms: 200 * attempt,\n });\n await sleep(200 * attempt);\n continue;\n }\n\n logger.error(\"deepseek.request_giveup\", {\n request_id: meta.request_id,\n attempts_used: attempt,\n last_status: lastStatus,\n final_status: e.statusCode,\n code: e.code,\n message: e.message,\n total_duration_ms: Date.now() - overallStarted,\n });\n throw e;\n } finally {\n clearTimeout(timer);\n }\n }\n\n throw lastErr || new Error(\"DeepSeek request failed\");\n}\n\nmodule.exports = {\n chatCompletion,\n MAX_ATTEMPTS,\n};\n"}}}}