style: clean up code formatting and remove trailing whitespace
refactor: reorganize imports and fix type imports
This commit is contained in:
1 parent
d3704602fd
commit
47c04de6fe
232 files changed
+7140
-4798
No files matched your search
@@ -1,6 +1,10 @@
|
||||
import { secureLogger } from "@/lib/secure-logger";
|
||||
import { buildGeminiParts, buildItemPrompt, InlineImageData } from "@/lib/ai/item-prompt";
|
||||
import {
|
||||
buildGeminiParts,
|
||||
buildItemPrompt,
|
||||
type InlineImageData,
|
||||
} from "@/lib/ai/item-prompt";
|
||||
import { listCategoryTemplates } from "@/lib/items/sqlite-manager";
|
||||
import { secureLogger } from "@/lib/secure-logger";
|
||||
|
||||
interface GenerateItemStructureInput {
|
||||
name: string;
|
||||
@@ -46,12 +50,14 @@ const FALLBACK_STRUCTURE = {
|
||||
};
|
||||
|
||||
export async function generateItemStructure(
|
||||
input: GenerateItemStructureInput
|
||||
input: GenerateItemStructureInput,
|
||||
): Promise<GeminiResponse> {
|
||||
const apiKey = process.env.GEMINI_API_KEY;
|
||||
|
||||
if (!apiKey) {
|
||||
secureLogger.warn("⚠️ GEMINI_API_KEY ausente – utilizando fallback estático.");
|
||||
secureLogger.warn(
|
||||
"⚠️ GEMINI_API_KEY ausente – utilizando fallback estático.",
|
||||
);
|
||||
return {
|
||||
structure: FALLBACK_STRUCTURE,
|
||||
raw: FALLBACK_STRUCTURE,
|
||||
@@ -66,7 +72,7 @@ export async function generateItemStructure(
|
||||
try {
|
||||
const templates = listCategoryTemplates();
|
||||
if (templates.length > 0) {
|
||||
const lines: string[] = ["Estruturas atuais no SQLite:"];
|
||||
const lines: string[] = ["Estruturas atuais no SQLite:"];
|
||||
templates.forEach((tpl) => {
|
||||
lines.push(`- Tabela: ${tpl.name}`);
|
||||
tpl.columns.forEach((col) => {
|
||||
@@ -75,7 +81,7 @@ export async function generateItemStructure(
|
||||
});
|
||||
sqliteSchemaText = lines.join("\n");
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (_e) {
|
||||
sqliteSchemaText = "[Falha ao listar SQLite]";
|
||||
}
|
||||
|
||||
@@ -144,7 +150,8 @@ export async function generateItemStructure(
|
||||
|
||||
if (!response.ok) {
|
||||
const status = response.status;
|
||||
const msg = bodyJson?.error?.message || `Gemini retornou status ${status}`;
|
||||
const msg =
|
||||
bodyJson?.error?.message || `Gemini retornou status ${status}`;
|
||||
const err = new Error(msg);
|
||||
(err as any).status = status;
|
||||
(err as any).response = bodyJson;
|
||||
@@ -210,7 +217,12 @@ export async function generateItemStructure(
|
||||
}
|
||||
}
|
||||
|
||||
function buildPrompt({ name, description, scope, server }: GenerateItemStructureInput) {
|
||||
function _buildPrompt({
|
||||
name,
|
||||
description,
|
||||
scope,
|
||||
server,
|
||||
}: GenerateItemStructureInput) {
|
||||
return `
|
||||
Você é um assistente que prepara carga útil em JSON para inserção de itens em banco de dados.
|
||||
|
||||
@@ -234,7 +246,9 @@ ${description}
|
||||
"""
|
||||
|
||||
Instruções:
|
||||
- Escolha uma tabela coerente com o escopo (ex.: "items_all" para global ou "items_${(server ?? "custom")
|
||||
- Escolha uma tabela coerente com o escopo (ex.: "items_all" para global ou "items_${(
|
||||
server ?? "custom"
|
||||
)
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "_")}" para servidor).
|
||||
- Dentro de "columns", inicie com "name" e "description".
|
||||
@@ -244,4 +258,3 @@ Instruções:
|
||||
- Garante que o JSON seja minuciosamente válido.
|
||||
`;
|
||||
}
|
||||
|
||||
+17
-9
@@ -1,5 +1,5 @@
|
||||
import { promises as fs } from "fs";
|
||||
import path from "path";
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
interface PromptContext {
|
||||
name: string;
|
||||
@@ -36,7 +36,9 @@ async function loadSchemaSummary(): Promise<string> {
|
||||
const body = match[2]
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line && !line.startsWith("//") && !line.startsWith("@@"))
|
||||
.filter(
|
||||
(line) => line && !line.startsWith("//") && !line.startsWith("@@"),
|
||||
)
|
||||
.join("\n");
|
||||
|
||||
blocks.push(`Model ${modelName} {\n${body}\n}`);
|
||||
@@ -60,7 +62,10 @@ Front-end fields (AdminItemForm):
|
||||
- dynamic metadata: campos variáveis definidos por categoria (servidores, atributos, etc)
|
||||
`.trim();
|
||||
|
||||
export async function buildItemPrompt(context: PromptContext, extraInstructions?: string) {
|
||||
export async function buildItemPrompt(
|
||||
context: PromptContext,
|
||||
extraInstructions?: string,
|
||||
) {
|
||||
const schemaSummary = await loadSchemaSummary();
|
||||
|
||||
const categoriesText =
|
||||
@@ -150,10 +155,14 @@ export interface InlineImageData {
|
||||
base64Data: string;
|
||||
}
|
||||
|
||||
export async function buildGeminiParts(prompt: string, images: InlineImageData[] = []) {
|
||||
const parts: Array<{ text?: string; inline_data?: { mimeType: string; data: string } }> = [
|
||||
{ text: prompt },
|
||||
];
|
||||
export async function buildGeminiParts(
|
||||
prompt: string,
|
||||
images: InlineImageData[] = [],
|
||||
) {
|
||||
const parts: Array<{
|
||||
text?: string;
|
||||
inline_data?: { mimeType: string; data: string };
|
||||
}> = [{ text: prompt }];
|
||||
|
||||
images.slice(0, 2).forEach((image) => {
|
||||
parts.push({
|
||||
@@ -166,4 +175,3 @@ export async function buildGeminiParts(prompt: string, images: InlineImageData[]
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
@@ -44,9 +44,13 @@ export function calculateTokenCost(
|
||||
const pricing = TOKEN_PRICING[model] ?? TOKEN_PRICING["gemini-2.5-flash"];
|
||||
const inputTokens = Math.max(0, Number(usage?.promptTokenCount || 0));
|
||||
const outputTokens = Math.max(0, Number(usage?.candidatesTokenCount || 0));
|
||||
const totalTokens = Math.max(0, Number(usage?.totalTokenCount || inputTokens + outputTokens));
|
||||
const totalTokens = Math.max(
|
||||
0,
|
||||
Number(usage?.totalTokenCount || inputTokens + outputTokens),
|
||||
);
|
||||
|
||||
const inputUsd = (inputTokens / 1_000_000) * pricing.inputPerMillionTextImageVideo;
|
||||
const inputUsd =
|
||||
(inputTokens / 1_000_000) * pricing.inputPerMillionTextImageVideo;
|
||||
const outputUsd = (outputTokens / 1_000_000) * pricing.outputPerMillion;
|
||||
const totalUsd = inputUsd + outputUsd;
|
||||
|
||||
@@ -58,4 +62,4 @@ export function calculateTokenCost(
|
||||
outputUsd,
|
||||
totalUsd,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,9 @@ export interface TokenUsageRecord {
|
||||
|
||||
const KEY_PREFIX = "ai:usage";
|
||||
|
||||
export async function recordTokenUsage(record: TokenUsageRecord): Promise<void> {
|
||||
export async function recordTokenUsage(
|
||||
record: TokenUsageRecord,
|
||||
): Promise<void> {
|
||||
const redis = await getRedisClient();
|
||||
const dayKey = `${KEY_PREFIX}:day:${new Date(record.timestamp).toISOString().slice(0, 10)}`; // YYYY-MM-DD
|
||||
const listKey = `${KEY_PREFIX}:records`;
|
||||
@@ -31,4 +33,4 @@ export async function recordTokenUsage(record: TokenUsageRecord): Promise<void>
|
||||
pipeline.lTrim(listKey, 0, 9999);
|
||||
|
||||
await pipeline.exec();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user