PreQuestionCandidate.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Database\Eloquent\Factories\HasFactory;
  4. use Illuminate\Database\Eloquent\Model;
  5. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  6. use App\Models\SourceFile;
  7. use App\Models\SourcePaper;
  8. use App\Models\PaperPart;
  9. class PreQuestionCandidate extends Model
  10. {
  11. use HasFactory;
  12. protected $fillable = [
  13. 'import_id',
  14. 'source_file_id',
  15. 'source_paper_id',
  16. 'part_id',
  17. 'sequence',
  18. 'index',
  19. 'order_index',
  20. 'question_number',
  21. 'order',
  22. 'raw_markdown',
  23. 'raw_hash',
  24. 'raw_text',
  25. 'clean_markdown',
  26. 'clean_hash',
  27. 'structured_json',
  28. 'stem',
  29. 'options',
  30. 'images',
  31. 'tables',
  32. 'is_question_candidate',
  33. 'ai_confidence',
  34. 'confidence',
  35. 'formula_detected',
  36. 'is_valid_question',
  37. 'status',
  38. 'meta',
  39. ];
  40. protected $casts = [
  41. 'is_question_candidate' => 'boolean',
  42. 'ai_confidence' => 'float',
  43. 'confidence' => 'decimal:2',
  44. 'sequence' => 'integer',
  45. 'order' => 'integer',
  46. 'options' => 'array',
  47. 'images' => 'array',
  48. 'tables' => 'array',
  49. 'formula_detected' => 'boolean',
  50. 'is_valid_question' => 'boolean',
  51. 'meta' => 'array',
  52. 'created_at' => 'datetime',
  53. 'updated_at' => 'datetime',
  54. ];
  55. public const STATUS_PENDING = 'pending';
  56. public const STATUS_REVIEWED = 'reviewed';
  57. public const STATUS_ACCEPTED = 'accepted';
  58. public const STATUS_REJECTED = 'rejected';
  59. public const STATUS_SUPERSEDED = 'superseded';
  60. public function import(): BelongsTo
  61. {
  62. return $this->belongsTo(MarkdownImport::class, 'import_id');
  63. }
  64. public function sourceFile(): BelongsTo
  65. {
  66. return $this->belongsTo(SourceFile::class, 'source_file_id');
  67. }
  68. public function sourcePaper(): BelongsTo
  69. {
  70. return $this->belongsTo(SourcePaper::class, 'source_paper_id');
  71. }
  72. public function part(): BelongsTo
  73. {
  74. return $this->belongsTo(PaperPart::class, 'part_id');
  75. }
  76. public function getConfidenceBadgeAttribute(): string
  77. {
  78. if ($this->ai_confidence === null) {
  79. return 'gray';
  80. }
  81. if ($this->ai_confidence >= 0.8) {
  82. return 'success';
  83. } elseif ($this->ai_confidence >= 0.5) {
  84. return 'warning';
  85. }
  86. return 'danger';
  87. }
  88. public function getStatusBadgeAttribute(): string
  89. {
  90. $badges = [
  91. self::STATUS_PENDING => 'gray',
  92. self::STATUS_REVIEWED => 'info',
  93. self::STATUS_ACCEPTED => 'success',
  94. self::STATUS_REJECTED => 'danger',
  95. self::STATUS_SUPERSEDED => 'gray',
  96. ];
  97. return $badges[$this->status] ?? 'gray';
  98. }
  99. public function getFirstImageAttribute(): ?string
  100. {
  101. if (empty($this->images)) {
  102. return null;
  103. }
  104. $images = is_string($this->images) ? json_decode($this->images, true) : $this->images;
  105. return $images[0] ?? null;
  106. }
  107. public function getStemPreviewAttribute(): string
  108. {
  109. if (!$this->stem) {
  110. return 'No stem extracted';
  111. }
  112. return \Str::limit($this->stem, 100);
  113. }
  114. }