Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/bingyanglu_claudio-fm.json
T

1 line
11 KiB
JSON
Raw 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": "bingyanglu/claudio-fm", "files": {"llm.js": {"4939b1adc5ddc5ed1289a1e93cd0235b98634abe": {"t": 1785745516.9611857, "n": 5307, "h": "d10cd19b8a965cac", "c": "const { spawn } = require('child_process');\n\nconst DEFAULT_TIMEOUT_MS = Number(process.env.LLM_TIMEOUT_MS || 120000);\nconst DEFAULT_PROVIDER = process.env.LLM_PROVIDER || 'deepseek';\nconst DEEPSEEK_BASE_URL = process.env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com';\nconst DEEPSEEK_MODEL = process.env.DEEPSEEK_MODEL || 'deepseek-v4-flash';\nconst DEEPSEEK_REASONING_EFFORT = process.env.DEEPSEEK_REASONING_EFFORT || '';\nconst DEEPSEEK_THINKING = process.env.DEEPSEEK_THINKING || '';\n\nasync function generateJson(prompt, options = {}) {\n const provider = options.provider || DEFAULT_PROVIDER;\n if (provider === 'deepseek') return callDeepSeek(prompt, options);\n if (provider === 'claude_cli') return callClaudeCli(prompt, options);\n throw new Error(`Unsupported LLM_PROVIDER: ${provider}`);\n}\n\nasync function callDeepSeek(prompt, options = {}) {\n if (!process.env.DEEPSEEK_API_KEY) {\n throw new Error('DEEPSEEK_API_KEY not set');\n }\n\n const OpenAI = await loadOpenAI();\n const client = new OpenAI({\n baseURL: process.env.DEEPSEEK_BASE_URL || DEEPSEEK_BASE_URL,\n apiKey: process.env.DEEPSEEK_API_KEY,\n });\n const model = options.model || process.env.DEEPSEEK_MODEL || DEEPSEEK_MODEL;\n const startAt = Date.now();\n console.log(`[LLM:deepseek] 调用中,model ${model},prompt ${prompt.length} 字符…`);\n\n const request = {\n model,\n messages: [\n { role: 'system', content: 'You are Claudio FM. Return strict JSON only.' },\n { role: 'user', content: prompt },\n ],\n stream: false,\n };\n if (DEEPSEEK_THINKING) request.thinking = { type: DEEPSEEK_THINKING };\n if (DEEPSEEK_REASONING_EFFORT) request.reasoning_effort = DEEPSEEK_REASONING_EFFORT;\n\n const completion = await withTimeout(\n client.chat.completions.create(request),\n options.timeoutMs || DEFAULT_TIMEOUT_MS,\n `DeepSeek request timed out after ${Math.round((options.timeoutMs || DEFAULT_TIMEOUT_MS) / 1000)}s`\n );\n const elapsed = ((Date.now() - startAt) / 1000).toFixed(1);\n const raw = completion.choices?.[0]?.message?.content?.trim() || '';\n const parsed = parseResponse(raw);\n logParsedResponse('deepseek', elapsed, parsed, raw);\n return parsed;\n}\n\nasync function loadOpenAI() {\n try {\n const mod = await import('openai');\n return mod.default || mod.OpenAI || mod;\n } catch (err) {\n throw new Error('OpenAI SDK not installed. Run `yarn add openai` or `npm install openai`.');\n }\n}\n\nfunction callClaudeCli(prompt, options = {}) {\n const timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS;\n const startAt = Date.now();\n console.log(`[LLM:claude_cli] 调用中,prompt ${prompt.length} 字符…`);\n return new Promise((resolve, reject) => {\n const proc = spawn('claude', ['-p', prompt], {\n env: { ...process.env },\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n const timer = setTimeout(() => {\n proc.kill();\n const stderrPreview = stderr.trim().slice(-800);\n console.error(`[LLM:claude_cli] 超时(${Math.round(timeoutMs / 1000)}s),已终止;prompt ${prompt.length} 字符`);\n if (stderrPreview) console.error(`[LLM:claude_cli] stderr 摘要: ${stderrPreview}`);\n reject(new Error('Claude subprocess timed out'));\n }, timeoutMs);\n\n proc.stdout.on('data', d => { stdout += d.toString(); });\n proc.stderr.on('data', d => {\n stderr += d.toString();\n process.stderr.write(d);\n });\n\n proc.on('close', () => {\n clearTimeout(timer);\n const elapsed = ((Date.now() - startAt) / 1000).toFixed(1);\n const raw = stdout.trim();\n const parsed = parseResponse(raw);\n logParsedResponse('claude_cli', elapsed, parsed, raw);\n if (!raw) console.warn('[LLM:claude_cli] 警告:返回内容为空');\n resolve(parsed);\n });\n\n proc.on('error', err => {\n clearTimeout(timer);\n console.error('[LLM:claude_cli] 进程错误:', err.message);\n reject(err);\n });\n });\n}\n\nfunction withTimeout(promise, timeoutMs, message) {\n let timer;\n const timeout = new Promise((_, reject) => {\n timer = setTimeout(() => reject(new Error(message)), timeoutMs);\n });\n return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));\n}\n\nfunction parseResponse(raw) {\n const jsonMatch = raw.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n try {\n const parsed = JSON.parse(jsonMatch[0]);\n return {\n title: parsed.title || '',\n say: parsed.say || '',\n play: Array.isArray(parsed.play) ? parsed.play : [],\n segments: Array.isArray(parsed.segments) ? parsed.segments : [],\n intros: Array.isArray(parsed.intros) ? parsed.intros : [],\n reason: parsed.reason || '',\n mode: parsed.mode || '',\n };\n } catch {}\n }\n return { title: '', say: raw || 'Okay.', play: [], segments: [], intros: [], reason: '', segue: '', mode: '' };\n}\n\nfunction logParsedResponse(provider, elapsed, parsed, raw) {\n const firstSegment = parsed.segments?.find(s => s?.text)?.text || parsed.say || '';\n const preview = firstSegment.slice(0, 60);\n console.log(`[LLM:${provider}] 响应 (${elapsed}s) → 「${parsed.title || '无标题'}」| ${parsed.play?.length || 0} 首 | segments: ${parsed.segments?.length || 0} | \"${preview}${preview.length >= 60 ? '…' : ''}\"`);\n if (!raw) console.warn(`[LLM:${provider}] 警告:返回内容为空`);\n}\n\nmodule.exports = { generateJson, parseResponse };\n"}, "1ffdd7c1051b5a447028fff57e99f461a085b36f": {"t": 1785753769.1064897, "n": 5307, "h": "d10cd19b8a965cac", "c": "const { spawn } = require('child_process');\n\nconst DEFAULT_TIMEOUT_MS = Number(process.env.LLM_TIMEOUT_MS || 120000);\nconst DEFAULT_PROVIDER = process.env.LLM_PROVIDER || 'deepseek';\nconst DEEPSEEK_BASE_URL = process.env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com';\nconst DEEPSEEK_MODEL = process.env.DEEPSEEK_MODEL || 'deepseek-v4-flash';\nconst DEEPSEEK_REASONING_EFFORT = process.env.DEEPSEEK_REASONING_EFFORT || '';\nconst DEEPSEEK_THINKING = process.env.DEEPSEEK_THINKING || '';\n\nasync function generateJson(prompt, options = {}) {\n const provider = options.provider || DEFAULT_PROVIDER;\n if (provider === 'deepseek') return callDeepSeek(prompt, options);\n if (provider === 'claude_cli') return callClaudeCli(prompt, options);\n throw new Error(`Unsupported LLM_PROVIDER: ${provider}`);\n}\n\nasync function callDeepSeek(prompt, options = {}) {\n if (!process.env.DEEPSEEK_API_KEY) {\n throw new Error('DEEPSEEK_API_KEY not set');\n }\n\n const OpenAI = await loadOpenAI();\n const client = new OpenAI({\n baseURL: process.env.DEEPSEEK_BASE_URL || DEEPSEEK_BASE_URL,\n apiKey: process.env.DEEPSEEK_API_KEY,\n });\n const model = options.model || process.env.DEEPSEEK_MODEL || DEEPSEEK_MODEL;\n const startAt = Date.now();\n console.log(`[LLM:deepseek] 调用中,model ${model},prompt ${prompt.length} 字符…`);\n\n const request = {\n model,\n messages: [\n { role: 'system', content: 'You are Claudio FM. Return strict JSON only.' },\n { role: 'user', content: prompt },\n ],\n stream: false,\n };\n if (DEEPSEEK_THINKING) request.thinking = { type: DEEPSEEK_THINKING };\n if (DEEPSEEK_REASONING_EFFORT) request.reasoning_effort = DEEPSEEK_REASONING_EFFORT;\n\n const completion = await withTimeout(\n client.chat.completions.create(request),\n options.timeoutMs || DEFAULT_TIMEOUT_MS,\n `DeepSeek request timed out after ${Math.round((options.timeoutMs || DEFAULT_TIMEOUT_MS) / 1000)}s`\n );\n const elapsed = ((Date.now() - startAt) / 1000).toFixed(1);\n const raw = completion.choices?.[0]?.message?.content?.trim() || '';\n const parsed = parseResponse(raw);\n logParsedResponse('deepseek', elapsed, parsed, raw);\n return parsed;\n}\n\nasync function loadOpenAI() {\n try {\n const mod = await import('openai');\n return mod.default || mod.OpenAI || mod;\n } catch (err) {\n throw new Error('OpenAI SDK not installed. Run `yarn add openai` or `npm install openai`.');\n }\n}\n\nfunction callClaudeCli(prompt, options = {}) {\n const timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS;\n const startAt = Date.now();\n console.log(`[LLM:claude_cli] 调用中,prompt ${prompt.length} 字符…`);\n return new Promise((resolve, reject) => {\n const proc = spawn('claude', ['-p', prompt], {\n env: { ...process.env },\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n const timer = setTimeout(() => {\n proc.kill();\n const stderrPreview = stderr.trim().slice(-800);\n console.error(`[LLM:claude_cli] 超时(${Math.round(timeoutMs / 1000)}s),已终止;prompt ${prompt.length} 字符`);\n if (stderrPreview) console.error(`[LLM:claude_cli] stderr 摘要: ${stderrPreview}`);\n reject(new Error('Claude subprocess timed out'));\n }, timeoutMs);\n\n proc.stdout.on('data', d => { stdout += d.toString(); });\n proc.stderr.on('data', d => {\n stderr += d.toString();\n process.stderr.write(d);\n });\n\n proc.on('close', () => {\n clearTimeout(timer);\n const elapsed = ((Date.now() - startAt) / 1000).toFixed(1);\n const raw = stdout.trim();\n const parsed = parseResponse(raw);\n logParsedResponse('claude_cli', elapsed, parsed, raw);\n if (!raw) console.warn('[LLM:claude_cli] 警告:返回内容为空');\n resolve(parsed);\n });\n\n proc.on('error', err => {\n clearTimeout(timer);\n console.error('[LLM:claude_cli] 进程错误:', err.message);\n reject(err);\n });\n });\n}\n\nfunction withTimeout(promise, timeoutMs, message) {\n let timer;\n const timeout = new Promise((_, reject) => {\n timer = setTimeout(() => reject(new Error(message)), timeoutMs);\n });\n return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));\n}\n\nfunction parseResponse(raw) {\n const jsonMatch = raw.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n try {\n const parsed = JSON.parse(jsonMatch[0]);\n return {\n title: parsed.title || '',\n say: parsed.say || '',\n play: Array.isArray(parsed.play) ? parsed.play : [],\n segments: Array.isArray(parsed.segments) ? parsed.segments : [],\n intros: Array.isArray(parsed.intros) ? parsed.intros : [],\n reason: parsed.reason || '',\n mode: parsed.mode || '',\n };\n } catch {}\n }\n return { title: '', say: raw || 'Okay.', play: [], segments: [], intros: [], reason: '', segue: '', mode: '' };\n}\n\nfunction logParsedResponse(provider, elapsed, parsed, raw) {\n const firstSegment = parsed.segments?.find(s => s?.text)?.text || parsed.say || '';\n const preview = firstSegment.slice(0, 60);\n console.log(`[LLM:${provider}] 响应 (${elapsed}s) → 「${parsed.title || '无标题'}」| ${parsed.play?.length || 0} 首 | segments: ${parsed.segments?.length || 0} | \"${preview}${preview.length >= 60 ? '…' : ''}\"`);\n if (!raw) console.warn(`[LLM:${provider}] 警告:返回内容为空`);\n}\n\nmodule.exports = { generateJson, parseResponse };\n"}}}}