feat(asl): Complete Day 5 - Fulltext Screening Backend API Development
- Implement 5 core API endpoints (create task, get progress, get results, update decision, export Excel) - Add FulltextScreeningController with Zod validation (652 lines) - Implement ExcelExporter service with 4-sheet report generation (352 lines) - Register routes under /api/v1/asl/fulltext-screening - Create 31 REST Client test cases - Add automated integration test script - Fix PDF extraction fallback mechanism in LLM12FieldsService - Update API design documentation to v3.0 - Update development plan to v1.2 - Create Day 5 development record - Clean up temporary test files
This commit is contained in:
141
backend/prisma/migrations/manual_fulltext_screening.sql
Normal file
141
backend/prisma/migrations/manual_fulltext_screening.sql
Normal file
@@ -0,0 +1,141 @@
|
||||
-- =====================================================
|
||||
-- 全文复筛数据库迁移脚本(手动执行)
|
||||
-- Schema: asl_schema
|
||||
-- 日期: 2025-11-23
|
||||
-- 说明: 只操作asl_schema,不影响其他schema
|
||||
-- =====================================================
|
||||
|
||||
-- 1. 修改 literatures 表,添加全文复筛相关字段
|
||||
ALTER TABLE asl_schema.literatures
|
||||
ADD COLUMN IF NOT EXISTS stage TEXT DEFAULT 'imported',
|
||||
ADD COLUMN IF NOT EXISTS has_pdf BOOLEAN DEFAULT false,
|
||||
ADD COLUMN IF NOT EXISTS pdf_storage_type TEXT,
|
||||
ADD COLUMN IF NOT EXISTS pdf_storage_ref TEXT,
|
||||
ADD COLUMN IF NOT EXISTS pdf_status TEXT DEFAULT 'pending',
|
||||
ADD COLUMN IF NOT EXISTS pdf_uploaded_at TIMESTAMP(3),
|
||||
ADD COLUMN IF NOT EXISTS full_text_storage_type TEXT,
|
||||
ADD COLUMN IF NOT EXISTS full_text_storage_ref TEXT,
|
||||
ADD COLUMN IF NOT EXISTS full_text_url TEXT,
|
||||
ADD COLUMN IF NOT EXISTS full_text_format TEXT,
|
||||
ADD COLUMN IF NOT EXISTS full_text_source TEXT,
|
||||
ADD COLUMN IF NOT EXISTS full_text_token_count INTEGER,
|
||||
ADD COLUMN IF NOT EXISTS full_text_extracted_at TIMESTAMP(3);
|
||||
|
||||
-- 添加索引
|
||||
CREATE INDEX IF NOT EXISTS idx_literatures_stage ON asl_schema.literatures(stage);
|
||||
CREATE INDEX IF NOT EXISTS idx_literatures_has_pdf ON asl_schema.literatures(has_pdf);
|
||||
CREATE INDEX IF NOT EXISTS idx_literatures_pdf_status ON asl_schema.literatures(pdf_status);
|
||||
|
||||
-- 2. 创建 fulltext_screening_tasks 表
|
||||
CREATE TABLE IF NOT EXISTS asl_schema.fulltext_screening_tasks (
|
||||
id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL,
|
||||
model_a TEXT NOT NULL,
|
||||
model_b TEXT NOT NULL,
|
||||
prompt_version TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
total_count INTEGER NOT NULL DEFAULT 0,
|
||||
processed_count INTEGER NOT NULL DEFAULT 0,
|
||||
success_count INTEGER NOT NULL DEFAULT 0,
|
||||
failed_count INTEGER NOT NULL DEFAULT 0,
|
||||
degraded_count INTEGER NOT NULL DEFAULT 0,
|
||||
total_tokens INTEGER DEFAULT 0,
|
||||
total_cost DOUBLE PRECISION DEFAULT 0,
|
||||
started_at TIMESTAMP(3),
|
||||
completed_at TIMESTAMP(3),
|
||||
estimated_end_at TIMESTAMP(3),
|
||||
error_message TEXT,
|
||||
error_stack TEXT,
|
||||
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_fulltext_task_project FOREIGN KEY (project_id)
|
||||
REFERENCES asl_schema.screening_projects(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 添加索引
|
||||
CREATE INDEX IF NOT EXISTS idx_fulltext_tasks_project_id ON asl_schema.fulltext_screening_tasks(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_fulltext_tasks_status ON asl_schema.fulltext_screening_tasks(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_fulltext_tasks_created_at ON asl_schema.fulltext_screening_tasks(created_at);
|
||||
|
||||
-- 3. 创建 fulltext_screening_results 表
|
||||
CREATE TABLE IF NOT EXISTS asl_schema.fulltext_screening_results (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_id TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
literature_id TEXT NOT NULL,
|
||||
|
||||
-- Model A (DeepSeek-V3) 结果
|
||||
model_a_name TEXT,
|
||||
model_a_status TEXT,
|
||||
model_a_fields JSONB,
|
||||
model_a_overall JSONB,
|
||||
model_a_processing_log JSONB,
|
||||
model_a_verification JSONB,
|
||||
model_a_tokens INTEGER,
|
||||
model_a_cost DOUBLE PRECISION,
|
||||
model_a_error TEXT,
|
||||
|
||||
-- Model B (Qwen-Max) 结果
|
||||
model_b_name TEXT,
|
||||
model_b_status TEXT,
|
||||
model_b_fields JSONB,
|
||||
model_b_overall JSONB,
|
||||
model_b_processing_log JSONB,
|
||||
model_b_verification JSONB,
|
||||
model_b_tokens INTEGER,
|
||||
model_b_cost DOUBLE PRECISION,
|
||||
model_b_error TEXT,
|
||||
|
||||
-- 验证结果
|
||||
medical_logic_issues JSONB,
|
||||
evidence_chain_issues JSONB,
|
||||
|
||||
-- 冲突检测
|
||||
is_conflict BOOLEAN DEFAULT false,
|
||||
conflict_severity TEXT,
|
||||
conflict_fields TEXT[],
|
||||
conflict_details JSONB,
|
||||
review_priority INTEGER DEFAULT 50,
|
||||
review_deadline TIMESTAMP(3),
|
||||
|
||||
-- 人工复核
|
||||
final_decision TEXT,
|
||||
final_decision_by TEXT,
|
||||
final_decision_at TIMESTAMP(3),
|
||||
exclusion_reason TEXT,
|
||||
review_notes TEXT,
|
||||
|
||||
-- 处理状态
|
||||
processing_status TEXT DEFAULT 'pending',
|
||||
is_degraded BOOLEAN DEFAULT false,
|
||||
degraded_model TEXT,
|
||||
|
||||
-- 元数据
|
||||
processed_at TIMESTAMP(3),
|
||||
prompt_version TEXT,
|
||||
raw_output_a JSONB,
|
||||
raw_output_b JSONB,
|
||||
created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT fk_fulltext_result_task FOREIGN KEY (task_id)
|
||||
REFERENCES asl_schema.fulltext_screening_tasks(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_fulltext_result_project FOREIGN KEY (project_id)
|
||||
REFERENCES asl_schema.screening_projects(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_fulltext_result_literature FOREIGN KEY (literature_id)
|
||||
REFERENCES asl_schema.literatures(id) ON DELETE CASCADE,
|
||||
CONSTRAINT unique_project_literature_fulltext UNIQUE (project_id, literature_id)
|
||||
);
|
||||
|
||||
-- 添加索引
|
||||
CREATE INDEX IF NOT EXISTS idx_fulltext_results_task_id ON asl_schema.fulltext_screening_results(task_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_fulltext_results_project_id ON asl_schema.fulltext_screening_results(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_fulltext_results_literature_id ON asl_schema.fulltext_screening_results(literature_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_fulltext_results_is_conflict ON asl_schema.fulltext_screening_results(is_conflict);
|
||||
CREATE INDEX IF NOT EXISTS idx_fulltext_results_final_decision ON asl_schema.fulltext_screening_results(final_decision);
|
||||
CREATE INDEX IF NOT EXISTS idx_fulltext_results_review_priority ON asl_schema.fulltext_screening_results(review_priority);
|
||||
|
||||
-- 完成
|
||||
SELECT 'Migration completed successfully!' AS status;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -114,6 +114,8 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user