From 17ac2288ab5b627c4a958f0bb363b0c7543e6db2 Mon Sep 17 00:00:00 2001 From: Raghart Date: Thu, 2 Apr 2026 11:56:40 -0400 Subject: [PATCH 1/5] r added another compact subscription to check if it works in prod --- backend/src/songs/songs.resolver.ts | 11 +++++++ .../src/components/Utils/hooks/useSongRec.tsx | 30 +++++++++---------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/backend/src/songs/songs.resolver.ts b/backend/src/songs/songs.resolver.ts index 3e38f84..525bda2 100644 --- a/backend/src/songs/songs.resolver.ts +++ b/backend/src/songs/songs.resolver.ts @@ -31,6 +31,17 @@ export class SongsResolver { return this.songsService.getSongData(songID); } + @Subscription(() => String, { resolve: (payload) => payload.aiResponse, }) + async *responseSub( + @Args('genres', { type: () => [String], defaultValue: ["Rock"] } ) genres: string[], + @Args('userVector', { type: () => [Float], defaultValue: USER_VECTOR }) userVector: number[], + ) { + const aiStream = await this.songsService.getAIStream(genres, userVector); + for await (const chunk of aiStream) { + yield { aiResponse: chunk.text }; + } + } + @Subscription(() => String) aiResponse() { return this.pubSub.asyncIterableIterator('AI_RESPONSE') diff --git a/frontend/src/components/Utils/hooks/useSongRec.tsx b/frontend/src/components/Utils/hooks/useSongRec.tsx index 3ca0823..cbb641b 100644 --- a/frontend/src/components/Utils/hooks/useSongRec.tsx +++ b/frontend/src/components/Utils/hooks/useSongRec.tsx @@ -8,15 +8,11 @@ const useSongRec = () => { const hasFetched = useRef(false); const [visibleCount, setVisibleCount] = useState(20); const [aiResponse, setAIResponse] = useState(""); - const [isSub, setIsSub] = useState(false); - const [streamAnswer] = useMutation(streamAIAnswer); - const { genres, energy, speechLevel, danceability, tempo, sentiment, voiceType, - mood, acousticness } = useAppSelector(state => state.songData); - const recommendations = useAppSelector(state => state.songData.results); - const visibleSongs = recommendations.slice(0, visibleCount); - const userVector = generateUserVector(tempo, danceability, energy, mood, speechLevel, - acousticness, voiceType, sentiment); - + const [streamAnswer, { called }] = useMutation(streamAIAnswer, { + onCompleted() { + console.log("mutation completed!") + } + }); const { loading } = useSubscription(aiSubscription, { onData({ data }) { const chunkText = data.data.aiResponse; @@ -24,19 +20,21 @@ const useSongRec = () => { setAIResponse(prev => prev + chunkText) }, }); + + const { genres, energy, speechLevel, danceability, tempo, sentiment, voiceType, + mood, acousticness } = useAppSelector(state => state.songData); + const recommendations = useAppSelector(state => state.songData.results); + const visibleSongs = recommendations.slice(0, visibleCount); + const userVector = generateUserVector(tempo, danceability, energy, mood, speechLevel, + acousticness, voiceType, sentiment); useEffect(() => { - const timer = setTimeout(() => setIsSub(false), 500); - return () => clearTimeout(timer) - }, []) - - useEffect(() => { - if (hasFetched.current || !loading || !isSub) return; + if (hasFetched.current || !loading || called) return; hasFetched.current = true; setAIResponse(""); console.log("using stream answer!") streamAnswer({ variables: { genres, userVector } }); - }, [genres, userVector, streamAnswer, loading, isSub]); + }, [genres, userVector, streamAnswer, loading]); const loadMoreSongs = () => { if (visibleSongs.length < recommendations.length) { From af5642391dbadbc4b6f5e3ca045995d5070c72c3 Mon Sep 17 00:00:00 2001 From: Raghart Date: Thu, 2 Apr 2026 12:00:17 -0400 Subject: [PATCH 2/5] r added query sub query to front --- frontend/src/queries/LaraRecQuerie.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/src/queries/LaraRecQuerie.ts b/frontend/src/queries/LaraRecQuerie.ts index 4ccc6b1..fdfee05 100644 --- a/frontend/src/queries/LaraRecQuerie.ts +++ b/frontend/src/queries/LaraRecQuerie.ts @@ -18,6 +18,12 @@ subscription { } `; +export const responseSub = gql` +subscription GetAIResponse($genres: [String!], $userVector: [Float!]) { + responseSub(genres: $genres, userVector: $userVector) +} +`; + export const streamAIAnswer = gql` mutation streamResponse($genres: [String!], $userVector: [Float!]) { streamAIResponse(genres: $genres, userVector: $userVector) From 47474770e7d7bc5beb74f69d4aac1c007b5011e0 Mon Sep 17 00:00:00 2001 From: Raghart Date: Thu, 2 Apr 2026 12:10:04 -0400 Subject: [PATCH 3/5] r implemmented compact sub async generator method --- .../src/components/Utils/hooks/useSongRec.tsx | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/Utils/hooks/useSongRec.tsx b/frontend/src/components/Utils/hooks/useSongRec.tsx index cbb641b..318ad85 100644 --- a/frontend/src/components/Utils/hooks/useSongRec.tsx +++ b/frontend/src/components/Utils/hooks/useSongRec.tsx @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from "react"; import { useAppSelector } from "../redux-hooks"; -import { aiSubscription, streamAIAnswer } from "@/queries/LaraRecQuerie"; +import { aiSubscription, responseSub, streamAIAnswer } from "@/queries/LaraRecQuerie"; import { useMutation, useSubscription } from "@apollo/client"; import generateUserVector from "../generateUserVector"; @@ -8,6 +8,20 @@ const useSongRec = () => { const hasFetched = useRef(false); const [visibleCount, setVisibleCount] = useState(20); const [aiResponse, setAIResponse] = useState(""); + const { genres, energy, speechLevel, danceability, tempo, sentiment, voiceType, + mood, acousticness } = useAppSelector(state => state.songData); + const userVector = generateUserVector(tempo, danceability, energy, mood, speechLevel, + acousticness, voiceType, sentiment); + + useSubscription(responseSub, { + variables: { genres, userVector }, + onData({ data }) { + console.log(data) + const chunkText = data.data.responseSub; + setAIResponse(prev => prev + chunkText); + } + }); + /* const [streamAnswer, { called }] = useMutation(streamAIAnswer, { onCompleted() { console.log("mutation completed!") @@ -20,14 +34,11 @@ const useSongRec = () => { setAIResponse(prev => prev + chunkText) }, }); - - const { genres, energy, speechLevel, danceability, tempo, sentiment, voiceType, - mood, acousticness } = useAppSelector(state => state.songData); + */ const recommendations = useAppSelector(state => state.songData.results); const visibleSongs = recommendations.slice(0, visibleCount); - const userVector = generateUserVector(tempo, danceability, energy, mood, speechLevel, - acousticness, voiceType, sentiment); + /* useEffect(() => { if (hasFetched.current || !loading || called) return; hasFetched.current = true; @@ -35,6 +46,7 @@ const useSongRec = () => { console.log("using stream answer!") streamAnswer({ variables: { genres, userVector } }); }, [genres, userVector, streamAnswer, loading]); + */ const loadMoreSongs = () => { if (visibleSongs.length < recommendations.length) { From e3a314f4fe650308bbe82c035eb751a33489de9d Mon Sep 17 00:00:00 2001 From: Raghart Date: Thu, 2 Apr 2026 12:12:09 -0400 Subject: [PATCH 4/5] r deleted old front data --- .../src/components/Utils/hooks/useSongRec.tsx | 32 +++---------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/frontend/src/components/Utils/hooks/useSongRec.tsx b/frontend/src/components/Utils/hooks/useSongRec.tsx index 318ad85..b8a72d6 100644 --- a/frontend/src/components/Utils/hooks/useSongRec.tsx +++ b/frontend/src/components/Utils/hooks/useSongRec.tsx @@ -1,11 +1,10 @@ -import { useEffect, useRef, useState } from "react"; +import { useState } from "react"; import { useAppSelector } from "../redux-hooks"; -import { aiSubscription, responseSub, streamAIAnswer } from "@/queries/LaraRecQuerie"; -import { useMutation, useSubscription } from "@apollo/client"; +import { responseSub } from "@/queries/LaraRecQuerie"; +import { useSubscription } from "@apollo/client"; import generateUserVector from "../generateUserVector"; const useSongRec = () => { - const hasFetched = useRef(false); const [visibleCount, setVisibleCount] = useState(20); const [aiResponse, setAIResponse] = useState(""); const { genres, energy, speechLevel, danceability, tempo, sentiment, voiceType, @@ -21,33 +20,10 @@ const useSongRec = () => { setAIResponse(prev => prev + chunkText); } }); - /* - const [streamAnswer, { called }] = useMutation(streamAIAnswer, { - onCompleted() { - console.log("mutation completed!") - } - }); - const { loading } = useSubscription(aiSubscription, { - onData({ data }) { - const chunkText = data.data.aiResponse; - console.log(chunkText); - setAIResponse(prev => prev + chunkText) - }, - }); - */ + const recommendations = useAppSelector(state => state.songData.results); const visibleSongs = recommendations.slice(0, visibleCount); - /* - useEffect(() => { - if (hasFetched.current || !loading || called) return; - hasFetched.current = true; - setAIResponse(""); - console.log("using stream answer!") - streamAnswer({ variables: { genres, userVector } }); - }, [genres, userVector, streamAnswer, loading]); - */ - const loadMoreSongs = () => { if (visibleSongs.length < recommendations.length) { setVisibleCount(prev => prev + 20); From 99e964ed78aa5a2ccfdb472c0f3ecbee8f9907de Mon Sep 17 00:00:00 2001 From: Raghart Date: Thu, 2 Apr 2026 12:17:08 -0400 Subject: [PATCH 5/5] r fixing back lint issues --- backend/src/songs/songs.resolver.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/songs/songs.resolver.ts b/backend/src/songs/songs.resolver.ts index 525bda2..ff55adc 100644 --- a/backend/src/songs/songs.resolver.ts +++ b/backend/src/songs/songs.resolver.ts @@ -31,11 +31,11 @@ export class SongsResolver { return this.songsService.getSongData(songID); } - @Subscription(() => String, { resolve: (payload) => payload.aiResponse, }) + @Subscription(() => String, { resolve: (payload: { aiResponse: string | undefined }) => payload.aiResponse, }) async *responseSub( @Args('genres', { type: () => [String], defaultValue: ["Rock"] } ) genres: string[], @Args('userVector', { type: () => [Float], defaultValue: USER_VECTOR }) userVector: number[], - ) { + ) : AsyncGenerator<{ aiResponse: string | undefined }> { const aiStream = await this.songsService.getAIStream(genres, userVector); for await (const chunk of aiStream) { yield { aiResponse: chunk.text };