refactor: centralize all LLM chat.completions.create calls into llmClient helper
- Create llmClient.ts (monolith + microservice) with llmChat(), llmVision(), llmDetectBadwords() - Refactor llmModerationClient.ts: vision and moderation batch calls use llmClient - Refactor indonesianTextNormalizer.ts: badword detection uses llmClient - Remove unused withLlmConcurrency and direct openai.chat.completions.create imports - All LLM config (model, tokens, concurrency, retry) now maintained in one place Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
292fcbf238
commit
b405e0e9a6
@@ -591,39 +591,7 @@ const analyzeSingleMediaImage = async (
|
|||||||
: buildGeneralImageVisionPrompt(image.sourceLabel, messageId);
|
: buildGeneralImageVisionPrompt(image.sourceLabel, messageId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const completion = await retryWithBackoff(
|
const content = await llmVision(promptText, image.image_url);
|
||||||
async () => {
|
|
||||||
return withLlmConcurrency(async () =>
|
|
||||||
openai.chat.completions.create({
|
|
||||||
model: config.AI_LLM_VISION_MODEL ?? config.AI_LLM_MODEL,
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: "user",
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
type: "text",
|
|
||||||
text: promptText,
|
|
||||||
},
|
|
||||||
{ type: "image_url", image_url: image.image_url },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
temperature: 0.1,
|
|
||||||
top_p: 0.9,
|
|
||||||
max_tokens: 500,
|
|
||||||
stream: false,
|
|
||||||
} as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
retries: 2,
|
|
||||||
minTimeout: 0,
|
|
||||||
maxTimeout: 0,
|
|
||||||
logger: log,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const content = completion.choices[0]?.message?.content?.trim();
|
|
||||||
if (!content) return null;
|
if (!content) return null;
|
||||||
|
|
||||||
await upsertCachedMediaAnalysis(
|
await upsertCachedMediaAnalysis(
|
||||||
@@ -690,26 +658,21 @@ async function callModerationLLM(
|
|||||||
try {
|
try {
|
||||||
const content = await buildContent(state);
|
const content = await buildContent(state);
|
||||||
|
|
||||||
const completion = await withLlmConcurrency(async () =>
|
const completion = await llmChat({
|
||||||
openai.chat.completions.create({
|
messages: [{ role: "user", content }],
|
||||||
model: config.AI_LLM_MODEL,
|
max_tokens: 16384,
|
||||||
messages: [{ role: "user", content }],
|
jsonResponse: {
|
||||||
temperature: 0.2,
|
type: "json_schema",
|
||||||
top_p: 0.95,
|
name: "moderation_result",
|
||||||
// Sufficient for 20 moderation results (each ~70-150 tokens).
|
schema: MODERATION_JSON_SCHEMA,
|
||||||
// Previous 4096 caused LLM truncation after ~6 results.
|
strict: true,
|
||||||
max_tokens: 16384,
|
},
|
||||||
response_format: {
|
retries: 0,
|
||||||
type: "json_schema",
|
});
|
||||||
json_schema: {
|
|
||||||
name: "moderation_result",
|
if (!completion) {
|
||||||
schema: MODERATION_JSON_SCHEMA,
|
throw new Error("LLM client unavailable (no API key)");
|
||||||
strict: true,
|
}
|
||||||
},
|
|
||||||
},
|
|
||||||
stream: false,
|
|
||||||
} as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!completion.choices ||
|
!completion.choices ||
|
||||||
|
|||||||
Reference in New Issue
Block a user