@orkg/scidquest 1.0.5 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +519 -28
- package/dist/assets/pdf.worker.min.mjs +28 -0
- package/dist/components/AI/AIConfigurationButton.d.ts +3 -0
- package/dist/components/AI/AIConfigurationDialog.d.ts +7 -0
- package/dist/components/TemplateQuestionaire/AIAssistantButton.d.ts +33 -0
- package/dist/components/TemplateQuestionaire/BufferedTextField.d.ts +19 -0
- package/dist/components/TemplateQuestionaire/FieldRow.d.ts +8 -0
- package/dist/components/TemplateQuestionaire/ImportDialog.d.ts +12 -0
- package/dist/components/TemplateQuestionaire/InfoTooltip.d.ts +7 -0
- package/dist/components/TemplateQuestionaire/InlineValidationFeedback.d.ts +8 -0
- package/dist/components/TemplateQuestionaire/NodeWrapper.d.ts +8 -0
- package/dist/components/TemplateQuestionaire/QuestionnaireAIHistoryDialog.d.ts +15 -0
- package/dist/components/TemplateQuestionaire/Questions/GroupQuestion.d.ts +30 -0
- package/dist/components/TemplateQuestionaire/Questions/MultiSelectQuestion.d.ts +31 -0
- package/dist/components/TemplateQuestionaire/Questions/QuestionRenderer.d.ts +32 -0
- package/dist/components/TemplateQuestionaire/Questions/RepeatGroupQuestion.d.ts +30 -0
- package/dist/components/TemplateQuestionaire/Questions/RepeatTextQuestion.d.ts +31 -0
- package/dist/components/TemplateQuestionaire/Questions/SelectQuestion.d.ts +31 -0
- package/dist/components/TemplateQuestionaire/Questions/TextQuestion.d.ts +32 -0
- package/dist/components/TemplateQuestionaire/SectionAccordion.d.ts +42 -0
- package/dist/components/TemplateQuestionaire/SuggestionBox.d.ts +30 -0
- package/dist/components/TemplateQuestionaire/TopSummaryBar.d.ts +43 -0
- package/dist/components/TemplateQuestionaire/ValidationStatusButton.d.ts +33 -0
- package/dist/context/QuestionnaireAIContext.d.ts +48 -0
- package/dist/hooks/useSuggestionGenerator.d.ts +30 -0
- package/dist/lib/adapter.d.ts +3 -0
- package/dist/lib/components/PDFUpload.d.ts +10 -0
- package/dist/lib/components/PdfViewer.d.ts +27 -0
- package/dist/lib/components/ResearchQuestionnaireApp.d.ts +32 -0
- package/dist/lib/components/ResearchQuestionnaireFieldAiWrapper.d.ts +25 -0
- package/dist/lib/components/TemplateQuestionnaire.d.ts +27 -0
- package/dist/lib/context.d.ts +14 -0
- package/dist/lib/hooks/useSuggestionGenerator.d.ts +26 -0
- package/dist/lib/index.d.ts +25 -0
- package/dist/lib/questionnaire-template-helpers.d.ts +10 -0
- package/dist/lib/research-questionnaire-workspace.d.ts +33 -0
- package/dist/lib/types.d.ts +121 -0
- package/dist/lib/utils/createLLMServiceFromAIService.d.ts +3 -0
- package/dist/scidquest.es.js +6679 -64083
- package/dist/semanticChunker-CNi7GgV8.js +84 -0
- package/dist/services/aiService.d.ts +39 -0
- package/dist/services/backendAIService.d.ts +191 -0
- package/dist/store/hooks.d.ts +4 -0
- package/dist/store/slices/aiSlice.d.ts +21 -0
- package/dist/store/store.d.ts +9 -0
- package/dist/types/context.d.ts +39 -0
- package/dist/utils/contextGatherer.d.ts +39 -0
- package/dist/utils/fuzzyPdfMatcher.d.ts +15 -0
- package/dist/utils/pdf.d.ts +25 -0
- package/dist/utils/pdfWorker.d.ts +10 -0
- package/dist/utils/robustPdfMatcher.d.ts +22 -0
- package/dist/utils/semanticChunker.d.ts +27 -0
- package/dist/utils/simplePdfMatcher.d.ts +13 -0
- package/dist/utils/structuredPdfExtractor.d.ts +34 -0
- package/dist/utils/suggestions.d.ts +88 -0
- package/dist/utils/theme.d.ts +6 -0
- package/dist/utils/tokenEstimator.d.ts +32 -0
- package/dist/utils/tokenPdfMatcher.d.ts +14 -0
- package/dist/utils/unicodeNormalizer.d.ts +13 -0
- package/dist/utils/validationRules.d.ts +51 -0
- package/package.json +30 -8
- package/dist/semanticChunker-CEckDeUn.js +0 -102
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { QuestionnaireTemplate } from '../types';
|
|
3
|
+
import type { StructuredDocument } from '../../utils/structuredPdfExtractor';
|
|
4
|
+
import { type ResearchQuestionnaireWorkspaceValue } from '../research-questionnaire-workspace';
|
|
5
|
+
export interface ResearchQuestionnaireAppProps {
|
|
6
|
+
templateSpec: QuestionnaireTemplate;
|
|
7
|
+
pdfTextExtractor?: {
|
|
8
|
+
extractFullText: (url: string) => Promise<string>;
|
|
9
|
+
};
|
|
10
|
+
structuredPdfExtractor?: {
|
|
11
|
+
extractStructuredDocument: (text: string) => Promise<StructuredDocument>;
|
|
12
|
+
};
|
|
13
|
+
maxPdfSizeBytes?: number;
|
|
14
|
+
layout?: 'split' | 'single';
|
|
15
|
+
showPdfViewer?: boolean;
|
|
16
|
+
onAnswersChange?: (answers: Record<string, any>) => void;
|
|
17
|
+
initialAnswers?: Record<string, any>;
|
|
18
|
+
sx?: any;
|
|
19
|
+
/**
|
|
20
|
+
* When set, the left column (split layout) or main body (single layout) renders
|
|
21
|
+
* this node instead of the built-in TemplateQuestionnaire. Use for host apps that
|
|
22
|
+
* supply their own form while keeping ScidQuest PDF extraction and workspace state.
|
|
23
|
+
*/
|
|
24
|
+
questionnaireSlot?: (ctx: ResearchQuestionnaireWorkspaceValue) => React.ReactNode;
|
|
25
|
+
/**
|
|
26
|
+
* Optional controlled answers. When both are set, the app does not keep a separate
|
|
27
|
+
* answers useState; the host owns the record (e.g. ORKG form values).
|
|
28
|
+
*/
|
|
29
|
+
answers?: Record<string, any>;
|
|
30
|
+
setAnswers?: React.Dispatch<React.SetStateAction<Record<string, any>>>;
|
|
31
|
+
}
|
|
32
|
+
export declare const ResearchQuestionnaireApp: React.FC<ResearchQuestionnaireAppProps>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AIVerificationResult } from '../types';
|
|
3
|
+
import type { ParentContext } from '../../types/context';
|
|
4
|
+
export type ResearchFieldAiQuestionType = 'text' | 'select' | 'multi_select' | 'repeat_text' | 'group';
|
|
5
|
+
export interface ResearchQuestionnaireFieldAiWrapperProps {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
questionId: string;
|
|
8
|
+
questionText: string;
|
|
9
|
+
questionType: ResearchFieldAiQuestionType;
|
|
10
|
+
questionOptions?: string[];
|
|
11
|
+
/** String form of the current field value (as sent to the LLM for verification). */
|
|
12
|
+
currentAnswer: string;
|
|
13
|
+
/** Called with the suggestion’s primary text when the user applies a suggestion. */
|
|
14
|
+
onApplySuggestion: (text: string) => void;
|
|
15
|
+
/** Force-hide AI chrome (e.g. custom blocks). */
|
|
16
|
+
disableAi?: boolean;
|
|
17
|
+
parentContext?: ParentContext;
|
|
18
|
+
onVerificationComplete?: (result: AIVerificationResult) => void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Wraps a host-rendered field with ScidQuest AI (suggest / verify) and PDF evidence UI.
|
|
22
|
+
* Requires {@link useResearchQuestionnaireWorkspace} (provided automatically when using
|
|
23
|
+
* `ResearchQuestionnaireApp` with `questionnaireSlot`).
|
|
24
|
+
*/
|
|
25
|
+
export declare const ResearchQuestionnaireFieldAiWrapper: React.FC<ResearchQuestionnaireFieldAiWrapperProps>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { StructuredDocument } from '../../utils/structuredPdfExtractor';
|
|
3
|
+
import type { QuestionnaireTemplate } from '../types';
|
|
4
|
+
export interface TemplateQuestionnaireProps {
|
|
5
|
+
templateSpec: QuestionnaireTemplate | null;
|
|
6
|
+
answers: Record<string, any>;
|
|
7
|
+
setAnswers: (next: Record<string, any>) => void;
|
|
8
|
+
pdfContent?: string;
|
|
9
|
+
structuredDocument?: StructuredDocument | null;
|
|
10
|
+
onNavigateToPage?: (pageNumber: number) => void;
|
|
11
|
+
pdfExtractionError?: Error | null;
|
|
12
|
+
onRetryExtraction?: () => void;
|
|
13
|
+
onHighlightsChange?: (highlights: Record<number, {
|
|
14
|
+
left: number;
|
|
15
|
+
top: number;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
}[]>) => void;
|
|
19
|
+
pdfUrl?: string | null;
|
|
20
|
+
pageWidth?: number | null;
|
|
21
|
+
aiConfig?: {
|
|
22
|
+
hidden?: boolean;
|
|
23
|
+
};
|
|
24
|
+
sx?: any;
|
|
25
|
+
}
|
|
26
|
+
declare const TemplateQuestionnaire: React.FC<TemplateQuestionnaireProps>;
|
|
27
|
+
export { TemplateQuestionnaire };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import { ScidQuestAdapter, LLMService } from './types';
|
|
3
|
+
export interface ScidQuestContextType {
|
|
4
|
+
adapter: ScidQuestAdapter;
|
|
5
|
+
}
|
|
6
|
+
interface ScidQuestProviderProps {
|
|
7
|
+
llmService: LLMService;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export declare const ScidQuestProvider: React.FC<ScidQuestProviderProps>;
|
|
11
|
+
export declare const useScidQuestContext: () => ScidQuestContextType;
|
|
12
|
+
/** Returns null outside `ScidQuestProvider` (for hooks that support optional embed + legacy paths). */
|
|
13
|
+
export declare const useOptionalScidQuestContext: () => ScidQuestContextType | null;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Suggestion, type FeedbackData } from '../../utils/suggestions';
|
|
2
|
+
interface UseSuggestionGeneratorProps {
|
|
3
|
+
questionText: string;
|
|
4
|
+
questionType: string;
|
|
5
|
+
questionOptions?: string[];
|
|
6
|
+
pdfContent?: string;
|
|
7
|
+
contextHistory?: Array<{
|
|
8
|
+
id: string;
|
|
9
|
+
type: string;
|
|
10
|
+
content: string;
|
|
11
|
+
timestamp: number;
|
|
12
|
+
metadata?: any;
|
|
13
|
+
}>;
|
|
14
|
+
previousFeedback?: FeedbackData[];
|
|
15
|
+
excludedSuggestionIds?: Set<string>;
|
|
16
|
+
}
|
|
17
|
+
interface UseSuggestionGeneratorReturn {
|
|
18
|
+
suggestions: Suggestion[];
|
|
19
|
+
loading: boolean;
|
|
20
|
+
error: string | null;
|
|
21
|
+
rawError: unknown;
|
|
22
|
+
generateSuggestions: () => Promise<void>;
|
|
23
|
+
clearSuggestions: () => void;
|
|
24
|
+
}
|
|
25
|
+
export declare const useSuggestionGenerator: ({ questionText, questionType, questionOptions, pdfContent, contextHistory, previousFeedback, excludedSuggestionIds, }: UseSuggestionGeneratorProps) => UseSuggestionGeneratorReturn;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export * from './types';
|
|
2
|
+
export * from './context';
|
|
3
|
+
export * from './hooks/useSuggestionGenerator';
|
|
4
|
+
import 'react-pdf/dist/Page/AnnotationLayer.css';
|
|
5
|
+
import 'react-pdf/dist/Page/TextLayer.css';
|
|
6
|
+
export { createScidQuestAdapter } from './adapter';
|
|
7
|
+
export { createLLMServiceFromAIService } from './utils/createLLMServiceFromAIService';
|
|
8
|
+
export type { ResearchQuestionnaireWorkspaceValue, ResearchQuestionnaireSlotRenderProps, } from './research-questionnaire-workspace';
|
|
9
|
+
export { ResearchQuestionnaireWorkspaceProvider, useResearchQuestionnaireWorkspace, } from './research-questionnaire-workspace';
|
|
10
|
+
export { buildQuestionDefinitions, siblingQuestionIdsFor, } from './questionnaire-template-helpers';
|
|
11
|
+
export { PDFUpload } from './components/PDFUpload';
|
|
12
|
+
export { PdfViewer } from './components/PdfViewer';
|
|
13
|
+
export { TemplateQuestionnaire } from './components/TemplateQuestionnaire';
|
|
14
|
+
export { ResearchQuestionnaireApp } from './components/ResearchQuestionnaireApp';
|
|
15
|
+
export { ResearchQuestionnaireFieldAiWrapper } from './components/ResearchQuestionnaireFieldAiWrapper';
|
|
16
|
+
export type { ResearchFieldAiQuestionType, ResearchQuestionnaireFieldAiWrapperProps, } from './components/ResearchQuestionnaireFieldAiWrapper';
|
|
17
|
+
export type { PDFUploadProps } from './components/PDFUpload';
|
|
18
|
+
export type { PdfViewerProps } from './components/PdfViewer';
|
|
19
|
+
export type { TemplateQuestionnaireProps } from './components/TemplateQuestionnaire';
|
|
20
|
+
export type { ResearchQuestionnaireAppProps } from './components/ResearchQuestionnaireApp';
|
|
21
|
+
import AIAssistantButton from '../components/TemplateQuestionaire/AIAssistantButton';
|
|
22
|
+
import SuggestionBox from '../components/TemplateQuestionaire/SuggestionBox';
|
|
23
|
+
export { AIAssistantButton, SuggestionBox };
|
|
24
|
+
export { default as AIConfigurationDialog } from '../components/AI/AIConfigurationDialog';
|
|
25
|
+
export { QuestionnaireAIProvider, QuestionnaireAIContext, } from '../context/QuestionnaireAIContext';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Question, QuestionnaireTemplate } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Flat map of question id → question definition (including nested subquestions / item_fields).
|
|
4
|
+
* Used by AI suggestion context gathering.
|
|
5
|
+
*/
|
|
6
|
+
export declare function buildQuestionDefinitions(template: QuestionnaireTemplate): Record<string, Question>;
|
|
7
|
+
/**
|
|
8
|
+
* Sibling question ids in the same section (top-level) or same group (nested).
|
|
9
|
+
*/
|
|
10
|
+
export declare function siblingQuestionIdsFor(template: QuestionnaireTemplate, questionId: string): string[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { QuestionnaireTemplate } from './types';
|
|
3
|
+
import type { StructuredDocument } from '../utils/structuredPdfExtractor';
|
|
4
|
+
/**
|
|
5
|
+
* PDF + questionnaire workspace passed to {@link ResearchQuestionnaireApp}
|
|
6
|
+
* `questionnaireSlot` and exposed to descendants via context.
|
|
7
|
+
*/
|
|
8
|
+
export type ResearchQuestionnaireWorkspaceValue = {
|
|
9
|
+
templateSpec: QuestionnaireTemplate;
|
|
10
|
+
answers: Record<string, unknown>;
|
|
11
|
+
setAnswers: React.Dispatch<React.SetStateAction<Record<string, unknown>>>;
|
|
12
|
+
pdfContent: string | undefined;
|
|
13
|
+
structuredDocument: StructuredDocument | null;
|
|
14
|
+
pdfUrl: string | null;
|
|
15
|
+
pageWidth: number | null;
|
|
16
|
+
onNavigateToPage: (pageNumber: number) => void;
|
|
17
|
+
onHighlightsChange: (highlights: Record<number, {
|
|
18
|
+
left: number;
|
|
19
|
+
top: number;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
}[]>) => void;
|
|
23
|
+
pdfExtractionError: Error | null;
|
|
24
|
+
onRetryExtraction: () => void;
|
|
25
|
+
};
|
|
26
|
+
/** Alias for embed API / docs. */
|
|
27
|
+
export type ResearchQuestionnaireSlotRenderProps = ResearchQuestionnaireWorkspaceValue;
|
|
28
|
+
export declare function ResearchQuestionnaireWorkspaceProvider({ value, children, }: {
|
|
29
|
+
value: ResearchQuestionnaireWorkspaceValue;
|
|
30
|
+
children: React.ReactNode;
|
|
31
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
/** `null` when not under {@link ResearchQuestionnaireWorkspaceProvider} (e.g. Form mode). */
|
|
33
|
+
export declare function useResearchQuestionnaireWorkspace(): ResearchQuestionnaireWorkspaceValue | null;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { GenerateSuggestionsRequest, GenerateSuggestionsResponse, Suggestion } from '../utils/suggestions';
|
|
2
|
+
import type { VerifyAnswerRequest, AIVerificationResult } from '../services/backendAIService';
|
|
3
|
+
export type { GenerateSuggestionsRequest, GenerateSuggestionsResponse, Suggestion, VerifyAnswerRequest, AIVerificationResult, };
|
|
4
|
+
/**
|
|
5
|
+
* Options for generating text with an LLM
|
|
6
|
+
*/
|
|
7
|
+
export interface LLMGenerateTextOptions {
|
|
8
|
+
temperature?: number;
|
|
9
|
+
maxTokens?: number;
|
|
10
|
+
systemContext?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Response from LLM text generation
|
|
14
|
+
*/
|
|
15
|
+
export interface LLMGenerateTextResponse {
|
|
16
|
+
text: string;
|
|
17
|
+
reasoning?: string;
|
|
18
|
+
usage?: {
|
|
19
|
+
promptTokens: number;
|
|
20
|
+
completionTokens: number;
|
|
21
|
+
totalTokens: number;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* LLM Service Interface
|
|
26
|
+
*
|
|
27
|
+
* This interface defines the contract for LLM functions that the ScidQuest library
|
|
28
|
+
* requires. Users must provide an implementation of this interface when using the library.
|
|
29
|
+
*
|
|
30
|
+
* This approach ensures:
|
|
31
|
+
* - Security: The library never handles API keys directly
|
|
32
|
+
* - Flexibility: Users can use any LLM provider or implementation
|
|
33
|
+
* - Efficiency: Users control caching, rate limiting, and optimization
|
|
34
|
+
*/
|
|
35
|
+
export interface LLMService {
|
|
36
|
+
/**
|
|
37
|
+
* Generate text from a prompt using the LLM
|
|
38
|
+
*
|
|
39
|
+
* @param prompt - The user prompt/question
|
|
40
|
+
* @param options - Optional generation parameters
|
|
41
|
+
* @returns Promise resolving to the generated text and optional metadata
|
|
42
|
+
*/
|
|
43
|
+
generateText(prompt: string, options?: LLMGenerateTextOptions): Promise<LLMGenerateTextResponse>;
|
|
44
|
+
/**
|
|
45
|
+
* Check if the LLM service is properly configured and ready to use
|
|
46
|
+
*
|
|
47
|
+
* @returns true if the service is configured and can be used
|
|
48
|
+
*/
|
|
49
|
+
isConfigured(): boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Internal adapter interface (used by library components)
|
|
53
|
+
* This wraps the LLMService to provide higher-level operations
|
|
54
|
+
*/
|
|
55
|
+
export interface ScidQuestAdapter {
|
|
56
|
+
generateSuggestions(request: GenerateSuggestionsRequest): Promise<GenerateSuggestionsResponse>;
|
|
57
|
+
verifyAnswer(request: VerifyAnswerRequest): Promise<AIVerificationResult>;
|
|
58
|
+
verifyAnswersBatch?(requests: VerifyAnswerRequest[]): Promise<AIVerificationResult[]>;
|
|
59
|
+
isConfigured(): boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface ValidationRule {
|
|
62
|
+
format?: string;
|
|
63
|
+
formatError?: string;
|
|
64
|
+
minLength?: number;
|
|
65
|
+
minLengthError?: string;
|
|
66
|
+
maxLength?: number;
|
|
67
|
+
maxLengthError?: string;
|
|
68
|
+
}
|
|
69
|
+
export interface Mapping {
|
|
70
|
+
field: string;
|
|
71
|
+
node?: string;
|
|
72
|
+
property_id?: string;
|
|
73
|
+
cardinality?: string;
|
|
74
|
+
class_id?: string;
|
|
75
|
+
subtemplate_id?: string;
|
|
76
|
+
property_value_mapping?: Record<string, string>;
|
|
77
|
+
}
|
|
78
|
+
export interface Link {
|
|
79
|
+
field: string;
|
|
80
|
+
node: string;
|
|
81
|
+
property_id?: string;
|
|
82
|
+
cardinality?: string;
|
|
83
|
+
class_id?: string;
|
|
84
|
+
subtemplate_id?: string;
|
|
85
|
+
}
|
|
86
|
+
export interface Question {
|
|
87
|
+
id: string;
|
|
88
|
+
label?: string;
|
|
89
|
+
title?: string;
|
|
90
|
+
type: string;
|
|
91
|
+
required?: boolean;
|
|
92
|
+
choice_type?: 'single' | 'multiple' | 'no';
|
|
93
|
+
options?: string[];
|
|
94
|
+
evidence_fields?: string[];
|
|
95
|
+
evidence_per_item?: boolean;
|
|
96
|
+
desc?: string;
|
|
97
|
+
validation?: ValidationRule;
|
|
98
|
+
maps_to_fields?: Mapping[];
|
|
99
|
+
links_via_field?: Link;
|
|
100
|
+
property_id?: string;
|
|
101
|
+
cardinality?: string;
|
|
102
|
+
class_id?: string;
|
|
103
|
+
subtemplate_id?: string;
|
|
104
|
+
parent_property_id?: string;
|
|
105
|
+
parent_class_id?: string;
|
|
106
|
+
parent_subtemplate_id?: string;
|
|
107
|
+
item_fields?: Question[];
|
|
108
|
+
subquestions?: Question[];
|
|
109
|
+
disable_ai_assistant?: boolean;
|
|
110
|
+
}
|
|
111
|
+
export interface Section {
|
|
112
|
+
id: string;
|
|
113
|
+
title: string;
|
|
114
|
+
questions: Question[];
|
|
115
|
+
}
|
|
116
|
+
export interface QuestionnaireTemplate {
|
|
117
|
+
version: string;
|
|
118
|
+
template: string;
|
|
119
|
+
template_id: string;
|
|
120
|
+
sections: Section[];
|
|
121
|
+
}
|