PreQuestionCandidate.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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. 'question_number',
  20. 'order',
  21. 'raw_markdown',
  22. 'clean_markdown',
  23. 'structured_json',
  24. 'stem',
  25. 'options',
  26. 'images',
  27. 'tables',
  28. 'is_question_candidate',
  29. 'ai_confidence',
  30. 'confidence',
  31. 'formula_detected',
  32. 'is_valid_question',
  33. 'status',
  34. ];
  35. protected $casts = [
  36. 'is_question_candidate' => 'boolean',
  37. 'ai_confidence' => 'float',
  38. 'confidence' => 'decimal:2',
  39. 'sequence' => 'integer',
  40. 'order' => 'integer',
  41. 'options' => 'array',
  42. 'images' => 'array',
  43. 'tables' => 'array',
  44. 'formula_detected' => 'boolean',
  45. 'is_valid_question' => 'boolean',
  46. 'created_at' => 'datetime',
  47. 'updated_at' => 'datetime',
  48. ];
  49. public const STATUS_PENDING = 'pending';
  50. public const STATUS_REVIEWED = 'reviewed';
  51. public const STATUS_ACCEPTED = 'accepted';
  52. public const STATUS_REJECTED = 'rejected';
  53. public const STATUS_SUPERSEDED = 'superseded';
  54. public function import(): BelongsTo
  55. {
  56. return $this->belongsTo(MarkdownImport::class, 'import_id');
  57. }
  58. public function sourceFile(): BelongsTo
  59. {
  60. return $this->belongsTo(SourceFile::class, 'source_file_id');
  61. }
  62. public function sourcePaper(): BelongsTo
  63. {
  64. return $this->belongsTo(SourcePaper::class, 'source_paper_id');
  65. }
  66. public function part(): BelongsTo
  67. {
  68. return $this->belongsTo(PaperPart::class, 'part_id');
  69. }
  70. public function getConfidenceBadgeAttribute(): string
  71. {
  72. if ($this->ai_confidence === null) {
  73. return 'gray';
  74. }
  75. if ($this->ai_confidence >= 0.8) {
  76. return 'success';
  77. } elseif ($this->ai_confidence >= 0.5) {
  78. return 'warning';
  79. }
  80. return 'danger';
  81. }
  82. public function getStatusBadgeAttribute(): string
  83. {
  84. $badges = [
  85. self::STATUS_PENDING => 'gray',
  86. self::STATUS_REVIEWED => 'info',
  87. self::STATUS_ACCEPTED => 'success',
  88. self::STATUS_REJECTED => 'danger',
  89. self::STATUS_SUPERSEDED => 'gray',
  90. ];
  91. return $badges[$this->status] ?? 'gray';
  92. }
  93. public function getFirstImageAttribute(): ?string
  94. {
  95. if (empty($this->images)) {
  96. return null;
  97. }
  98. $images = is_string($this->images) ? json_decode($this->images, true) : $this->images;
  99. return $images[0] ?? null;
  100. }
  101. public function getStemPreviewAttribute(): string
  102. {
  103. if (!$this->stem) {
  104. return 'No stem extracted';
  105. }
  106. return \Str::limit($this->stem, 100);
  107. }
  108. }