Last active
May 10, 2024 12:52
-
-
Save risaddex/818ac1f2b09702d84c63781b83bb7e2e to your computer and use it in GitHub Desktop.
Exemplo de implementação do import de dados para o SOS-RS usando NodeJS / Webstreams API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Prisma } from '@prisma/client'; | |
import { parse } from 'csv'; | |
import { createReadStream } from 'node:fs'; | |
import { Readable, Transform } from 'node:stream'; | |
import { TransformStream, WritableStream } from 'node:stream/web'; | |
/** | |
* Padrão utilizado | |
* `nome_do_local, endereco, whatsapp, lat, lng, itens_disponiveis, itens_em_falta` | |
*/ | |
// const fileSourceStream = createReadStream(__dirname+'/planilha_porto_alegre - comida.csv'); | |
const sourceStreamHttpRequest = fetch('https://docs.google.com/spreadsheets/d/18hY52i65lIdLE2UsugjnKdnE_ubrBCI6nCR0XQurSBk/gviz/tq?tqx=out:csv&sheet=planilha_porto_alegre') | |
const csvParser = parse({},function(err,data){ | |
if(err) console.error(err); | |
return data | |
}); | |
const transformCsvLineToShelter = new TransformStream({ | |
async transform(chunk,controller){ | |
const [nome_do_local,endereco,whatsapp,lat,lng,_itens_disponiveis,itens_em_falta] = chunk; | |
const shelter: Partial<Prisma.ShelterCreateInput> = { | |
name: nome_do_local, | |
address: endereco, | |
contact: whatsapp, | |
latitude: lat, | |
longitude: lng, | |
verified: false, | |
} | |
const shelterSuppliesByCategory = await detectSupplyCategoryUsingAI(itens_em_falta); | |
console.log("🚀 ~ transform ~ shelterSuppliesByCategory:", shelterSuppliesByCategory) | |
controller.enqueue(shelter); | |
}, | |
}); | |
/** | |
* https://stackoverflow.com/questions/44672942/stream-response-to-file-using-fetch-api-and-fs-createwritestream | |
*/ | |
function responseToReadable(response: Response) { | |
const rs = new Readable(); | |
if (!response.body) { | |
rs.push(null); | |
return rs; | |
} | |
const reader = response.body.getReader(); | |
rs._read = async () => { | |
const result = await reader.read(); | |
if (!result.done) { | |
rs.push(Buffer.from(result.value)); | |
} else { | |
rs.push(null); | |
return; | |
} | |
}; | |
return rs; | |
} | |
export async function parseCsv(){ | |
let sheltersSaved = 0; | |
Readable.toWeb(responseToReadable(await sourceStreamHttpRequest)) | |
.pipeThrough(Transform.toWeb(csvParser)) | |
.pipeThrough(transformCsvLineToShelter) | |
.pipeTo(new WritableStream({ | |
async write(shelter){ | |
console.log(`${++sheltersSaved} processados.`) | |
}, | |
close(){ | |
console.log('Job done'); | |
} | |
})) | |
; | |
} | |
//TODO: integrar com alguma LLM para categorizar com base nas categorias existentes no banco | |
async function detectSupplyCategoryUsingAI(input):Promise<{name:string,categoryName?:string}[]>{ | |
if(typeof input !== 'string'){ | |
return []; | |
} | |
return input.split(',').filter(Boolean).map(item => ({ | |
name:item.trim(), | |
categoryName:'' | |
})); | |
} | |
parseCsv() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment