@musnows/scriverse 0.5.2 → 0.5.3

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/dist/store.js CHANGED
@@ -3371,8 +3371,13 @@ export class Store {
3371
3371
  this.getWork(workId);
3372
3372
  const reviewId = id("review");
3373
3373
  const timestamp = now();
3374
- this.db.run(`INSERT INTO review_items (id, work_id, item_type, severity, title, description, entity_refs_json, evidence_json,
3375
- suggestion, status, resolution_note, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, reviewId, workId, input.itemType, input.severity ?? "medium", input.title, input.description ?? "", JSON.stringify(input.entityRefs ?? []), JSON.stringify(input.evidence ?? []), input.suggestion ?? "", input.status ?? "pending", input.resolutionNote ?? "", timestamp, timestamp);
3374
+ const result = this.db.run(`INSERT OR IGNORE INTO review_items (id, work_id, item_type, dedupe_key, severity, title, description, entity_refs_json, evidence_json,
3375
+ suggestion, status, resolution_note, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, reviewId, workId, input.itemType, input.dedupeKey ?? "", input.severity ?? "medium", input.title, input.description ?? "", JSON.stringify(input.entityRefs ?? []), JSON.stringify(input.evidence ?? []), input.suggestion ?? "", input.status ?? "pending", input.resolutionNote ?? "", timestamp, timestamp);
3376
+ if (result.changes === 0 && input.dedupeKey) {
3377
+ const existing = this.db.get("SELECT * FROM review_items WHERE work_id = ? AND item_type = ? AND dedupe_key = ?", workId, input.itemType, input.dedupeKey);
3378
+ if (existing)
3379
+ return this.mapReviewItem(existing);
3380
+ }
3376
3381
  return this.getReviewItem(reviewId);
3377
3382
  }
3378
3383
  listReviewItems(workId, status) {
@@ -3707,9 +3712,13 @@ export class Store {
3707
3712
  else if (scope.type === "settings") {
3708
3713
  Object.assign(sourceVersions, this.relationshipSettingsSourceVersions(workId));
3709
3714
  }
3710
- this.db.run(`INSERT INTO analysis_tasks (id, work_id, task_type, scope_json, status, source_versions_json, created_at, updated_at, created_by_user_id)
3711
- VALUES (?, ?, ?, ?, 'pending', ?, ?, ?, ?)`, taskId, workId, input.taskType, JSON.stringify(scope), JSON.stringify(sourceVersions), timestamp, timestamp, currentRequestActor()?.userId ?? null);
3712
- this.audit(workId, "task.created", "analysis-task", taskId, { taskType: input.taskType, scope });
3715
+ this.db.run(`INSERT INTO analysis_tasks (id, work_id, model_id, task_type, scope_json, status, source_versions_json, created_at, updated_at, created_by_user_id)
3716
+ VALUES (?, ?, ?, ?, ?, 'pending', ?, ?, ?, ?)`, taskId, workId, input.modelId ?? null, input.taskType, JSON.stringify(scope), JSON.stringify(sourceVersions), timestamp, timestamp, currentRequestActor()?.userId ?? null);
3717
+ this.audit(workId, "task.created", "analysis-task", taskId, {
3718
+ taskType: input.taskType,
3719
+ scope,
3720
+ modelId: input.modelId ?? null
3721
+ });
3713
3722
  this.notifyAnalysisTaskQueued(workId);
3714
3723
  return this.getTask(taskId);
3715
3724
  }
@@ -3722,8 +3731,11 @@ export class Store {
3722
3731
  FROM analysis_tasks WHERE work_id = ?`, workId) ?? {};
3723
3732
  const total = numberValue(statsRow, "total");
3724
3733
  const page = paginationSql(pagination);
3725
- const rows = this.db.all(`SELECT id, task_type, scope_json, status, progress, created_at, updated_at
3726
- FROM analysis_tasks WHERE work_id = ? ORDER BY created_at DESC, id DESC${page.sql}`, workId, ...page.params);
3734
+ const rows = this.db.all(`SELECT task.id, task.model_id, task.task_type, task.scope_json, task.status, task.progress, task.created_at, task.updated_at,
3735
+ model.display_name AS model_display_name, model.model_id AS model_api_id
3736
+ FROM analysis_tasks task
3737
+ LEFT JOIN models model ON model.id = task.model_id
3738
+ WHERE task.work_id = ? ORDER BY task.created_at DESC, task.id DESC${page.sql}`, workId, ...page.params);
3727
3739
  const chapterSummaries = new Map(this.db.all(`SELECT chapter.id, chapter.title, volume.title AS volume_title
3728
3740
  FROM chapters chapter JOIN volumes volume ON volume.id = chapter.volume_id
3729
3741
  WHERE chapter.work_id = ?`, workId).map((row) => [
@@ -4474,9 +4486,15 @@ export class Store {
4474
4486
  const targetSummary = analysisTarget.mode === "targeted-characters" && targetNames.length
4475
4487
  ? `重点分析 ${targetNames.join("、")} 与其他已建档人物之间的关系`
4476
4488
  : "分析范围内已建档人物之间的长期关系";
4489
+ const sourceSelection = result.sourceSelection && typeof result.sourceSelection === "object" && !Array.isArray(result.sourceSelection)
4490
+ ? result.sourceSelection
4491
+ : null;
4477
4492
  summary = missingRelationshipIds.length > 0
4478
4493
  ? `${targetSummary}。任务结果记录 ${relationshipIds.length} 条关系,当前作品中保留 ${relationships.length} 条可展示关系,另有 ${missingRelationshipIds.length} 条已删除或合并。`
4479
4494
  : `${targetSummary},共形成 ${relationships.length} 条可展示结果。`;
4495
+ if (sourceSelection) {
4496
+ summary += ` 来源筛选命中 ${Number(sourceSelection.exactSourceCount ?? 0)} 个精确来源,确认 ${Number(sourceSelection.confirmedSourceCount ?? 0)} 个疑似来源。`;
4497
+ }
4480
4498
  const actionMetrics = [
4481
4499
  ["新建", result.createdCount],
4482
4500
  ["更新", result.updatedCount],
@@ -4487,7 +4505,14 @@ export class Store {
4487
4505
  metric("任务记录", relationshipIds.length || relationships.length),
4488
4506
  metric("当前可展示", relationships.length),
4489
4507
  metric("已删除或合并", missingRelationshipIds.length),
4490
- metric("跳过", Array.isArray(result.skipped) ? result.skipped.length : 0)
4508
+ metric("跳过", Array.isArray(result.skipped) ? result.skipped.length : 0),
4509
+ ...(sourceSelection ? [
4510
+ metric("精确来源", Number(sourceSelection.exactSourceCount ?? 0)),
4511
+ metric("模糊候选", Number(sourceSelection.fuzzyCandidateCount ?? 0)),
4512
+ metric("确认来源", Number(sourceSelection.confirmedSourceCount ?? 0)),
4513
+ metric("排除", Number(sourceSelection.rejectedSourceCount ?? 0)),
4514
+ metric("不确定", Number(sourceSelection.uncertainSourceCount ?? 0))
4515
+ ] : [])
4491
4516
  ];
4492
4517
  storageTargets.unshift({
4493
4518
  label: "人物关系",
@@ -4496,6 +4521,15 @@ export class Store {
4496
4521
  count: relationshipIds.length || relationships.length,
4497
4522
  note: `任务记录 ${relationshipIds.length || relationships.length} 条关系,当前可读取 ${relationships.length} 条;关系候选需由作者确认。`
4498
4523
  });
4524
+ const variantReviewIds = sourceSelection && Array.isArray(sourceSelection.reviewIds) ? sourceSelection.reviewIds.map(String) : [];
4525
+ if (variantReviewIds.length > 0)
4526
+ storageTargets.unshift({
4527
+ label: "疑似人物名错字",
4528
+ entity: "审核中心",
4529
+ key: "reviews",
4530
+ count: variantReviewIds.length,
4531
+ note: "仅生成待处理审核项,不会修改正文或人物别名。"
4532
+ });
4499
4533
  sections = [
4500
4534
  { title: "分析出的关系", totalCount: relationships.length, items: relationships.slice(0, 100), emptyMessage: "没有形成可展示的人物关系。" },
4501
4535
  section("未写入候选", result.skipped, "没有候选被跳过。")
@@ -4599,6 +4633,7 @@ export class Store {
4599
4633
  return {
4600
4634
  id: requiredString(row, "id"),
4601
4635
  workId,
4636
+ model: this.analysisTaskModel(row),
4602
4637
  taskType,
4603
4638
  scope,
4604
4639
  scopeSummary: this.taskScopeSummary(workId, scope, characterNames),
@@ -4617,6 +4652,7 @@ export class Store {
4617
4652
  const scope = json(requiredString(row, "scope_json"), {});
4618
4653
  return {
4619
4654
  id: requiredString(row, "id"),
4655
+ model: this.analysisTaskModel(row),
4620
4656
  taskType: requiredString(row, "task_type"),
4621
4657
  scopeSummary: this.taskScopeSummaryFromMaps(scope, chapterSummaries, volumeTitles, characterNames),
4622
4658
  scopeSummaryWithoutCharacterNames: this.taskScopeSummaryFromMaps(scope, chapterSummaries, volumeTitles, new Map(), false),
@@ -4626,6 +4662,21 @@ export class Store {
4626
4662
  updatedAt: requiredString(row, "updated_at")
4627
4663
  };
4628
4664
  }
4665
+ analysisTaskModel(row) {
4666
+ const modelId = optionalString(row, "model_id");
4667
+ if (!modelId)
4668
+ return null;
4669
+ const model = row.model_display_name !== undefined
4670
+ ? row
4671
+ : this.db.get("SELECT display_name AS model_display_name, model_id AS model_api_id FROM models WHERE id = ?", modelId);
4672
+ if (!model)
4673
+ return { id: modelId, displayName: "模型已删除", modelId: "", deleted: true };
4674
+ return {
4675
+ id: modelId,
4676
+ displayName: requiredString(model, "model_display_name"),
4677
+ modelId: requiredString(model, "model_api_id")
4678
+ };
4679
+ }
4629
4680
  taskScopeSummaryFromMaps(scope, chapterSummaries, volumeTitles, characterNames, includeCharacterNames = true) {
4630
4681
  const targetedSuffix = this.taskTargetedSuffix(scope, characterNames, includeCharacterNames);
4631
4682
  if (typeof scope.chapterId === "string")