opensentinel 3.1.1 → 3.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +126 -83
- package/dist/agent-manager-7N7REQZQ.js +39 -0
- package/dist/agent-processor-I23VWQY3.js +280 -0
- package/dist/agent-processor-I23VWQY3.js.map +1 -0
- package/dist/agent-types-2T4PXLFQ.js +12 -0
- package/dist/alerting-4I37GG4U.js +699 -0
- package/dist/alerting-4I37GG4U.js.map +1 -0
- package/dist/analysis-agent-JWN2GXYE.js +288 -0
- package/dist/analysis-agent-JWN2GXYE.js.map +1 -0
- package/dist/{archiver-AVNBYCKQ.js → archiver-XLRIIXPY.js} +86 -17
- package/dist/archiver-XLRIIXPY.js.map +1 -0
- package/dist/{audit-logger-OBPR7CRO.js → audit-logger-AU3TMWKI.js} +6 -5
- package/dist/{auth-UOX5K2BE.js → auth-PH5IHISW.js} +2 -2
- package/dist/{autonomy-ZXDBDQUJ.js → autonomy-N7W5XPLX.js} +4 -3
- package/dist/autonomy-N7W5XPLX.js.map +1 -0
- package/dist/{aws-s3-Q4LLZZPD.js → aws-s3-QZMURYXB.js} +2 -2
- package/dist/{backup-restore-PZ7CYYB7.js → backup-restore-72OQTZO3.js} +2 -2
- package/dist/{blocks-R3PODY47.js → blocks-YOWOESDD.js} +4 -4
- package/dist/bot-MU2TJQ3Y.js +46 -0
- package/dist/brain-SLA474EU.js +65 -0
- package/dist/{camera-monitor-M5CYKUU4.js → camera-monitor-LHTUWHEL.js} +2 -2
- package/dist/{charts-V7ARZNKF.js → charts-FJ32GQK7.js} +2 -2
- package/dist/{chunk-6PMVAAA7.js → chunk-2RGPWU77.js} +3 -3
- package/dist/{chunk-TVEWKIK3.js → chunk-2WTKTG2C.js} +2 -2
- package/dist/{chunk-MXAPLSJ5.js → chunk-45YXODSB.js} +2 -2
- package/dist/{chunk-SJSUSJ47.js → chunk-4YJRBMMA.js} +2 -2
- package/dist/chunk-643M3AP5.js +564 -0
- package/dist/chunk-643M3AP5.js.map +1 -0
- package/dist/{chunk-766ASQWE.js → chunk-6JY4HNUH.js} +2413 -2368
- package/dist/chunk-6JY4HNUH.js.map +1 -0
- package/dist/chunk-6LTLIYAQ.js +194 -0
- package/dist/chunk-6LTLIYAQ.js.map +1 -0
- package/dist/chunk-6UZPE35A.js +724 -0
- package/dist/chunk-6UZPE35A.js.map +1 -0
- package/dist/chunk-6W6PTJFT.js +181 -0
- package/dist/chunk-6W6PTJFT.js.map +1 -0
- package/dist/chunk-7MZN73J2.js +162 -0
- package/dist/chunk-7MZN73J2.js.map +1 -0
- package/dist/{chunk-SVAPX2XN.js → chunk-A24GPVLY.js} +9 -7
- package/dist/{chunk-SVAPX2XN.js.map → chunk-A24GPVLY.js.map} +1 -1
- package/dist/chunk-AD6YEH6U.js +3408 -0
- package/dist/chunk-AD6YEH6U.js.map +1 -0
- package/dist/chunk-ADTDYJO7.js +265 -0
- package/dist/chunk-ADTDYJO7.js.map +1 -0
- package/dist/{chunk-WRAKK6K6.js → chunk-AR34B6XR.js} +5 -3
- package/dist/{chunk-WRAKK6K6.js.map → chunk-AR34B6XR.js.map} +1 -1
- package/dist/chunk-BMOUYXLX.js +418 -0
- package/dist/chunk-BMOUYXLX.js.map +1 -0
- package/dist/chunk-C6PELIHS.js +60 -0
- package/dist/chunk-C6PELIHS.js.map +1 -0
- package/dist/{chunk-MQJ2ECQT.js → chunk-CUPEENUY.js} +3 -3
- package/dist/{chunk-RZ4YESBG.js → chunk-DOYGMNMK.js} +1 -1
- package/dist/chunk-DOYGMNMK.js.map +1 -0
- package/dist/chunk-FFV2SXFD.js +380 -0
- package/dist/chunk-FFV2SXFD.js.map +1 -0
- package/dist/{chunk-EVE7MIIY.js → chunk-GUKKW7JI.js} +15 -16
- package/dist/chunk-GUKKW7JI.js.map +1 -0
- package/dist/{chunk-66OJ3WB4.js → chunk-H3BOLSTS.js} +2 -2
- package/dist/chunk-HKOPRRDJ.js +1021 -0
- package/dist/chunk-HKOPRRDJ.js.map +1 -0
- package/dist/{chunk-BXZ6EA52.js → chunk-HTF2GIQC.js} +57 -3
- package/dist/chunk-HTF2GIQC.js.map +1 -0
- package/dist/{chunk-TYAGMJNV.js → chunk-JOA5A3G3.js} +5 -5
- package/dist/{chunk-OCVQGBJK.js → chunk-KABG5PG3.js} +6 -4
- package/dist/{chunk-OCVQGBJK.js.map → chunk-KABG5PG3.js.map} +1 -1
- package/dist/{chunk-VEHFVBLI.js → chunk-KT7NLIXP.js} +2 -2
- package/dist/chunk-LFDXEYYB.js +150 -0
- package/dist/chunk-LFDXEYYB.js.map +1 -0
- package/dist/{chunk-I6BDYQIG.js → chunk-M7YLQHFP.js} +6 -6
- package/dist/chunk-M7YLQHFP.js.map +1 -0
- package/dist/{chunk-AYUKPTSM.js → chunk-MFK34XSY.js} +96 -218
- package/dist/chunk-MFK34XSY.js.map +1 -0
- package/dist/chunk-MIC5IBQF.js +386 -0
- package/dist/chunk-MIC5IBQF.js.map +1 -0
- package/dist/{chunk-4UOE5TUZ.js → chunk-NMSHVO5O.js} +4 -4
- package/dist/{chunk-XKYRH4FM.js → chunk-NYVBXUGD.js} +13 -32
- package/dist/chunk-NYVBXUGD.js.map +1 -0
- package/dist/chunk-ODCFS5WD.js +463 -0
- package/dist/chunk-ODCFS5WD.js.map +1 -0
- package/dist/{chunk-ZLZKF2PM.js → chunk-PUNIMPMY.js} +32 -2
- package/dist/chunk-PUNIMPMY.js.map +1 -0
- package/dist/chunk-S4NJJS5C.js +37 -0
- package/dist/chunk-S4NJJS5C.js.map +1 -0
- package/dist/{chunk-NHMBTUMW.js → chunk-TAAZB5KN.js} +2 -2
- package/dist/{chunk-BRBWNV65.js → chunk-U2X2J3FI.js} +3 -3
- package/dist/chunk-U2X2J3FI.js.map +1 -0
- package/dist/{chunk-PLDDJCW6.js → chunk-UP2VWCW5.js} +1 -12
- package/dist/{chunk-4GLYY4NN.js → chunk-UWUIJTT4.js} +8 -2
- package/dist/chunk-UWUIJTT4.js.map +1 -0
- package/dist/{chunk-SPPMCAKG.js → chunk-VKMFUIVA.js} +2 -2
- package/dist/chunk-VKMFUIVA.js.map +1 -0
- package/dist/chunk-WZAH34TG.js +129 -0
- package/dist/chunk-WZAH34TG.js.map +1 -0
- package/dist/{chunk-H5RQOFO2.js → chunk-X6Q3K3L2.js} +6 -6
- package/dist/chunk-X6Q3K3L2.js.map +1 -0
- package/dist/chunk-XTX7EK43.js +134 -0
- package/dist/chunk-XTX7EK43.js.map +1 -0
- package/dist/chunk-ZIYTHUM5.js +457 -0
- package/dist/chunk-ZIYTHUM5.js.map +1 -0
- package/dist/chunker-K6WTR62A.js +12 -0
- package/dist/cli.js +1 -1
- package/dist/{client-ZQSFPMOB.js → client-FOIYPOZQ.js} +5 -6
- package/dist/{clipboard-manager-TEO2GEDN.js → clipboard-manager-4SBNESGZ.js} +2 -2
- package/dist/coding-agent-DESSU3AC.js +233 -0
- package/dist/coding-agent-DESSU3AC.js.map +1 -0
- package/dist/commands/setup.js +1 -1
- package/dist/commands/start.js +2 -2
- package/dist/commands/status.js +1 -1
- package/dist/commands/stop.js +1 -1
- package/dist/commands/utils.js +1 -1
- package/dist/cost-tracker-EMOIOYH7.js +11 -0
- package/dist/{cron-explain-HHQKPD3M.js → cron-explain-UOOOYWZZ.js} +2 -2
- package/dist/{crypto-4AP47IKC.js → crypto-2VG3RJR2.js} +2 -2
- package/dist/{databases-37X4CI2Y.js → databases-XDPMG5AV.js} +4 -4
- package/dist/db-LRIOKQBO.js +77 -0
- package/dist/discord-NKR3X4AV.js +80 -0
- package/dist/documents-EYIYLZK2.js +184 -0
- package/dist/documents-EYIYLZK2.js.map +1 -0
- package/dist/docx-parser-EXL4TN5E.js +16 -0
- package/dist/{email-K7LO2IPB.js → email-EAQNULVD.js} +33 -25
- package/dist/{email-K7LO2IPB.js.map → email-EAQNULVD.js.map} +1 -1
- package/dist/{enhanced-retrieval-DNLLEM4Z.js → enhanced-retrieval-OGHT6TS5.js} +11 -8
- package/dist/{enhanced-retrieval-DNLLEM4Z.js.map → enhanced-retrieval-OGHT6TS5.js.map} +1 -1
- package/dist/enrichment-pipeline-CMUVBDC7.js +14 -0
- package/dist/{entity-resolution-Y3IUWEAT.js → entity-resolution-4X4JU43O.js} +6 -5
- package/dist/env-CHOFICED.js +12 -0
- package/dist/error-tracker-SVQSDQDW.js +32 -0
- package/dist/finnhub-X7ZMQSXF.js +178 -0
- package/dist/finnhub-X7ZMQSXF.js.map +1 -0
- package/dist/fred-TMUF3J2V.js +203 -0
- package/dist/fred-TMUF3J2V.js.map +1 -0
- package/dist/github-KGNILDWJ.js +833 -0
- package/dist/github-KGNILDWJ.js.map +1 -0
- package/dist/{google-workspace-DKWUVNGC.js → google-workspace-TSZPZK5G.js} +2 -2
- package/dist/{hash-tool-ULQYD7B5.js → hash-tool-ENAB5LWH.js} +2 -2
- package/dist/{heartbeat-monitor-GCISLXI3.js → heartbeat-monitor-KRDYTDBF.js} +2 -2
- package/dist/hooks-N4MIFBVM.js +14 -0
- package/dist/{image-generation-OSU7FP6F.js → image-generation-MDE6AVQO.js} +2 -2
- package/dist/imessage-V2XNDDHT.js +43 -0
- package/dist/inbox-summarizer-DKKRYXDR.js +55 -0
- package/dist/{incident-response-C5J7Q6DT.js → incident-response-ZTIKUWEO.js} +8 -6
- package/dist/{incident-response-C5J7Q6DT.js.map → incident-response-ZTIKUWEO.js.map} +1 -1
- package/dist/{inventory-manager-352OHXWD.js → inventory-manager-C67BSZM6.js} +2 -2
- package/dist/{jira-GSGDBMIG.js → jira-PAGZWUBJ.js} +2 -2
- package/dist/{json-tool-QE2SYHEG.js → json-tool-4FK5RNER.js} +2 -2
- package/dist/{key-rotation-DPHU4ZTB.js → key-rotation-WCC5FOYS.js} +2 -2
- package/dist/knowledge-base-J7PJ7MZ3.js +46 -0
- package/dist/lib.d.ts +73 -1
- package/dist/lib.js +86 -76
- package/dist/lib.js.map +1 -1
- package/dist/{mailchimp-KKNF6QJ7.js → mailchimp-ZFYDC44J.js} +2 -2
- package/dist/{matrix-QVHG76I7.js → matrix-XHTR53VQ.js} +29 -21
- package/dist/{matrix-QVHG76I7.js.map → matrix-XHTR53VQ.js.map} +1 -1
- package/dist/{mcp-3JI6W7ZE.js → mcp-3C2TN67D.js} +3 -3
- package/dist/metrics-VJDWQWU7.js +25 -0
- package/dist/{microsoft365-UCBKJHNX.js → microsoft365-6G2IJMWC.js} +2 -2
- package/dist/multi-user-S56GUD6L.js +411 -0
- package/dist/multi-user-S56GUD6L.js.map +1 -0
- package/dist/{ocr-AC7NPX33.js → ocr-LGUIPKVZ.js} +6 -4
- package/dist/{ollama-BOAMSPLJ.js → ollama-J7CU45WT.js} +2 -2
- package/dist/osint-agent-RL5XPBRQ.js +189 -0
- package/dist/osint-agent-RL5XPBRQ.js.map +1 -0
- package/dist/{pages-MI523RB7.js → pages-XDE7JRCA.js} +5 -5
- package/dist/{pair-JDFTERIK.js → pair-YZJFQUU5.js} +2 -2
- package/dist/{pairing-IFQYCPNS.js → pairing-77N47RAT.js} +2 -2
- package/dist/{pdf-ALQVOEJR.js → pdf-67HGXCFJ.js} +3 -3
- package/dist/pdf-parser-YLMTTYHL.js +14 -0
- package/dist/{presentations-DSV5IHG5.js → presentations-HXTAMGHT.js} +3 -3
- package/dist/presentations-HXTAMGHT.js.map +1 -0
- package/dist/{prometheus-JNT2BD4L.js → prometheus-YETCZO4I.js} +2 -2
- package/dist/{providers-J4LYPHDR.js → providers-H6YIC3MG.js} +6 -4
- package/dist/{qr-code-WIX4PB4U.js → qr-code-6WZJHRKL.js} +2 -2
- package/dist/{quickbooks-XB4NII2S.js → quickbooks-N675W7IK.js} +2 -2
- package/dist/{regex-tool-W4ABRKGK.js → regex-tool-6Q63LQ7B.js} +2 -2
- package/dist/regex-tool-6Q63LQ7B.js.map +1 -0
- package/dist/research-agent-WCRSY3UZ.js +168 -0
- package/dist/research-agent-WCRSY3UZ.js.map +1 -0
- package/dist/risk-engine-YKCPT5D5.js +10 -0
- package/dist/risk-engine-YKCPT5D5.js.map +1 -0
- package/dist/scheduler-CA5UNHZV.js +73 -0
- package/dist/scheduler-CA5UNHZV.js.map +1 -0
- package/dist/schema-ALJ67YVG.js +72 -0
- package/dist/schema-ALJ67YVG.js.map +1 -0
- package/dist/{search-BCLBO5E3.js → search-GMLKBHSW.js} +4 -4
- package/dist/search-GMLKBHSW.js.map +1 -0
- package/dist/{sendgrid-RNXCAFKM.js → sendgrid-QGJIVPWV.js} +2 -2
- package/dist/{shopify-NCXYJB4R.js → shopify-ON2PAU27.js} +2 -2
- package/dist/signal-X7IQJGRQ.js +43 -0
- package/dist/signal-X7IQJGRQ.js.map +1 -0
- package/dist/slack-P2LFUJUQ.js +85 -0
- package/dist/slack-P2LFUJUQ.js.map +1 -0
- package/dist/{sms-M3JIOTCW.js → sms-4VME2HUL.js} +4 -4
- package/dist/sms-4VME2HUL.js.map +1 -0
- package/dist/{src-VYUE6LRA.js → src-S5KX4YEV.js} +179 -48
- package/dist/src-S5KX4YEV.js.map +1 -0
- package/dist/{stocks-XXWBPOCU.js → stocks-4M4HZWZS.js} +2 -2
- package/dist/stocks-4M4HZWZS.js.map +1 -0
- package/dist/text-extractor-OAUBAW5P.js +12 -0
- package/dist/text-extractor-OAUBAW5P.js.map +1 -0
- package/dist/{text-transform-6SGUA5Z4.js → text-transform-HCLCUDFZ.js} +2 -2
- package/dist/text-transform-HCLCUDFZ.js.map +1 -0
- package/dist/tools-FGPN522P.js +46 -0
- package/dist/tools-FGPN522P.js.map +1 -0
- package/dist/{tunnel-IWMXUML4.js → tunnel-XOUVVRAK.js} +4 -2
- package/dist/tunnel-XOUVVRAK.js.map +1 -0
- package/dist/{twilio-53GEW5JT.js → twilio-3L7DUNYQ.js} +2 -2
- package/dist/{unit-converter-ZYXMEZOE.js → unit-converter-LYPAHU64.js} +2 -2
- package/dist/unit-converter-LYPAHU64.js.map +1 -0
- package/dist/whatsapp-KRPQ4YUX.js +43 -0
- package/dist/whatsapp-KRPQ4YUX.js.map +1 -0
- package/dist/{word-document-7B6SJMAY.js → word-document-D6N2C47N.js} +4 -4
- package/dist/word-document-D6N2C47N.js.map +1 -0
- package/dist/workflow-store-ZYAYE5P6.js +373 -0
- package/dist/workflow-store-ZYAYE5P6.js.map +1 -0
- package/dist/writing-agent-VDGLNOGO.js +243 -0
- package/dist/writing-agent-VDGLNOGO.js.map +1 -0
- package/dist/{xero-QYO66D45.js → xero-UHAHVYSD.js} +2 -2
- package/dist/{zapier-webhook-TBZ5YF2A.js → zapier-webhook-NIELLTXR.js} +2 -2
- package/package.json +11 -1
- package/dist/archiver-AVNBYCKQ.js.map +0 -1
- package/dist/autonomy-ZXDBDQUJ.js.map +0 -1
- package/dist/bot-QRARP4UN.js +0 -36
- package/dist/brain-7XLLM3KC.js +0 -56
- package/dist/chunk-4GLYY4NN.js.map +0 -1
- package/dist/chunk-766ASQWE.js.map +0 -1
- package/dist/chunk-AYUKPTSM.js.map +0 -1
- package/dist/chunk-BRBWNV65.js.map +0 -1
- package/dist/chunk-BXZ6EA52.js.map +0 -1
- package/dist/chunk-EVE7MIIY.js.map +0 -1
- package/dist/chunk-H5RQOFO2.js.map +0 -1
- package/dist/chunk-I6BDYQIG.js.map +0 -1
- package/dist/chunk-IZJMVV7O.js +0 -347
- package/dist/chunk-IZJMVV7O.js.map +0 -1
- package/dist/chunk-O7IH7JTI.js +0 -1898
- package/dist/chunk-O7IH7JTI.js.map +0 -1
- package/dist/chunk-RZ4YESBG.js.map +0 -1
- package/dist/chunk-SPPMCAKG.js.map +0 -1
- package/dist/chunk-VRD5CYRL.js +0 -1568
- package/dist/chunk-VRD5CYRL.js.map +0 -1
- package/dist/chunk-XKYRH4FM.js.map +0 -1
- package/dist/chunk-ZLZKF2PM.js.map +0 -1
- package/dist/discord-B3HUPGQ6.js +0 -70
- package/dist/dist-UISMLMFN.js +0 -21847
- package/dist/dist-UISMLMFN.js.map +0 -1
- package/dist/enrichment-pipeline-MNHNW65K.js +0 -13
- package/dist/env-IWXUVTCB.js +0 -12
- package/dist/imessage-NGA2XF2V.js +0 -35
- package/dist/inbox-summarizer-NRI4S7IF.js +0 -47
- package/dist/presentations-DSV5IHG5.js.map +0 -1
- package/dist/scheduler-VK4WFERV.js +0 -63
- package/dist/signal-6CGDFYL2.js +0 -35
- package/dist/slack-IZQWIKOH.js +0 -75
- package/dist/src-VYUE6LRA.js.map +0 -1
- package/dist/tools-2RLEI2N6.js +0 -38
- package/dist/tunnel-IWMXUML4.js.map +0 -1
- package/dist/whatsapp-LFX6YKCM.js +0 -35
- package/dist/word-document-7B6SJMAY.js.map +0 -1
- /package/dist/{audit-logger-OBPR7CRO.js.map → agent-manager-7N7REQZQ.js.map} +0 -0
- /package/dist/{auth-UOX5K2BE.js.map → agent-types-2T4PXLFQ.js.map} +0 -0
- /package/dist/{backup-restore-PZ7CYYB7.js.map → audit-logger-AU3TMWKI.js.map} +0 -0
- /package/dist/{blocks-R3PODY47.js.map → auth-PH5IHISW.js.map} +0 -0
- /package/dist/{aws-s3-Q4LLZZPD.js.map → aws-s3-QZMURYXB.js.map} +0 -0
- /package/dist/{bot-QRARP4UN.js.map → backup-restore-72OQTZO3.js.map} +0 -0
- /package/dist/{brain-7XLLM3KC.js.map → blocks-YOWOESDD.js.map} +0 -0
- /package/dist/{chunk-PLDDJCW6.js.map → bot-MU2TJQ3Y.js.map} +0 -0
- /package/dist/{client-ZQSFPMOB.js.map → brain-SLA474EU.js.map} +0 -0
- /package/dist/{camera-monitor-M5CYKUU4.js.map → camera-monitor-LHTUWHEL.js.map} +0 -0
- /package/dist/{charts-V7ARZNKF.js.map → charts-FJ32GQK7.js.map} +0 -0
- /package/dist/{chunk-6PMVAAA7.js.map → chunk-2RGPWU77.js.map} +0 -0
- /package/dist/{chunk-TVEWKIK3.js.map → chunk-2WTKTG2C.js.map} +0 -0
- /package/dist/{chunk-MXAPLSJ5.js.map → chunk-45YXODSB.js.map} +0 -0
- /package/dist/{chunk-SJSUSJ47.js.map → chunk-4YJRBMMA.js.map} +0 -0
- /package/dist/{chunk-MQJ2ECQT.js.map → chunk-CUPEENUY.js.map} +0 -0
- /package/dist/{chunk-66OJ3WB4.js.map → chunk-H3BOLSTS.js.map} +0 -0
- /package/dist/{chunk-TYAGMJNV.js.map → chunk-JOA5A3G3.js.map} +0 -0
- /package/dist/{chunk-VEHFVBLI.js.map → chunk-KT7NLIXP.js.map} +0 -0
- /package/dist/{chunk-4UOE5TUZ.js.map → chunk-NMSHVO5O.js.map} +0 -0
- /package/dist/{chunk-NHMBTUMW.js.map → chunk-TAAZB5KN.js.map} +0 -0
- /package/dist/{clipboard-manager-TEO2GEDN.js.map → chunk-UP2VWCW5.js.map} +0 -0
- /package/dist/{cron-explain-HHQKPD3M.js.map → chunker-K6WTR62A.js.map} +0 -0
- /package/dist/{crypto-4AP47IKC.js.map → client-FOIYPOZQ.js.map} +0 -0
- /package/dist/{databases-37X4CI2Y.js.map → clipboard-manager-4SBNESGZ.js.map} +0 -0
- /package/dist/{discord-B3HUPGQ6.js.map → cost-tracker-EMOIOYH7.js.map} +0 -0
- /package/dist/{enrichment-pipeline-MNHNW65K.js.map → cron-explain-UOOOYWZZ.js.map} +0 -0
- /package/dist/{entity-resolution-Y3IUWEAT.js.map → crypto-2VG3RJR2.js.map} +0 -0
- /package/dist/{env-IWXUVTCB.js.map → databases-XDPMG5AV.js.map} +0 -0
- /package/dist/{hash-tool-ULQYD7B5.js.map → db-LRIOKQBO.js.map} +0 -0
- /package/dist/{heartbeat-monitor-GCISLXI3.js.map → discord-NKR3X4AV.js.map} +0 -0
- /package/dist/{imessage-NGA2XF2V.js.map → docx-parser-EXL4TN5E.js.map} +0 -0
- /package/dist/{inbox-summarizer-NRI4S7IF.js.map → enrichment-pipeline-CMUVBDC7.js.map} +0 -0
- /package/dist/{inventory-manager-352OHXWD.js.map → entity-resolution-4X4JU43O.js.map} +0 -0
- /package/dist/{json-tool-QE2SYHEG.js.map → env-CHOFICED.js.map} +0 -0
- /package/dist/{key-rotation-DPHU4ZTB.js.map → error-tracker-SVQSDQDW.js.map} +0 -0
- /package/dist/{google-workspace-DKWUVNGC.js.map → google-workspace-TSZPZK5G.js.map} +0 -0
- /package/dist/{mcp-3JI6W7ZE.js.map → hash-tool-ENAB5LWH.js.map} +0 -0
- /package/dist/{ocr-AC7NPX33.js.map → heartbeat-monitor-KRDYTDBF.js.map} +0 -0
- /package/dist/{ollama-BOAMSPLJ.js.map → hooks-N4MIFBVM.js.map} +0 -0
- /package/dist/{image-generation-OSU7FP6F.js.map → image-generation-MDE6AVQO.js.map} +0 -0
- /package/dist/{pages-MI523RB7.js.map → imessage-V2XNDDHT.js.map} +0 -0
- /package/dist/{pairing-IFQYCPNS.js.map → inbox-summarizer-DKKRYXDR.js.map} +0 -0
- /package/dist/{pdf-ALQVOEJR.js.map → inventory-manager-C67BSZM6.js.map} +0 -0
- /package/dist/{jira-GSGDBMIG.js.map → jira-PAGZWUBJ.js.map} +0 -0
- /package/dist/{prometheus-JNT2BD4L.js.map → json-tool-4FK5RNER.js.map} +0 -0
- /package/dist/{providers-J4LYPHDR.js.map → key-rotation-WCC5FOYS.js.map} +0 -0
- /package/dist/{qr-code-WIX4PB4U.js.map → knowledge-base-J7PJ7MZ3.js.map} +0 -0
- /package/dist/{mailchimp-KKNF6QJ7.js.map → mailchimp-ZFYDC44J.js.map} +0 -0
- /package/dist/{regex-tool-W4ABRKGK.js.map → mcp-3C2TN67D.js.map} +0 -0
- /package/dist/{scheduler-VK4WFERV.js.map → metrics-VJDWQWU7.js.map} +0 -0
- /package/dist/{microsoft365-UCBKJHNX.js.map → microsoft365-6G2IJMWC.js.map} +0 -0
- /package/dist/{search-BCLBO5E3.js.map → ocr-LGUIPKVZ.js.map} +0 -0
- /package/dist/{signal-6CGDFYL2.js.map → ollama-J7CU45WT.js.map} +0 -0
- /package/dist/{slack-IZQWIKOH.js.map → pages-XDE7JRCA.js.map} +0 -0
- /package/dist/{pair-JDFTERIK.js.map → pair-YZJFQUU5.js.map} +0 -0
- /package/dist/{sms-M3JIOTCW.js.map → pairing-77N47RAT.js.map} +0 -0
- /package/dist/{stocks-XXWBPOCU.js.map → pdf-67HGXCFJ.js.map} +0 -0
- /package/dist/{text-transform-6SGUA5Z4.js.map → pdf-parser-YLMTTYHL.js.map} +0 -0
- /package/dist/{tools-2RLEI2N6.js.map → prometheus-YETCZO4I.js.map} +0 -0
- /package/dist/{unit-converter-ZYXMEZOE.js.map → providers-H6YIC3MG.js.map} +0 -0
- /package/dist/{whatsapp-LFX6YKCM.js.map → qr-code-6WZJHRKL.js.map} +0 -0
- /package/dist/{quickbooks-XB4NII2S.js.map → quickbooks-N675W7IK.js.map} +0 -0
- /package/dist/{sendgrid-RNXCAFKM.js.map → sendgrid-QGJIVPWV.js.map} +0 -0
- /package/dist/{shopify-NCXYJB4R.js.map → shopify-ON2PAU27.js.map} +0 -0
- /package/dist/{twilio-53GEW5JT.js.map → twilio-3L7DUNYQ.js.map} +0 -0
- /package/dist/{xero-QYO66D45.js.map → xero-UHAHVYSD.js.map} +0 -0
- /package/dist/{zapier-webhook-TBZ5YF2A.js.map → zapier-webhook-NIELLTXR.js.map} +0 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parsePDF
|
|
3
|
+
} from "./chunk-XTX7EK43.js";
|
|
4
|
+
import {
|
|
5
|
+
parseDOCX
|
|
6
|
+
} from "./chunk-6W6PTJFT.js";
|
|
7
|
+
import {
|
|
8
|
+
extractText,
|
|
9
|
+
isSupportedTextFormat
|
|
10
|
+
} from "./chunk-MIC5IBQF.js";
|
|
11
|
+
import {
|
|
12
|
+
chunkText
|
|
13
|
+
} from "./chunk-ZIYTHUM5.js";
|
|
14
|
+
import {
|
|
15
|
+
db
|
|
16
|
+
} from "./chunk-S4NJJS5C.js";
|
|
17
|
+
import {
|
|
18
|
+
env
|
|
19
|
+
} from "./chunk-PUNIMPMY.js";
|
|
20
|
+
import {
|
|
21
|
+
documentChunks,
|
|
22
|
+
documents
|
|
23
|
+
} from "./chunk-NYVBXUGD.js";
|
|
24
|
+
|
|
25
|
+
// src/integrations/documents/knowledge-base.ts
|
|
26
|
+
import { sql, eq, and, desc, inArray } from "drizzle-orm";
|
|
27
|
+
import OpenAI from "openai";
|
|
28
|
+
import * as fs from "fs/promises";
|
|
29
|
+
import * as path from "path";
|
|
30
|
+
import { nanoid } from "nanoid";
|
|
31
|
+
var openai = new OpenAI({ apiKey: env.OPENAI_API_KEY });
|
|
32
|
+
async function generateEmbedding(text) {
|
|
33
|
+
const response = await openai.embeddings.create({
|
|
34
|
+
model: "text-embedding-3-small",
|
|
35
|
+
input: text
|
|
36
|
+
});
|
|
37
|
+
return response.data[0].embedding;
|
|
38
|
+
}
|
|
39
|
+
async function generateEmbeddings(texts) {
|
|
40
|
+
if (texts.length === 0) return [];
|
|
41
|
+
const batchSize = 2048;
|
|
42
|
+
const allEmbeddings = [];
|
|
43
|
+
for (let i = 0; i < texts.length; i += batchSize) {
|
|
44
|
+
const batch = texts.slice(i, i + batchSize);
|
|
45
|
+
const response = await openai.embeddings.create({
|
|
46
|
+
model: "text-embedding-3-small",
|
|
47
|
+
input: batch
|
|
48
|
+
});
|
|
49
|
+
allEmbeddings.push(...response.data.map((d) => d.embedding));
|
|
50
|
+
}
|
|
51
|
+
return allEmbeddings;
|
|
52
|
+
}
|
|
53
|
+
async function ingestDocument(input, options = {}) {
|
|
54
|
+
let buffer;
|
|
55
|
+
let filename;
|
|
56
|
+
let mimeType;
|
|
57
|
+
if (typeof input === "string") {
|
|
58
|
+
const absolutePath = path.isAbsolute(input) ? input : path.resolve(input);
|
|
59
|
+
buffer = await fs.readFile(absolutePath);
|
|
60
|
+
filename = path.basename(input);
|
|
61
|
+
mimeType = getMimeType(filename);
|
|
62
|
+
} else {
|
|
63
|
+
buffer = input;
|
|
64
|
+
filename = options.name;
|
|
65
|
+
mimeType = options.metadata?.customFields?.mimeType;
|
|
66
|
+
}
|
|
67
|
+
const documentName = options.name || filename || `document-${nanoid(8)}`;
|
|
68
|
+
const [doc] = await db.insert(documents).values({
|
|
69
|
+
name: documentName,
|
|
70
|
+
filename,
|
|
71
|
+
mimeType,
|
|
72
|
+
fileSize: buffer.length,
|
|
73
|
+
source: options.source || "upload",
|
|
74
|
+
sourceUrl: options.sourceUrl,
|
|
75
|
+
metadata: options.metadata,
|
|
76
|
+
status: "processing",
|
|
77
|
+
userId: options.userId
|
|
78
|
+
}).returning();
|
|
79
|
+
try {
|
|
80
|
+
let text;
|
|
81
|
+
let extractedMetadata = {};
|
|
82
|
+
const ext = filename ? path.extname(filename).toLowerCase().slice(1) : "";
|
|
83
|
+
if (mimeType === "application/pdf" || ext === "pdf") {
|
|
84
|
+
const result = await parsePDF(buffer);
|
|
85
|
+
text = result.text;
|
|
86
|
+
extractedMetadata = {
|
|
87
|
+
title: result.metadata.title,
|
|
88
|
+
author: result.metadata.author,
|
|
89
|
+
pageCount: result.pageCount
|
|
90
|
+
};
|
|
91
|
+
} else if (mimeType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document" || ext === "docx") {
|
|
92
|
+
const result = await parseDOCX(buffer);
|
|
93
|
+
text = result.text;
|
|
94
|
+
extractedMetadata = {
|
|
95
|
+
wordCount: result.metadata.wordCount
|
|
96
|
+
};
|
|
97
|
+
} else if (isSupportedTextFormat(ext)) {
|
|
98
|
+
const result = await extractText(buffer, { format: ext });
|
|
99
|
+
text = result.text;
|
|
100
|
+
extractedMetadata = {
|
|
101
|
+
wordCount: result.metadata.wordCount
|
|
102
|
+
};
|
|
103
|
+
} else {
|
|
104
|
+
text = buffer.toString("utf-8");
|
|
105
|
+
extractedMetadata = {
|
|
106
|
+
wordCount: text.split(/\s+/).length
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const chunks = chunkText(text, options.chunkOptions);
|
|
110
|
+
if (chunks.length === 0) {
|
|
111
|
+
throw new Error("Document produced no chunks - it may be empty");
|
|
112
|
+
}
|
|
113
|
+
let embeddings = [];
|
|
114
|
+
if (!options.skipEmbeddings) {
|
|
115
|
+
embeddings = await generateEmbeddings(chunks.map((c) => c.content));
|
|
116
|
+
}
|
|
117
|
+
const chunkRecords = chunks.map((chunk, idx) => ({
|
|
118
|
+
documentId: doc.id,
|
|
119
|
+
chunkIndex: chunk.index,
|
|
120
|
+
content: chunk.content,
|
|
121
|
+
embedding: options.skipEmbeddings ? void 0 : embeddings[idx],
|
|
122
|
+
tokenCount: chunk.tokenEstimate,
|
|
123
|
+
metadata: {
|
|
124
|
+
sectionHeader: chunk.metadata.sectionHeader,
|
|
125
|
+
paragraphNumber: chunk.metadata.paragraphNumber,
|
|
126
|
+
startOffset: chunk.startOffset,
|
|
127
|
+
endOffset: chunk.endOffset
|
|
128
|
+
}
|
|
129
|
+
}));
|
|
130
|
+
const batchSize = 100;
|
|
131
|
+
for (let i = 0; i < chunkRecords.length; i += batchSize) {
|
|
132
|
+
const batch = chunkRecords.slice(i, i + batchSize);
|
|
133
|
+
await db.insert(documentChunks).values(batch);
|
|
134
|
+
}
|
|
135
|
+
const totalTokens = chunks.reduce((sum, c) => sum + c.tokenEstimate, 0);
|
|
136
|
+
const [updated] = await db.update(documents).set({
|
|
137
|
+
status: "completed",
|
|
138
|
+
chunkCount: chunks.length,
|
|
139
|
+
totalTokens,
|
|
140
|
+
metadata: {
|
|
141
|
+
...extractedMetadata,
|
|
142
|
+
...options.metadata
|
|
143
|
+
},
|
|
144
|
+
processedAt: /* @__PURE__ */ new Date(),
|
|
145
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
146
|
+
}).where(eq(documents.id, doc.id)).returning();
|
|
147
|
+
return mapDocumentToInfo(updated);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
150
|
+
await db.update(documents).set({
|
|
151
|
+
status: "failed",
|
|
152
|
+
errorMessage,
|
|
153
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
154
|
+
}).where(eq(documents.id, doc.id));
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function ingestDocuments(inputs) {
|
|
159
|
+
const results = [];
|
|
160
|
+
for (const { input, options } of inputs) {
|
|
161
|
+
try {
|
|
162
|
+
const result = await ingestDocument(input, options);
|
|
163
|
+
results.push(result);
|
|
164
|
+
} catch (error) {
|
|
165
|
+
console.error(`Failed to ingest document:`, error);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return results;
|
|
169
|
+
}
|
|
170
|
+
async function queryKnowledgeBase(query, options = {}) {
|
|
171
|
+
const {
|
|
172
|
+
limit = 5,
|
|
173
|
+
minSimilarity = 0,
|
|
174
|
+
documentIds,
|
|
175
|
+
userId,
|
|
176
|
+
tags,
|
|
177
|
+
includeMetadata = false
|
|
178
|
+
} = options;
|
|
179
|
+
const queryEmbedding = await generateEmbedding(query);
|
|
180
|
+
let queryBuilder = sql`
|
|
181
|
+
SELECT
|
|
182
|
+
dc.id as chunk_id,
|
|
183
|
+
dc.document_id,
|
|
184
|
+
d.name as document_name,
|
|
185
|
+
dc.content,
|
|
186
|
+
dc.metadata as chunk_metadata,
|
|
187
|
+
${includeMetadata ? sql`d.metadata as document_metadata,` : sql``}
|
|
188
|
+
1 - (dc.embedding <=> ${JSON.stringify(queryEmbedding)}::vector) as similarity
|
|
189
|
+
FROM document_chunks dc
|
|
190
|
+
JOIN documents d ON dc.document_id = d.id
|
|
191
|
+
WHERE d.status = 'completed'
|
|
192
|
+
`;
|
|
193
|
+
if (documentIds && documentIds.length > 0) {
|
|
194
|
+
queryBuilder = sql`${queryBuilder} AND dc.document_id = ANY(${documentIds}::uuid[])`;
|
|
195
|
+
}
|
|
196
|
+
if (userId) {
|
|
197
|
+
queryBuilder = sql`${queryBuilder} AND d.user_id = ${userId}`;
|
|
198
|
+
}
|
|
199
|
+
if (tags && tags.length > 0) {
|
|
200
|
+
queryBuilder = sql`${queryBuilder} AND d.metadata->'tags' ?| ${tags}`;
|
|
201
|
+
}
|
|
202
|
+
queryBuilder = sql`
|
|
203
|
+
${queryBuilder}
|
|
204
|
+
AND 1 - (dc.embedding <=> ${JSON.stringify(queryEmbedding)}::vector) >= ${minSimilarity}
|
|
205
|
+
ORDER BY dc.embedding <=> ${JSON.stringify(queryEmbedding)}::vector
|
|
206
|
+
LIMIT ${limit}
|
|
207
|
+
`;
|
|
208
|
+
const results = await db.execute(queryBuilder);
|
|
209
|
+
return (results.rows || results).map((row) => ({
|
|
210
|
+
chunkId: row.chunk_id,
|
|
211
|
+
documentId: row.document_id,
|
|
212
|
+
documentName: row.document_name,
|
|
213
|
+
content: row.content,
|
|
214
|
+
similarity: parseFloat(row.similarity),
|
|
215
|
+
metadata: row.chunk_metadata,
|
|
216
|
+
documentMetadata: includeMetadata ? row.document_metadata : void 0
|
|
217
|
+
}));
|
|
218
|
+
}
|
|
219
|
+
async function searchDocuments(query, options = {}) {
|
|
220
|
+
return queryKnowledgeBase(query, options);
|
|
221
|
+
}
|
|
222
|
+
async function getQueryContext(query, options = {}) {
|
|
223
|
+
const results = await queryKnowledgeBase(query, {
|
|
224
|
+
...options,
|
|
225
|
+
includeMetadata: true
|
|
226
|
+
});
|
|
227
|
+
if (results.length === 0) {
|
|
228
|
+
return "";
|
|
229
|
+
}
|
|
230
|
+
const contextParts = results.map((result, idx) => {
|
|
231
|
+
const header = result.documentMetadata?.title || result.documentName;
|
|
232
|
+
const section = result.metadata.sectionHeader ? ` - ${result.metadata.sectionHeader}` : "";
|
|
233
|
+
const similarity = (result.similarity * 100).toFixed(0);
|
|
234
|
+
return `[Source ${idx + 1}: ${header}${section} (${similarity}% relevance)]
|
|
235
|
+
${result.content}`;
|
|
236
|
+
});
|
|
237
|
+
return `Relevant knowledge from documents:
|
|
238
|
+
|
|
239
|
+
${contextParts.join("\n\n---\n\n")}`;
|
|
240
|
+
}
|
|
241
|
+
async function listDocuments(options) {
|
|
242
|
+
const conditions = [];
|
|
243
|
+
if (options?.userId) {
|
|
244
|
+
conditions.push(eq(documents.userId, options.userId));
|
|
245
|
+
}
|
|
246
|
+
if (options?.status) {
|
|
247
|
+
conditions.push(eq(documents.status, options.status));
|
|
248
|
+
}
|
|
249
|
+
const whereClause = conditions.length > 0 ? and(...conditions) : void 0;
|
|
250
|
+
const countResult = await db.select({ count: sql`count(*)` }).from(documents).where(whereClause);
|
|
251
|
+
const total = Number(countResult[0].count);
|
|
252
|
+
let query = db.select().from(documents).where(whereClause).orderBy(desc(documents.createdAt));
|
|
253
|
+
if (options?.limit) {
|
|
254
|
+
query = query.limit(options.limit);
|
|
255
|
+
}
|
|
256
|
+
if (options?.offset) {
|
|
257
|
+
query = query.offset(options.offset);
|
|
258
|
+
}
|
|
259
|
+
const docs = await query;
|
|
260
|
+
return {
|
|
261
|
+
documents: docs.map(mapDocumentToInfo),
|
|
262
|
+
total
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
async function getDocument(documentId) {
|
|
266
|
+
const [doc] = await db.select().from(documents).where(eq(documents.id, documentId));
|
|
267
|
+
return doc ? mapDocumentToInfo(doc) : null;
|
|
268
|
+
}
|
|
269
|
+
async function deleteDocument(documentId) {
|
|
270
|
+
const result = await db.delete(documents).where(eq(documents.id, documentId)).returning();
|
|
271
|
+
return result.length > 0;
|
|
272
|
+
}
|
|
273
|
+
async function deleteDocuments(documentIds) {
|
|
274
|
+
const result = await db.delete(documents).where(inArray(documents.id, documentIds)).returning();
|
|
275
|
+
return result.length;
|
|
276
|
+
}
|
|
277
|
+
async function updateDocumentMetadata(documentId, metadata) {
|
|
278
|
+
const [doc] = await db.select().from(documents).where(eq(documents.id, documentId));
|
|
279
|
+
if (!doc) return null;
|
|
280
|
+
const [updated] = await db.update(documents).set({
|
|
281
|
+
metadata: {
|
|
282
|
+
...doc.metadata,
|
|
283
|
+
...metadata
|
|
284
|
+
},
|
|
285
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
286
|
+
}).where(eq(documents.id, documentId)).returning();
|
|
287
|
+
return mapDocumentToInfo(updated);
|
|
288
|
+
}
|
|
289
|
+
async function getDocumentChunks(documentId) {
|
|
290
|
+
const chunks = await db.select({
|
|
291
|
+
id: documentChunks.id,
|
|
292
|
+
index: documentChunks.chunkIndex,
|
|
293
|
+
content: documentChunks.content,
|
|
294
|
+
metadata: documentChunks.metadata
|
|
295
|
+
}).from(documentChunks).where(eq(documentChunks.documentId, documentId)).orderBy(documentChunks.chunkIndex);
|
|
296
|
+
return chunks.map((c) => ({
|
|
297
|
+
id: c.id,
|
|
298
|
+
index: c.index,
|
|
299
|
+
content: c.content,
|
|
300
|
+
metadata: c.metadata
|
|
301
|
+
}));
|
|
302
|
+
}
|
|
303
|
+
function getMimeType(filename) {
|
|
304
|
+
const ext = path.extname(filename).toLowerCase();
|
|
305
|
+
const mimeTypes = {
|
|
306
|
+
".pdf": "application/pdf",
|
|
307
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
308
|
+
".doc": "application/msword",
|
|
309
|
+
".txt": "text/plain",
|
|
310
|
+
".md": "text/markdown",
|
|
311
|
+
".html": "text/html",
|
|
312
|
+
".htm": "text/html",
|
|
313
|
+
".csv": "text/csv",
|
|
314
|
+
".json": "application/json",
|
|
315
|
+
".xml": "application/xml",
|
|
316
|
+
".yaml": "application/yaml",
|
|
317
|
+
".yml": "application/yaml"
|
|
318
|
+
};
|
|
319
|
+
return mimeTypes[ext];
|
|
320
|
+
}
|
|
321
|
+
function mapDocumentToInfo(doc) {
|
|
322
|
+
return {
|
|
323
|
+
id: doc.id,
|
|
324
|
+
name: doc.name,
|
|
325
|
+
filename: doc.filename || void 0,
|
|
326
|
+
mimeType: doc.mimeType || void 0,
|
|
327
|
+
fileSize: doc.fileSize || void 0,
|
|
328
|
+
source: doc.source || void 0,
|
|
329
|
+
sourceUrl: doc.sourceUrl || void 0,
|
|
330
|
+
metadata: doc.metadata,
|
|
331
|
+
status: doc.status,
|
|
332
|
+
errorMessage: doc.errorMessage || void 0,
|
|
333
|
+
chunkCount: doc.chunkCount || 0,
|
|
334
|
+
totalTokens: doc.totalTokens || 0,
|
|
335
|
+
userId: doc.userId || void 0,
|
|
336
|
+
createdAt: doc.createdAt,
|
|
337
|
+
updatedAt: doc.updatedAt,
|
|
338
|
+
processedAt: doc.processedAt || void 0
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
async function getKnowledgeBaseStats(userId) {
|
|
342
|
+
const whereClause = userId ? eq(documents.userId, userId) : void 0;
|
|
343
|
+
const docStats = await db.select({
|
|
344
|
+
count: sql`count(*)`,
|
|
345
|
+
totalChunks: sql`coalesce(sum(chunk_count), 0)`,
|
|
346
|
+
totalTokens: sql`coalesce(sum(total_tokens), 0)`
|
|
347
|
+
}).from(documents).where(whereClause);
|
|
348
|
+
const statusStats = await db.select({
|
|
349
|
+
status: documents.status,
|
|
350
|
+
count: sql`count(*)`
|
|
351
|
+
}).from(documents).where(whereClause).groupBy(documents.status);
|
|
352
|
+
const statusBreakdown = {};
|
|
353
|
+
for (const stat of statusStats) {
|
|
354
|
+
statusBreakdown[stat.status] = Number(stat.count);
|
|
355
|
+
}
|
|
356
|
+
return {
|
|
357
|
+
documentCount: Number(docStats[0].count),
|
|
358
|
+
chunkCount: Number(docStats[0].totalChunks),
|
|
359
|
+
totalTokens: Number(docStats[0].totalTokens),
|
|
360
|
+
statusBreakdown
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export {
|
|
365
|
+
generateEmbedding,
|
|
366
|
+
generateEmbeddings,
|
|
367
|
+
ingestDocument,
|
|
368
|
+
ingestDocuments,
|
|
369
|
+
queryKnowledgeBase,
|
|
370
|
+
searchDocuments,
|
|
371
|
+
getQueryContext,
|
|
372
|
+
listDocuments,
|
|
373
|
+
getDocument,
|
|
374
|
+
deleteDocument,
|
|
375
|
+
deleteDocuments,
|
|
376
|
+
updateDocumentMetadata,
|
|
377
|
+
getDocumentChunks,
|
|
378
|
+
getKnowledgeBaseStats
|
|
379
|
+
};
|
|
380
|
+
//# sourceMappingURL=chunk-FFV2SXFD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/integrations/documents/knowledge-base.ts"],"sourcesContent":["/**\r\n * Knowledge Base for OpenSentinel Document Ingestion\r\n *\r\n * Stores and queries document embeddings using pgvector for similarity search.\r\n */\r\n\r\nimport { db, documents, documentChunks } from \"../../db\";\r\nimport { sql, eq, and, desc, inArray } from \"drizzle-orm\";\r\nimport OpenAI from \"openai\";\r\nimport { env } from \"../../config/env\";\r\nimport { chunkText, type Chunk, type ChunkerOptions } from \"./chunker\";\r\nimport { parsePDF } from \"./pdf-parser\";\r\nimport { parseDOCX } from \"./docx-parser\";\r\nimport { extractText, isSupportedTextFormat } from \"./text-extractor\";\r\nimport * as fs from \"fs/promises\";\r\nimport * as path from \"path\";\r\nimport { nanoid } from \"nanoid\";\r\n\r\n// Initialize OpenAI client\r\nconst openai = new OpenAI({ apiKey: env.OPENAI_API_KEY });\r\n\r\n// Re-export the schema tables for convenience\r\nexport { documents, documentChunks };\r\n\r\n// ============================================\r\n// TYPES\r\n// ============================================\r\n\r\nexport interface DocumentMetadata {\r\n title?: string;\r\n author?: string;\r\n description?: string;\r\n tags?: string[];\r\n pageCount?: number;\r\n wordCount?: number;\r\n language?: string;\r\n customFields?: Record<string, unknown>;\r\n}\r\n\r\nexport interface ChunkDBMetadata {\r\n sectionHeader?: string;\r\n pageNumber?: number;\r\n paragraphNumber?: number;\r\n startOffset: number;\r\n endOffset: number;\r\n}\r\n\r\nexport interface IngestOptions {\r\n /** Document name (defaults to filename) */\r\n name?: string;\r\n /** Source type */\r\n source?: \"upload\" | \"url\" | \"api\";\r\n /** Source URL if applicable */\r\n sourceUrl?: string;\r\n /** Additional metadata */\r\n metadata?: Partial<DocumentMetadata>;\r\n /** User ID for ownership */\r\n userId?: string;\r\n /** Chunking options */\r\n chunkOptions?: ChunkerOptions;\r\n /** Skip embedding generation (for testing) */\r\n skipEmbeddings?: boolean;\r\n}\r\n\r\nexport interface QueryOptions {\r\n /** Maximum number of results */\r\n limit?: number;\r\n /** Minimum similarity score (0-1) */\r\n minSimilarity?: number;\r\n /** Filter by document IDs */\r\n documentIds?: string[];\r\n /** Filter by user ID */\r\n userId?: string;\r\n /** Filter by tags */\r\n tags?: string[];\r\n /** Include document metadata in results */\r\n includeMetadata?: boolean;\r\n}\r\n\r\nexport interface QueryResult {\r\n /** Chunk ID */\r\n chunkId: string;\r\n /** Document ID */\r\n documentId: string;\r\n /** Document name */\r\n documentName: string;\r\n /** Chunk content */\r\n content: string;\r\n /** Similarity score (0-1) */\r\n similarity: number;\r\n /** Chunk metadata */\r\n metadata: ChunkDBMetadata;\r\n /** Document metadata (if requested) */\r\n documentMetadata?: DocumentMetadata;\r\n}\r\n\r\nexport interface DocumentInfo {\r\n id: string;\r\n name: string;\r\n filename?: string;\r\n mimeType?: string;\r\n fileSize?: number;\r\n source?: string;\r\n sourceUrl?: string;\r\n metadata?: DocumentMetadata;\r\n status: \"pending\" | \"processing\" | \"completed\" | \"failed\";\r\n errorMessage?: string;\r\n chunkCount: number;\r\n totalTokens: number;\r\n userId?: string;\r\n createdAt: Date;\r\n updatedAt: Date;\r\n processedAt?: Date;\r\n}\r\n\r\n// ============================================\r\n// EMBEDDING FUNCTIONS\r\n// ============================================\r\n\r\n/**\r\n * Generate embedding for text using OpenAI\r\n */\r\nexport async function generateEmbedding(text: string): Promise<number[]> {\r\n const response = await openai.embeddings.create({\r\n model: \"text-embedding-3-small\",\r\n input: text,\r\n });\r\n return response.data[0].embedding;\r\n}\r\n\r\n/**\r\n * Generate embeddings for multiple texts (batched)\r\n */\r\nexport async function generateEmbeddings(\r\n texts: string[]\r\n): Promise<number[][]> {\r\n if (texts.length === 0) return [];\r\n\r\n // OpenAI supports up to 2048 inputs per request\r\n const batchSize = 2048;\r\n const allEmbeddings: number[][] = [];\r\n\r\n for (let i = 0; i < texts.length; i += batchSize) {\r\n const batch = texts.slice(i, i + batchSize);\r\n const response = await openai.embeddings.create({\r\n model: \"text-embedding-3-small\",\r\n input: batch,\r\n });\r\n\r\n allEmbeddings.push(...response.data.map((d) => d.embedding));\r\n }\r\n\r\n return allEmbeddings;\r\n}\r\n\r\n// ============================================\r\n// DOCUMENT INGESTION\r\n// ============================================\r\n\r\n/**\r\n * Ingest a document from file path or buffer\r\n */\r\nexport async function ingestDocument(\r\n input: string | Buffer,\r\n options: IngestOptions = {}\r\n): Promise<DocumentInfo> {\r\n let buffer: Buffer;\r\n let filename: string | undefined;\r\n let mimeType: string | undefined;\r\n\r\n // Read file if path is provided\r\n if (typeof input === \"string\") {\r\n const absolutePath = path.isAbsolute(input) ? input : path.resolve(input);\r\n buffer = await fs.readFile(absolutePath);\r\n filename = path.basename(input);\r\n mimeType = getMimeType(filename);\r\n } else {\r\n buffer = input;\r\n filename = options.name;\r\n mimeType = options.metadata?.customFields?.mimeType as string | undefined;\r\n }\r\n\r\n const documentName = options.name || filename || `document-${nanoid(8)}`;\r\n\r\n // Create document record\r\n const [doc] = await db\r\n .insert(documents)\r\n .values({\r\n name: documentName,\r\n filename,\r\n mimeType,\r\n fileSize: buffer.length,\r\n source: options.source || \"upload\",\r\n sourceUrl: options.sourceUrl,\r\n metadata: options.metadata as DocumentMetadata,\r\n status: \"processing\",\r\n userId: options.userId,\r\n })\r\n .returning();\r\n\r\n try {\r\n // Extract text based on file type\r\n let text: string;\r\n let extractedMetadata: Partial<DocumentMetadata> = {};\r\n\r\n const ext = filename ? path.extname(filename).toLowerCase().slice(1) : \"\";\r\n\r\n if (mimeType === \"application/pdf\" || ext === \"pdf\") {\r\n const result = await parsePDF(buffer);\r\n text = result.text;\r\n extractedMetadata = {\r\n title: result.metadata.title,\r\n author: result.metadata.author,\r\n pageCount: result.pageCount,\r\n };\r\n } else if (\r\n mimeType ===\r\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\" ||\r\n ext === \"docx\"\r\n ) {\r\n const result = await parseDOCX(buffer);\r\n text = result.text;\r\n extractedMetadata = {\r\n wordCount: result.metadata.wordCount,\r\n };\r\n } else if (isSupportedTextFormat(ext)) {\r\n const result = await extractText(buffer, { format: ext as any });\r\n text = result.text;\r\n extractedMetadata = {\r\n wordCount: result.metadata.wordCount,\r\n };\r\n } else {\r\n // Try to extract as plain text\r\n text = buffer.toString(\"utf-8\");\r\n extractedMetadata = {\r\n wordCount: text.split(/\\s+/).length,\r\n };\r\n }\r\n\r\n // Chunk the text\r\n const chunks = chunkText(text, options.chunkOptions);\r\n\r\n if (chunks.length === 0) {\r\n throw new Error(\"Document produced no chunks - it may be empty\");\r\n }\r\n\r\n // Generate embeddings\r\n let embeddings: number[][] = [];\r\n if (!options.skipEmbeddings) {\r\n embeddings = await generateEmbeddings(chunks.map((c) => c.content));\r\n }\r\n\r\n // Store chunks\r\n const chunkRecords = chunks.map((chunk, idx) => ({\r\n documentId: doc.id,\r\n chunkIndex: chunk.index,\r\n content: chunk.content,\r\n embedding: options.skipEmbeddings ? undefined : embeddings[idx],\r\n tokenCount: chunk.tokenEstimate,\r\n metadata: {\r\n sectionHeader: chunk.metadata.sectionHeader,\r\n paragraphNumber: chunk.metadata.paragraphNumber,\r\n startOffset: chunk.startOffset,\r\n endOffset: chunk.endOffset,\r\n } as ChunkDBMetadata,\r\n }));\r\n\r\n // Insert chunks in batches\r\n const batchSize = 100;\r\n for (let i = 0; i < chunkRecords.length; i += batchSize) {\r\n const batch = chunkRecords.slice(i, i + batchSize);\r\n await db.insert(documentChunks).values(batch);\r\n }\r\n\r\n // Calculate total tokens\r\n const totalTokens = chunks.reduce((sum, c) => sum + c.tokenEstimate, 0);\r\n\r\n // Update document status\r\n const [updated] = await db\r\n .update(documents)\r\n .set({\r\n status: \"completed\",\r\n chunkCount: chunks.length,\r\n totalTokens,\r\n metadata: {\r\n ...extractedMetadata,\r\n ...options.metadata,\r\n },\r\n processedAt: new Date(),\r\n updatedAt: new Date(),\r\n })\r\n .where(eq(documents.id, doc.id))\r\n .returning();\r\n\r\n return mapDocumentToInfo(updated);\r\n } catch (error) {\r\n // Update document with error\r\n const errorMessage =\r\n error instanceof Error ? error.message : \"Unknown error\";\r\n await db\r\n .update(documents)\r\n .set({\r\n status: \"failed\",\r\n errorMessage,\r\n updatedAt: new Date(),\r\n })\r\n .where(eq(documents.id, doc.id));\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Ingest multiple documents\r\n */\r\nexport async function ingestDocuments(\r\n inputs: Array<{ input: string | Buffer; options?: IngestOptions }>\r\n): Promise<DocumentInfo[]> {\r\n const results: DocumentInfo[] = [];\r\n\r\n for (const { input, options } of inputs) {\r\n try {\r\n const result = await ingestDocument(input, options);\r\n results.push(result);\r\n } catch (error) {\r\n console.error(`Failed to ingest document:`, error);\r\n // Continue with other documents\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\n// ============================================\r\n// QUERY FUNCTIONS\r\n// ============================================\r\n\r\n/**\r\n * Query the knowledge base with natural language\r\n */\r\nexport async function queryKnowledgeBase(\r\n query: string,\r\n options: QueryOptions = {}\r\n): Promise<QueryResult[]> {\r\n const {\r\n limit = 5,\r\n minSimilarity = 0.0,\r\n documentIds,\r\n userId,\r\n tags,\r\n includeMetadata = false,\r\n } = options;\r\n\r\n // Generate query embedding\r\n const queryEmbedding = await generateEmbedding(query);\r\n\r\n // Build the query\r\n let queryBuilder = sql`\r\n SELECT\r\n dc.id as chunk_id,\r\n dc.document_id,\r\n d.name as document_name,\r\n dc.content,\r\n dc.metadata as chunk_metadata,\r\n ${includeMetadata ? sql`d.metadata as document_metadata,` : sql``}\r\n 1 - (dc.embedding <=> ${JSON.stringify(queryEmbedding)}::vector) as similarity\r\n FROM document_chunks dc\r\n JOIN documents d ON dc.document_id = d.id\r\n WHERE d.status = 'completed'\r\n `;\r\n\r\n // Add filters\r\n if (documentIds && documentIds.length > 0) {\r\n queryBuilder = sql`${queryBuilder} AND dc.document_id = ANY(${documentIds}::uuid[])`;\r\n }\r\n\r\n if (userId) {\r\n queryBuilder = sql`${queryBuilder} AND d.user_id = ${userId}`;\r\n }\r\n\r\n if (tags && tags.length > 0) {\r\n queryBuilder = sql`${queryBuilder} AND d.metadata->'tags' ?| ${tags}`;\r\n }\r\n\r\n // Add similarity filter and ordering\r\n queryBuilder = sql`\r\n ${queryBuilder}\r\n AND 1 - (dc.embedding <=> ${JSON.stringify(queryEmbedding)}::vector) >= ${minSimilarity}\r\n ORDER BY dc.embedding <=> ${JSON.stringify(queryEmbedding)}::vector\r\n LIMIT ${limit}\r\n `;\r\n\r\n const results = await db.execute(queryBuilder) as any;\r\n\r\n return (results.rows || results).map((row: any) => ({\r\n chunkId: row.chunk_id,\r\n documentId: row.document_id,\r\n documentName: row.document_name,\r\n content: row.content,\r\n similarity: parseFloat(row.similarity),\r\n metadata: row.chunk_metadata,\r\n documentMetadata: includeMetadata ? row.document_metadata : undefined,\r\n }));\r\n}\r\n\r\n/**\r\n * Search documents by text similarity\r\n */\r\nexport async function searchDocuments(\r\n query: string,\r\n options: QueryOptions = {}\r\n): Promise<QueryResult[]> {\r\n return queryKnowledgeBase(query, options);\r\n}\r\n\r\n/**\r\n * Get context for a query (formatted for LLM)\r\n */\r\nexport async function getQueryContext(\r\n query: string,\r\n options: QueryOptions = {}\r\n): Promise<string> {\r\n const results = await queryKnowledgeBase(query, {\r\n ...options,\r\n includeMetadata: true,\r\n });\r\n\r\n if (results.length === 0) {\r\n return \"\";\r\n }\r\n\r\n const contextParts = results.map((result, idx) => {\r\n const header = result.documentMetadata?.title || result.documentName;\r\n const section = result.metadata.sectionHeader\r\n ? ` - ${result.metadata.sectionHeader}`\r\n : \"\";\r\n const similarity = (result.similarity * 100).toFixed(0);\r\n\r\n return `[Source ${idx + 1}: ${header}${section} (${similarity}% relevance)]\r\n${result.content}`;\r\n });\r\n\r\n return `Relevant knowledge from documents:\r\n\r\n${contextParts.join(\"\\n\\n---\\n\\n\")}`;\r\n}\r\n\r\n// ============================================\r\n// DOCUMENT MANAGEMENT\r\n// ============================================\r\n\r\n/**\r\n * List all documents\r\n */\r\nexport async function listDocuments(options?: {\r\n userId?: string;\r\n status?: \"pending\" | \"processing\" | \"completed\" | \"failed\";\r\n limit?: number;\r\n offset?: number;\r\n}): Promise<{ documents: DocumentInfo[]; total: number }> {\r\n const conditions = [];\r\n\r\n if (options?.userId) {\r\n conditions.push(eq(documents.userId, options.userId));\r\n }\r\n\r\n if (options?.status) {\r\n conditions.push(eq(documents.status, options.status));\r\n }\r\n\r\n const whereClause = conditions.length > 0 ? and(...conditions) : undefined;\r\n\r\n // Get total count\r\n const countResult = await db\r\n .select({ count: sql<number>`count(*)` })\r\n .from(documents)\r\n .where(whereClause);\r\n const total = Number(countResult[0].count);\r\n\r\n // Get documents\r\n let query = db\r\n .select()\r\n .from(documents)\r\n .where(whereClause)\r\n .orderBy(desc(documents.createdAt));\r\n\r\n if (options?.limit) {\r\n query = query.limit(options.limit) as typeof query;\r\n }\r\n\r\n if (options?.offset) {\r\n query = query.offset(options.offset) as typeof query;\r\n }\r\n\r\n const docs = await query;\r\n\r\n return {\r\n documents: docs.map(mapDocumentToInfo),\r\n total,\r\n };\r\n}\r\n\r\n/**\r\n * Get a specific document by ID\r\n */\r\nexport async function getDocument(documentId: string): Promise<DocumentInfo | null> {\r\n const [doc] = await db\r\n .select()\r\n .from(documents)\r\n .where(eq(documents.id, documentId));\r\n\r\n return doc ? mapDocumentToInfo(doc) : null;\r\n}\r\n\r\n/**\r\n * Delete a document and its chunks\r\n */\r\nexport async function deleteDocument(documentId: string): Promise<boolean> {\r\n // Chunks are deleted automatically due to cascade\r\n const result = await db\r\n .delete(documents)\r\n .where(eq(documents.id, documentId))\r\n .returning();\r\n\r\n return result.length > 0;\r\n}\r\n\r\n/**\r\n * Delete multiple documents\r\n */\r\nexport async function deleteDocuments(documentIds: string[]): Promise<number> {\r\n const result = await db\r\n .delete(documents)\r\n .where(inArray(documents.id, documentIds))\r\n .returning();\r\n\r\n return result.length;\r\n}\r\n\r\n/**\r\n * Update document metadata\r\n */\r\nexport async function updateDocumentMetadata(\r\n documentId: string,\r\n metadata: Partial<DocumentMetadata>\r\n): Promise<DocumentInfo | null> {\r\n const [doc] = await db\r\n .select()\r\n .from(documents)\r\n .where(eq(documents.id, documentId));\r\n\r\n if (!doc) return null;\r\n\r\n const [updated] = await db\r\n .update(documents)\r\n .set({\r\n metadata: {\r\n ...(doc.metadata as DocumentMetadata),\r\n ...metadata,\r\n },\r\n updatedAt: new Date(),\r\n })\r\n .where(eq(documents.id, documentId))\r\n .returning();\r\n\r\n return mapDocumentToInfo(updated);\r\n}\r\n\r\n/**\r\n * Get document chunks\r\n */\r\nexport async function getDocumentChunks(\r\n documentId: string\r\n): Promise<Array<{ id: string; index: number; content: string; metadata: ChunkDBMetadata }>> {\r\n const chunks = await db\r\n .select({\r\n id: documentChunks.id,\r\n index: documentChunks.chunkIndex,\r\n content: documentChunks.content,\r\n metadata: documentChunks.metadata,\r\n })\r\n .from(documentChunks)\r\n .where(eq(documentChunks.documentId, documentId))\r\n .orderBy(documentChunks.chunkIndex);\r\n\r\n return chunks.map((c) => ({\r\n id: c.id,\r\n index: c.index,\r\n content: c.content,\r\n metadata: c.metadata as ChunkDBMetadata,\r\n }));\r\n}\r\n\r\n// ============================================\r\n// UTILITY FUNCTIONS\r\n// ============================================\r\n\r\n/**\r\n * Get MIME type from filename\r\n */\r\nfunction getMimeType(filename: string): string | undefined {\r\n const ext = path.extname(filename).toLowerCase();\r\n const mimeTypes: Record<string, string> = {\r\n \".pdf\": \"application/pdf\",\r\n \".docx\":\r\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\r\n \".doc\": \"application/msword\",\r\n \".txt\": \"text/plain\",\r\n \".md\": \"text/markdown\",\r\n \".html\": \"text/html\",\r\n \".htm\": \"text/html\",\r\n \".csv\": \"text/csv\",\r\n \".json\": \"application/json\",\r\n \".xml\": \"application/xml\",\r\n \".yaml\": \"application/yaml\",\r\n \".yml\": \"application/yaml\",\r\n };\r\n return mimeTypes[ext];\r\n}\r\n\r\n/**\r\n * Map database document to DocumentInfo\r\n */\r\nfunction mapDocumentToInfo(doc: typeof documents.$inferSelect): DocumentInfo {\r\n return {\r\n id: doc.id,\r\n name: doc.name,\r\n filename: doc.filename || undefined,\r\n mimeType: doc.mimeType || undefined,\r\n fileSize: doc.fileSize || undefined,\r\n source: doc.source || undefined,\r\n sourceUrl: doc.sourceUrl || undefined,\r\n metadata: doc.metadata as DocumentMetadata | undefined,\r\n status: doc.status as \"pending\" | \"processing\" | \"completed\" | \"failed\",\r\n errorMessage: doc.errorMessage || undefined,\r\n chunkCount: doc.chunkCount || 0,\r\n totalTokens: doc.totalTokens || 0,\r\n userId: doc.userId || undefined,\r\n createdAt: doc.createdAt,\r\n updatedAt: doc.updatedAt,\r\n processedAt: doc.processedAt || undefined,\r\n };\r\n}\r\n\r\n/**\r\n * Get knowledge base statistics\r\n */\r\nexport async function getKnowledgeBaseStats(userId?: string): Promise<{\r\n documentCount: number;\r\n chunkCount: number;\r\n totalTokens: number;\r\n statusBreakdown: Record<string, number>;\r\n}> {\r\n const whereClause = userId ? eq(documents.userId, userId) : undefined;\r\n\r\n // Get document stats\r\n const docStats = await db\r\n .select({\r\n count: sql<number>`count(*)`,\r\n totalChunks: sql<number>`coalesce(sum(chunk_count), 0)`,\r\n totalTokens: sql<number>`coalesce(sum(total_tokens), 0)`,\r\n })\r\n .from(documents)\r\n .where(whereClause);\r\n\r\n // Get status breakdown\r\n const statusStats = await db\r\n .select({\r\n status: documents.status,\r\n count: sql<number>`count(*)`,\r\n })\r\n .from(documents)\r\n .where(whereClause)\r\n .groupBy(documents.status);\r\n\r\n const statusBreakdown: Record<string, number> = {};\r\n for (const stat of statusStats) {\r\n statusBreakdown[stat.status] = Number(stat.count);\r\n }\r\n\r\n return {\r\n documentCount: Number(docStats[0].count),\r\n chunkCount: Number(docStats[0].totalChunks),\r\n totalTokens: Number(docStats[0].totalTokens),\r\n statusBreakdown,\r\n };\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
providerRegistry
|
|
3
|
+
} from "./chunk-HTF2GIQC.js";
|
|
1
4
|
import {
|
|
2
5
|
isPathAllowed
|
|
3
6
|
} from "./chunk-CQ4JURG7.js";
|
|
4
|
-
import {
|
|
5
|
-
env
|
|
6
|
-
} from "./chunk-ZLZKF2PM.js";
|
|
7
7
|
|
|
8
8
|
// src/tools/image-analysis.ts
|
|
9
|
-
import Anthropic from "@anthropic-ai/sdk";
|
|
10
9
|
import { readFile } from "fs/promises";
|
|
11
|
-
var anthropic = new Anthropic({
|
|
12
|
-
apiKey: env.CLAUDE_API_KEY
|
|
13
|
-
});
|
|
14
10
|
var SUPPORTED_TYPES = {
|
|
15
11
|
".jpg": "image/jpeg",
|
|
16
12
|
".jpeg": "image/jpeg",
|
|
@@ -24,7 +20,8 @@ function getMimeType(filename) {
|
|
|
24
20
|
}
|
|
25
21
|
async function analyzeImageUrl(imageUrl, prompt) {
|
|
26
22
|
try {
|
|
27
|
-
const
|
|
23
|
+
const provider = providerRegistry.getDefault();
|
|
24
|
+
const response = await provider.createMessage({
|
|
28
25
|
model: "claude-sonnet-4-20250514",
|
|
29
26
|
max_tokens: 1024,
|
|
30
27
|
messages: [
|
|
@@ -49,7 +46,7 @@ async function analyzeImageUrl(imageUrl, prompt) {
|
|
|
49
46
|
const textContent = response.content.find((c) => c.type === "text");
|
|
50
47
|
return {
|
|
51
48
|
success: true,
|
|
52
|
-
analysis: textContent?.
|
|
49
|
+
analysis: textContent?.text
|
|
53
50
|
};
|
|
54
51
|
} catch (error) {
|
|
55
52
|
return {
|
|
@@ -75,7 +72,8 @@ async function analyzeImageFile(filePath, prompt) {
|
|
|
75
72
|
}
|
|
76
73
|
const imageData = await readFile(filePath);
|
|
77
74
|
const base64 = imageData.toString("base64");
|
|
78
|
-
const
|
|
75
|
+
const provider = providerRegistry.getDefault();
|
|
76
|
+
const response = await provider.createMessage({
|
|
79
77
|
model: "claude-sonnet-4-20250514",
|
|
80
78
|
max_tokens: 1024,
|
|
81
79
|
messages: [
|
|
@@ -86,7 +84,7 @@ async function analyzeImageFile(filePath, prompt) {
|
|
|
86
84
|
type: "image",
|
|
87
85
|
source: {
|
|
88
86
|
type: "base64",
|
|
89
|
-
|
|
87
|
+
mediaType: mimeType,
|
|
90
88
|
data: base64
|
|
91
89
|
}
|
|
92
90
|
},
|
|
@@ -101,7 +99,7 @@ async function analyzeImageFile(filePath, prompt) {
|
|
|
101
99
|
const textContent = response.content.find((c) => c.type === "text");
|
|
102
100
|
return {
|
|
103
101
|
success: true,
|
|
104
|
-
analysis: textContent?.
|
|
102
|
+
analysis: textContent?.text
|
|
105
103
|
};
|
|
106
104
|
} catch (error) {
|
|
107
105
|
return {
|
|
@@ -113,7 +111,8 @@ async function analyzeImageFile(filePath, prompt) {
|
|
|
113
111
|
async function analyzeImageBuffer(imageBuffer, mimeType, prompt) {
|
|
114
112
|
try {
|
|
115
113
|
const base64 = imageBuffer.toString("base64");
|
|
116
|
-
const
|
|
114
|
+
const provider = providerRegistry.getDefault();
|
|
115
|
+
const response = await provider.createMessage({
|
|
117
116
|
model: "claude-sonnet-4-20250514",
|
|
118
117
|
max_tokens: 1024,
|
|
119
118
|
messages: [
|
|
@@ -124,7 +123,7 @@ async function analyzeImageBuffer(imageBuffer, mimeType, prompt) {
|
|
|
124
123
|
type: "image",
|
|
125
124
|
source: {
|
|
126
125
|
type: "base64",
|
|
127
|
-
|
|
126
|
+
mediaType: mimeType,
|
|
128
127
|
data: base64
|
|
129
128
|
}
|
|
130
129
|
},
|
|
@@ -139,7 +138,7 @@ async function analyzeImageBuffer(imageBuffer, mimeType, prompt) {
|
|
|
139
138
|
const textContent = response.content.find((c) => c.type === "text");
|
|
140
139
|
return {
|
|
141
140
|
success: true,
|
|
142
|
-
analysis: textContent?.
|
|
141
|
+
analysis: textContent?.text
|
|
143
142
|
};
|
|
144
143
|
} catch (error) {
|
|
145
144
|
return {
|
|
@@ -287,4 +286,4 @@ export {
|
|
|
287
286
|
extractStructuredData,
|
|
288
287
|
ocr_default
|
|
289
288
|
};
|
|
290
|
-
//# sourceMappingURL=chunk-
|
|
289
|
+
//# sourceMappingURL=chunk-GUKKW7JI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tools/image-analysis.ts","../src/tools/ocr.ts"],"sourcesContent":["import { providerRegistry } from \"../core/providers\";\nimport { readFile } from \"fs/promises\";\nimport { isPathAllowed } from \"../utils/paths\";\n\nexport interface ImageAnalysisResult {\n success: boolean;\n analysis?: string;\n error?: string;\n}\n\n// Supported image MIME types\nconst SUPPORTED_TYPES: Record<string, string> = {\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n};\n\nfunction getMimeType(filename: string): string | null {\n const ext = filename.toLowerCase().slice(filename.lastIndexOf(\".\"));\n return SUPPORTED_TYPES[ext] || null;\n}\n\n// Analyze image from URL\nexport async function analyzeImageUrl(\n imageUrl: string,\n prompt: string\n): Promise<ImageAnalysisResult> {\n try {\n const provider = providerRegistry.getDefault();\n const response = await provider.createMessage({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 1024,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"url\",\n url: imageUrl,\n },\n },\n {\n type: \"text\",\n text: prompt || \"Describe this image in detail.\",\n },\n ],\n },\n ],\n });\n\n const textContent = response.content.find((c) => c.type === \"text\");\n return {\n success: true,\n analysis: textContent?.text,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n// Analyze image from local file\nexport async function analyzeImageFile(\n filePath: string,\n prompt: string\n): Promise<ImageAnalysisResult> {\n try {\n // Security check\n if (!isPathAllowed(filePath)) {\n return {\n success: false,\n error: \"Access to this path is not allowed\",\n };\n }\n\n const mimeType = getMimeType(filePath);\n if (!mimeType) {\n return {\n success: false,\n error: \"Unsupported image format. Supported: jpg, png, gif, webp\",\n };\n }\n\n const imageData = await readFile(filePath);\n const base64 = imageData.toString(\"base64\");\n\n const provider = providerRegistry.getDefault();\n const response = await provider.createMessage({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 1024,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"base64\",\n mediaType: mimeType,\n data: base64,\n },\n },\n {\n type: \"text\",\n text: prompt || \"Describe this image in detail.\",\n },\n ],\n },\n ],\n });\n\n const textContent = response.content.find((c) => c.type === \"text\");\n return {\n success: true,\n analysis: textContent?.text,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n// Analyze image from buffer\nexport async function analyzeImageBuffer(\n imageBuffer: Buffer,\n mimeType: \"image/jpeg\" | \"image/png\" | \"image/gif\" | \"image/webp\",\n prompt: string\n): Promise<ImageAnalysisResult> {\n try {\n const base64 = imageBuffer.toString(\"base64\");\n\n const provider = providerRegistry.getDefault();\n const response = await provider.createMessage({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 1024,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"base64\",\n mediaType: mimeType,\n data: base64,\n },\n },\n {\n type: \"text\",\n text: prompt || \"Describe this image in detail.\",\n },\n ],\n },\n ],\n });\n\n const textContent = response.content.find((c) => c.type === \"text\");\n return {\n success: true,\n analysis: textContent?.text,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n// Combined function for tool use\nexport async function analyzeImage(\n options: {\n imageUrl?: string;\n imagePath?: string;\n prompt: string;\n }\n): Promise<ImageAnalysisResult> {\n if (options.imageUrl) {\n return analyzeImageUrl(options.imageUrl, options.prompt);\n }\n\n if (options.imagePath) {\n return analyzeImageFile(options.imagePath, options.prompt);\n }\n\n return {\n success: false,\n error: \"Either imageUrl or imagePath must be provided\",\n };\n}\n\nexport default {\n analyzeImage,\n analyzeImageUrl,\n analyzeImageFile,\n analyzeImageBuffer,\n};\n","import { readFile } from \"fs/promises\";\nimport { isPathAllowed } from \"../utils/paths\";\nimport { analyzeImageFile } from \"./image-analysis\";\n\nexport interface OCRResult {\n success: boolean;\n text?: string;\n confidence?: number;\n error?: string;\n}\n\n// OCR using Tesseract.js (local, no API key needed)\nexport async function ocrWithTesseract(\n filePath: string,\n language: string = \"eng\"\n): Promise<OCRResult> {\n try {\n const Tesseract = await import(\"tesseract.js\");\n const worker = await Tesseract.createWorker(language);\n const { data } = await worker.recognize(filePath);\n await worker.terminate();\n\n return {\n success: true,\n text: data.text,\n confidence: data.confidence / 100,\n };\n } catch (error) {\n return {\n success: false,\n error: `Tesseract OCR failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n\n// Use LLM Vision for OCR (most reliable for complex documents)\nexport async function ocrWithVision(\n filePath: string,\n language?: string\n): Promise<OCRResult> {\n const prompt = language\n ? `Extract all text from this image. The text is in ${language}. Return only the extracted text, preserving the original formatting and layout as much as possible.`\n : `Extract all text from this image. Return only the extracted text, preserving the original formatting and layout as much as possible.`;\n\n const result = await analyzeImageFile(filePath, prompt);\n\n if (result.success && result.analysis) {\n return {\n success: true,\n text: result.analysis,\n };\n }\n\n return {\n success: false,\n error: result.error || \"Failed to extract text\",\n };\n}\n\n// OCR using Tesseract.js as primary, falling back to Vision API\nexport async function ocrSimple(filePath: string): Promise<OCRResult> {\n const result = await ocrWithTesseract(filePath);\n if (result.success && result.confidence && result.confidence > 0.6) {\n return result;\n }\n // Fall back to Vision API on low confidence or failure\n return ocrWithVision(filePath);\n}\n\n// OCR for PDF files (extract text from each page)\nexport async function ocrPdf(\n filePath: string,\n pages?: string // e.g., \"1-5\" or \"1,3,5\"\n): Promise<OCRResult> {\n // For PDFs, we'll use LLM Vision on the file directly\n const prompt = `Extract all text from this PDF document. Return the text content, preserving the structure and formatting as much as possible. If there are multiple pages, separate them clearly.`;\n\n const result = await analyzeImageFile(filePath, prompt);\n\n if (result.success && result.analysis) {\n return {\n success: true,\n text: result.analysis,\n };\n }\n\n return {\n success: false,\n error: result.error || \"Failed to extract text from PDF\",\n };\n}\n\n// Main OCR function that determines the best approach\nexport async function performOCR(\n filePath: string,\n options?: {\n language?: string;\n useVision?: boolean;\n }\n): Promise<OCRResult> {\n // Security check\n if (!isPathAllowed(filePath)) {\n return {\n success: false,\n error: \"Access to this path is not allowed\",\n };\n }\n\n const ext = filePath.toLowerCase().slice(filePath.lastIndexOf(\".\"));\n\n // PDF handling\n if (ext === \".pdf\") {\n return ocrPdf(filePath);\n }\n\n // Image handling - use Vision API (most accurate)\n if ([\".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".bmp\", \".tiff\"].includes(ext)) {\n if (options?.useVision !== false) {\n return ocrWithVision(filePath, options?.language);\n }\n return ocrSimple(filePath);\n }\n\n return {\n success: false,\n error: `Unsupported file type: ${ext}`,\n };\n}\n\n// Extract structured data from document (tables, forms)\nexport async function extractStructuredData(\n filePath: string,\n dataType?: \"table\" | \"form\" | \"receipt\" | \"invoice\"\n): Promise<{\n success: boolean;\n data?: Record<string, unknown>;\n error?: string;\n}> {\n const prompts: Record<string, string> = {\n table: `Extract all tables from this image. Return the data as JSON arrays where each table is an array of rows, and each row is an array of cell values.`,\n form: `Extract all form fields from this image. Return as a JSON object where keys are field labels and values are the filled-in content.`,\n receipt: `Extract receipt information from this image. Return as JSON with: store_name, date, items (array with name, quantity, price), subtotal, tax, total.`,\n invoice: `Extract invoice information from this image. Return as JSON with: vendor, invoice_number, date, due_date, line_items (array), subtotal, tax, total, billing_address.`,\n };\n\n const prompt = dataType\n ? prompts[dataType]\n : `Extract any structured data from this image. Return as JSON.`;\n\n const result = await analyzeImageFile(filePath, prompt);\n\n if (result.success && result.analysis) {\n try {\n // Try to parse as JSON\n const jsonMatch = result.analysis.match(/```json\\n?([\\s\\S]*?)\\n?```/);\n if (jsonMatch) {\n return {\n success: true,\n data: JSON.parse(jsonMatch[1]),\n };\n }\n\n // Try direct parse\n const data = JSON.parse(result.analysis);\n return { success: true, data };\n } catch {\n // Return raw text if not JSON\n return {\n success: true,\n data: { rawText: result.analysis },\n };\n }\n }\n\n return {\n success: false,\n error: result.error || \"Failed to extract structured data\",\n };\n}\n\nexport default {\n performOCR,\n ocrWithVision,\n ocrWithTesseract,\n extractStructuredData,\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
chatWithTools
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6JY4HNUH.js";
|
|
4
4
|
|
|
5
5
|
// src/inputs/whatsapp/index.ts
|
|
6
6
|
import makeWASocket, {
|
|
@@ -120,4 +120,4 @@ export {
|
|
|
120
120
|
WhatsAppBot,
|
|
121
121
|
whatsapp_default
|
|
122
122
|
};
|
|
123
|
-
//# sourceMappingURL=chunk-
|
|
123
|
+
//# sourceMappingURL=chunk-H3BOLSTS.js.map
|