QuestionReviewService.php 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. <?php
  2. namespace App\Services;
  3. use App\Domain\Questions\QuestionPipeline;
  4. use App\Models\PreQuestionCandidate;
  5. use App\Models\Question;
  6. use App\Models\QuestionMeta;
  7. use Illuminate\Support\Facades\DB;
  8. class QuestionReviewService
  9. {
  10. public function __construct(private readonly QuestionPipeline $pipeline)
  11. {
  12. }
  13. public function promoteCandidateToQuestion(int $candidateId): ?Question
  14. {
  15. $candidate = PreQuestionCandidate::find($candidateId);
  16. if (!$candidate) {
  17. return null;
  18. }
  19. return DB::transaction(function () use ($candidate) {
  20. $payload = $this->pipeline->run([
  21. 'raw' => $candidate->raw_markdown ?? $candidate->raw_text ?? '',
  22. 'options' => $candidate->options ?? [],
  23. ]);
  24. $questionType = $payload['question_type'] ?? $this->inferQuestionType($candidate);
  25. $question = Question::create([
  26. 'question_code' => $this->buildQuestionCode($candidate),
  27. 'question_type' => $questionType,
  28. 'stem' => $payload['stem'] ?? $candidate->stem ?? $candidate->raw_text ?? '',
  29. 'options' => $payload['options'] ?? $candidate->options ?? null,
  30. 'answer' => null,
  31. 'solution' => null,
  32. 'difficulty' => $payload['difficulty'] ?? 1,
  33. 'source_file_id' => $candidate->source_file_id,
  34. 'source_paper_id' => $candidate->source_paper_id,
  35. 'paper_part_id' => $candidate->part_id,
  36. 'meta' => [
  37. 'candidate_id' => $candidate->id,
  38. ],
  39. ]);
  40. QuestionMeta::updateOrCreate(
  41. ['question_id' => $question->id],
  42. [
  43. 'abilities' => [],
  44. 'generation_info' => [
  45. 'source' => 'candidate',
  46. 'candidate_id' => $candidate->id,
  47. ],
  48. 'review_status' => 'pending',
  49. ]
  50. );
  51. $candidate->status = PreQuestionCandidate::STATUS_ACCEPTED;
  52. $candidate->save();
  53. return $question;
  54. });
  55. }
  56. private function inferQuestionType(PreQuestionCandidate $candidate): string
  57. {
  58. if (!empty($candidate->options)) {
  59. return 'choice';
  60. }
  61. return 'short';
  62. }
  63. private function buildQuestionCode(PreQuestionCandidate $candidate): string
  64. {
  65. return sprintf('Q-%s-%d', date('Ymd'), $candidate->id);
  66. }
  67. }