Xianbao QIAN
models - pop up page
16bec5a
raw
history blame
15.4 kB
'use client';
import { useState, useEffect } from 'react';
import * as duckdb from '@duckdb/duckdb-wasm';
import Table from './components/Table';
import Modal from './components/Modal';
type ModelData = {
ancestor: string;
direct_children: string[] | null;
all_children: string[];
all_children_count: number;
direct_children_count: number | null;
};
type OrgData = {
org: string;
family_model_count: number;
family_direct_children_count: number;
family_all_children_count: number;
};
export default function Home() {
const [allModels, setAllModels] = useState<ModelData[]>([]);
const [orgData, setOrgData] = useState<OrgData[]>([]);
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(100);
const [filterText, setFilterText] = useState('');
const [isLoading, setIsLoading] = useState(true);
const [orderBy, setOrderBy] = useState<'all_children' | 'direct_children'>('all_children');
const [activeTab, setActiveTab] = useState<'models' | 'orgs'>('models');
const [orgCurrentPage, setOrgCurrentPage] = useState(1);
const [orgPageSize, setOrgPageSize] = useState(100);
const [orgOrderBy, setOrgOrderBy] = useState<keyof OrgData>('family_all_children_count');
const [orgFilterText, setOrgFilterText] = useState('');
const [selectedModel, setSelectedModel] = useState<ModelData | null>(null);
const [selectedOrg, setSelectedOrg] = useState<string | null>(null);
const [selectedOrgModels, setSelectedOrgModels] = useState<ModelData[]>([]);
const [selectedModelChildren, setSelectedModelChildren] = useState<string[]>([]);
const [selectedModelChildrenType, setSelectedModelChildrenType] = useState<'direct' | 'all'>('all');
const [modelChildrenPage, setModelChildrenPage] = useState(1);
const [orgModelsPage, setOrgModelsPage] = useState(1);
const modalPageSize = 10;
useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
const tab = urlParams.get('tab');
const page = urlParams.get('page');
const order = urlParams.get('order');
const filter = urlParams.get('filter');
const orgFilter = urlParams.get('orgFilter');
if (tab === 'orgs') {
setActiveTab('orgs');
}
if (page) {
setCurrentPage(parseInt(page, 10));
}
if (order === 'direct_children') {
setOrderBy('direct_children');
} else {
setOrderBy('all_children');
}
if (filter) {
setFilterText(filter);
}
if (orgFilter) {
setOrgFilterText(orgFilter);
}
}, []);
useEffect(() => {
const urlParams = new URLSearchParams();
if (activeTab === 'orgs') {
urlParams.set('tab', 'orgs');
}
if (currentPage > 1) {
urlParams.set('page', currentPage.toString());
}
if (orderBy === 'direct_children') {
urlParams.set('order', 'direct_children');
}
if (filterText) {
urlParams.set('filter', filterText);
}
if (orgFilterText) {
urlParams.set('orgFilter', orgFilterText);
}
const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
window.history.replaceState(null, '', newUrl);
}, [activeTab, currentPage, orderBy, filterText, orgFilterText]);
useEffect(() => {
async function fetchData() {
const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();
// Select a bundle based on browser checks
const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);
const worker_url = URL.createObjectURL(
new Blob([`importScripts("${bundle.mainWorker!}");`], { type: 'text/javascript' })
);
// Instantiate the asynchronous version of DuckDB-Wasm
const worker = new Worker(worker_url);
const logger = new duckdb.ConsoleLogger();
const db = new duckdb.AsyncDuckDB(logger, worker);
await db.instantiate(bundle.mainModule, bundle.pthreadWorker);
// Register the Parquet file using the URL
await db.registerFileURL(
'ancestor_children.parquet',
`${window.location.origin}/ancestor_children.parquet`,
duckdb.DuckDBDataProtocol.HTTP,
false
);
// Execute the SQL query using the registered Parquet file
const query = `
SELECT
ancestor,
direct_children,
all_children,
CAST(all_children_count AS INTEGER) AS all_children_count,
CAST(direct_children_count AS INTEGER) AS direct_children_count
FROM 'ancestor_children.parquet'
`;
const conn = await db.connect();
const result = await conn.query(query);
// Convert the result to a JavaScript array
const data: ModelData[] = result.toArray();
// Execute the SQL query to get the grouped org data with additional counts
const orgQuery = `
SELECT
SPLIT_PART(ancestor, '/', 1) AS org,
CAST(COUNT(DISTINCT ancestor) AS INTEGER) AS family_model_count,
CAST(SUM(direct_children_count) AS INTEGER) AS family_direct_children_count,
CAST(SUM(all_children_count) AS INTEGER) AS family_all_children_count
FROM 'ancestor_children.parquet'
GROUP BY org
ORDER BY family_all_children_count DESC
`;
const orgResult = await conn.query(orgQuery);
// Convert the org result to a JavaScript array
const orgData: OrgData[] = orgResult.toArray();
// Close the connection and terminate the worker
await conn.close();
await db.terminate();
setAllModels(data);
setOrgData(orgData);
setIsLoading(false);
}
fetchData();
}, []);
const filteredModels = allModels.filter((model) =>
model.ancestor.toLowerCase().includes(filterText.toLowerCase())
);
const sortedModels = filteredModels.sort((a, b) => {
if (orderBy === 'all_children') {
return b.all_children_count - a.all_children_count;
} else {
return (b.direct_children_count ?? 0) - (a.direct_children_count ?? 0);
}
});
const handleTabChange = (tab: 'models' | 'orgs') => {
setActiveTab(tab);
setCurrentPage(1);
setOrderBy('all_children');
setFilterText('');
setOrgFilterText('');
};
const handlePageChange = (page: number, tab: 'models' | 'orgs') => {
if (tab === 'models') {
setCurrentPage(page);
} else {
setOrgCurrentPage(page);
}
};
const handleOrderByClick = (column: 'all_children' | 'direct_children') => {
setOrderBy(column);
setCurrentPage(1);
};
const filteredOrgData = orgData.filter((org) =>
org.org.toLowerCase().includes(orgFilterText.toLowerCase())
);
const sortedOrgData = filteredOrgData.sort((a, b) => {
if (orgOrderBy === 'org') {
return a.org.localeCompare(b.org);
}
return b[orgOrderBy] - a[orgOrderBy];
});
const paginatedOrgData = sortedOrgData.slice(
(orgCurrentPage - 1) * orgPageSize,
orgCurrentPage * orgPageSize
);
const orgTotalPages = Math.ceil(sortedOrgData.length / orgPageSize);
const handleModelChildrenClick = (model: ModelData, type: 'direct' | 'all') => {
console.log('Model data:', model);
console.log('Children type:', type);
setSelectedModel(model);
setSelectedModelChildrenType(type);
let children;
if (type === 'direct') {
children = model.direct_children || [];
} else {
children = model.all_children || [];
}
console.log('Children:', children);
// Handle Vector data structure
if (children && typeof children === 'object' && 'get' in children && 'length' in children) {
const vectorChildren = [];
for (let i = 0; i < children.length; i++) {
vectorChildren.push(children.get(i));
}
setSelectedModelChildren(vectorChildren);
} else if (Array.isArray(children)) {
setSelectedModelChildren(children);
} else {
console.error('Unexpected children data structure:', children);
setSelectedModelChildren([]);
}
};
const handleOrgModelsClick = (org: string) => {
setSelectedOrg(org);
const orgModels = allModels.filter((model) => model.ancestor.split('/')[0] === org);
setSelectedOrgModels(orgModels);
};
const handleModelChildrenPageChange = (page: number) => {
setModelChildrenPage(page);
};
const handleOrgModelsPageChange = (page: number) => {
setOrgModelsPage(page);
};
return (
<main className="container mx-auto py-8 bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
<h1 className="text-4xl font-bold mb-4">All Models</h1>
<div className="mb-4 flex space-x-4">
<a
href={`?tab=models`}
onClick={(e) => {
e.preventDefault();
handleTabChange('models');
}}
className={`px-4 py-2 rounded-md ${
activeTab === 'models'
? 'bg-blue-500 dark:bg-blue-600 text-white'
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-200'
}`}
>
Models
</a>
<a
href={`?tab=orgs`}
onClick={(e) => {
e.preventDefault();
handleTabChange('orgs');
}}
className={`px-4 py-2 rounded-md ${
activeTab === 'orgs'
? 'bg-blue-500 dark:bg-blue-600 text-white'
: 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-200'
}`}
>
Organizations
</a>
</div>
{activeTab === 'models' ? (
<>
<div className="mb-4">
<input
type="text"
placeholder="Filter by model name"
value={filterText}
onChange={(e) => setFilterText(e.target.value)}
className="px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-white"
/>
</div>
{isLoading ? (
<p>Loading data...</p>
) : (
<Table
data={sortedModels}
columns={[
{
key: 'ancestor',
label: 'Model',
},
{
key: 'direct_children_count',
label: 'Direct Children',
render: (value, row) => (
<button
className="text-right text-blue-500 hover:underline"
onClick={() => handleModelChildrenClick(row, 'direct')}
>
{value ?? 0}
</button>
),
},
{
key: 'all_children_count',
label: 'All Children',
render: (value, row) => (
<button
className="text-right text-blue-500 hover:underline"
onClick={() => handleModelChildrenClick(row, 'all')}
>
{value}
</button>
),
},
]}
orderBy={orderBy}
onOrderByChange={(key) => {
if (key === 'all_children' || key === 'direct_children') {
setOrderBy(key);
setCurrentPage(1);
}
}}
pageSize={pageSize}
currentPage={currentPage}
onPageChange={(page) => handlePageChange(page, 'models')}
/>
)}
</>
) : (
<>
<div className="mb-4">
<input
type="text"
placeholder="Filter by organization name"
value={orgFilterText}
onChange={(e) => setOrgFilterText(e.target.value)}
className="px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-white"
/>
</div>
{isLoading ? (
<p>Loading data...</p>
) : (
<Table
data={paginatedOrgData}
columns={[
{
key: 'org',
label: 'Organization',
},
{
key: 'family_model_count',
label: 'Model Count',
render: (value, row) => (
<button
className="text-right text-blue-500 hover:underline"
onClick={() => handleOrgModelsClick(row.org)}
>
{value}
</button>
),
},
{
key: 'family_direct_children_count',
label: 'Direct Children',
render: (value) => <span className="text-right">{value}</span>,
},
{
key: 'family_all_children_count',
label: 'All Children',
render: (value) => <span className="text-right">{value}</span>,
},
]}
orderBy={orgOrderBy}
onOrderByChange={(key) => setOrgOrderBy(key)}
pageSize={orgPageSize}
currentPage={orgCurrentPage}
onPageChange={(page) => handlePageChange(page, 'orgs')}
/>
)}
</>
)}
{selectedModel && (
<Modal onClose={() => {
setSelectedModel(null);
setModelChildrenPage(1);
}}>
<h2 className="text-2xl font-bold mb-4">
{selectedModelChildrenType === 'direct' ? 'Direct Children' : 'All Children'} of {selectedModel.ancestor}
</h2>
{selectedModelChildren.length > 0 ? (
<Table
data={selectedModelChildren.map((child, index) => ({ id: index, model: child }))}
columns={[{ key: 'model', label: 'Model' }]}
pageSize={modalPageSize}
currentPage={modelChildrenPage}
onPageChange={handleModelChildrenPageChange}
/>
) : (
<p>No children found for this model.</p>
)}
</Modal>
)}
{selectedOrg && (
<Modal onClose={() => {
setSelectedOrg(null);
setOrgModelsPage(1);
}}>
<h2 className="text-2xl font-bold mb-4">Models under {selectedOrg}</h2>
{selectedOrgModels.length > 0 ? (
<Table
data={selectedOrgModels}
columns={[
{
key: 'ancestor',
label: 'Model',
},
{
key: 'direct_children_count',
label: 'Direct Children',
render: (value) => <span className="text-right">{value ?? 0}</span>,
},
{
key: 'all_children_count',
label: 'All Children',
render: (value) => <span className="text-right">{value}</span>,
},
]}
pageSize={modalPageSize}
currentPage={orgModelsPage}
onPageChange={handleOrgModelsPageChange}
/>
) : (
<p>No models found for this organization.</p>
)}
</Modal>
)}
</main>
);
}