From 506a98cb7d25c8179d3a7759a8f752241a6a1110 Mon Sep 17 00:00:00 2001 From: reng Date: Tue, 23 Dec 2025 12:49:59 +0800 Subject: [PATCH] update --- v2/app/package-lock.json | 7 +++ v2/app/package.json | 1 + v2/app/src/components/graph.jsx | 57 ++++++++++--------- v2/app/src/components/point.jsx | 99 +++++++++++++++++++++++++++++++++ v2/app/src/utils/draw.js | 25 +++++++++ v2/app/src/utils/parsing.js | 2 +- 6 files changed, 164 insertions(+), 27 deletions(-) create mode 100644 v2/app/src/components/point.jsx diff --git a/v2/app/package-lock.json b/v2/app/package-lock.json index 1a193d1..b7c63f6 100644 --- a/v2/app/package-lock.json +++ b/v2/app/package-lock.json @@ -15,6 +15,7 @@ "@tauri-apps/plugin-fs": "^2.4.4", "@tauri-apps/plugin-http": "^2.5.4", "@tauri-apps/plugin-opener": "^2", + "gsap": "^3.14.2", "html-to-text": "^9.0.5", "react": "^19.1.0", "react-dom": "^19.1.0", @@ -2302,6 +2303,12 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, + "node_modules/gsap": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.14.2.tgz", + "integrity": "sha512-P8/mMxVLU7o4+55+1TCnQrPmgjPKnwkzkXOK1asnR9Jg2lna4tEY5qBJjMmAaOBDDZWtlRjBXjLa0w53G/uBLA==", + "license": "Standard 'no charge' license: https://gsap.com/standard-license." + }, "node_modules/hls.js": { "version": "1.6.15", "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.15.tgz", diff --git a/v2/app/package.json b/v2/app/package.json index 643c98c..55288fe 100644 --- a/v2/app/package.json +++ b/v2/app/package.json @@ -17,6 +17,7 @@ "@tauri-apps/plugin-fs": "^2.4.4", "@tauri-apps/plugin-http": "^2.5.4", "@tauri-apps/plugin-opener": "^2", + "gsap": "^3.14.2", "html-to-text": "^9.0.5", "react": "^19.1.0", "react-dom": "^19.1.0", diff --git a/v2/app/src/components/graph.jsx b/v2/app/src/components/graph.jsx index 40a066e..592c80f 100644 --- a/v2/app/src/components/graph.jsx +++ b/v2/app/src/components/graph.jsx @@ -1,15 +1,18 @@ import { Canvas } from '@react-three/fiber' -import * as THREE from 'three'; + import { useEffect, useState } from 'react' -import { get3dCoordinates } from '../utils/draw'; -import { Box, Html, OrbitControls, PerspectiveCamera, Bounds, useBounds } from '@react-three/drei' +import { generateLinesFromPoints, get3dCoordinates } from '../utils/draw'; +import { OrbitControls, PerspectiveCamera, Bounds, useBounds, Line } from '@react-three/drei' +import Point from './point.jsx'; +import * as THREE from 'three'; -const PointScale=200; -const PointSize=6; export default function Graph({results}){ const [points, setPoints]=useState(); + const [lines, setLines]=useState(); + + const [showContent, setShowContent]=useState(false); const bounds = useBounds(); function zoomToFit(){ @@ -38,6 +41,11 @@ export default function Graph({results}){ get3dCoordinates(results.map(item=>item.vector)).then(newPoints=>{ console.log("3D Points:", newPoints); setPoints(newPoints); + + generateLinesFromPoints(newPoints).then(newLines=>{ + console.log("Lines:", newLines); + setLines(newLines); + }); }); @@ -45,7 +53,11 @@ export default function Graph({results}){ return (<> - +
+ setShowContent(e.target.checked)} /> + +
{/* */} @@ -56,29 +68,22 @@ export default function Graph({results}){ {Array.isArray(points) && points?.map((point, index)=>( - - - - -
-
{(()=>{
-                                    let p=JSON.parse(results[index].payload.text);  
-                                    return `${p.content}\nKeywords: ${p.keywords.join(", ")}`;
-                                })()}
-
- -
+ + ))} +
+ + + {Array.isArray(lines) && lines?.map((line, index)=>( + ))}
- {/* - - */} - {/* */}
) diff --git a/v2/app/src/components/point.jsx b/v2/app/src/components/point.jsx new file mode 100644 index 0000000..38350d7 --- /dev/null +++ b/v2/app/src/components/point.jsx @@ -0,0 +1,99 @@ +import { Html } from '@react-three/drei' +import { useEffect, useRef, useState } from 'react'; +import * as THREE from 'three'; +import gsap from 'gsap'; + + +export const PointScale=200; +const PointSize=6; + +const PointDuration=5; +const KeywordOffset=0; + +export default function Point({point, index, totalPoints, result, showContent}) { + + const [payload, setPayload]=useState(); + const [showPayload, setShowPayload]=useState(false); + + const meshRef=useRef(); + const refText=useRef(); + + useEffect(()=>{ + if(!payload) return; + const lifeTime=payload.number/payload.total; + console.log("Point lifeTime:", lifeTime); + + // animate point size based on lifeTime + const targetSize=PointSize *0.2; + const initialSize=0; + + const timeline=gsap.timeline({ repeat:-1}); + timeline.set(meshRef.current.scale, { + x: initialSize, y: initialSize, z: initialSize, + }); + timeline.set(refText.current, { + scale: initialSize, + opacity: 0, + }); + timeline.fromTo(meshRef.current.scale, { + x: initialSize, y: initialSize, z: initialSize, + }, { + x: PointSize, y: PointSize, z: PointSize, + duration:PointDuration, + delay: lifeTime *5, + ease: "power3.in", + onUpdate:()=>{ + if(refText.current){ + refText.current.style.transform=`scale(${meshRef.current.scale.x / PointSize})`; + refText.current.style.opacity=`${meshRef.current.scale.x / PointSize}`; + } + } + }); + timeline.to(meshRef.current.scale, { + x: targetSize, y: targetSize, z: targetSize, + duration:PointDuration, + ease: "power3.out", + onUpdate:()=>{ + if(refText.current){ + refText.current.style.transform=`scale(${meshRef.current.scale.x / PointSize})`; + refText.current.style.opacity=`${meshRef.current.scale.x / PointSize}`; + } + } + }); + + timeline.play(); + + return ()=>{ + timeline.kill(); + }; + + },[payload]); + + useEffect(()=>{ + + setPayload(JSON.parse(result.payload.text)); + + },[point]); + + + return ( + + + + +
+
+ {payload?.keywords.map((el, index)=>{el})} +
+ {showContent &&
{(()=>{
+                        return `${payload?.content}`;
+                    })()}
} +
+ +
+ ) +} \ No newline at end of file diff --git a/v2/app/src/utils/draw.js b/v2/app/src/utils/draw.js index dc68fec..8877fcf 100644 --- a/v2/app/src/utils/draw.js +++ b/v2/app/src/utils/draw.js @@ -1,4 +1,5 @@ import { UMAP } from 'umap-js'; +import { PointScale } from '../components/point'; export async function get3dCoordinates(rawPoints) { @@ -15,4 +16,28 @@ export async function get3dCoordinates(rawPoints) { return []; } +} + +export async function generateLinesFromPoints(points){ + if(!Array.isArray(points) || points.length<2){ + return []; + } + + const lines=[]; + + for(let i=0; i 20) continue; // skip if too far apart + + lines.push([start.map(coord => coord * PointScale), end.map(coord => coord * PointScale)]); + } + + return lines; } \ No newline at end of file diff --git a/v2/app/src/utils/parsing.js b/v2/app/src/utils/parsing.js index 7a59616..e7b42d9 100644 --- a/v2/app/src/utils/parsing.js +++ b/v2/app/src/utils/parsing.js @@ -172,7 +172,7 @@ async function searchQdrant(query_embeddings){ }, body: JSON.stringify({ vector: query_embeddings, - limit: 10, + limit: 50, with_payload: true, with_vector: true })