App local (Node + SQLite) para captura, tratamento e exportacao de leads comerciais, com dashboard de gestao, login/usuarios e integracao Z-PRO. Co-Authored-By: Claude <noreply@anthropic.com>
114 lines
4.0 KiB
JavaScript
114 lines
4.0 KiB
JavaScript
import { loadDotEnv } from '../src/env.mjs';
|
|
import { openDb, ensureSeeds } from '../src/db.mjs';
|
|
import { runCapture, createCaptureRun } from '../src/capture/runner.mjs';
|
|
import { describeSources } from '../src/sources/index.mjs';
|
|
|
|
// CLI de captura (uso avancado / testes). A interface principal e o app:
|
|
// node scripts/servidor.mjs (ou o GTI-Comercial.exe)
|
|
//
|
|
// Exemplos:
|
|
// node scripts/capturar-leads.mjs --sources=mock
|
|
// node scripts/capturar-leads.mjs --sources=cnpj-base --uf=BA --cities="Santo Antonio de Jesus"
|
|
// node scripts/capturar-leads.mjs --sources=cnpj-base,overpass --uf=BA --cities=all --segments=all
|
|
|
|
await loadDotEnv();
|
|
|
|
const args = new Map(
|
|
process.argv.slice(2).map((arg) => {
|
|
const [key, value = 'true'] = arg.replace(/^--/, '').split('=');
|
|
return [key, value];
|
|
})
|
|
);
|
|
|
|
function usage() {
|
|
const fontes = describeSources().map((s) => ` ${s.id} — ${s.label}${s.disponivel ? '' : ` (indisponivel: ${s.motivo})`}`);
|
|
return [
|
|
'Uso: node scripts/capturar-leads.mjs --sources=<ids> [opcoes]',
|
|
'',
|
|
'Opcoes:',
|
|
' --sources=cnpj-base,overpass fontes separadas por virgula (ou "mock")',
|
|
' --uf=BA estado alvo',
|
|
' --cities=all | "A,B,C" cidades (all = todas as cidades da UF na base)',
|
|
' --segments=all | "a,b,c" nichos pelo nome (all = todos os 57)',
|
|
' --segment-limit=N usa so os N primeiros nichos',
|
|
' --city-limit=N usa so as N primeiras cidades',
|
|
' --max=10 max de resultados por consulta (fontes de API)',
|
|
' --query-limit=0 max total de consultas (0 = sem limite)',
|
|
'',
|
|
'Fontes:',
|
|
...fontes
|
|
].join('\n');
|
|
}
|
|
|
|
async function main() {
|
|
if (args.has('help')) {
|
|
console.log(usage());
|
|
return;
|
|
}
|
|
|
|
const db = openDb();
|
|
await ensureSeeds(db, { log: (m) => console.log(`[captura] ${m}`) });
|
|
|
|
const uf = (args.get('uf') || 'BA').toUpperCase();
|
|
const sources = (args.get('sources') || 'mock').split(',').map((s) => s.trim()).filter(Boolean);
|
|
|
|
let segments = db.prepare('SELECT * FROM segments WHERE active = 1 ORDER BY id').all().map((row) => ({
|
|
name: row.name,
|
|
label: row.label,
|
|
interest: row.interest,
|
|
queries: JSON.parse(row.queries_json),
|
|
cnaeCodes: JSON.parse(row.cnae_codes_json),
|
|
overpassTags: JSON.parse(row.overpass_tags_json),
|
|
pains: JSON.parse(row.pains_json)
|
|
}));
|
|
|
|
const segmentsArg = args.get('segments');
|
|
if (segmentsArg && segmentsArg !== 'all') {
|
|
const wanted = new Set(segmentsArg.split(',').map((s) => s.trim()));
|
|
segments = segments.filter((s) => wanted.has(s.name));
|
|
}
|
|
const segmentLimit = Number(args.get('segment-limit') || 0);
|
|
if (segmentLimit > 0) segments = segments.slice(0, segmentLimit);
|
|
|
|
let cities;
|
|
const citiesArg = args.get('cities') || 'all';
|
|
if (citiesArg === 'all') {
|
|
cities = db.prepare('SELECT nome FROM municipios WHERE uf = ? ORDER BY nome').all(uf).map((r) => r.nome);
|
|
} else {
|
|
cities = citiesArg.split(',').map((c) => c.trim()).filter(Boolean);
|
|
}
|
|
const cityLimit = Number(args.get('city-limit') || 0);
|
|
if (cityLimit > 0) cities = cities.slice(0, cityLimit);
|
|
|
|
const params = {
|
|
sources,
|
|
uf,
|
|
cities,
|
|
segments,
|
|
limits: {
|
|
maxPerQuery: Number(args.get('max') || 10),
|
|
queryLimit: Number(args.get('query-limit') || 0),
|
|
googlePages: Number(args.get('google-pages') || 3)
|
|
}
|
|
};
|
|
|
|
console.log(`[captura] fontes: ${sources.join(', ')} | UF: ${uf} | cidades: ${cities.length} | nichos: ${segments.length}`);
|
|
|
|
const runId = createCaptureRun(db, { ...params, segments: segments.map((s) => s.name) });
|
|
const summary = await runCapture({
|
|
db,
|
|
runId,
|
|
params,
|
|
emit: (p) => console.log(`[captura] ${p.phase}: ${p.message || ''}`),
|
|
log: (m) => console.log(`[captura] ${m}`)
|
|
});
|
|
|
|
console.log(`[captura] resultado: ${summary.raw} brutos, ${summary.new} novos, ${summary.dup} duplicados (${summary.status})`);
|
|
db.close();
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error(`[captura] erro: ${error.stack || error.message}`);
|
|
process.exit(1);
|
|
});
|