Guest User

Untitled

a guest
Jun 27th, 2024
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.40 KB | None | 0 0
  1. import {
  2. Index,
  3. Pinecone,
  4. PineconeRecord,
  5. RecordMetadata,
  6. } from "@pinecone-database/pinecone";
  7. import { downloadFromS3 } from "./s3.server";
  8. import { PDFLoader } from "@langchain/community/document_loaders/fs/pdf";
  9. import {
  10. Document,
  11. RecursiveCharacterTextSplitter,
  12. } from "@pinecone-database/doc-splitter";
  13. import { getEmbeddings } from "./embeddings";
  14. import { Vector } from "@pinecone-database/pinecone/dist/pinecone-generated-ts-fetch";
  15. import md5 from "md5";
  16. import { convertToAscii } from "./utils";
  17.  
  18. let pinecone: Pinecone | null = null;
  19. const api = process.env.PINECONE_API_KEY || "";
  20.  
  21. export const getPineconeClient = () => {
  22. if (!pinecone) {
  23. pinecone = new Pinecone({
  24. apiKey: api,
  25. });
  26. }
  27. return pinecone;
  28. };
  29.  
  30. type PDFPage = {
  31. pageContent: string;
  32. metadata: {
  33. loc: { pageNumber: number };
  34. };
  35. };
  36.  
  37. export async function loadS3IntoPinecone(fileKey: string) {
  38. try {
  39. // 1. Obtain the PDF
  40. console.log("Downloading PDF from S3...");
  41. const file_name = await downloadFromS3(fileKey);
  42.  
  43. if (!file_name) {
  44. throw new Error("File not found");
  45. }
  46.  
  47. // 2. Download and read PDF
  48. console.log("Reading PDF...");
  49. const loader = new PDFLoader(file_name as string);
  50. const pages = (await loader.load()) as PDFPage[];
  51.  
  52. // 3. Split and segment the PDF
  53. console.log("Splitting PDF...");
  54. const documents = await Promise.all(pages.map(prepareDocument));
  55.  
  56. // 4. Vectorize and embed individual docs
  57. console.log("Embedding documents...");
  58. const vectors = await Promise.all(documents.flat().map(embedDocument));
  59.  
  60. // 5. Upload to Pinecone
  61. const client = await getPineconeClient();
  62. const pineconeIndex = client.Index("teachtalk");
  63.  
  64. console.log("inserting vectors into pinecone");
  65.  
  66.  
  67. const namespace = convertToAscii(fileKey);
  68.  
  69. // Push vectors to Pinecone index
  70. await pineconeIndex.upsert({
  71. vectors: vectors as PineconeRecord<RecordMetadata>[],
  72. namespace: namespace,
  73. });
  74.  
  75. console.log("Upload complete");
  76. } catch (error) {
  77. console.error("Error in loadS3IntoPinecone", error);
  78. }
  79. }
  80.  
  81. async function embedDocument(doc: Document): Promise<Vector> {
  82. try {
  83. const embeddings = await getEmbeddings(doc.pageContent);
  84. const hash = md5(doc.pageContent);
  85.  
  86. return {
  87. id: hash,
  88. values: embeddings,
  89. metadata: {
  90. text: doc.metadata.text,
  91. pageNumber: doc.metadata.pageNumber,
  92. },
  93. } as PineconeRecord;
  94. } catch (error) {
  95. console.error("Error in embedding document", error);
  96. throw error; // Ensure errors are propagated
  97. }
  98. }
  99.  
  100. // Converts to bytes then to a string
  101. export const truncateStringByBytes = (str: string, bytes: number) => {
  102. const enc = new TextEncoder();
  103. return new TextDecoder("utf-8").decode(enc.encode(str).slice(0, bytes));
  104. };
  105.  
  106. async function prepareDocument(page: PDFPage): Promise<Document[]> {
  107. let { pageContent, metadata } = page;
  108.  
  109. // Replace empty line with space
  110. pageContent = pageContent.replace(/\n/g, "");
  111.  
  112. // Split the docs
  113. const splitter = new RecursiveCharacterTextSplitter();
  114. const docs = await splitter.splitDocuments([
  115. new Document({
  116. pageContent,
  117. metadata: {
  118. pageNumber: metadata.loc.pageNumber,
  119. text: truncateStringByBytes(pageContent, 36000),
  120. },
  121. }),
  122. ]);
  123.  
  124. return docs;
  125. }
  126.  
Advertisement
Add Comment
Please, Sign In to add comment