Replaced the dedicated /admin/subscriptions page with a redirect to the central admin panel’s subscriptions tab. Removed session checks, imports, and the AdminSubscriptionDashboard since routing and access are now handled centrally. This streamlines admin UX and keeps access control unified.
147 lines
3.7 KiB
TypeScript
147 lines
3.7 KiB
TypeScript
import { secureLogger } from "@/lib/secure-logger";
|
||
|
||
interface GenerateItemStructureInput {
|
||
name: string;
|
||
description: string;
|
||
scope: "global" | "server";
|
||
server?: string | null;
|
||
}
|
||
|
||
interface GeminiResponse {
|
||
structure: {
|
||
table: string;
|
||
columns: Record<string, unknown>;
|
||
};
|
||
raw: unknown;
|
||
}
|
||
|
||
const FALLBACK_STRUCTURE = {
|
||
table: "items_all",
|
||
columns: {
|
||
name: "Final Fate",
|
||
description:
|
||
"Item lendário utilizado no slot de tocha. Oferece bônus massivos em skills mágicas, velocidade e efeitos de leech.",
|
||
attributes: {
|
||
shielding: 20,
|
||
death_magic: 120,
|
||
mana_leech: { value: 30, chance: 100 },
|
||
life_leech: { value: 25, chance: 100 },
|
||
critical_hit: { damage: 25, chance: 75 },
|
||
speed: 1000,
|
||
protection_physical: 40,
|
||
damage_reflection: 80,
|
||
},
|
||
},
|
||
};
|
||
|
||
export async function generateItemStructure(
|
||
input: GenerateItemStructureInput
|
||
): Promise<GeminiResponse> {
|
||
const apiKey = process.env.GEMINI_API_KEY;
|
||
|
||
if (!apiKey) {
|
||
secureLogger.warn("⚠️ GEMINI_API_KEY ausente – utilizando fallback estático.");
|
||
return {
|
||
structure: FALLBACK_STRUCTURE,
|
||
raw: FALLBACK_STRUCTURE,
|
||
};
|
||
}
|
||
|
||
const url =
|
||
"https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=" +
|
||
apiKey;
|
||
|
||
const prompt = buildPrompt(input);
|
||
|
||
try {
|
||
const response = await fetch(url, {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
body: JSON.stringify({
|
||
contents: [
|
||
{
|
||
role: "user",
|
||
parts: [{ text: prompt }],
|
||
},
|
||
],
|
||
generationConfig: {
|
||
temperature: 0,
|
||
topP: 0.1,
|
||
},
|
||
}),
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`Gemini retornou status ${response.status}`);
|
||
}
|
||
|
||
const data = await response.json();
|
||
const text =
|
||
data?.candidates?.[0]?.content?.parts?.[0]?.text ??
|
||
data?.candidates?.[0]?.output_text;
|
||
|
||
if (!text) {
|
||
throw new Error("Resposta do Gemini vazia ou inválida.");
|
||
}
|
||
|
||
const cleaned = text
|
||
.replace(/```json/gi, "")
|
||
.replace(/```/g, "")
|
||
.trim();
|
||
|
||
const parsed = JSON.parse(cleaned);
|
||
|
||
return {
|
||
structure: parsed,
|
||
raw: data,
|
||
};
|
||
} catch (error) {
|
||
secureLogger.error("❌ Falha ao gerar estrutura via Gemini", {
|
||
error: error instanceof Error ? error.message : "Erro desconhecido",
|
||
});
|
||
|
||
return {
|
||
structure: FALLBACK_STRUCTURE,
|
||
raw: FALLBACK_STRUCTURE,
|
||
};
|
||
}
|
||
}
|
||
|
||
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.
|
||
|
||
Requisitos obrigatórios:
|
||
- Responda SOMENTE com JSON válido, sem comentários, sem markdown, sem texto adicional.
|
||
- Formato esperado:
|
||
{
|
||
"table": "nome_da_tabela",
|
||
"columns": {
|
||
"...": "..."
|
||
}
|
||
}
|
||
- Nunca inclua explicações fora do JSON.
|
||
|
||
Contexto do item:
|
||
- Nome: ${name}
|
||
- Escopo: ${scope === "server" ? `específico do servidor ${server ?? "não informado"}` : "global"}
|
||
- Descrição original (mantenha estrutura e extrair atributos quando possível):
|
||
"""
|
||
${description}
|
||
"""
|
||
|
||
Instruções:
|
||
- 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".
|
||
- Modele atributos numéricos em objetos ou subtabelas conforme necessário (ex.: {"attributes": {...}}).
|
||
- Quando não tiver certeza de um campo, deixe nulo.
|
||
- Nunca invente dados além do que estiver na descrição.
|
||
- Garante que o JSON seja minuciosamente válido.
|
||
`;
|
||
}
|
||
|