diff --git a/src/Apps/InfiniteDiscovery/InfiniteDiscoveryApp.tsx b/src/Apps/InfiniteDiscovery/InfiniteDiscoveryApp.tsx new file mode 100644 index 00000000000..ce27d851dee --- /dev/null +++ b/src/Apps/InfiniteDiscovery/InfiniteDiscoveryApp.tsx @@ -0,0 +1,401 @@ +import { + Button, + Checkbox, + Expandable, + Flex, + Input, + Label, + Separator, + Text, +} from "@artsy/palette" +import { sampleSize } from "lodash" +import React, { useEffect } from "react" + +const buildMetaphysicsQuery = ( + likedArtworks, + dismissedArtworks, + weight, + artworksCountForTaste = 3, + mltFields = [], + artworksLimit, +) => { + const likedArtworkIds = likedArtworks.map(artwork => artwork.id) + const dismissedArtworkIds = dismissedArtworks.map(artwork => artwork.id) + + const variables = { + osWeights: weight, + likedArtworkIds: + likedArtworkIds.length > artworksCountForTaste - 1 + ? likedArtworkIds.slice(-artworksCountForTaste) + : [], + excludeArtworkIds: + likedArtworkIds.length < artworksCountForTaste + ? [...likedArtworkIds, ...dismissedArtworkIds] + : // split artworks after the last artworksCountForTaste liked artwork + [ + ...likedArtworkIds.slice(0, -artworksCountForTaste), + ...dismissedArtworkIds, + ], + ...(mltFields.length > 0 && { mltFields }), + limit: artworksLimit, + } + + return { + query: ` + query InfiniteDiscoveryAppQuery($likedArtworkIds: [String], $excludeArtworkIds: [String], $osWeights: [Float], $mltFields: [String], $limit: Int) { + discoverArtworks( + osWeights: $osWeights, + likedArtworkIds: $likedArtworkIds, + excludeArtworkIds: $excludeArtworkIds, + mltFields: $mltFields, + limit: $limit + ) { + edges { + node { + id: internalID + title + artistNames + medium + image { + url + } + } + } + } + } + `, + variables, + } +} + +const request = async (url, opts) => { + try { + const options: RequestInit = { + method: opts.method || "POST", + headers: { + "Content-Type": "application/json", + "Cache-Control": "no-cache", + "X-Access-Token": window.sd.CURRENT_USER.accessToken, + "X-User-Id": window.sd.CURRENT_USER.id, + }, + body: opts.body, + } + + const response = await fetch(url, options) + + if (!response?.ok) { + throw new Error(`Response status: ${response.status}`) + } + + const json = await response.json() + return json + } catch (error) { + console.log("Error fetching data") + console.error(error.message) + } +} + +export const InfiniteDiscoveryApp = () => { + const [artworks, setArtworks] = React.useState([]) as any + const [likedArtworks, setLikedArtworks] = React.useState([]) as any + const [dismissedArtworks, setDismissedArtworks] = React.useState([]) as any + const [loading, setLoading] = React.useState(false) + const [mltWeight, setMltWeight] = React.useState(0.6) + const [knnWeight, setKnnWeight] = React.useState(0.4) + const [tasteArtworks, setTasteArtworks] = React.useState(3) + const [mltFields, setMltFields] = React.useState([ + "genes", + "materials", + "tags", + "medium", + ]) + const [artworksLimit, setArtworksLimit] = React.useState(5) + + const onLike = artwork => { + setLikedArtworks([...likedArtworks, artwork]) + } + + const onDismiss = artwork => { + setDismissedArtworks([...dismissedArtworks, artwork]) + } + + const handleCheckboxChange = field => { + setMltFields(prevFields => { + const updatedFields = prevFields.includes(field) + ? prevFields.filter(f => f !== field) + : [...prevFields, field] + return updatedFields + }) + } + + const initialArtworks = async () => { + const response = await request("https://metaphysics-staging.artsy.net/v2", { + body: JSON.stringify( + buildMetaphysicsQuery( + likedArtworks, + dismissedArtworks, + [0.6, 0.4], + tasteArtworks, + mltFields as any, + artworksLimit, + ), + ), + }) + + const artworks = response?.data?.discoverArtworks?.edges.map( + edge => edge.node, + ) + setArtworks(sampleSize(artworks, 10)) + setLoading(false) + } + + const submitSearch = async () => { + setLoading(true) + + // continue showing curated artworks if liked artworks are less than 3 + if (likedArtworks.length < 3) { + return initialArtworks() + } + + const response = await request("https://metaphysics-staging.artsy.net/v2", { + body: JSON.stringify( + buildMetaphysicsQuery( + likedArtworks, + dismissedArtworks, + [mltWeight, knnWeight], + tasteArtworks, + mltFields as any, + artworksLimit, + ), + ), + }) + + const artworks = response?.data?.discoverArtworks?.edges.map( + edge => edge.node, + ) + setArtworks(artworks) + setLoading(false) + } + + useEffect(() => { + initialArtworks() + }, []) // eslint-disable-line + + if (artworks.length === 0) { + return