diff --git a/.github/workflows/bbqs-bot-gsheet-to-kg.yml b/.github/workflows/bbqs-bot-gsheet-to-kg.yml index b0630cd..80faf42 100644 --- a/.github/workflows/bbqs-bot-gsheet-to-kg.yml +++ b/.github/workflows/bbqs-bot-gsheet-to-kg.yml @@ -62,16 +62,16 @@ jobs: python scripts/process_sheet_and_save.py \ --spreadsheet-id "${SHEET_ID}" \ --sheet-name "${SHEET_NAME}" \ - --csv-out data/sheets/output_normalized.csv \ - --json-out data/sheets/output_kg.jsonl \ + --csv-out ui/public/output_normalized.csv \ + --json-out ui/public/output_kg.jsonl \ --sa-key-file sa_key.json # Mapping is ON by default; to disable add: --no-llm-mapping # To choose a specific model add: --openrouter-model openai/gpt-4o-mini - name: Verify outputs exist run: | - test -f "data/sheets/output_normalized.csv" || (echo " CSV missing" && exit 1) - test -f "data/sheets/output_kg.jsonl" || (echo " NDJSON missing" && exit 1) + test -f "ui/public/output_normalized.csv" || (echo " CSV missing" && exit 1) + test -f "ui/public/output_kg.jsonl" || (echo " NDJSON missing" && exit 1) echo " Outputs present" - name: Commit generated files @@ -81,7 +81,7 @@ jobs: GIT_COMMITTER_NAME: github-actions[bot] GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com run: | - git add data/sheets/output_normalized.csv data/sheets/output_kg.jsonl + git add ui/public/output_normalized.csv ui/public/output_kg.jsonl if ! git diff --cached --quiet; then git commit -m "chore: update from Google Sheets → CSV (mapped) + NDJSON (KG)" git push diff --git a/.github/workflows/deploy_ui.yml b/.github/workflows/deploy_ui.yml index 8179e09..c3de439 100644 --- a/.github/workflows/deploy_ui.yml +++ b/.github/workflows/deploy_ui.yml @@ -1,26 +1,24 @@ -name: Deploy UI to GitHub Pages +name: Deploy to GitHub Pages on: push: - branches: [ master ] + branches: [ main, use-public-directory ] pull_request: - branches: [ master ] + types: [closed] + branches: [ main ] -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: group: "pages" cancel-in-progress: false jobs: - # Build job build: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.merged == true) runs-on: ubuntu-latest steps: - name: Checkout @@ -30,67 +28,36 @@ jobs: uses: actions/setup-node@v4 with: node-version: '18' - cache: 'npm' - cache-dependency-path: 'ui/package-lock.json' - - name: Install dependencies - run: npm ci - working-directory: ./ui + - name: Set NEXT_PUBLIC_BASE_PATH + run: echo "NEXT_PUBLIC_BASE_PATH=/bbqs-kg/ui" >> $GITHUB_ENV - - name: Setup environment - run: | - # Create .env.local in the ui directory - cd ui - if [ ! -f .env.local ]; then - echo "DATA_PATH=../data/sheets/output_kg.jsonl" > .env.local - fi + - name: Install dependencies + run: npm install -f + working-directory: ui - name: Copy data for static build run: | mkdir -p public - cp ../data/sheets/output_kg.jsonl public/data.jsonl - working-directory: ./ui + cp ../data/sheets/output_kg.jsonl public/output_kg.jsonl + working-directory: ui - - name: Build with Next.js + - name: Build static site with Next.js run: npm run build - working-directory: ./ui - env: - NODE_ENV: production - - - name: List build output - run: | - echo "Build output contents:" - ls -la out/ - echo "Static files:" - find out/ -name "*.html" -o -name "*.css" -o -name "*.js" | head -10 - working-directory: ./ui - - - name: Copy data to build output - run: | - # Copy the data file to the build output directory - cp public/data.jsonl out/data.jsonl - echo "Data file copied to build output:" - ls -la out/data.jsonl - working-directory: ./ui - - - name: Setup Pages - uses: actions/configure-pages@v4 + working-directory: ui - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: - # Upload the 'out' directory from the ui folder - path: './ui/out' + path: ui/out - # Deployment job deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build - if: github.ref == 'refs/heads/master' steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/ui/app/api/data/route.ts b/ui/app/api/data/route.ts deleted file mode 100644 index 0ddf85e..0000000 --- a/ui/app/api/data/route.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { NextResponse } from 'next/server'; -import fs from 'fs'; -import path from 'path'; -import { KnowledgeGraphEntry, CommunityMember } from '@/lib/types'; - -async function loadKnowledgeGraphData(): Promise { - try { - // Use environment variable for data path, fallback to default - // used for dev/server setting where no static generation and for github we use lib/data.ts. - const dataPath = process.env.DATA_PATH || path.join(process.cwd(), 'data', 'output_kg.jsonl'); - - // If DATA_PATH is provided as a relative path, resolve it from the project root - const resolvedPath = path.isAbsolute(dataPath) - ? dataPath - : path.join(process.cwd(), dataPath); - - console.log(`Loading data from: ${resolvedPath}`); - - if (!fs.existsSync(resolvedPath)) { - console.error(`Data file not found at: ${resolvedPath}`); - return []; - } - - const fileContent = fs.readFileSync(resolvedPath, 'utf-8'); - return JSON.parse(fileContent); - } catch (error) { - console.error('Error loading knowledge graph data:', error); - return []; - } -} - -function transformToCommunityMembers(data: KnowledgeGraphEntry[]): CommunityMember[] { - return data - .filter(entry => entry.fields.Name) // Only include entries with names - .map((entry, index) => { - const expertise = entry.fields.Expertise || ''; - const interest = entry.fields.Interest || ''; - const role = entry.fields.Role || ''; - const note = entry.fields.Note || ''; - - // Extract keywords from mappings - const keywords = [ - ...(entry.mappings.Expertise?.map(m => m.concept_label).filter(Boolean) || []), - ...(entry.mappings.Interest?.map(m => m.concept_label).filter(Boolean) || []), - ...(entry.mappings.Role?.map(m => m.concept_label).filter(Boolean) || []) - ]; - - // Determine type based on role/expertise - let type = 'Community Member'; - if (role.toLowerCase().includes('student') || role.toLowerCase().includes('graduate')) { - type = 'Student'; - } else if (role.toLowerCase().includes('researcher') || role.toLowerCase().includes('research')) { - type = 'Researcher'; - } else if (role.toLowerCase().includes('professor') || role.toLowerCase().includes('faculty')) { - type = 'Faculty'; - } else if (role.toLowerCase().includes('developer') || role.toLowerCase().includes('engineer')) { - type = 'Developer'; - } - - - - // Determine programming language - let programmingLanguage = ''; - if (expertise.toLowerCase().includes('python') || interest.toLowerCase().includes('python')) { - programmingLanguage = 'Python'; - } else if (expertise.toLowerCase().includes('r') || interest.toLowerCase().includes('r')) { - programmingLanguage = 'R'; - } else if (expertise.toLowerCase().includes('matlab') || interest.toLowerCase().includes('matlab')) { - programmingLanguage = 'MATLAB'; - } else if (expertise.toLowerCase().includes('git') || interest.toLowerCase().includes('git')) { - programmingLanguage = 'Git'; - } - - // Determine platform - let platform = 'NA'; - if (expertise.toLowerCase().includes('jupyter') || interest.toLowerCase().includes('jupyter')) { - platform = 'Jupyter'; - } else if (expertise.toLowerCase().includes('rstudio') || interest.toLowerCase().includes('rstudio')) { - platform = 'RStudio'; - } else if (expertise.toLowerCase().includes('matlab') || interest.toLowerCase().includes('matlab')) { - platform = 'MATLAB'; - } - - // Determine quadrants based on what they want to share/learn - const quadrants = []; - if (expertise.toLowerCase().includes('reference') || interest.toLowerCase().includes('reference')) { - quadrants.push('information-oriented (reference)'); - } - if (expertise.toLowerCase().includes('explanation') || interest.toLowerCase().includes('explanation')) { - quadrants.push('understanding-oriented (explanation)'); - } - if (expertise.toLowerCase().includes('tutorial') || interest.toLowerCase().includes('tutorial')) { - quadrants.push('learning-oriented (tutorials)'); - } - if (expertise.toLowerCase().includes('guide') || interest.toLowerCase().includes('guide')) { - quadrants.push('problem-oriented (how to guides)'); - } - - // Create description from role, expertise, and interests - const description = note || `${role ? `Role: ${role}. ` : ''}${expertise ? `Expertise: ${expertise}. ` : ''}${interest ? `Interests: ${interest}` : ''}`.trim(); - - return { - id: `member-${index}`, - title: entry.fields.Name || 'Anonymous Member', - description: description, - type, - keywords: Array.from(new Set(keywords.filter(Boolean))) as string[], - programmingLanguage, - platform, - originalData: entry // Include the original data for ontology mappings - }; - }); -} - -export async function GET() { - try { - const kgData = await loadKnowledgeGraphData(); - const communityMembers = transformToCommunityMembers(kgData); - - // Extract all unique categories from mappings - const allCategories = new Set(); - - kgData.forEach(entry => { - // Extract concept labels from all mapping fields - Object.values(entry.mappings).forEach(mappingArray => { - if (Array.isArray(mappingArray)) { - mappingArray.forEach(mapping => { - if (mapping.concept_label) { - allCategories.add(mapping.concept_label); - } - }); - } - }); - }); - - const categories = Array.from(allCategories).sort(); - - return NextResponse.json({ - materials: communityMembers, - categories: categories - }); - } catch (error) { - console.error('Error in API route:', error); - return NextResponse.json({ error: 'Failed to load data' }, { status: 500 }); - } -} diff --git a/ui/app/layout.tsx b/ui/app/layout.tsx index 50c882a..fd0e2d0 100644 --- a/ui/app/layout.tsx +++ b/ui/app/layout.tsx @@ -1,9 +1,6 @@ import type { Metadata } from 'next' -import { Inter } from 'next/font/google' import './globals.css' -const inter = Inter({ subsets: ['latin'] }) - export const metadata: Metadata = { title: 'The People of BBQS - Knowledge Graph', description: 'Explore the expertise and knowledge of BBQS community members', @@ -16,7 +13,7 @@ export default function RootLayout({ }) { return ( - {children} + {children} ) } diff --git a/ui/components/CommunityManager.tsx b/ui/components/CommunityManager.tsx index e7316a4..f9c3b2e 100644 --- a/ui/components/CommunityManager.tsx +++ b/ui/components/CommunityManager.tsx @@ -1,7 +1,7 @@ 'use client'; import { useMemo, useState } from 'react'; -import { BookOpen, Clock, ExternalLink, Eye, Edit, ChevronLeft, ChevronRight, X } from 'lucide-react'; +import { BookOpen, Eye, ChevronLeft, ChevronRight, X } from 'lucide-react'; import { CommunityMember } from '@/lib/types'; import { useFilters } from '@/contexts/FilterContext'; @@ -51,7 +51,7 @@ export default function CommunityMembersList({ materials }: CommunityMembersList // Reset to first page when filters change useMemo(() => { setCurrentPage(1); - }, [filters.searchTerm, filters.selectedQuadrants, filters.selectedCategories]); + }, [filters.searchTerm, filters.selectedCategories]); // Calculate pagination const totalPages = Math.ceil(filteredMaterials.length / itemsPerPage); @@ -59,18 +59,7 @@ export default function CommunityMembersList({ materials }: CommunityMembersList const endIndex = startIndex + itemsPerPage; const currentMaterials = filteredMaterials.slice(startIndex, endIndex); - const getTypeIcon = (type: string) => { - switch (type.toLowerCase()) { - case 'hands-on tutorial / notebooks': - return ; - case 'course': - return ; - case 'workshop': - return ; - default: - return ; - } - }; + return (
diff --git a/ui/contexts/FilterContext.tsx b/ui/contexts/FilterContext.tsx index f1a943d..0564f47 100644 --- a/ui/contexts/FilterContext.tsx +++ b/ui/contexts/FilterContext.tsx @@ -4,14 +4,12 @@ import { createContext, useContext, useState, ReactNode } from 'react'; interface FilterState { searchTerm: string; - selectedQuadrants: string[]; selectedCategories: string[]; } interface FilterContextType { filters: FilterState; setSearchTerm: (term: string) => void; - setSelectedQuadrants: (quadrants: string[]) => void; setSelectedCategories: (categories: string[]) => void; clearAllFilters: () => void; } @@ -21,7 +19,6 @@ const FilterContext = createContext(undefined); export function FilterProvider({ children }: { children: ReactNode }) { const [filters, setFilters] = useState({ searchTerm: '', - selectedQuadrants: [], selectedCategories: [], }); @@ -31,9 +28,7 @@ export function FilterProvider({ children }: { children: ReactNode }) { - const setSelectedQuadrants = (quadrants: string[]) => { - setFilters(prev => ({ ...prev, selectedQuadrants: quadrants })); - }; + const setSelectedCategories = (categories: string[]) => { setFilters(prev => ({ ...prev, selectedCategories: categories })); @@ -42,7 +37,6 @@ export function FilterProvider({ children }: { children: ReactNode }) { const clearAllFilters = () => { setFilters({ searchTerm: '', - selectedQuadrants: [], selectedCategories: [], }); }; @@ -52,7 +46,6 @@ export function FilterProvider({ children }: { children: ReactNode }) { value={{ filters, setSearchTerm, - setSelectedQuadrants, setSelectedCategories, clearAllFilters, }} diff --git a/ui/lib/data.ts b/ui/lib/data.ts index df769b2..a7b9650 100644 --- a/ui/lib/data.ts +++ b/ui/lib/data.ts @@ -4,22 +4,20 @@ import { KnowledgeGraphEntry, CommunityMember } from './types'; export async function fetchCommunityMembers(): Promise<{members: CommunityMember[], categories: string[]}> { try { console.log('Starting fetchCommunityMembers'); - const base = process.env.NEXT_PUBLIC_BASE_PATH || ''; + const base = typeof window !== 'undefined' ? (window as any).__NEXT_DATA__?.basePath || '' : ''; console.log('Base path resolved to:', base); // For static export, we'll use a different approach - if (process.env.NODE_ENV === 'production') { + if (typeof window !== 'undefined' && window.location.hostname !== 'localhost') { console.log('Entering production block'); // In production (GitHub Pages), load from static data file // IMPORTANT: no hardcoded leading slash without basePath - const dataUrl = `${base}/data.jsonl`; + const dataUrl = `${base}/output_kg.jsonl`; console.log('Fetching data from:', dataUrl, 'base:', base); - console.log('NODE_ENV:', process.env.NODE_ENV); - console.log('NEXT_PUBLIC_BASE_PATH:', process.env.NEXT_PUBLIC_BASE_PATH); const response = await fetch(dataUrl); console.log('Response status:', response.status); - console.log('Response headers:', Object.fromEntries(response.headers.entries())); + console.log('Response headers:', Array.from(response.headers.entries())); if (!response.ok) { console.error('Failed to fetch data from:', dataUrl, 'Status:', response.status); @@ -53,32 +51,73 @@ export async function fetchCommunityMembers(): Promise<{members: CommunityMember }); } - // Transform to community members + // Transform to community members (matching API route logic) const members: CommunityMember[] = []; const allCategories = new Set(); kgData.forEach((entry: any, index: number) => { if (!entry.fields?.Name) return; + const expertise = entry.fields.Expertise || ''; + const interest = entry.fields.Interest || ''; + const role = entry.fields.Role || ''; + const note = entry.fields.Note || ''; + // Extract keywords from mappings - const keywords: string[] = []; - Object.values(entry.mappings).forEach((mappingArray: any) => { - if (Array.isArray(mappingArray)) { - mappingArray.forEach((mapping: any) => { - if (mapping.concept_label) { - keywords.push(mapping.concept_label); - allCategories.add(mapping.concept_label); - } - }); - } - }); + const keywords = [ + ...(entry.mappings.Expertise?.map((m: any) => m.concept_label).filter(Boolean) || []), + ...(entry.mappings.Interest?.map((m: any) => m.concept_label).filter(Boolean) || []), + ...(entry.mappings.Role?.map((m: any) => m.concept_label).filter(Boolean) || []) + ]; + + // Add keywords to categories + keywords.forEach(keyword => allCategories.add(keyword)); + + // Determine type based on role/expertise + let type = 'Community Member'; + if (role.toLowerCase().includes('student') || role.toLowerCase().includes('graduate')) { + type = 'Student'; + } else if (role.toLowerCase().includes('researcher') || role.toLowerCase().includes('research')) { + type = 'Researcher'; + } else if (role.toLowerCase().includes('professor') || role.toLowerCase().includes('faculty')) { + type = 'Faculty'; + } else if (role.toLowerCase().includes('developer') || role.toLowerCase().includes('engineer')) { + type = 'Developer'; + } + + // Determine programming language + let programmingLanguage = ''; + if (expertise.toLowerCase().includes('python') || interest.toLowerCase().includes('python')) { + programmingLanguage = 'Python'; + } else if (expertise.toLowerCase().includes('r') || interest.toLowerCase().includes('r')) { + programmingLanguage = 'R'; + } else if (expertise.toLowerCase().includes('matlab') || interest.toLowerCase().includes('matlab')) { + programmingLanguage = 'MATLAB'; + } else if (expertise.toLowerCase().includes('git') || interest.toLowerCase().includes('git')) { + programmingLanguage = 'Git'; + } + + // Determine platform + let platform = 'NA'; + if (expertise.toLowerCase().includes('jupyter') || interest.toLowerCase().includes('jupyter')) { + platform = 'Jupyter'; + } else if (expertise.toLowerCase().includes('rstudio') || interest.toLowerCase().includes('rstudio')) { + platform = 'RStudio'; + } else if (expertise.toLowerCase().includes('matlab') || interest.toLowerCase().includes('matlab')) { + platform = 'MATLAB'; + } + + // Create description from role, expertise, and interests + const description = note || `${role ? `Role: ${role}. ` : ''}${expertise ? `Expertise: ${expertise}. ` : ''}${interest ? `Interests: ${interest}` : ''}`.trim(); members.push({ id: `member-${index}`, title: entry.fields.Name, - description: entry.fields.Note || '', - type: 'Community Member', - keywords, + description: description, + type, + keywords: Array.from(new Set(keywords.filter(Boolean))) as string[], + programmingLanguage, + platform, originalData: entry }); }); @@ -89,15 +128,97 @@ export async function fetchCommunityMembers(): Promise<{members: CommunityMember }; } - // In development, use the API route - const response = await fetch('/api/data'); + // In development, also use static data file + const dataUrl = '/output_kg.jsonl'; + const response = await fetch(dataUrl); if (!response.ok) { throw new Error('Failed to fetch data'); } - const data = await response.json(); + const text = await response.text(); + + let kgData; + if (text.trim().startsWith('[')) { + kgData = JSON.parse(text); + } else { + const lines = text.trim().split('\n'); + kgData = lines.map((line, index) => { + try { + return JSON.parse(line); + } catch (error) { + console.error(`Error parsing line ${index}:`, line, error); + throw error; + } + }); + } + + // Transform to community members (matching the same logic as production) + const members: CommunityMember[] = []; + const allCategories = new Set(); + + kgData.forEach((entry: any, index: number) => { + if (!entry.fields?.Name) return; + + const expertise = entry.fields.Expertise || ''; + const interest = entry.fields.Interest || ''; + const role = entry.fields.Role || ''; + const note = entry.fields.Note || ''; + + const keywords = [ + ...(entry.mappings.Expertise?.map((m: any) => m.concept_label).filter(Boolean) || []), + ...(entry.mappings.Interest?.map((m: any) => m.concept_label).filter(Boolean) || []), + ...(entry.mappings.Role?.map((m: any) => m.concept_label).filter(Boolean) || []) + ]; + + keywords.forEach(keyword => allCategories.add(keyword)); + + let type = 'Community Member'; + if (role.toLowerCase().includes('student') || role.toLowerCase().includes('graduate')) { + type = 'Student'; + } else if (role.toLowerCase().includes('researcher') || role.toLowerCase().includes('research')) { + type = 'Researcher'; + } else if (role.toLowerCase().includes('professor') || role.toLowerCase().includes('faculty')) { + type = 'Faculty'; + } else if (role.toLowerCase().includes('developer') || role.toLowerCase().includes('engineer')) { + type = 'Developer'; + } + + let programmingLanguage = ''; + if (expertise.toLowerCase().includes('python') || interest.toLowerCase().includes('python')) { + programmingLanguage = 'Python'; + } else if (expertise.toLowerCase().includes('r') || interest.toLowerCase().includes('r')) { + programmingLanguage = 'R'; + } else if (expertise.toLowerCase().includes('matlab') || interest.toLowerCase().includes('matlab')) { + programmingLanguage = 'MATLAB'; + } else if (expertise.toLowerCase().includes('git') || interest.toLowerCase().includes('git')) { + programmingLanguage = 'Git'; + } + + let platform = 'NA'; + if (expertise.toLowerCase().includes('jupyter') || interest.toLowerCase().includes('jupyter')) { + platform = 'Jupyter'; + } else if (expertise.toLowerCase().includes('rstudio') || interest.toLowerCase().includes('rstudio')) { + platform = 'RStudio'; + } else if (expertise.toLowerCase().includes('matlab') || interest.toLowerCase().includes('matlab')) { + platform = 'MATLAB'; + } + + const description = note || `${role ? `Role: ${role}. ` : ''}${expertise ? `Expertise: ${expertise}. ` : ''}${interest ? `Interests: ${interest}` : ''}`.trim(); + + members.push({ + id: `member-${index}`, + title: entry.fields.Name, + description: description, + type, + keywords: Array.from(new Set(keywords.filter(Boolean))) as string[], + programmingLanguage, + platform, + originalData: entry + }); + }); + return { - members: data.materials || [], - categories: data.categories || [] + members, + categories: Array.from(allCategories).sort() }; } catch (error) { console.error('Error fetching community members:', error); diff --git a/ui/lib/types.ts b/ui/lib/types.ts index a68a8a8..3061609 100644 --- a/ui/lib/types.ts +++ b/ui/lib/types.ts @@ -36,12 +36,7 @@ export interface CommunityMember { keywords: string[]; programmingLanguage?: string; platform?: string; - accessMaterial?: string; originalData?: KnowledgeGraphEntry; // Include original data for ontology mappings } -export interface FilterState { - search: string; - selectedQuadrants: string[]; - selectedCategories: string[]; -} + diff --git a/ui/package.json b/ui/package.json index 868d815..ad34844 100644 --- a/ui/package.json +++ b/ui/package.json @@ -6,8 +6,7 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint", - "setup": "node scripts/setup.js" + "lint": "next lint" }, "dependencies": { "next": "14.0.0", diff --git a/ui/public/output_kg.jsonl b/ui/public/output_kg.jsonl new file mode 100644 index 0000000..f721fd6 --- /dev/null +++ b/ui/public/output_kg.jsonl @@ -0,0 +1,584 @@ +[ + { + "fields": { + "Role": "I work with the DCAIC Leadership team", + "Expertise": "methods for reproducible research", + "Interest": "how the human social brain develops", + "Note": "This is a great consortium", + "Name": "David Kennedy", + "Time": "45855.71949074074" + }, + "mappings": { + "Role": [], + "Expertise": [], + "Interest": [] + } + }, + { + "fields": { + "Role": "graduate student, DCAIC, supporting primarily AI/ML and data standards working groups", + "Expertise": "data analysis of high dimensional data, specifically dimensionality reduction, method development with synthetic validation, information theory", + "Interest": "Experimental design & data details across projects; custom softwares; analytical approaches and best practices", + "Note": "", + "Name": "Kailin Zhuang", + "Time": "45855.73806712963" + }, + "mappings": { + "Role": [ + { + "concept_label": null, + "ontology_id": null, + "ontology": null, + "confidence": null, + "explanation": null + } + ], + "Expertise": [ + { + "concept_label": "Information Theory", + "ontology_id": "Wikidata:Q57459", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "The study of quantification, storage, and communication of information." + } + ], + "Interest": [ + { + "concept_label": null, + "ontology_id": null, + "ontology": null, + "confidence": null, + "explanation": null + } + ] + } + }, + { + "fields": { + "Role": "MEG, MRI, MRS, data acquisition, analysis. In humans. Mostly children. Often children with NDDs", + "Expertise": "", + "Interest": "", + "Note": "", + "Name": "Tim Roberts", + "Time": "45855.744050925925" + }, + "mappings": { + "Role": [ + { + "concept_label": "Magnetoencephalography", + "ontology_id": "UMLS:C0001387", + "ontology": "UMLS", + "confidence": 0.95, + "explanation": "A non-invasive neuroimaging technique that measures the magnetic fields produced by brain activity." + }, + { + "concept_label": "Magnetic Resonance Imaging", + "ontology_id": "UMLS:C0022021", + "ontology": "UMLS", + "confidence": 0.95, + "explanation": "A medical imaging technique used to form pictures of the anatomy and the physiological processes of the body." + }, + { + "concept_label": "Magnetic Resonance Spectroscopy", + "ontology_id": "UMLS:C0032699", + "ontology": "UMLS", + "confidence": 0.9, + "explanation": "A non-invasive imaging technique used to measure the concentration of certain metabolites in brain tissue." + }, + { + "concept_label": "Data Acquisition", + "ontology_id": "UMLS:C0031396", + "ontology": "UMLS", + "confidence": 0.85, + "explanation": "The process of collecting data from various sources." + } + ], + "Expertise": [], + "Interest": [] + } + }, + { + "fields": { + "Role": "Pediatrics Research, Neuroimaging research (MEG), Vulnerable Populations", + "Expertise": "Psychometrics, standardized behavioral/cognitive measures, behavioral support protocols for participants", + "Interest": "Methods in computational neuroscience, EEG data acquisition and measurement workflows, multivariate statistics procedures for multimodal research, concepts in electrical engineering and computational neuroscience as they pertain to neuroimaging research", + "Note": "", + "Name": "Aditya Bhise", + "Time": "45855.74747685185" + }, + "mappings": { + "Role": [ + { + "concept_label": "Pediatrics", + "ontology_id": "Wikidata:Q16996", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Field of medicine that involves the medical care of infants, children, and adolescents." + }, + { + "concept_label": "Vulnerable population", + "ontology_id": "Wikidata:Q1656684", + "ontology": "Wikidata", + "confidence": 0.8, + "explanation": "Groups who are at a higher risk of experiencing harm or adversity." + } + ], + "Expertise": [ + { + "concept_label": "Psychometrics", + "ontology_id": "Wikidata:Q135583", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Field concerned with the theory and technique of psychological measurement." + }, + { + "concept_label": "Standardized test", + "ontology_id": "Wikidata:Q868222", + "ontology": "Wikidata", + "confidence": 0.7, + "explanation": "Tests that are administered and scored in a consistent manner." + } + ], + "Interest": [ + { + "concept_label": "Electroencephalography", + "ontology_id": "Wikidata:Q24970", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Method to record electrical activity of the brain." + }, + { + "concept_label": "Electrical engineering", + "ontology_id": "Wikidata:Q1886", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Field of engineering that deals with the study and application of electricity." + } + ] + } + }, + { + "fields": { + "Role": "Devices, Neural Interfaces, Hardware and Embedded Design, Human", + "Expertise": "Whatever I know", + "Interest": "", + "Note": "", + "Name": "Uros Topalovic", + "Time": "45855.756516203706" + }, + "mappings": { + "Role": [ + { + "concept_label": "Device", + "ontology_id": "Wikidata:Q1052511", + "ontology": "Wikidata", + "confidence": 0.8, + "explanation": "General category of devices." + }, + { + "concept_label": "Neural Interface", + "ontology_id": "Wikidata:Q10543626", + "ontology": "Wikidata", + "confidence": 0.85, + "explanation": "Interfaces that allow interaction with neural systems." + }, + { + "concept_label": "Human", + "ontology_id": "Wikidata:Q5", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Human species." + } + ], + "Expertise": [ + { + "concept_label": null, + "ontology_id": null, + "ontology": null, + "confidence": null, + "explanation": null + } + ], + "Interest": [] + } + }, + { + "fields": { + "Role": "Data Acquisition, mice, social behavior, spikegadgets", + "Expertise": "Data acquisition of HR, neural, and respiratory data in freely socially behaving mice", + "Interest": "", + "Note": "", + "Name": "Sequioa Smith", + "Time": "45855.75599537037" + }, + "mappings": { + "Role": [ + { + "concept_label": "Data Acquisition", + "ontology_id": "UMLS:C0031396", + "ontology": "UMLS", + "confidence": 0.85, + "explanation": "The process of collecting data from various sources." + }, + { + "concept_label": "Data Acquisition", + "ontology_id": null, + "ontology": null, + "confidence": 0.8, + "explanation": "Field related to the collection of data for analysis" + }, + { + "concept_label": "Mouse", + "ontology_id": "Wikidata:Q25189", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Common laboratory animal used in research" + }, + { + "concept_label": "Social Behavior", + "ontology_id": "UMLS:C0226743", + "ontology": "UMLS", + "confidence": 0.9, + "explanation": "Behavior that involves interaction among individuals of the same species" + } + ], + "Expertise": [], + "Interest": [] + } + }, + { + "fields": { + "Role": "NIH Program Officer", + "Expertise": "", + "Interest": "", + "Note": "", + "Name": "Dana Schloesser", + "Time": "45856.79157407407" + }, + "mappings": { + "Role": [ + { + "concept_label": null, + "ontology_id": null, + "ontology": null, + "confidence": null, + "explanation": null + } + ], + "Expertise": [], + "Interest": [] + } + }, + { + "fields": { + "Role": "neuroinformatics, machine learning, neuroimaging, signal processing, infrastructure", + "Expertise": "signal processing, machine learning, infrastructure", + "Interest": "ethics, governance, machine learning", + "Note": "", + "Name": "Satrajit Ghosh", + "Time": "45855.73793981481" + }, + "mappings": { + "Role": [ + { + "concept_label": "Neuroinformatics", + "ontology_id": "Wikidata:Q175019", + "ontology": "Wikidata", + "confidence": 0.8, + "explanation": "Field that uses computational approaches to understand the brain" + }, + { + "concept_label": "Machine learning", + "ontology_id": "Wikidata:Q21803", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Subfield of artificial intelligence" + }, + { + "concept_label": "Neuroimaging", + "ontology_id": "Wikidata:Q85110", + "ontology": "Wikidata", + "confidence": 0.8, + "explanation": "Techniques to visualize the brain" + }, + { + "concept_label": "Signal processing", + "ontology_id": "Wikidata:Q11790", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Analysis of signals" + }, + { + "concept_label": "Infrastructure", + "ontology_id": "Wikidata:Q2344413", + "ontology": "Wikidata", + "confidence": 0.7, + "explanation": "Fundamental facilities and systems serving a country, city, or area" + } + ], + "Expertise": [ + { + "concept_label": "Signal processing", + "ontology_id": "Wikidata:Q11790", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Analysis of signals" + }, + { + "concept_label": "Machine learning", + "ontology_id": "Wikidata:Q21803", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Subfield of artificial intelligence" + }, + { + "concept_label": "Infrastructure", + "ontology_id": "Wikidata:Q2344413", + "ontology": "Wikidata", + "confidence": 0.7, + "explanation": "Fundamental facilities and systems serving a country, city, or area" + } + ], + "Interest": [ + { + "concept_label": "Ethics", + "ontology_id": "Wikidata:Q1907", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Moral principles that govern a person's behavior" + }, + { + "concept_label": "Governance", + "ontology_id": "Wikidata:Q209218", + "ontology": "Wikidata", + "confidence": 0.8, + "explanation": "The action or manner of governing a state, organization, etc." + }, + { + "concept_label": "Machine learning", + "ontology_id": "Wikidata:Q21803", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Subfield of artificial intelligence" + } + ] + } + }, + { + "fields": { + "Role": "Oversee the EMBER Data Archive", + "Expertise": "Data Ecosystems, Data Analysis, Data Sharing, Data Pipelines", + "Interest": "Data Acquisition (from various teams, to help)", + "Note": "", + "Name": "Brock Wester", + "Time": "45855.75269675926" + }, + "mappings": { + "Role": [ + { + "concept_label": null, + "ontology_id": null, + "ontology": null, + "confidence": null, + "explanation": null + } + ], + "Expertise": [ + { + "concept_label": null, + "ontology_id": null, + "ontology": null, + "confidence": null, + "explanation": null + }, + { + "concept_label": "Data Analysis", + "ontology_id": "Wikidata:Q31431", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "The process of inspecting, cleansing, transforming, and modeling data." + }, + { + "concept_label": "Data analysis", + "ontology_id": "Wikidata:Q32888", + "ontology": "Wikidata", + "confidence": 0.8, + "explanation": "Process of inspecting, cleaning, and modeling data" + } + ], + "Interest": [] + } + }, + { + "fields": { + "Role": "computational cognitive neuroscience", + "Expertise": "data analysis, data management", + "Interest": "devices, design, data acquisition, animal work", + "Note": "", + "Name": "Yibei Chen", + "Time": "45863.10055555555" + }, + "mappings": { + "Role": [ + { + "concept_label": "Computational Neuroscience", + "ontology_id": "Wikidata:Q29582", + "ontology": "Wikidata", + "confidence": 0.8, + "explanation": "Field that uses computational approaches to understand the function of the brain." + } + ], + "Expertise": [ + { + "concept_label": "Data Analysis", + "ontology_id": "Wikidata:Q31431", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "The process of inspecting, cleansing, transforming, and modeling data." + }, + { + "concept_label": "Data analysis", + "ontology_id": "Wikidata:Q32888", + "ontology": "Wikidata", + "confidence": 0.8, + "explanation": "Process of inspecting, cleaning, and modeling data" + }, + { + "concept_label": "Data Analysis", + "ontology_id": "Wikidata:Q205163", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Process of systematically applying statistical and logical techniques to describe and evaluate data." + }, + { + "concept_label": "Data Management", + "ontology_id": "Wikidata:Q224977", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Development and execution of architectures, policies, practices, and procedures to manage the data lifecycle." + } + ], + "Interest": [ + { + "concept_label": "Device", + "ontology_id": "Wikidata:Q27447", + "ontology": "Wikidata", + "confidence": 0.8, + "explanation": "Tool or instrument used for a particular purpose." + }, + { + "concept_label": "Design", + "ontology_id": "Wikidata:Q22680", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Process of generating solutions for problems, primarily visual and functional parameters." + }, + { + "concept_label": "Data acquisition", + "ontology_id": "Wikidata:Q29634", + "ontology": "Wikidata", + "confidence": 0.85, + "explanation": "The process of obtaining data from various sources" + }, + { + "concept_label": "Data Acquisition", + "ontology_id": "Wikidata:Q1153394", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Process of collecting and measuring physical phenomena." + }, + { + "concept_label": "Animal Testing", + "ontology_id": "Wikidata:Q28139", + "ontology": "Wikidata", + "confidence": 0.7, + "explanation": "Use of non-human animals in research." + } + ] + } + }, + { + "fields": { + "Role": "I am working on the Capturing Autobiographical memory formation in People moving Through real-world spaces Using synchronized wearables and intracranial Recordings of EEG. My work includes: Data Analysis, Data Acquisition, Research Design, and Devices development", + "Expertise": "Device and Hardware design, Data Analysis particularly EEG/iEEG signal processing, Eye-tracking, fMRI, and Statistical Analysis in human", + "Interest": "Challenges in Device and Hardware design, and Data Analysis, Automated Video processing in human and animals", + "Note": "", + "Name": "Alireza Kazemi", + "Time": "45890.844375" + }, + "mappings": { + "Role": [ + { + "concept_label": "Data Acquisition", + "ontology_id": "UMLS:C0031396", + "ontology": "UMLS", + "confidence": 0.85, + "explanation": "The process of collecting data from various sources." + }, + { + "concept_label": "Data Acquisition", + "ontology_id": null, + "ontology": null, + "confidence": 0.8, + "explanation": "Field related to the collection of data for analysis" + } + ], + "Expertise": [ + { + "concept_label": "Eye Tracking", + "ontology_id": "Wikidata:Q159068", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "Technology used to measure eye positions and movements." + }, + { + "concept_label": "Functional Magnetic Resonance Imaging", + "ontology_id": "UMLS:C0016211", + "ontology": "UMLS", + "confidence": 0.9, + "explanation": "A technique used to measure and map brain activity." + } + ], + "Interest": [ + { + "concept_label": "Data Analysis", + "ontology_id": "Wikidata:Q35006968", + "ontology": "Wikidata", + "confidence": 0.85, + "explanation": "The process of inspecting, cleansing, transforming, and modeling data." + } + ] + } + }, + { + "fields": { + "Role": "I work with Knowledge Graphs", + "Expertise": "Knowledge Graphs and its benefits", + "Interest": "Neuroscience", + "Note": "", + "Name": "Tek Raj Chhetri", + "Time": "45895.837858796294" + }, + "mappings": { + "Role": [], + "Expertise": [ + { + "concept_label": "Knowledge Graphs", + "ontology_id": null, + "ontology": null, + "confidence": 0.8, + "explanation": "A technology used to provide benefits in data management and retrieval." + } + ], + "Interest": [ + { + "concept_label": "Neuroscience", + "ontology_id": "Wikidata:Q12132", + "ontology": "Wikidata", + "confidence": 0.9, + "explanation": "The scientific study of the nervous system." + } + ] + } + } +] \ No newline at end of file diff --git a/ui/public/output_normalized.csv b/ui/public/output_normalized.csv new file mode 100644 index 0000000..9349cc5 --- /dev/null +++ b/ui/public/output_normalized.csv @@ -0,0 +1,13 @@ +Role,Expertise,Interest,Note,Name,Time +I work with the DCAIC Leadership team,methods for reproducible research,how the human social brain develops,This is a great consortium,David Kennedy,45855.71949074074 +"graduate student, DCAIC, supporting primarily AI/ML and data standards working groups","data analysis of high dimensional data, specifically dimensionality reduction, method development with synthetic validation, information theory",Experimental design & data details across projects; custom softwares; analytical approaches and best practices,,Kailin Zhuang,45855.73806712963 +"MEG, MRI, MRS, data acquisition, analysis. In humans. Mostly children. Often children with NDDs",,,,Tim Roberts,45855.744050925925 +"Pediatrics Research, Neuroimaging research (MEG), Vulnerable Populations","Psychometrics, standardized behavioral/cognitive measures, behavioral support protocols for participants","Methods in computational neuroscience, EEG data acquisition and measurement workflows, multivariate statistics procedures for multimodal research, concepts in electrical engineering and computational neuroscience as they pertain to neuroimaging research",,Aditya Bhise,45855.74747685185 +"Devices, Neural Interfaces, Hardware and Embedded Design, Human",Whatever I know,,,Uros Topalovic,45855.756516203706 +"Data Acquisition, mice, social behavior, spikegadgets","Data acquisition of HR, neural, and respiratory data in freely socially behaving mice",,,Sequioa Smith,45855.75599537037 +NIH Program Officer,,,,Dana Schloesser,45856.79157407407 +"neuroinformatics, machine learning, neuroimaging, signal processing, infrastructure","signal processing, machine learning, infrastructure","ethics, governance, machine learning",,Satrajit Ghosh,45855.73793981481 +Oversee the EMBER Data Archive,"Data Ecosystems, Data Analysis, Data Sharing, Data Pipelines","Data Acquisition (from various teams, to help)",,Brock Wester,45855.75269675926 +computational cognitive neuroscience,"data analysis, data management","devices, design, data acquisition, animal work",,Yibei Chen,45863.10055555555 +"I am working on the Capturing Autobiographical memory formation in People moving Through real-world spaces Using synchronized wearables and intracranial Recordings of EEG. My work includes: Data Analysis, Data Acquisition, Research Design, and Devices development","Device and Hardware design, Data Analysis particularly EEG/iEEG signal processing, Eye-tracking, fMRI, and Statistical Analysis in human","Challenges in Device and Hardware design, and Data Analysis, Automated Video processing in human and animals",,Alireza Kazemi,45890.844375 +I work with Knowledge Graphs,Knowledge Graphs and its benefits,Neuroscience,,Tek Raj Chhetri,45895.837858796294