add group color

main
reng 3 weeks ago
parent 4573d34fb9
commit 81ae2c7e29
  1. 2
      v2/app/src/App.css
  2. 2
      v2/app/src/App.jsx
  3. 51
      v2/app/src/components/graph.jsx
  4. 22
      v2/app/src/components/point.jsx
  5. 26
      v2/app/src/utils/draw.js
  6. 2
      v2/app/src/utils/osc.js
  7. 15
      v2/app/src/utils/parsing.js

@ -17,5 +17,5 @@ form{
/* @apply text-sm opacity-50; */
}
.keyword > span {
@apply bg-gray-200 text-black rounded-full p-2;
@apply bg-gray-800 rounded-full p-2;
}

@ -14,7 +14,7 @@ function App() {
const [themes, setThemes]=useState([]);
const [keywords, setKeywords]=useState([]);
const [results, setResults]=useState([]);
const [selectTab, setSelectTab]=useState('text');
const [selectTab, setSelectTab]=useState(DisplayTypes[1]);
function preText(){

@ -7,21 +7,30 @@ import Point, {PointContentType} from './point.jsx';
import { useControls, button } from "leva";
import { sendOsc } from '../utils/osc.js';
function getColorFromIndex(index, length){
const hue = (index / length) * 360;
return `hsl(${hue}, 100%, 50%)`;
}
export default function Graph({results}){
const [points, setPoints]=useState();
const [lines, setLines]=useState();
// const [drawLines, setDrawLines]=useState(false);
// const [showContent, setShowContent]=useState(true);
// const [showKeyword, setShowKeyword]=useState(false);
const { showContent, contentType, showKeywords, showLines, textToShow } = useControls({
const { showContent, contentType, showKeywords, showLines, textToShow, drawDistance, distToKeywords, keywordColor } = useControls({
showContent: { value: true },
contentType: { options: Object.values(PointContentType), value: PointContentType.Teaser },
showKeywords: { value: false },
showLines: { value: false },
textToShow: { value: 20, min: 5, max: 100, step: 5 },
drawDistance: { value: 0.2, min: 0.1, max: 5, step: 0.01 },
keywordColor: { value: true },
distToKeywords: { value: 3, min: 0.1, max: 10, step: 0.01 },
});
@ -35,13 +44,36 @@ export default function Graph({results}){
bounds?.refresh().clip().fit();
}
function getColorByGroup(result){
if(!keywordColor) return 'white';
if(!result || !result.payload )
return 'white';
if(result.type==='keyword'){
return getColorFromIndex(parseInt(result.id), 20);
}
const group = result.payload.group[0];
if(group.distance<distToKeywords){
const index=parseInt(group.id);
console.log("Group color index:", index, "for group id:", group.id);
return getColorFromIndex(index, 20);
}
return 'white';
}
useEffect(()=>{
zoomToFit();
if(!points || points.length===0) return;
points.forEach((point, index)=>{
console.log(`send osc Point ${index}: (${point[0].toFixed(2)}, ${point[1].toFixed(2)}, ${point[2].toFixed(2)})`);
// console.log(`send osc Point ${index}: (${point[0].toFixed(2)}, ${point[1].toFixed(2)}, ${point[2].toFixed(2)})`);
sendOsc('/point',JSON.stringify({
index: index,
x: point[0],
@ -52,6 +84,18 @@ export default function Graph({results}){
});
}, [points]);
useEffect(()=>{
if(!results || results.length===0){
setLines([]);
return;
}
generateLinesFromPoints(points, drawDistance).then(newLines=>{
console.log("Lines updated due to drawDistance change:", newLines);
setLines(newLines);
});
},[drawDistance]);
useEffect(()=>{
if(!results || results.length===0){
@ -68,7 +112,7 @@ export default function Graph({results}){
console.log("3D Points:", newPoints);
setPoints(newPoints);
generateLinesFromPoints(newPoints, 10).then(newLines=>{
generateLinesFromPoints(newPoints, drawDistance).then(newLines=>{
console.log("Lines:", newLines);
setLines(newLines);
});
@ -94,6 +138,7 @@ export default function Graph({results}){
result={results?.[index]}
showContent={showContent} showKeyword={showKeywords} contentType={contentType}
textToShow={textToShow}
color={getColorByGroup(results?.[index])}
/>
))}
</group>

@ -31,7 +31,7 @@ export const PointContentType={
}
export default function Point({point, index, totalPoints, result, showContent, showKeyword, contentType, textToShow}) {
export default function Point({point, index, totalPoints, result, showContent, showKeyword, contentType, textToShow, color}) {
const [payload, setPayload]=useState();
const [showPayload, setShowPayload]=useState(false);
@ -118,16 +118,17 @@ export default function Point({point, index, totalPoints, result, showContent, s
const finalHtmlScale = depthScaleFactor * (currentMeshScale / PointSize);
refText.current.style.transform = `translate(-50%, -50%) scale(${finalHtmlScale})`;
if(payload.normalized_time===-1){
if(payload.keywords.length==1){
// meshRef.current.scale.set(PointSize, PointSize, PointSize);
refText.current.style.opacity = 1;
refText.current.style.transform = `translate(-50%, -50%) scale(1)`;
refText.current.style.filter = `none`;
}else{
refText.current.style.opacity *= alpha;
// CSS
const blurAmount = distance > DEPTH_CONFIG.FADE_START ? (distance - DEPTH_CONFIG.FADE_START) / 20 : 0;
refText.current.style.filter = `blur(${Math.min(blurAmount, 4)}px)`;
refText.current.style.filter = `blur(${Math.min(blurAmount, 2)}px)`;
}
//
// refText.current.style.display = alpha <= 0.01 ? 'none' : 'block';
@ -263,18 +264,21 @@ export default function Point({point, index, totalPoints, result, showContent, s
<mesh ref={meshRef} position={[point[0]*PointScale, point[1]*PointScale, point[2]*PointScale]}>
<sphereGeometry args={[PointSize, 32, 32]} />
<meshStandardMaterial
color={new THREE.Color().setHSL(1, 0, 0.2)}
emissive={new THREE.Color().setHSL(1, 0, 0.2)}
color={new THREE.Color().set(color)}
emissive={new THREE.Color().set(color)}
emissiveIntensity={0.5}
/>
<Html>
<div ref={refText} className='text-white p-2 select-none text-center opacity-0'>
{payload?.keywords && <div className={`flex flex-row justify-center flex-wrap text-[1rem] ${showKeyword ? 'block' : 'hidden'}`}>
{payload?.keywords.map((el, index)=><span key={index} className='px-2' style={{transform: `translate(${Math.random() * KeywordOffset}px,${Math.random() * KeywordOffset}px)`}}>{el}</span>)}
<div ref={refText} className=' p-2 select-none text-center opacity-0 flex flex-col items-center justify-center'>
{showKeyword && payload?.keywords.length>1 && <div className={`flex flex-row justify-center flex-wrap text-[1rem] ${showKeyword ? 'block' : 'hidden'}`}
style={{color: color || 'white'}}>
{payload?.keywords.map((el, index)=><span key={index} className='px-2 bg-gray-800 rounded-full' style={{transform: `translate(${Math.random() * KeywordOffset}px,${Math.random() * KeywordOffset}px)`}}>{el}</span>)}
</div>}
{/* {color!='white' && !showKeyword && payload?.keywords.length>1 && <div className='w-[1rem] aspect-square rounded-full' style={{backgroundColor: color}}></div>} */}
{<div
className={`text-[2rem] text-white rounded p-2 text-center max-w-[50vw] min-w-[20vw] splittext ${showContent ? 'block' : 'hidden'} ${payload?.type??''}`}
className={`text-[2rem] rounded p-2 text-center max-w-[50vw] min-w-[20vw] splittext ${showContent ? 'block' : 'hidden'} ${payload?.type??''}`}
// style={{width: `${Math.random()*(payload?.content.length/5 || 10) + 20}vw`}}
style={{color: color}}
dangerouslySetInnerHTML={{__html: getContent()}}
></div>}
</div>

@ -26,17 +26,21 @@ export async function generateLinesFromPoints(points, maxDistance=300) {
const lines=[];
for(let i=0; i<points.length -1; i++){
const start=points[i];
const end=points[i+1];
const distance=Math.sqrt(
Math.pow(end[0]-start[0], 2) +
Math.pow(end[1]-start[1], 2) +
Math.pow(end[2]-start[2], 2)
);
if(distance > maxDistance) continue; // skip if too far apart
lines.push([start.map(coord => coord * PointScale), end.map(coord => coord * PointScale)]);
for(let j=i+1; j<points.length -1; j++){
if(i===j) continue; // skip same point
const start=points[i];
const end=points[j];
const distance=Math.sqrt(
Math.pow(end[0]-start[0], 2) +
Math.pow(end[1]-start[1], 2) +
Math.pow(end[2]-start[2], 2)
);
// console.log(`Distance between point ${i} and ${i+1}:`, distance);
if(distance > maxDistance) continue; // skip if too far apart
lines.push([start.map(coord => coord * PointScale), end.map(coord => coord * PointScale)]);
}
}
return lines;

@ -3,6 +3,6 @@ import { invoke } from "@tauri-apps/api/core";
const TD_OSC_PORT=7000;
export function sendOsc(key, message){
console.log("Sending OSC:", key, message);
// console.log("Sending OSC:", key, message);
invoke('send_osc_message', {key: `${key}`, message: message, host:'0.0.0.0:0', target:`127.0.0.1:${TD_OSC_PORT}`})
}

@ -141,6 +141,7 @@ export async function searchByKeywords(keywordIds, limit){
// get keyword embeddings from Qdrant
let allResults = [];
let keywords=[];
for(const keywordId of keywordIds){
const res=await fetch(`http://localhost:6333/collections/${COLLECTION_KEYWORD}/points/${parseInt(keywordId)-1}`, {
method: 'GET',
@ -157,9 +158,9 @@ export async function searchByKeywords(keywordIds, limit){
const data = await res.json();
console.log(data);
const results = await searchQdrant(data.result.vector, Math.floor(limit/keywordIds.length));
// const results = await searchQdrant(data.result.vector, Math.floor(limit/keywordIds.length));
allResults.push(...results);
// allResults.push(...results);
const keypoint={
type: 'keyword',
@ -170,6 +171,16 @@ export async function searchByKeywords(keywordIds, limit){
keywords.push(keypoint);
allResults.push(keypoint);
}
// search by centroid of keywords
const centroid = new Array(keywords[0].vector.length).fill(0);
keywords.forEach(kw=>{
kw.vector.forEach((val, index)=>{
centroid[index] += val/keywords.length;
});
});
const results = await searchQdrant(centroid, limit);
allResults.push(...results);
normalizeResultTime(allResults);

Loading…
Cancel
Save