You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

204 lines
7.1 KiB

import { useEffect, useState } from "react";
import "./App.css";
import { searchByText, searchByTheme, processTheme, processKeywords, searchByKeywords } from "./utils/parsing";
import Graph from "./components/graph";
const files=['大家想到未來不會很絕望嗎','日常生活','有人懂嗎','看到學貸還款通知書寄來','租屋網站'];
const ContentTags=['Summary','Keywords','Order','User','Content'];
const DisplayTypes=['text','point'];
function App() {
const [themes, setThemes]=useState([]);
const [keywords, setKeywords]=useState([]);
const [results, setResults]=useState([]);
const [selectTab, setSelectTab]=useState(DisplayTypes[1]);
function preText(){
files.forEach(async (file)=>{
const url = `assets/collect/${file}.json`;
await processData(url);
});
}
function preTheme(){
if(themes?.length>0)
processTheme(themes);
}
function preKeywords(){
if(keywords?.length>0)
processKeywords(keywords, 'keywords_v1');
}
function processRaw(){
processRawFiles('resources/raw/1222', 'resources/collect/1222');
}
useEffect(()=>{
if(!results || results.length===0) return;
},[results]);
useEffect(()=>{
fetch('themes_v2.json').then(response=>response.json()).then(async (json)=>{
// console.log(json);
setThemes(json);
});
fetch('keywords.json').then(response=>response.json()).then(async (json)=>{
// console.log(json);
setKeywords(json);
});
},[]);
return (
<main className="flex flex-col justify-center gap-2 p-4">
<div className="flex flex-row flex-wrap gap-2 border rounded p-2">
<button onClick={preTheme}>reset theme embedding</button>
<button onClick={preKeywords}>reset keyword embedding</button>
<span>search limit = <input type="number" name="numResults" defaultValue={50} min={1} max={200} /></span>
</div>
<p id="embeddings"></p>
{/* <form>
<p>search by any text</p>
<input type="text" name="query" placeholder="Enter your query" />
<button type="button" onClick={()=>{
const query = document.querySelector('input[name="query"]').value;
searchByText(query).then(res=>{
setResults(res);
});
}}>
Search
</button>
</form> */}
<form>
<p>search by theme</p>
<select name="collection">
{themes.map((theme, index)=>(
<option key={index} value={theme.id}>{theme.title} [{theme.keywords.join(", ")}]</option>
))}
</select>
<button type="button" onClick={()=>{
const collection = document.querySelector('select[name="collection"]').value;
console.log("Selected collection:", collection);
// const id=themes.find(item=>item.title===collection)?.id;
const limit=parseInt(document.querySelector('input[name="numResults"]').value) || 50;
searchByTheme(collection, limit).then(res=>{
setResults(res);
});
}}>
Search
</button>
</form>
<form>
<p>search by keyword</p>
<div className="flex flex-row flex-wrap gap-2">
{keywords.map((keyword, index)=>(
<span key={index}>
<input type="checkbox" name="keyword" value={keyword.id} /> {keyword.title}
</span>
))}
</div>
<button type="button" onClick={()=>{
const selectedKeywords = Array.from(document.querySelectorAll('input[name="keyword"]:checked')).map(el=>el.value);
console.log("Selected keywords:", selectedKeywords);
if(selectedKeywords.length===0){
return;
}
// keep 4 max
const limitedKeywords = selectedKeywords.slice(0,4);
const limit = parseInt(document.querySelector('input[name="numResults"]').value) || 50;
searchByKeywords(limitedKeywords, limit).then(res=>{
setResults(res);
});
}}>
Search
</button>
</form>
<div>
<div>Results={results?.length}</div>
{DisplayTypes.map((type)=>(
<button
key={type}
onClick={()=>{
setSelectTab(type);
}}
disabled={selectTab===type}
className={selectTab===type ? 'bg-blue-500 text-white' : ''}
>
{type}
</button>
))}
</div>
{selectTab==='text' && (
<div id="search-results">
<div className="border-b p-2 my-2 grid grid-cols-6 gap-2 font-bold">
<div>#</div>
<div>Score</div>
<div>Order</div>
<div>Teaser</div>
<div className="col-span-2">Content</div>
<div className="bg-pink-200 text-xs self-center">Summary</div>
<div className="flex flex-row gap-2 flex-wrap items-center text-xs">Keywords</div>
<div className="text-xs">Distance to Keywords</div>
</div>
{results?.length>0 && results.map((item, index)=>{
let output={};
return (
<div key={index} className="border-b p-2 my-2 grid grid-cols-6 gap-2">
<div>#{index+1}</div>
<p>score={item.score?.toFixed(4)}</p>
{(()=>{
if(item.type==='keyword'){
const payload=JSON.parse(item.payload.text);
return (<>
<div colSpan={2} className="col-span-2 font-bold">{payload?.title}</div>
<div className="col-span-3">--</div>
<div className="bg-pink-200 text-xs self-center">--</div>
<div className="flex flex-row gap-2 flex-wrap items-center text-xs">--</div>
</>);
}
let p={
...item.payload,
metadata: JSON.parse(item.payload.metadata),
};
return (<>
<div>{p.number}/{p.total}</div>
<div className="">{p.teaser}</div>
<div className="col-span-2">{p.metadata.text}</div>
<div className="bg-pink-200 text-xs self-center">{p.summry}</div>
<div className="flex flex-row gap-2 flex-wrap items-center text-xs">{p.keywords.map(el=><span className="bg-gray-200 rounded-full px-2" key={el}>{el}</span>)}</div>
<div className="text-xs">{p.group.map(el=>(<>
<span>{el.title}({el.distance.toFixed(2)}) </span>
</>))}</div>
</>);
})()}
</div>
);
})}
</div>
)}
{selectTab==='point' && (
<Graph results={results} />
)}
</main>
);
}
export default App;