From f7a55cb06541aea8fc7963c8a25092fd68dbfc08 Mon Sep 17 00:00:00 2001 From: Kyle Ramachandran Date: Mon, 8 Apr 2024 20:40:16 -0700 Subject: [PATCH 1/6] working on embeddings --- package-lock.json | 570 ++++++++++++++++++++++++++++++++- package.json | 4 +- src/queries/recommendations.js | 42 +++ 3 files changed, 612 insertions(+), 4 deletions(-) create mode 100644 src/queries/recommendations.js diff --git a/package-lock.json b/package-lock.json index b1f5b69..13bfd92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "@rneui/themed": "^4.0.0-rc.8", "@supabase/supabase-js": "^2.36.0", "@types/validator": "^13.11.5", + "@xenova/transformers": "^2.16.1", "axios": "^1.5.0", "cheerio": "^1.0.0-rc.12", "deprecated-react-native-prop-types": "^4.2.1", @@ -73,8 +74,7 @@ "eslint-config-universe": "^12.0.0", "husky": "^8.0.3", "prettier": "^3.0.3", - "supabase": "^1.110.1", - "typescript": "^5.1.3" + "supabase": "^1.110.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -3677,6 +3677,14 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@huggingface/jinja": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.2.2.tgz", + "integrity": "sha512-/KPde26khDUIPkTGU82jdtTW9UAuvUTumCAbFs/7giR0SxsvZC4hru51PBvpijH6BVkHcROcvZM/lpy5h1jRRA==", + "engines": { + "node": ">=18" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.11", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", @@ -4765,6 +4773,60 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", @@ -7237,6 +7299,11 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, "node_modules/@types/node": { "version": "20.6.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.3.tgz", @@ -7689,6 +7756,19 @@ "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0" } }, + "node_modules/@xenova/transformers": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@xenova/transformers/-/transformers-2.16.1.tgz", + "integrity": "sha512-p2ii7v7oC3Se0PC012dn4vt196GCroaN5ngOYJYkfg0/ce8A5frsrnnnktOBJuejG3bW5Hreb7JZ/KxtUaKd8w==", + "dependencies": { + "@huggingface/jinja": "^0.2.2", + "onnxruntime-web": "1.14.0", + "sharp": "^0.32.0" + }, + "optionalDependencies": { + "onnxruntime-node": "1.14.0" + } + }, "node_modules/@xmldom/xmldom": { "version": "0.7.13", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz", @@ -8123,6 +8203,11 @@ "node": ">= 6" } }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==" + }, "node_modules/babel-core": { "version": "7.0.0-bridge.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", @@ -8371,6 +8456,38 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/bare-events": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz", + "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==", + "optional": true + }, + "node_modules/bare-fs": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.2.3.tgz", + "integrity": "sha512-amG72llr9pstfXOBOHve1WjiuKKAMnebcmMbPWDZ7BCevAoJLpugjuAPRsDINEyjT0a6tbaVx3DctkXIRbLuJw==", + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-path": "^2.0.0", + "streamx": "^2.13.0" + } + }, + "node_modules/bare-os": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.2.1.tgz", + "integrity": "sha512-OwPyHgBBMkhC29Hl3O4/YfxW9n7mdTr2+SsO29XBWKKJsbgj3mnorDB80r5TiCQgQstgE5ga1qNYrpes6NvX2w==", + "optional": true + }, + "node_modules/bare-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.1.tgz", + "integrity": "sha512-OHM+iwRDRMDBsSW7kl3dO62JyHdBKO3B25FB9vNQBPcGHMo4+eA8Yj41Lfbk3pS/seDY+siNge0LdRTulAau/A==", + "optional": true, + "dependencies": { + "bare-os": "^2.1.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -9604,6 +9721,20 @@ "node": ">=0.10" } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -11072,6 +11203,14 @@ "node": ">=6" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, "node_modules/expo": { "version": "49.0.23", "resolved": "https://registry.npmjs.org/expo/-/expo-49.0.23.tgz", @@ -11395,6 +11534,11 @@ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "dev": true }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, "node_modules/fast-glob": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", @@ -11668,6 +11812,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/flatbuffers": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", + "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==" + }, "node_modules/flatted": { "version": "3.2.9", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", @@ -11761,6 +11910,11 @@ "node": ">= 0.6" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -11908,6 +12062,11 @@ "node": ">=6" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, "node_modules/glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -12025,6 +12184,11 @@ "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/guid-typescript": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz", + "integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==" + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -14399,6 +14563,11 @@ "node": ">=6" } }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -15246,6 +15415,17 @@ "node": ">=4" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -15342,6 +15522,11 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -15416,6 +15601,11 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -15467,11 +15657,57 @@ "node": ">=12.0.0" } }, + "node_modules/node-abi": { + "version": "3.57.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.57.0.tgz", + "integrity": "sha512-Dp+A9JWxRaKuHP35H77I4kCKesDy5HUDEmScia2FyncMTOXASMyg251F5PhFoDA5uqBrDDffiLpbqnrZmNXW+g==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" + }, "node_modules/node-dir": { "version": "0.1.17", "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", @@ -15786,6 +16022,46 @@ "node": ">=4" } }, + "node_modules/onnx-proto": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/onnx-proto/-/onnx-proto-4.0.4.tgz", + "integrity": "sha512-aldMOB3HRoo6q/phyB6QRQxSt895HNNw82BNyZ2CMh4bjeKv7g/c+VpAFtJuEMVfYLMbRx61hbuqnKceLeDcDA==", + "dependencies": { + "protobufjs": "^6.8.8" + } + }, + "node_modules/onnxruntime-common": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.14.0.tgz", + "integrity": "sha512-3LJpegM2iMNRX2wUmtYfeX/ytfOzNwAWKSq1HbRrKc9+uqG/FsEA0bbKZl1btQeZaXhC26l44NWpNUeXPII7Ew==" + }, + "node_modules/onnxruntime-node": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.14.0.tgz", + "integrity": "sha512-5ba7TWomIV/9b6NH/1x/8QEeowsb+jBEvFzU6z0T4mNsFwdPqXeFUM7uxC6QeSRkEbWu3qEB0VMjrvzN/0S9+w==", + "optional": true, + "os": [ + "win32", + "darwin", + "linux" + ], + "dependencies": { + "onnxruntime-common": "~1.14.0" + } + }, + "node_modules/onnxruntime-web": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.14.0.tgz", + "integrity": "sha512-Kcqf43UMfW8mCydVGcX9OMXI2VN17c0p6XvR7IPSZzBf/6lteBzXHvcEVWDPmCKuGombl997HgLqj91F11DzXw==", + "dependencies": { + "flatbuffers": "^1.12.0", + "guid-typescript": "^1.0.9", + "long": "^4.0.0", + "onnx-proto": "^4.0.4", + "onnxruntime-common": "~1.14.0", + "platform": "^1.3.6" + } + }, "node_modules/open": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", @@ -16306,6 +16582,11 @@ "node": ">=4" } }, + "node_modules/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" + }, "node_modules/plist": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", @@ -16375,6 +16656,83 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/prebuild-install/node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/prebuild-install/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -16519,6 +16877,31 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -16612,6 +16995,11 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + }, "node_modules/ramda": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", @@ -18020,6 +18408,94 @@ "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" }, + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/sharp/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/sharp/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/sharp/node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/sharp/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -18065,6 +18541,49 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/simple-plist": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz", @@ -18260,6 +18779,18 @@ "node": ">= 0.10.0" } }, + "node_modules/streamx": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz", + "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==", + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, "node_modules/strict-uri-encode": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", @@ -18669,6 +19200,29 @@ "node": ">=10" } }, + "node_modules/tar-fs": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", + "integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/tar/node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", @@ -18965,6 +19519,17 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", @@ -19091,6 +19656,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 7ba5f15..61357d6 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@rneui/themed": "^4.0.0-rc.8", "@supabase/supabase-js": "^2.36.0", "@types/validator": "^13.11.5", + "@xenova/transformers": "^2.16.1", "axios": "^1.5.0", "cheerio": "^1.0.0-rc.12", "deprecated-react-native-prop-types": "^4.2.1", @@ -77,8 +78,7 @@ "eslint-config-universe": "^12.0.0", "husky": "^8.0.3", "prettier": "^3.0.3", - "supabase": "^1.110.1", - "typescript": "^5.1.3" + "supabase": "^1.110.1" }, "private": true } diff --git a/src/queries/recommendations.js b/src/queries/recommendations.js new file mode 100644 index 0000000..d6dd3d7 --- /dev/null +++ b/src/queries/recommendations.js @@ -0,0 +1,42 @@ +import { pipeline, env } from '@xenova/transformers'; +import supabase from '../utils/supabase.ts'; + +// Configuration for Deno runtime +env.useBrowserCache = false; + +const pipe = async () => { + await pipeline('feature-extraction', 'Supabase/gte-small'); +}; + +// Generate the embedding from the user input +const generateEmbedding = async text => { + const output = await pipe(text, { + pooling: 'mean', + normalize: true, + }); + + // Extract the embedding output + return Array.from(output.data); +}; + +const getStories = () => { + return supabase.from('stories').select('*').is('embedding', null); +}; + +const addStoryEmbedding = async story => { + const embedding = await generateEmbedding(story.title); + await supabase.from('stories').update({ embedding }).eq('id', story.id); + console.log('Generated embeddings for story: ', story.id); +}; + +const processAllStories = async () => { + const { data: stories } = await getStories(); + + if (!stories?.length) { + return; + } + await Promise.all(stories.map(story => addStoryEmbedding(story))); + processAllStories(); +}; + +processAllStories(); From 7de2046e5ca0fc2e96910289c7c6b7c7e34c5a7b Mon Sep 17 00:00:00 2001 From: Kyle Ramachandran Date: Mon, 15 Apr 2024 16:30:59 -0700 Subject: [PATCH 2/6] working on recently viewed --- src/app/(tabs)/home/index.tsx | 42 +++++++++++++++++++++++++++++++--- src/queries/recommendations.js | 42 ---------------------------------- src/queries/stories.tsx | 35 ++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 47 deletions(-) delete mode 100644 src/queries/recommendations.js diff --git a/src/app/(tabs)/home/index.tsx b/src/app/(tabs)/home/index.tsx index 871b0ee..e7cc41b 100644 --- a/src/app/(tabs)/home/index.tsx +++ b/src/app/(tabs)/home/index.tsx @@ -7,6 +7,7 @@ import styles from './styles'; import Icon from '../../../../assets/icons'; import ContentCard from '../../../components/ContentCard/ContentCard'; import PreviewCard from '../../../components/PreviewCard/PreviewCard'; +import AsyncStorage from '@react-native-async-storage/async-storage'; import { fetchUsername } from '../../../queries/profiles'; import { fetchFeaturedStoriesDescription, @@ -14,7 +15,7 @@ import { fetchNewStories, fetchRecommendedStories, } from '../../../queries/stories'; -import { StoryCard, StoryPreview } from '../../../queries/types'; +import { StoryCard, StoryPreview, Story } from '../../../queries/types'; import globalStyles from '../../../styles/globalStyles'; import { useSession } from '../../../utils/AuthContext'; @@ -23,12 +24,33 @@ function HomeScreen() { const [username, setUsername] = useState(''); const [loading, setLoading] = useState(true); const [featuredStories, setFeaturedStories] = useState([]); + const [recentlyViewed, setRecentlyViewed] = useState([]); const [featuredStoriesDescription, setFeaturedStoriesDescription] = useState(''); const [recommendedStories, setRecommendedStories] = useState([]); const [newStories, setNewStories] = useState([]); + const setRecentStory = async (recentStories: StoryPreview[]) => { + try { + const jsonValue = JSON.stringify(recentStories); + await AsyncStorage.setItem('GWN_RECENT_STORIES_ARRAY', jsonValue); + } catch (error) { + console.log(error); + } + }; + useEffect(() => { + const getRecentStory = async () => { + try { + const jsonValue = await AsyncStorage.getItem( + 'GWN_RECENT_STORIES_ARRAY', + ); + return jsonValue != null ? JSON.parse(jsonValue) : []; + } catch (error) { + console.log(error); + } + }; + (async () => { const [ usernameResponse, @@ -36,24 +58,38 @@ function HomeScreen() { featuredStoryDescriptionResponse, recommendedStoriesResponse, newStoriesResponse, + recentStoryResponse, ] = await Promise.all([ fetchUsername(user?.id).catch(() => ''), fetchFeaturedStoryPreviews().catch(() => []), fetchFeaturedStoriesDescription().catch(() => ''), - fetchRecommendedStories().catch(() => []), + fetchRecommendedStories(recentlyViewed).catch(() => []), fetchNewStories().catch(() => []), + getRecentStory(), ]); - setUsername(usernameResponse); setFeaturedStories(featuredStoryResponse); setFeaturedStoriesDescription(featuredStoryDescriptionResponse); setRecommendedStories(recommendedStoriesResponse); setNewStories(newStoriesResponse); + setRecentlyViewed(recentStoryResponse); })().finally(() => { setLoading(false); + async () => { + const recommendedStoriesResponse = await fetchRecommendedStories( + recentlyViewed, + ).catch(() => []); + setRecommendedStories(recommendedStoriesResponse); + }; }); }, [user]); + // useEffect(() => { + // (async () => { + + // }) + // }, [recentlyViewed]) + return ( { - await pipeline('feature-extraction', 'Supabase/gte-small'); -}; - -// Generate the embedding from the user input -const generateEmbedding = async text => { - const output = await pipe(text, { - pooling: 'mean', - normalize: true, - }); - - // Extract the embedding output - return Array.from(output.data); -}; - -const getStories = () => { - return supabase.from('stories').select('*').is('embedding', null); -}; - -const addStoryEmbedding = async story => { - const embedding = await generateEmbedding(story.title); - await supabase.from('stories').update({ embedding }).eq('id', story.id); - console.log('Generated embeddings for story: ', story.id); -}; - -const processAllStories = async () => { - const { data: stories } = await getStories(); - - if (!stories?.length) { - return; - } - await Promise.all(stories.map(story => addStoryEmbedding(story))); - processAllStories(); -}; - -processAllStories(); diff --git a/src/queries/stories.tsx b/src/queries/stories.tsx index 86747ad..c2fee41 100644 --- a/src/queries/stories.tsx +++ b/src/queries/stories.tsx @@ -1,5 +1,7 @@ import { Story, StoryPreview, StoryCard } from './types'; +import AsyncStorage from '@react-native-async-storage/async-storage'; import supabase from '../utils/supabase'; +import { useState } from 'react'; export async function fetchAllStoryPreviews(): Promise { const { data, error } = await supabase.rpc('fetch_all_story_previews'); @@ -57,8 +59,37 @@ export async function fetchFeaturedStoriesDescription(): Promise { } } -export async function fetchRecommendedStories(): Promise { - const { data, error } = await supabase.rpc('fetch_recommended_stories'); +export async function fetchRecommendedStories( + recentlyViewed: StoryCard[], +): Promise { + const recentlyViewedID = recentlyViewed[0].id; //change to take in multiple stories + + const getStoryEmbedding = async () => { + const { data } = await supabase + .from('stories') + .select('embedding') + .eq('id', recentlyViewedID); + + if (error) { + console.log(error); + throw new Error( + `An error occured when trying to fetch embeddings: ${error.details}`, + ); + } else { + if (data) return data[0].embedding as number; + } + }; + + const embedding = await getStoryEmbedding(); + + const { data, error } = await supabase.rpc( + 'fetch_users_recommended_stories', + { + query_embedding: embedding, + match_threshold: 0.0, + match_count: 5, + }, + ); if (error) { console.log(error); From 7b9de74ce60548446e65d2c4c8057659246305ab Mon Sep 17 00:00:00 2001 From: Kyle Ramachandran Date: Tue, 16 Apr 2024 13:08:01 -0700 Subject: [PATCH 3/6] recommended stories bug --- src/app/(tabs)/home/index.tsx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/app/(tabs)/home/index.tsx b/src/app/(tabs)/home/index.tsx index e7cc41b..ec1db18 100644 --- a/src/app/(tabs)/home/index.tsx +++ b/src/app/(tabs)/home/index.tsx @@ -75,21 +75,12 @@ function HomeScreen() { setRecentlyViewed(recentStoryResponse); })().finally(() => { setLoading(false); - async () => { - const recommendedStoriesResponse = await fetchRecommendedStories( - recentlyViewed, - ).catch(() => []); - setRecommendedStories(recommendedStoriesResponse); - }; }); }, [user]); - // useEffect(() => { - // (async () => { - - // }) - // }, [recentlyViewed]) + useEffect(() => {}, []); + console.log(recommendedStories); return ( Date: Tue, 16 Apr 2024 13:31:47 -0700 Subject: [PATCH 4/6] fix(recommendations): uses query response directly for recommendations --- src/app/(tabs)/home/index.tsx | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/app/(tabs)/home/index.tsx b/src/app/(tabs)/home/index.tsx index ec1db18..4dd6424 100644 --- a/src/app/(tabs)/home/index.tsx +++ b/src/app/(tabs)/home/index.tsx @@ -1,3 +1,4 @@ +import AsyncStorage from '@react-native-async-storage/async-storage'; import { router } from 'expo-router'; import { useEffect, useState } from 'react'; import { Pressable, ScrollView, Text, View } from 'react-native'; @@ -7,7 +8,6 @@ import styles from './styles'; import Icon from '../../../../assets/icons'; import ContentCard from '../../../components/ContentCard/ContentCard'; import PreviewCard from '../../../components/PreviewCard/PreviewCard'; -import AsyncStorage from '@react-native-async-storage/async-storage'; import { fetchUsername } from '../../../queries/profiles'; import { fetchFeaturedStoriesDescription, @@ -51,28 +51,40 @@ function HomeScreen() { } }; + const getRecommendedStories = async () => { + const recentStoryResponse = await getRecentStory(); + // console.log('recentStoryResponse', recentStoryResponse); + // setRecentlyViewed(recentStoryResponse); + // console.log('state: recentlyViewed', recentlyViewed); + const recommendedStoriesResponse = + await fetchRecommendedStories(recentStoryResponse); + setRecommendedStories(recommendedStoriesResponse); + // return recommendedStoriesResponse; + }; + (async () => { const [ usernameResponse, featuredStoryResponse, featuredStoryDescriptionResponse, - recommendedStoriesResponse, + // recommendedStoriesResponse, newStoriesResponse, - recentStoryResponse, + // recentStoryResponse, ] = await Promise.all([ fetchUsername(user?.id).catch(() => ''), fetchFeaturedStoryPreviews().catch(() => []), fetchFeaturedStoriesDescription().catch(() => ''), - fetchRecommendedStories(recentlyViewed).catch(() => []), + // fetchRecommendedStories(recentlyViewed).catch(() => []), // need to set recentlyViewed before fetchNewStories().catch(() => []), - getRecentStory(), + // getRecentStory(), ]); setUsername(usernameResponse); setFeaturedStories(featuredStoryResponse); setFeaturedStoriesDescription(featuredStoryDescriptionResponse); - setRecommendedStories(recommendedStoriesResponse); + // setRecommendedStories(recommendedStoriesResponse); setNewStories(newStoriesResponse); - setRecentlyViewed(recentStoryResponse); + // setRecentlyViewed(recentStoryResponse); + await getRecommendedStories(); })().finally(() => { setLoading(false); }); @@ -80,7 +92,7 @@ function HomeScreen() { useEffect(() => {}, []); - console.log(recommendedStories); + // console.log(recommendedStories); return ( Date: Sat, 20 Apr 2024 13:42:00 -0700 Subject: [PATCH 5/6] finished implementing recommendation alg --- src/app/(tabs)/home/index.tsx | 96 ++++++++++++++++++++--------------- src/queries/stories.tsx | 87 +++++++++++++++++++++++-------- 2 files changed, 121 insertions(+), 62 deletions(-) diff --git a/src/app/(tabs)/home/index.tsx b/src/app/(tabs)/home/index.tsx index 4dd6424..01eee5c 100644 --- a/src/app/(tabs)/home/index.tsx +++ b/src/app/(tabs)/home/index.tsx @@ -14,6 +14,7 @@ import { fetchFeaturedStoryPreviews, fetchNewStories, fetchRecommendedStories, + fetchStoryPreviewById, } from '../../../queries/stories'; import { StoryCard, StoryPreview, Story } from '../../../queries/types'; import globalStyles from '../../../styles/globalStyles'; @@ -30,7 +31,16 @@ function HomeScreen() { const [recommendedStories, setRecommendedStories] = useState([]); const [newStories, setNewStories] = useState([]); - const setRecentStory = async (recentStories: StoryPreview[]) => { + const getRecentStory = async () => { + try { + const jsonValue = await AsyncStorage.getItem('GWN_RECENT_STORIES_ARRAY'); + return jsonValue != null ? JSON.parse(jsonValue) : []; + } catch (error) { + console.log(error); + } + }; + + const setRecentStory = async (recentStories: StoryCard[]) => { try { const jsonValue = JSON.stringify(recentStories); await AsyncStorage.setItem('GWN_RECENT_STORIES_ARRAY', jsonValue); @@ -39,27 +49,50 @@ function HomeScreen() { } }; - useEffect(() => { - const getRecentStory = async () => { - try { - const jsonValue = await AsyncStorage.getItem( - 'GWN_RECENT_STORIES_ARRAY', - ); - return jsonValue != null ? JSON.parse(jsonValue) : []; - } catch (error) { - console.log(error); + const handleStoryPreviewPressed = (story: StoryPreview) => { + recentlyViewedStacking(story); + router.push({ + pathname: '/story', + params: { storyId: story.id.toString() }, + }); + }; + + const handleStoryCardPressed = async (story: StoryCard) => { + const newStoryArray = await fetchStoryPreviewById(story.id); + recentlyViewedStacking(newStoryArray[0]); + router.push({ + pathname: '/story', + params: { storyId: story.id.toString() }, + }); + }; + + const recentlyViewedStacking = async (story: StoryPreview) => { + const maxArrayLength = 5; + const newRecentlyViewed = [...recentlyViewed]; + + for (let i = 0; i < recentlyViewed.length; i++) { + if (story.id === recentlyViewed[i].id) { + newRecentlyViewed.splice(i, 1); + break; } - }; + } + + if (newRecentlyViewed.length >= maxArrayLength) { + newRecentlyViewed.splice(-1, 1); + } + newRecentlyViewed.splice(0, 0, story); + + setRecentStory(newRecentlyViewed); + setRecentlyViewed(newRecentlyViewed); + }; + + useEffect(() => { const getRecommendedStories = async () => { const recentStoryResponse = await getRecentStory(); - // console.log('recentStoryResponse', recentStoryResponse); - // setRecentlyViewed(recentStoryResponse); - // console.log('state: recentlyViewed', recentlyViewed); const recommendedStoriesResponse = await fetchRecommendedStories(recentStoryResponse); setRecommendedStories(recommendedStoriesResponse); - // return recommendedStoriesResponse; }; (async () => { @@ -67,32 +100,26 @@ function HomeScreen() { usernameResponse, featuredStoryResponse, featuredStoryDescriptionResponse, - // recommendedStoriesResponse, newStoriesResponse, - // recentStoryResponse, + recentStoryResponse, ] = await Promise.all([ fetchUsername(user?.id).catch(() => ''), fetchFeaturedStoryPreviews().catch(() => []), fetchFeaturedStoriesDescription().catch(() => ''), - // fetchRecommendedStories(recentlyViewed).catch(() => []), // need to set recentlyViewed before fetchNewStories().catch(() => []), - // getRecentStory(), + getRecentStory(), ]); setUsername(usernameResponse); setFeaturedStories(featuredStoryResponse); setFeaturedStoriesDescription(featuredStoryDescriptionResponse); - // setRecommendedStories(recommendedStoriesResponse); setNewStories(newStoriesResponse); - // setRecentlyViewed(recentStoryResponse); + setRecentlyViewed(recentStoryResponse); await getRecommendedStories(); })().finally(() => { setLoading(false); }); }, [user]); - useEffect(() => {}, []); - - // console.log(recommendedStories); return ( - router.push({ - pathname: '/story', - params: { storyId: story.id.toString() }, - }) - } + pressFunction={() => handleStoryPreviewPressed(story)} /> ))} @@ -164,12 +186,7 @@ function HomeScreen() { title={story.title} author={story.author_name} authorImage={story.author_image} - pressFunction={() => - router.push({ - pathname: '/story', - params: { storyId: story.id.toString() }, - }) - } + pressFunction={() => handleStoryCardPressed(story)} image={story.featured_media} /> ))} @@ -193,12 +210,7 @@ function HomeScreen() { title={story.title} author={story.author_name} authorImage={story.author_image} - pressFunction={() => - router.push({ - pathname: '/story', - params: { storyId: story.id.toString() }, - }) - } + pressFunction={() => handleStoryCardPressed(story)} image={story.featured_media} /> ))} diff --git a/src/queries/stories.tsx b/src/queries/stories.tsx index c2fee41..209b301 100644 --- a/src/queries/stories.tsx +++ b/src/queries/stories.tsx @@ -60,34 +60,81 @@ export async function fetchFeaturedStoriesDescription(): Promise { } export async function fetchRecommendedStories( - recentlyViewed: StoryCard[], -): Promise { - const recentlyViewedID = recentlyViewed[0].id; //change to take in multiple stories - - const getStoryEmbedding = async () => { - const { data } = await supabase - .from('stories') - .select('embedding') - .eq('id', recentlyViewedID); - - if (error) { - console.log(error); - throw new Error( - `An error occured when trying to fetch embeddings: ${error.details}`, - ); - } else { - if (data) return data[0].embedding as number; - } + inputStories: StoryPreview[], +): Promise { + if (inputStories.length == 0) { + return []; + } + const storyIDs = inputStories.map(story => story.id); + + //fill storyIDs with 0's if less than 5 ids + for (let n = storyIDs.length; n < 5; n++) { + storyIDs[n] = 0; + } + + //get embedding vectors for each of the inputs + const getStoryEmbeddings = async () => { + const embeddings = inputStories.map(async story => { + const { data, error } = await supabase + .from('stories') + .select('embedding') + .eq('id', story.id); + + if (error) { + console.log(error); + throw new Error( + `An error occured when trying to fetch embeddings: ${error.details}`, + ); + } else { + if (data) { + return data[0].embedding as string; + } + } + }); + + return await Promise.all(embeddings); }; - const embedding = await getStoryEmbedding(); + //get embeddings of every story in inputStory + const embeddingsArray = await getStoryEmbeddings(); + const newEmbeddingsArray = []; + for (let k = 0; k < embeddingsArray.length; k++) { + const stringLength = embeddingsArray[k]?.length; + if (stringLength) { + const embedding = embeddingsArray[k]?.substring(1, stringLength - 1); + const formattedEmbedding = embedding?.split(','); + newEmbeddingsArray[k] = formattedEmbedding; + } + } + const embeddingsLength = + newEmbeddingsArray.length > 5 ? 5 : newEmbeddingsArray.length; + + //calculate average embedding vector + const averageEmbedding: number[] = []; + for (let m = 0; m < 384; m++) { + averageEmbedding[m] = 0; + } + for (let i = 0; i < embeddingsLength; i++) { + const vector = newEmbeddingsArray[i]; + if (vector) { + for (let j = 0; j < vector.length; j++) { + const element = parseFloat(vector[j]); + averageEmbedding[j] += element / embeddingsLength; + } + } + } const { data, error } = await supabase.rpc( 'fetch_users_recommended_stories', { - query_embedding: embedding, + query_embedding: averageEmbedding, match_threshold: 0.0, match_count: 5, + storyid1: storyIDs[0], + storyid2: storyIDs[1], + storyid3: storyIDs[2], + storyid4: storyIDs[3], + storyid5: storyIDs[4], }, ); From 66542403a6f2135a2212265cbe6eeada6d744bdb Mon Sep 17 00:00:00 2001 From: Aditya Pawar Date: Sun, 21 Apr 2024 14:59:16 -0700 Subject: [PATCH 6/6] Small merge changes --- src/app/(tabs)/home/index.tsx | 5 ++++- src/queries/savedStories.tsx | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/(tabs)/home/index.tsx b/src/app/(tabs)/home/index.tsx index 47b29a0..ddca1a3 100644 --- a/src/app/(tabs)/home/index.tsx +++ b/src/app/(tabs)/home/index.tsx @@ -22,7 +22,7 @@ import { fetchRecommendedStories, fetchStoryPreviewById, } from '../../../queries/stories'; -import { StoryCard, StoryPreview, Story } from '../../../queries/types'; +import { StoryCard, StoryPreview } from '../../../queries/types'; import globalStyles from '../../../styles/globalStyles'; import { useSession } from '../../../utils/AuthContext'; @@ -96,6 +96,7 @@ function HomeScreen() { useEffect(() => { const getRecommendedStories = async () => { const recentStoryResponse = await getRecentStory(); + const recommendedStoriesResponse = await fetchRecommendedStories(recentStoryResponse); setRecommendedStories(recommendedStoriesResponse); @@ -191,6 +192,7 @@ function HomeScreen() { {recommendedStories.map(story => ( ( { let { data, error } = await supabase.rpc('is_story_saved_for_user', { - list_name: 'reading list', + list_name: SavedList.READING_LIST, story_db_id: storyId, user_uuid: userId, });