git-subtree-dir: coordenador git-subtree-mainline:facbe2e340git-subtree-split:ce7af94d55
88 lines
3.4 KiB
JavaScript
88 lines
3.4 KiB
JavaScript
const { normalizeGlpiText } = require('./normalize');
|
|
|
|
function normalizeTicket(row, extras) {
|
|
const followups = ((extras && extras.followups) || []).map((f) => ({
|
|
id: f.id,
|
|
date: f.date,
|
|
texto: normalizeGlpiText(f.texto),
|
|
}));
|
|
const tasks = ((extras && extras.tasks) || []).map((t) => ({
|
|
id: t.id,
|
|
date: t.date,
|
|
status: t.status,
|
|
texto: normalizeGlpiText(t.texto),
|
|
}));
|
|
return {
|
|
id: Number(row.id),
|
|
titulo: normalizeGlpiText(row.titulo),
|
|
descricao: normalizeGlpiText(row.descricao),
|
|
status: Number(row.status),
|
|
status_nome: row.status_nome,
|
|
aberto_em: row.aberto_em,
|
|
ultima_interacao_em: row.ultima_interacao_em,
|
|
dias_aberto: Number(row.dias_aberto),
|
|
dias_sem_interacao: Number(row.dias_sem_interacao),
|
|
sla_vencido: Number(row.sla_vencido) === 1,
|
|
sla_em_risco: Number(row.sla_em_risco) === 1,
|
|
horas_ate_sla: row.horas_ate_sla == null ? null : Number(row.horas_ate_sla),
|
|
prioridade: Number(row.prioridade),
|
|
urgencia: Number(row.urgencia),
|
|
impacto: Number(row.impacto),
|
|
entidade: row.entidade,
|
|
categoria: row.categoria,
|
|
tecnico_atribuido: row.tecnico_atribuido,
|
|
sem_tecnico: Number(row.sem_tecnico) === 1,
|
|
link_glpi: row.link_glpi,
|
|
score_criticidade: Number(row.score_criticidade),
|
|
followups,
|
|
tasks,
|
|
};
|
|
}
|
|
|
|
function truncate(text, maxChars) {
|
|
const clean = String(text || '').replace(/\s+/g, ' ').trim();
|
|
return clean.length > maxChars ? `${clean.slice(0, Math.max(0, maxChars - 3))}...` : clean;
|
|
}
|
|
|
|
// Corta pelo tamanho total sem achatar quebras de linha -- usado só no corte final do
|
|
// contexto inteiro (o texto de cada seção já foi normalizado/truncado individualmente).
|
|
function truncatePreservingLines(text, maxChars) {
|
|
const str = String(text || '');
|
|
return str.length > maxChars ? `${str.slice(0, Math.max(0, maxChars - 3))}...` : str;
|
|
}
|
|
|
|
// Contexto com secoes delimitadas (TITULO / DESCRICAO / STATUS-TECNICO-GRUPO / FOLLOW-UPS /
|
|
// TAREFAS), nao uma unica string sem estrutura semantica. O texto de cada campo ja chega
|
|
// normalizado (normalizeTicket ja rodou normalizeGlpiText em titulo/descricao/texto).
|
|
function buildAiContextText(ticket, maxChars) {
|
|
const budget = Math.max(200, Number(maxChars) || 4000);
|
|
|
|
const followupsText = ticket.followups
|
|
.slice(-5)
|
|
.map((f) => `- [${f.date}] ${truncate(f.texto, 300) || '(sem conteudo)'}`)
|
|
.join('\n');
|
|
const tasksText = ticket.tasks
|
|
.slice(-5)
|
|
.map((t) => `- [${t.date} status=${t.status}] ${truncate(t.texto, 300) || '(sem conteudo)'}`)
|
|
.join('\n');
|
|
|
|
const secoes = [
|
|
`TITULO\n${truncate(ticket.titulo, 200) || '(sem titulo)'}`,
|
|
`DESCRICAO ORIGINAL\n${truncate(ticket.descricao, 800) || '(sem descricao)'}`,
|
|
[
|
|
`STATUS: ${ticket.status_nome}`,
|
|
`TECNICO: ${ticket.tecnico_atribuido}`,
|
|
`GRUPO/ENTIDADE: ${ticket.entidade} | CATEGORIA: ${ticket.categoria}`,
|
|
`PRIORIDADE: ${ticket.prioridade} URGENCIA: ${ticket.urgencia} IMPACTO: ${ticket.impacto}`,
|
|
`SLA vencido: ${ticket.sla_vencido} | Dias sem interacao: ${ticket.dias_sem_interacao} | Dias aberto: ${ticket.dias_aberto}`,
|
|
].join('\n'),
|
|
`FOLLOW-UPS\n${followupsText || '(nenhum)'}`,
|
|
`TAREFAS\n${tasksText || '(nenhuma)'}`,
|
|
];
|
|
|
|
const contextoCompleto = `Chamado #${ticket.id}\n\n${secoes.join('\n\n')}`;
|
|
return truncatePreservingLines(contextoCompleto, budget);
|
|
}
|
|
|
|
module.exports = { normalizeTicket, buildAiContextText, truncate, truncatePreservingLines };
|