Citation generator added

This commit is contained in:
2024-10-28 19:08:33 -07:00
parent 9e55ba90e1
commit 2f26afb36f
3 changed files with 72 additions and 14 deletions

View File

@@ -2,7 +2,7 @@
abstract = {Human-robot interaction (HRI) research plays a pivotal role in shaping how robots communicate and collaborate with humans. However, conducting HRI studies, particularly those employing the Wizard-of-Oz (WoZ) technique, can be challenging. WoZ user studies can have complexities at the technical and methodological levels that may render the results irreproducible. We propose to address these challenges with HRIStudio, a novel web-based platform designed to streamline the design, execution, and analysis of WoZ experiments. HRIStudio offers an intuitive interface for experiment creation, real-time control and monitoring during experimental runs, and comprehensive data logging and playback tools for analysis and reproducibility. By lowering technical barriers, promoting collaboration, and offering methodological guidelines, HRIStudio aims to make human-centered robotics research easier, and at the same time, empower researchers to develop scientifically rigorous user studies.}, abstract = {Human-robot interaction (HRI) research plays a pivotal role in shaping how robots communicate and collaborate with humans. However, conducting HRI studies, particularly those employing the Wizard-of-Oz (WoZ) technique, can be challenging. WoZ user studies can have complexities at the technical and methodological levels that may render the results irreproducible. We propose to address these challenges with HRIStudio, a novel web-based platform designed to streamline the design, execution, and analysis of WoZ experiments. HRIStudio offers an intuitive interface for experiment creation, real-time control and monitoring during experimental runs, and comprehensive data logging and playback tools for analysis and reproducibility. By lowering technical barriers, promoting collaboration, and offering methodological guidelines, HRIStudio aims to make human-centered robotics research easier, and at the same time, empower researchers to develop scientifically rigorous user studies.},
author = {O'Connor, Sean and Perrone, L. Felipe}, author = {O'Connor, Sean and Perrone, L. Felipe},
title = {HRIStudio: A Framework for Wizard-of-Oz Experiments in Human-Robot Interaction Studies (Late Breaking Report)}, title = {HRIStudio: A Framework for Wizard-of-Oz Experiments in Human-Robot Interaction Studies (Late Breaking Report)},
booktitle={33rd IEEE International Conference on Robot and Human Interactive Communication (RO-MAN)}, booktitle={33rd IEEE International Conference on Robot and Human Interactive Communication},
year = {2024} year = {2024}
url = {https://soconnor.dev/publications/hristudio-lbr.pdf}, url = {https://soconnor.dev/publications/hristudio-lbr.pdf},
paperUrl = {/publications/hristudio-lbr.pdf}, paperUrl = {/publications/hristudio-lbr.pdf},

View File

@@ -1,17 +1,18 @@
'use client'; 'use client';
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "~/components/ui/card"; import { ArrowUpRight, BookOpenText, FileText, Presentation } from "lucide-react";
import { Badge } from "~/components/ui/badge";
import { ArrowUpRight, FileText, Presentation } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { parseBibtex } from "~/lib/bibtex";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import type { Publication } from "~/lib/bibtex"; import { Badge } from "~/components/ui/badge";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
import { Skeleton } from "~/components/ui/skeleton"; import { Skeleton } from "~/components/ui/skeleton";
import type { Publication } from "~/lib/bibtex";
import { parseBibtex } from "~/lib/bibtex";
export default function PublicationsPage() { export default function PublicationsPage() {
const [publications, setPublications] = useState<Publication[]>([]); const [publications, setPublications] = useState<Publication[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const tagsToStrip = ['paperUrl', 'posterUrl'];
useEffect(() => { useEffect(() => {
fetch('/publications.bib') fetch('/publications.bib')
@@ -23,6 +24,38 @@ export default function PublicationsPage() {
}); });
}, []); }, []);
const downloadBibtex = (pub: Publication) => {
const { title, authors, venue, year, doi, abstract, type, citationType, citationKey } = pub;
let bibtexEntry = `@${citationType}{${citationKey},\n`;
bibtexEntry += ` title = {${title}},\n`;
bibtexEntry += ` author = {${authors.join(' and ')}},\n`;
bibtexEntry += ` year = {${year}},\n`;
if (type === 'conference' || type === 'workshop') {
bibtexEntry += ` organization = {${venue}},\n`;
} else if (type === 'journal') {
bibtexEntry += ` journal = {${venue}},\n`;
} else if (type === 'thesis') {
bibtexEntry += ` school = {${venue}},\n`;
}
if (doi) {
bibtexEntry += ` doi = {${doi}},\n`;
}
if (abstract) {
bibtexEntry += ` abstract = {${abstract}},\n`;
}
bibtexEntry += `}\n`;
const blob = new Blob([bibtexEntry], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `refs.bib`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
};
return ( return (
<div className="space-y-8"> <div className="space-y-8">
<section className="prose prose-zinc dark:prose-invert max-w-none"> <section className="prose prose-zinc dark:prose-invert max-w-none">
@@ -49,9 +82,9 @@ export default function PublicationsPage() {
<CardHeader className="pb-2"> <CardHeader className="pb-2">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<CardTitle>{pub.title}</CardTitle> <CardTitle>{pub.title}</CardTitle>
{pub.url && ( {pub.paperUrl && (
<Link <Link
href={pub.url} href={pub.paperUrl}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-muted-foreground hover:text-primary" className="text-muted-foreground hover:text-primary"
@@ -113,6 +146,14 @@ export default function PublicationsPage() {
</Badge> </Badge>
</Link> </Link>
)} )}
<Badge
onClick={() => downloadBibtex(pub)}
className="cursor-pointer capitalize"
variant="outline"
>
<BookOpenText className="h-4 w-4" />
BibTeX
</Badge>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>

View File

@@ -8,12 +8,15 @@ export type Publication = {
paperUrl?: string; paperUrl?: string;
posterUrl?: string; posterUrl?: string;
abstract?: string; abstract?: string;
citationType?: string;
citationKey?: string;
type: 'conference' | 'journal' | 'workshop' | 'thesis'; type: 'conference' | 'journal' | 'workshop' | 'thesis';
}; };
type BibTeXEntry = { type BibTeXEntry = {
type: string; type: string;
fields: Record<string, string>; fields: Record<string, string>;
citationKey: string;
}; };
function parseAuthors(authorString: string): string[] { function parseAuthors(authorString: string): string[] {
@@ -31,10 +34,11 @@ function parseAuthors(authorString: string): string[] {
function parseBibTeXEntry(entry: string): BibTeXEntry | null { function parseBibTeXEntry(entry: string): BibTeXEntry | null {
// Match the entry type and content // Match the entry type and content
const typeMatch = entry.match(/^(\w+)\s*{\s*[\w\d-_]+\s*,/); const typeMatch = entry.match(/^(\w+)\s*{\s*([\w\d-_]+)\s*,/);
if (!typeMatch) return null; if (!typeMatch) return null;
const type = typeMatch[1]!.toLowerCase(); const type = typeMatch[1]!.toLowerCase();
const citationKey = typeMatch[2];
const content = entry.slice(typeMatch[0].length); const content = entry.slice(typeMatch[0].length);
const fields: Record<string, string> = {}; const fields: Record<string, string> = {};
@@ -68,7 +72,7 @@ function parseBibTeXEntry(entry: string): BibTeXEntry | null {
fields[currentField] = buffer.trim(); fields[currentField] = buffer.trim();
} }
return { type, fields }; return { type, fields, citationKey: citationKey! };
} }
export function parseBibtex(bibtex: string): Publication[] { export function parseBibtex(bibtex: string): Publication[] {
@@ -79,10 +83,21 @@ export function parseBibtex(bibtex: string): Publication[] {
.filter((entry): entry is BibTeXEntry => entry !== null); .filter((entry): entry is BibTeXEntry => entry !== null);
return entries.map(entry => { return entries.map(entry => {
const publicationType = const publicationType = (() => {
entry.type === 'inproceedings' ? 'conference' : switch (entry.type) {
entry.type === 'article' ? 'journal' : case 'inproceedings':
entry.type === 'mastersthesis' ? 'thesis' : 'workshop'; case 'conference':
return 'conference';
case 'article':
return 'journal';
case 'mastersthesis':
return 'thesis';
case 'workshop':
return 'workshop';
default:
return 'journal';
}
})();
return { return {
title: entry.fields.title?.replace(/[{}]/g, '') || '', title: entry.fields.title?.replace(/[{}]/g, '') || '',
@@ -94,6 +109,8 @@ export function parseBibtex(bibtex: string): Publication[] {
paperUrl: entry.fields.paperurl, paperUrl: entry.fields.paperurl,
posterUrl: entry.fields.posterurl, posterUrl: entry.fields.posterurl,
abstract: entry.fields.abstract, abstract: entry.fields.abstract,
citationType: entry.type,
citationKey: entry.citationKey,
type: publicationType type: publicationType
}; };
}); });