npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@orkg/scidquest

v1.1.7

Published

SciD-QuESt: From Scientific Documents to Knowledge - Questionnaire-Based Extraction and Structuring of Knowledge in the Open Research Knowledge Graph with LLMs and Human Validation

Readme

SciD-QuESt: From Scientific Documents to Knowledge

SciD-QuESt Logo

An AI-assisted React library for structured research-paper analysis workflows.

ScidQuest provides a reusable UI and workflow foundation for extracting structured information from research papers (PDF) with template-driven forms, model-assisted suggestions, and answer verification.

Table of Contents

About

ScidQuest is distributed as an npm package: @orkg/scidquest.

It is intended for teams building research tooling that requires:

  • PDF-first review workflows
  • structured questionnaire-based extraction
  • AI-assisted response generation and verification
  • portable frontend integration with modern React stacks

(back to top)

Key Features

  • PDF upload and viewing with zoom and page navigation
  • Split-panel analysis UI for side-by-side document and questionnaire usage
  • Template-driven forms for consistent data extraction
  • AI suggestions for draft answers from document context
  • AI verification to validate user answers against source content
  • Local persistence for in-progress analysis sessions
  • Embeddable workflows with custom forms while keeping PDF extraction and per-field AI

(back to top)

Installation

Install the package with npm:

npm install @orkg/scidquest

(back to top)

Styles

Import the published stylesheet in your application entrypoint (or layout):

import "@orkg/scidquest/dist/contribute-standalone.css";

(back to top)

Quick start

The smallest end-to-end flow is: implement LLMService, wrap the tree with ScidQuestProvider (and QuestionnaireAIProvider if you use AI chrome such as AIAssistantButton or ResearchQuestionnaireFieldAiWrapper), then render ResearchQuestionnaireApp with a QuestionnaireTemplate and either the default questionnaire or a custom questionnaireSlot.

import React, { useMemo, useState } from "react";
import { createRoot } from "react-dom/client";
import "@orkg/scidquest/dist/contribute-standalone.css";
import {
  ScidQuestProvider,
  QuestionnaireAIProvider,
  ResearchQuestionnaireApp,
  type LLMService,
  type QuestionnaireTemplate,
} from "@orkg/scidquest";

const templateSpec: QuestionnaireTemplate = {
  version: "1",
  template: "demo",
  template_id: "demo",
  sections: [
    {
      id: "sec1",
      title: "Example",
      questions: [
        {
          id: "q1",
          label: "Main contribution",
          type: "text",
          required: true,
        },
      ],
    },
  ],
};

class DemoLLM implements LLMService {
  async generateText(prompt: string, options?: { systemContext?: string }) {
    // Replace with your provider (OpenAI, Azure, local, etc.).
    return { text: '{"suggestions":[{"rank":1,"text":"…","confidence":0.9,"evidence":[]}]}' };
  }
  isConfigured() {
    return true;
  }
}

function App() {
  const llmService = useMemo(() => new DemoLLM(), []);
  const [answers, setAnswers] = useState<Record<string, unknown>>({});

  return (
    <QuestionnaireAIProvider>
      <ScidQuestProvider llmService={llmService}>
        <ResearchQuestionnaireApp
          templateSpec={templateSpec}
          answers={answers}
          setAnswers={setAnswers}
          layout="split"
        />
      </ScidQuestProvider>
    </QuestionnaireAIProvider>
  );
}

createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

Typical end-user workflow inside the default UI:

  1. Upload a PDF file (default max 30 MB).
  2. Wait for text extraction; complete template questions.
  3. Request AI suggestions where needed; jump to PDF evidence when offered.
  4. Run batch verification from the summary bar where available.
  5. Export or import JSON progress.

(back to top)

Provider stack

| Order (outer → inner) | Purpose | | --- | --- | | QuestionnaireAIProvider | Persists suggestion/verification history used by AIAssistantButton and related UI (localStorage key questionnaire-ai-history). | | ScidQuestProvider | Supplies LLMService via an internal ScidQuestAdapter (Redux store included for internal widgets). | | ResearchQuestionnaireWorkspaceProvider | Injected automatically by ResearchQuestionnaireApp around questionnaireSlot only; exposes PDF/answers/template to useResearchQuestionnaireWorkspace. |

If you only use useSuggestionGenerator and never mount AIAssistantButton / ResearchQuestionnaireFieldAiWrapper, you can omit QuestionnaireAIProvider. For the full questionnaire UI or embed wrappers, include it.

(back to top)

Library API reference

Everything below is imported from @orkg/scidquest unless noted.

ScidQuestProvider and useScidQuestContext

Purpose: Connects your LLMService to hooks and components that call adapter.generateSuggestions, adapter.verifyAnswer, or batch verification.

Props (ScidQuestProvider):

| Prop | Type | Description | | --- | --- | --- | | llmService | LLMService | Required. Your implementation of text generation and configuration checks. | | children | ReactNode | App subtree that needs ScidQuest AI APIs. |

useScidQuestContext() returns { adapter: ScidQuestAdapter }. Throws if used outside ScidQuestProvider.

import { ScidQuestProvider, useScidQuestContext } from "@orkg/scidquest";

function Child() {
  const { adapter } = useScidQuestContext();
  return <button type="button" onClick={() => void adapter.isConfigured()}>Check</button>;
}

<ScidQuestProvider llmService={llmService}>
  <Child />
</ScidQuestProvider>

(back to top)

LLMService, ScidQuestAdapter, and createScidQuestAdapter

LLMService is the contract you implement: the library never holds API keys. Implement generateText(prompt, options?) returning { text, reasoning?, usage? } and isConfigured().

createScidQuestAdapter(llmService) builds a ScidQuestAdapter: generateSuggestions, verifyAnswer, optional verifyAnswersBatch, and isConfigured. Advanced integrations can implement ScidQuestAdapter directly instead of using createScidQuestAdapter, then you would need a custom way to inject it (the shipped ScidQuestProvider always uses createScidQuestAdapter).

import { createScidQuestAdapter, type LLMService } from "@orkg/scidquest";

const adapter = createScidQuestAdapter(myLlmService);
await adapter.verifyAnswer({
  questionId: "q1",
  questionText: "Contribution?",
  currentAnswer: "They propose a new metric.",
  pdfContent: extractedPlainText,
});

(back to top)

useSuggestionGenerator

Purpose: Call the adapter’s suggestion pipeline from arbitrary UI (no PDF viewer required). Requires ScidQuestProvider.

Parameters:

| Option | Type | Description | | --- | --- | --- | | questionText | string | Wording shown to the model. | | questionType | string | Template field type (e.g. text, select). | | questionOptions | string[]? | For choice-style questions. | | pdfContent | string? | Extracted document text; required for a successful run. | | contextHistory | history entries | Prior suggestions for diversity (see type exports). | | previousFeedback | array | Thumbs/comments from prior runs (shape matches suggestion feedback entries: ids, rating, optional comment, timestamp). | | excludedSuggestionIds | Set<string> | IDs to strip from contextHistory. |

Returns: { suggestions, loading, error, rawError, generateSuggestions, clearSuggestions }.

import { useSuggestionGenerator } from "@orkg/scidquest";

function Panel({ pdfText }: { pdfText: string }) {
  const { suggestions, loading, error, generateSuggestions, clearSuggestions } =
    useSuggestionGenerator({
      questionText: "What is the research objective?",
      questionType: "text",
      pdfContent: pdfText,
    });

  return (
    <>
      <button type="button" disabled={loading} onClick={() => void generateSuggestions()}>
        Suggest
      </button>
      <button type="button" onClick={clearSuggestions}>Clear</button>
      {error && <p role="alert">{error}</p>}
      <ul>
        {suggestions.map((s) => (
          <li key={s.id}>{typeof s.text === "string" ? s.text : s.text.join(", ")}</li>
        ))}
      </ul>
    </>
  );
}

(back to top)

ResearchQuestionnaireApp

Purpose: Orchestrates PDF upload, PdfViewer, plain-text extraction, optional structured document extraction, split or single-column layout, and either the built-in TemplateQuestionnaire or a custom questionnaireSlot.

Props (ResearchQuestionnaireAppProps):

| Prop | Type | Default | Description | | --- | --- | --- | --- | | templateSpec | QuestionnaireTemplate | (required) | Sections and question definitions. | | pdfTextExtractor | { extractFullText(url: string): Promise<string> } | built-in | Override for bundlers or custom PDF pipelines. | | structuredPdfExtractor | { extractStructuredDocument(text: string): Promise<StructuredDocument> } | built-in | Builds structured sections from extracted text. | | maxPdfSizeBytes | number | 30 MB | Passed to PDFUpload. | | layout | 'split' \| 'single' | 'split' | Desktop split panel vs stacked flow; narrow viewports behave like single. | | showPdfViewer | boolean | true | Hide the PDF column but keep extraction if a URL exists. | | onAnswersChange | (answers) => void | — | Fires whenever answers updates. | | initialAnswers | Record<string, unknown> | {} | Seed state when uncontrolled. | | answers / setAnswers | controlled pair | — | When both set, the host owns answer state. | | questionnaireSlot | (ctx: ResearchQuestionnaireWorkspaceValue) => ReactNode | — | Embed mode: replace built-in questionnaire; ctx includes pdfContent, answers, navigation, highlights. | | sx | MUI sx | — | Root Box styling. |

<ResearchQuestionnaireApp
  templateSpec={templateSpec}
  answers={answers}
  setAnswers={setAnswers}
  layout="split"
  showPdfViewer
  onAnswersChange={() => {}}
/>

Embed mode (custom form, same PDF pipeline):

<ResearchQuestionnaireApp
  templateSpec={templateSpec}
  answers={answers}
  setAnswers={setAnswers}
  questionnaireSlot={(ctx) => (
    <MyForm
      answers={ctx.answers}
      setAnswers={ctx.setAnswers}
      pdfText={ctx.pdfContent}
      onJumpToPage={ctx.onNavigateToPage}
    />
  )}
/>

See docs/EMBEDDING.md for embedding caveats (bundlers, QuestionnaireAIProvider).

(back to top)

TemplateQuestionnaire

Purpose: Full questionnaire UI: section accordions, validation, export/import JSON, localStorage autosave, AI verification batch from the summary bar, and integration with PDF navigation and highlights when props are passed.

Requires: ScidQuestProvider (uses adapter for verification).

Main props (TemplateQuestionnaireProps):

| Prop | Type | Description | | --- | --- | --- | | templateSpec | QuestionnaireTemplate \| null | When null, shows a short loading placeholder. | | answers / setAnswers | Record<string, unknown> + updater | Controlled answer map (question ids as keys; repeat sections use arrays under section ids per template). | | pdfContent | string? | Plain text passed to AI flows. | | structuredDocument | StructuredDocument \| null? | Improves evidence handling when present. | | onNavigateToPage | (page: number) => void | Scroll PDF to page. | | onHighlightsChange | highlight map | Receives highlight rects keyed by page. | | pdfUrl / pageWidth | viewer sync | Used for evidence UI alignment. | | pdfExtractionError / onRetryExtraction | error UX | Shown in the top bar when extraction fails. | | aiConfig.hidden | boolean | Hides AI configuration entry points in the summary bar when set. | | sx | MUI sx | Wrapper styling. |

<TemplateQuestionnaire
  templateSpec={templateSpec}
  answers={answers}
  setAnswers={setAnswers}
  pdfContent={extractedText}
  structuredDocument={structured}
  onNavigateToPage={goToPage}
  onHighlightsChange={setHighlights}
  pdfUrl={blobUrl}
  pageWidth={pageWidth}
/>

(back to top)

PDFUpload

Purpose: Drag-and-drop or file-picker PDF upload with type and size validation and optional clear.

Props (PDFUploadProps):

| Prop | Type | Default | Description | | --- | --- | --- | --- | | onFileSelected | (file: File) => void | required | Called with a validated PDF File. | | onFileRemoved | () => void | — | Called when the user clears the selection. | | maxSizeBytes | number | 30 MB | Rejects larger files. | | accept | string | application/pdf | Input accept attribute. | | disabled | boolean | false | Disables interaction. | | sx | MUI sx | — | Root Box styling. |

const [file, setFile] = useState<File | null>(null);

<PDFUpload
  maxSizeBytes={20 * 1024 * 1024}
  onFileSelected={(f) => setFile(f)}
  onFileRemoved={() => setFile(null)}
/>

(back to top)

PdfViewer

Purpose: Renders PDF pages with react-pdf, zoom, page controls, optional full-document text extraction via pdfTextExtractor, and optional highlight overlays.

Props (PdfViewerProps):

| Prop | Type | Description | | --- | --- | --- | | refContainer | RefObject<HTMLDivElement> | Scroll container for pages (must be the element that scrolls). | | pdfUrl | string \| null \| undefined | Blob URL or remote PDF URL. | | pageWidth | number \| null | Pixel width of each page. | | registerCommands | (cmds: { goToPage(n) }) => void | Optional imperative navigation hook-up. | | onTextExtracted | (text: string) => void | Called when pdfTextExtractor finishes. | | onExtractionError | (err: Error) => void | Extraction failure path. | | highlights | Record<number, Array<{ left, top, width, height }>> | Yellow overlays per page number. | | pdfTextExtractor | { extractFullText(url: string): Promise<string> } \| null | When null/omitted, no automatic extraction. |

const scrollRef = useRef<HTMLDivElement>(null);
const [url, setUrl] = useState<string | null>(null);

<Box ref={scrollRef} sx={{ height: 480, overflow: "auto" }}>
  <PdfViewer
    refContainer={scrollRef}
    pdfUrl={url}
    pageWidth={720}
    pdfTextExtractor={myExtractor}
    onTextExtracted={setPlainText}
    onExtractionError={console.error}
    highlights={highlightsByPage}
  />
</Box>

The viewer configures pdfjs worker from unpkg; override at app level if your CSP requires a self-hosted worker.

(back to top)

ResearchQuestionnaireWorkspaceProvider and useResearchQuestionnaireWorkspace

Purpose: Exposes the workspace value (ResearchQuestionnaireWorkspaceValue) to descendants: template, answers, extracted PDF text, structured document, PDF URL, pageWidth, navigation and highlight callbacks, and extraction error/retry.

ResearchQuestionnaireApp wraps questionnaireSlot output with ResearchQuestionnaireWorkspaceProvider. When you render TemplateQuestionnaire alone (without the app), no workspace context is present unless you add the provider yourself.

useResearchQuestionnaireWorkspace() returns the value or null when used outside the provider (the field AI wrapper treats null as “no workspace” and renders children only).

import {
  ResearchQuestionnaireWorkspaceProvider,
  useResearchQuestionnaireWorkspace,
} from "@orkg/scidquest";

function Inner() {
  const ws = useResearchQuestionnaireWorkspace();
  if (!ws) return null;
  return <span>{ws.pdfContent?.slice(0, 80)}…</span>;
}

<ResearchQuestionnaireWorkspaceProvider value={workspaceValue}>
  <Inner />
</ResearchQuestionnaireWorkspaceProvider>

(back to top)

ResearchQuestionnaireFieldAiWrapper

Purpose: Wraps a single host-rendered control with the same AI affordances as built-in fields: suggestion generation, verification entry via AIAssistantButton, and SuggestionBox wired to workspace navigation/highlights.

Requires: Inside ResearchQuestionnaireWorkspaceProvider (automatic in embed mode under ResearchQuestionnaireApp) and ScidQuestProvider. For full AIAssistantButton behavior (history dialog, etc.), also use QuestionnaireAIProvider.

Props (ResearchQuestionnaireFieldAiWrapperProps):

| Prop | Type | Description | | --- | --- | --- | | children | ReactNode | Your input component. | | questionId | string | Must match an id in templateSpec for sibling/context helpers. | | questionText | string | Label or prompt sent to the model. | | questionType | ResearchFieldAiQuestionType | text \| select \| multi_select \| repeat_text \| group. | | questionOptions | string[]? | For select-style fields. | | currentAnswer | string | String form of the value for verification. | | onApplySuggestion | (text: string) => void | Apply chosen suggestion text into your state. | | disableAi | boolean? | Force-disable AI chrome. | | parentContext | ParentContext? | Optional nested/group context (see app types/context). | | onVerificationComplete | (result: AIVerificationResult) => void | Per-field verification callback. |

If the template marks the question with disable_ai_assistant: true, the wrapper renders children only.

<ResearchQuestionnaireFieldAiWrapper
  questionId="contribution"
  questionText="Main contribution"
  questionType="text"
  currentAnswer={String(value ?? "")}
  onApplySuggestion={(t) => setValue(t)}
>
  <TextField fullWidth value={value} onChange={(e) => setValue(e.target.value)} />
</ResearchQuestionnaireFieldAiWrapper>

(back to top)

AIAssistantButton and SuggestionBox

Lower-level building blocks used inside ResearchQuestionnaireFieldAiWrapper. Prefer the wrapper unless you need a fully custom layout.

AIAssistantButton (forwardRef, exposes AIAssistantButtonRef with triggerSuggestion / triggerVerification):

  • Expects ScidQuestProvider, and QuestionnaireAIProvider for history features.
  • Props include questionId, questionText, questionType, questionOptions, currentAnswer, pdfContent, structuredDocument, allAnswers, siblingQuestionIds, questionDefinitions, callbacks onSuggestionsGenerated, onError, onVerificationComplete, optional parentContext, disabled, etc.

SuggestionBox displays ranked suggestions, loading/error states, evidence navigation, collapse, regenerate, and feedback hooks (onFeedback, onApply, onNavigateToPage, onHighlightsChange, …).

import { AIAssistantButton, SuggestionBox, QuestionnaireAIProvider } from "@orkg/scidquest";

// Typical usage is through ResearchQuestionnaireFieldAiWrapper; direct composition
// requires you to manage suggestion list state and refs yourself (see source).

(back to top)

QuestionnaireAIProvider and QuestionnaireAIContext

Purpose: In-memory and localStorage-backed history for questionnaire AI events (QuestionnaireAIState / QuestionnaireAIHistory).

QuestionnaireAIProvider: wrap near the root of anything that mounts AIAssistantButton (or the field wrapper that uses it).

QuestionnaireAIContext: the React context object. The package does not export the useQuestionnaireAI hook; use useContext(QuestionnaireAIContext) if you need programmatic access to addToHistory, getHistoryByQuestion, clearHistory, etc., and guard for undefined.

import { useContext } from "react";
import { QuestionnaireAIContext, QuestionnaireAIProvider } from "@orkg/scidquest";

function HistoryLength() {
  const api = useContext(QuestionnaireAIContext);
  if (!api) return null;
  return <span>{api.state.history.length} events</span>;
}

<QuestionnaireAIProvider>
  <HistoryLength />
</QuestionnaireAIProvider>

(back to top)

buildQuestionDefinitions and siblingQuestionIdsFor

Purpose: Template helpers for advanced AI context.

  • buildQuestionDefinitions(template) — flat map questionId → Question including nested subquestions / item_fields.
  • siblingQuestionIdsFor(template, questionId) — ids in the same section top-level group or same nested group; used to gather related answers for prompting.
import { buildQuestionDefinitions, siblingQuestionIdsFor } from "@orkg/scidquest";

const defs = buildQuestionDefinitions(templateSpec);
const siblings = siblingQuestionIdsFor(templateSpec, "q1");

(back to top)

Types

The package re-exports TypeScript types for templates, LLM wiring, suggestions, and verification. Commonly used names:

| Name | Role | | --- | --- | | QuestionnaireTemplate, Section, Question, ValidationRule, Mapping, Link | JSON template model for forms and AI metadata. | | LLMService, LLMGenerateTextOptions, LLMGenerateTextResponse | Bring-your-own-model contract. | | ScidQuestAdapter | Higher-level adapter implemented by createScidQuestAdapter. | | GenerateSuggestionsRequest, GenerateSuggestionsResponse, Suggestion, FeedbackData | Suggestion API surface. | | VerifyAnswerRequest, AIVerificationResult | Verification API surface. | | ResearchQuestionnaireWorkspaceValue, ResearchQuestionnaireSlotRenderProps | Alias pair for embed slot props / workspace context. | | PDFUploadProps, PdfViewerProps, TemplateQuestionnaireProps, ResearchQuestionnaireAppProps | Component prop types. | | ResearchFieldAiQuestionType, ResearchQuestionnaireFieldAiWrapperProps | Field wrapper typing. |

Consult dist/index.d.ts after npm run build for the authoritative export list.

(back to top)

Configuration

When developing this repository locally, copy environment examples if present and configure provider keys for standalone demos:

cp .env.example .env

Consumer applications supply credentials inside their own LLMService implementation; the library does not read .env in the host app for you.

(back to top)

Peer Dependencies

ScidQuest expects the following peer dependencies in the host project:

  • react ^18.3.1
  • react-dom ^18.3.1
  • @mui/material ^6.4.11
  • @emotion/react ^11.14.0
  • @emotion/styled ^11.14.0

(back to top)

Further reading

(back to top)

Development

Run the package locally:

npm install
npm run dev

Build distributable artifacts:

npm run build

Preview the production build:

npm run preview

(back to top)

Project Structure

ScidQuest/
├── src/
│   ├── lib/                # Published library entry (`src/lib/index.ts`)
│   ├── pages/              # Page-level views (demo app)
│   ├── components/         # Shared UI (some re-exported by lib)
│   ├── services/           # AI/provider integrations
│   ├── utils/              # PDF, suggestions, validation
│   ├── templates/          # Questionnaire templates
│   ├── store/              # Redux (used inside provider)
│   ├── context/            # Questionnaire AI context
│   ├── App.tsx
│   ├── Router.tsx
│   └── main.tsx
├── docs/
├── index.html
├── package.json
├── tsconfig.json
└── vite.config.ts

(back to top)

License

This project is released under the MIT License.