PromptService.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <?php
  2. namespace App\Services;
  3. use App\Models\PromptTemplate;
  4. use Illuminate\Support\Facades\Log;
  5. class PromptService
  6. {
  7. /**
  8. * 获取提示词列表
  9. */
  10. public function listPrompts(?string $type = null, ?string $active = null): array
  11. {
  12. $query = PromptTemplate::query();
  13. if ($type) {
  14. $query->where('template_type', $type);
  15. }
  16. if ($active !== null) {
  17. $query->where('is_active', $active === 'yes' || $active === true);
  18. }
  19. return $query->orderByDesc('updated_at')
  20. ->get()
  21. ->map(fn (PromptTemplate $prompt) => $this->mapPrompt($prompt))
  22. ->values()
  23. ->all();
  24. }
  25. /**
  26. * 保存提示词
  27. */
  28. public function savePrompt(array $data): array
  29. {
  30. try {
  31. $templateName = (string) ($data['template_name'] ?? '');
  32. if ($templateName === '') {
  33. return ['success' => false, 'message' => '模板名称不能为空'];
  34. }
  35. $payload = [
  36. 'template_type' => $data['template_type'] ?? 'question_generation',
  37. 'template_content' => $data['template_content'] ?? '',
  38. 'variables' => $this->parseJsonField($data['variables'] ?? []),
  39. 'description' => $data['description'] ?? null,
  40. 'tags' => $this->parseJsonField($data['tags'] ?? []),
  41. 'is_active' => ($data['is_active'] ?? 'yes') === 'yes' || ($data['is_active'] === true),
  42. ];
  43. PromptTemplate::updateOrCreate(
  44. ['template_name' => $templateName],
  45. $payload
  46. );
  47. return ['success' => true, 'message' => '提示词已保存'];
  48. } catch (\Exception $e) {
  49. Log::error('保存提示词异常', [
  50. 'error' => $e->getMessage()
  51. ]);
  52. return ['success' => false, 'message' => '保存失败'];
  53. }
  54. }
  55. public function deletePrompt(string $templateName): bool
  56. {
  57. return PromptTemplate::where('template_name', $templateName)->delete() > 0;
  58. }
  59. public function getPrompt(string $templateName): ?array
  60. {
  61. $prompt = PromptTemplate::where('template_name', $templateName)->first();
  62. return $prompt ? $this->mapPrompt($prompt) : null;
  63. }
  64. public function getPromptContent(string $templateName): ?string
  65. {
  66. $prompt = PromptTemplate::where('template_name', $templateName)->first();
  67. return $prompt?->template_content;
  68. }
  69. /**
  70. * 获取默认提示词模板
  71. */
  72. public function getDefaultPromptTemplate(): string
  73. {
  74. return '你是资深的中学数学命题专家,请为{knowledge_point}知识点生成高质量题目。
  75. 【核心要求】
  76. 1. 题目必须符合{grade_level}年级水平
  77. 2. 难度分布:基础({basic_ratio}%) + 中等({intermediate_ratio}%) + 拔高({advanced_ratio}%)
  78. 3. 题型分配:选择题({choice}道) + 填空题({fill}道) + 解答题({solution}道)
  79. 【技能覆盖】
  80. {skill_coverage}
  81. 【图示处理】
  82. - 如果原题涉及图形/示意图/坐标系/几何草图,必须在题干内内嵌一段完整的 <svg> 标签来还原图形;不要使用外链图片、base64 或占位符。
  83. - SVG 要包含明确的宽高(建议 260~360 像素),只使用基础图元(line、rect、circle、polygon、path、text),并给出必要的坐标、角点和标注文本。
  84. - 确保题干文本描述与 SVG 一致,例如“如图所示”后紧跟 SVG,且 SVG 放在题干末尾即可被前端直接渲染。
  85. 【质量标准】
  86. - 准确性:100%正确
  87. - 多样性:避免重复
  88. - 梯度性:难度递进合理
  89. - 实用性:贴近实际应用
  90. 【输出格式】
  91. {
  92. "total": {count},
  93. "questions": [
  94. {
  95. "id": "唯一标识",
  96. "stem": "题干",
  97. "answer": "标准答案",
  98. "solution": "详细解答",
  99. "difficulty": 难度值(0.3/0.6/0.85),
  100. "skill": "关联技能"
  101. }
  102. ]
  103. }';
  104. }
  105. /**
  106. * 检查服务健康状态
  107. */
  108. public function checkHealth(): bool
  109. {
  110. return true;
  111. }
  112. private function parseJsonField($value): array
  113. {
  114. if (is_array($value)) {
  115. return $value;
  116. }
  117. if (is_string($value) && $value !== '') {
  118. try {
  119. $decoded = json_decode($value, true, 512, JSON_THROW_ON_ERROR);
  120. return is_array($decoded) ? $decoded : [];
  121. } catch (\Throwable) {
  122. return [];
  123. }
  124. }
  125. return [];
  126. }
  127. private function mapPrompt(PromptTemplate $prompt): array
  128. {
  129. $variables = $prompt->variables ?? [];
  130. $tags = $prompt->tags ?? [];
  131. return [
  132. 'template_name' => $prompt->template_name,
  133. 'template_type' => $prompt->template_type,
  134. 'template_content' => $prompt->template_content,
  135. 'variables' => json_encode($variables, JSON_UNESCAPED_UNICODE),
  136. 'description' => $prompt->description,
  137. 'tags' => json_encode($tags, JSON_UNESCAPED_UNICODE),
  138. 'is_active' => $prompt->is_active ? 'yes' : 'no',
  139. 'updated_at' => $prompt->updated_at,
  140. ];
  141. }
  142. }