46a10ba091
后端: - assessment-template entity: attemptLimit/scheduledStart/End/reviewMode/shuffleQuestions - DTO 更新: 新增 P2 字段验证 - startSession: 尝试次数检查、预约时段检查、题目随机排序 - getSessionState: reviewMode 控制答案可见性 - 新增 GET /assessment/:id/review 回顾端点 前端: - AssessmentTemplateManager: 新增尝试次数/答题回顾/题目排序/预约时段配置 - AssessmentView: 答题回顾按钮(完成页)+提交确认弹窗+标记回头功能 - types.ts: 新增 P2 字段类型 - assessmentService: 新增 getReview 方法 - 进度导航点: 可视化题序+标记状态 测试 20项全部通过 + 系统测试 142项全部通过 ✅ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
437 lines
9.9 KiB
TypeScript
437 lines
9.9 KiB
TypeScript
|
|
export interface IndexingConfig {
|
|
chunkSize: number;
|
|
chunkOverlap: number;
|
|
embeddingModelId: string;
|
|
mode?: 'fast' | 'precise'; // Processing mode: fast/precise
|
|
groupIds?: string[]; // Groups to associate with the file upon upload
|
|
}
|
|
|
|
|
|
export interface VisionAnalysisResult {
|
|
text: string; // Extracted text content
|
|
images: ImageDescription[]; // Image descriptions
|
|
layout: string; // Layout type
|
|
confidence: number; // 信頼度 (0-1)
|
|
pageIndex?: number; // Page number
|
|
}
|
|
|
|
export interface ImageDescription {
|
|
type: string; // Image type (graph/diagram/flowchart etc.)
|
|
description: string; // Detailed description
|
|
position?: number; // Position within the page
|
|
}
|
|
|
|
export interface PipelineResult {
|
|
success: boolean;
|
|
fileId: string;
|
|
fileName: string;
|
|
totalPages: number;
|
|
processedPages: number;
|
|
failedPages: number;
|
|
results: VisionAnalysisResult[];
|
|
cost: number; // Cost (USD)
|
|
duration: number; // Duration (seconds)
|
|
mode: 'precise';
|
|
}
|
|
|
|
export interface ModeRecommendation {
|
|
recommendedMode: 'precise' | 'fast';
|
|
reason: string;
|
|
estimatedCost?: number; // Estimated cost (USD)
|
|
estimatedTime?: number; // Estimated time (seconds)
|
|
warnings?: string[];
|
|
}
|
|
|
|
// Type definitions for knowledge base extensions
|
|
export interface KnowledgeGroup {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
color: string;
|
|
fileCount: number;
|
|
parentId?: string | null;
|
|
children?: KnowledgeGroup[];
|
|
createdAt: string;
|
|
updatedAt?: string;
|
|
}
|
|
|
|
export interface CreateGroupData {
|
|
name: string;
|
|
description?: string;
|
|
color?: string;
|
|
parentId?: string | null;
|
|
}
|
|
|
|
export interface UpdateGroupData {
|
|
name?: string;
|
|
description?: string;
|
|
color?: string;
|
|
parentId?: string | null;
|
|
}
|
|
|
|
export interface KnowledgeFile {
|
|
id: string;
|
|
name: string;
|
|
originalName: string;
|
|
title?: string;
|
|
content?: string;
|
|
size: number;
|
|
type: string;
|
|
status: 'pending' | 'indexing' | 'extracted' | 'vectorized' | 'failed' | 'ready' | 'error';
|
|
groups?: KnowledgeGroup[];
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
export interface SearchHistoryItem {
|
|
id: string;
|
|
title: string;
|
|
selectedGroups: string[] | null;
|
|
messageCount: number;
|
|
lastMessageAt: string;
|
|
createdAt: string;
|
|
}
|
|
|
|
export interface SearchHistoryDetail {
|
|
id: string;
|
|
title: string;
|
|
selectedGroups: string[] | null;
|
|
messages: Array<{
|
|
id: string;
|
|
role: 'user' | 'assistant';
|
|
content: string;
|
|
sources?: Array<{
|
|
fileName: string;
|
|
content: string;
|
|
score: number;
|
|
chunkIndex: number;
|
|
}>;
|
|
createdAt: string;
|
|
}>;
|
|
}
|
|
|
|
export interface PDFStatus {
|
|
status: 'pending' | 'converting' | 'ready' | 'failed';
|
|
pdfPath?: string;
|
|
error?: string;
|
|
}
|
|
|
|
export interface NoteCategory {
|
|
id: string
|
|
name: string
|
|
parentId?: string
|
|
level: number
|
|
userId: string
|
|
tenantId: string
|
|
createdAt: string
|
|
updatedAt: string
|
|
}
|
|
|
|
export interface Note {
|
|
id: string;
|
|
title: string;
|
|
content: string;
|
|
userId: string;
|
|
tenantId?: string;
|
|
groupId?: string;
|
|
categoryId?: string;
|
|
sharingStatus: 'PRIVATE' | 'TENANT' | 'GLOBAL_PENDING' | 'GLOBAL_APPROVED';
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
user?: {
|
|
id: string;
|
|
username: string;
|
|
name?: string;
|
|
};
|
|
}
|
|
|
|
export interface RawFile {
|
|
name: string;
|
|
type: string;
|
|
size: number;
|
|
content: string;
|
|
preview?: string;
|
|
file: File; // Keep original file for upload
|
|
isNote?: boolean;
|
|
textContent?: string;
|
|
}
|
|
|
|
export enum Role {
|
|
USER = 'user',
|
|
MODEL = 'model',
|
|
}
|
|
|
|
export interface Message {
|
|
id: string;
|
|
role: Role;
|
|
text: string;
|
|
timestamp: number;
|
|
isError?: boolean;
|
|
sources?: ChatSource[];
|
|
}
|
|
|
|
export interface ChatSource {
|
|
fileName: string;
|
|
title?: string;
|
|
content: string;
|
|
score: number;
|
|
chunkIndex: number;
|
|
fileId?: string;
|
|
}
|
|
|
|
export interface ChatState {
|
|
messages: Message[];
|
|
isLoading: boolean;
|
|
}
|
|
|
|
export type Language = 'ja' | 'en' | 'zh';
|
|
|
|
export enum ModelType {
|
|
// Changed from type to enum
|
|
LLM = "llm",
|
|
EMBEDDING = "embedding",
|
|
RERANK = "rerank",
|
|
VISION = "vision",
|
|
}
|
|
|
|
// 1. Model Definition (The "Provider" setup)
|
|
export interface ModelConfig {
|
|
id: string;
|
|
name: string; // Display name, e.g. "My DeepSeek"
|
|
modelId: string; // The actual string ID sent to API, e.g., "gpt-4o"
|
|
baseUrl?: string; // Base URL for OpenAI compatible API
|
|
apiKey?: string; // API key for the service
|
|
type: ModelType;
|
|
dimensions?: number; // Vector dimensions of the embedding model
|
|
supportsVision?: boolean; // Whether it supports vision capabilities
|
|
|
|
// ==================== Additional Fields ====================
|
|
/**
|
|
* Model's input token limit
|
|
* e.g., OpenAI=8191, Gemini=2048
|
|
*/
|
|
maxInputTokens?: number;
|
|
|
|
/**
|
|
* Batch processing limit (maximum number of inputs per request)
|
|
* e.g., OpenAI=2048, Gemini=100
|
|
*/
|
|
maxBatchSize?: number;
|
|
|
|
/**
|
|
* Whether it is a vector model (for identification in system settings)
|
|
*/
|
|
isVectorModel?: boolean;
|
|
|
|
/**
|
|
* Model provider name (for display)
|
|
* e.g., "OpenAI", "Google Gemini", "Custom"
|
|
*/
|
|
providerName?: string;
|
|
|
|
/**
|
|
* Whether it is enabled
|
|
*/
|
|
isEnabled?: boolean;
|
|
|
|
/**
|
|
* Whether to use this model as the default
|
|
*/
|
|
isDefault?: boolean;
|
|
}
|
|
|
|
// 2. Application Logic Settings (The "App" setup)
|
|
export interface AppSettings {
|
|
// References to ModelConfig IDs
|
|
selectedLLMId: string;
|
|
selectedEmbeddingId: string; // Default for new uploads, and used for query encoding
|
|
selectedRerankId: string;
|
|
|
|
// Model Hyperparameters
|
|
temperature: number;
|
|
maxTokens: number;
|
|
|
|
// Retrieval
|
|
enableRerank: boolean;
|
|
topK: number;
|
|
similarityThreshold: number; // Similarity threshold for vector search
|
|
rerankSimilarityThreshold: number; // Similarity threshold for reranking
|
|
enableFullTextSearch: boolean; // Whether to enable full-text search
|
|
hybridVectorWeight: number; // Vector weight for hybrid search
|
|
|
|
// Search Enhancement
|
|
enableQueryExpansion: boolean;
|
|
enableHyDE: boolean;
|
|
|
|
chunkSize?: number;
|
|
chunkOverlap?: number;
|
|
|
|
// Language
|
|
language?: string;
|
|
|
|
// Coach
|
|
coachKbId?: string;
|
|
|
|
// Vision
|
|
selectedVisionId?: string;
|
|
}
|
|
|
|
// Default Models (Frontend specific)
|
|
export const DEFAULT_MODELS: ModelConfig[] = [];
|
|
|
|
export const DEFAULT_SETTINGS: AppSettings = {
|
|
selectedLLMId: '',
|
|
selectedEmbeddingId: '',
|
|
selectedRerankId: '',
|
|
selectedVisionId: '',
|
|
|
|
temperature: 0.3,
|
|
maxTokens: 8192,
|
|
|
|
enableRerank: false,
|
|
topK: 4,
|
|
similarityThreshold: 0.3, // Default similarity threshold for vector search
|
|
rerankSimilarityThreshold: 0.5, // Default similarity threshold for reranking
|
|
enableFullTextSearch: false, // Turn off full-text search by default
|
|
hybridVectorWeight: 0.7, // Vector weight for hybrid search
|
|
enableQueryExpansion: false,
|
|
enableHyDE: false,
|
|
chunkSize: 1000,
|
|
chunkOverlap: 100,
|
|
language: 'ja',
|
|
};
|
|
|
|
export const API_BASE_URL = '/api'
|
|
|
|
export interface Tenant {
|
|
id: string;
|
|
name: string;
|
|
domain?: string;
|
|
parentId?: string | null;
|
|
children?: Tenant[];
|
|
members?: TenantMember[];
|
|
settings_obj?: any;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
export interface TenantMember {
|
|
id: string;
|
|
userId: string;
|
|
tenantId: string;
|
|
role: string;
|
|
user?: {
|
|
id: string;
|
|
username: string;
|
|
displayName?: string;
|
|
email?: string;
|
|
};
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
// Assessment Template Types
|
|
export interface AssessmentDimension {
|
|
name: string;
|
|
label: string;
|
|
weight: number;
|
|
}
|
|
|
|
export interface AssessmentTemplate {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
keywords?: string[];
|
|
questionCount: number;
|
|
difficultyDistribution?: Record<string, number>;
|
|
style?: string;
|
|
knowledgeBaseId?: string;
|
|
knowledgeGroupId?: string;
|
|
knowledgeGroup?: KnowledgeGroup;
|
|
dimensions?: AssessmentDimension[];
|
|
passingScore?: number;
|
|
totalTimeLimit?: number;
|
|
perQuestionTimeLimit?: number;
|
|
/** P2: Max attempts (0=unlimited) */
|
|
attemptLimit?: number;
|
|
/** P2: Scheduled window */
|
|
scheduledStart?: string | null;
|
|
scheduledEnd?: string | null;
|
|
/** P2: Review mode */
|
|
reviewMode?: string;
|
|
/** P2: Shuffle questions */
|
|
shuffleQuestions?: boolean;
|
|
isActive: boolean;
|
|
version: number;
|
|
creatorId: string;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
export interface CreateTemplateData {
|
|
name: string;
|
|
description?: string;
|
|
keywords?: string[];
|
|
questionCount?: number;
|
|
difficultyDistribution?: Record<string, number>;
|
|
style?: string;
|
|
knowledgeBaseId?: string;
|
|
knowledgeGroupId?: string;
|
|
dimensions?: AssessmentDimension[];
|
|
passingScore?: number;
|
|
totalTimeLimit?: number;
|
|
perQuestionTimeLimit?: number;
|
|
/** P2 */
|
|
attemptLimit?: number;
|
|
scheduledStart?: string | null;
|
|
scheduledEnd?: string | null;
|
|
reviewMode?: string;
|
|
shuffleQuestions?: boolean;
|
|
}
|
|
|
|
export interface UpdateTemplateData extends Partial<CreateTemplateData> {
|
|
isActive?: boolean;
|
|
}
|
|
|
|
export interface QuestionBank {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
status: 'DRAFT' | 'PENDING_REVIEW' | 'PUBLISHED' | 'REJECTED';
|
|
templateId?: string | null;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
export interface QuestionBankItem {
|
|
id: string;
|
|
bankId: string;
|
|
questionText: string;
|
|
questionType: 'SHORT_ANSWER' | 'MULTIPLE_CHOICE' | 'TRUE_FALSE';
|
|
options?: string[] | null;
|
|
correctAnswer?: string | null;
|
|
keyPoints: string[];
|
|
difficulty: 'STANDARD' | 'ADVANCED' | 'SPECIALIST';
|
|
dimension: 'PROMPT' | 'LLM' | 'IDE' | 'DEV_PATTERN' | 'WORK_CAPABILITY';
|
|
basis?: string | null;
|
|
status: 'PENDING_REVIEW' | 'PUBLISHED';
|
|
createdAt: string;
|
|
}
|
|
|
|
export interface CreateQuestionBankData {
|
|
name: string;
|
|
description?: string;
|
|
templateId?: string;
|
|
}
|
|
|
|
export interface CreateQuestionBankItemData {
|
|
questionText: string;
|
|
questionType: 'SHORT_ANSWER' | 'MULTIPLE_CHOICE' | 'TRUE_FALSE';
|
|
options?: string[];
|
|
correctAnswer?: string;
|
|
keyPoints: string[];
|
|
difficulty: 'STANDARD' | 'ADVANCED' | 'SPECIALIST';
|
|
dimension: 'PROMPT' | 'LLM' | 'IDE' | 'DEV_PATTERN' | 'WORK_CAPABILITY';
|
|
}
|