AiTaskPrepare.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <?php
  2. namespace App\Http\Api;
  3. use App\Models\Task;
  4. use App\Models\PaliText;
  5. use App\Models\PaliSentence;
  6. use App\Models\AiModel;
  7. use App\Models\Sentence;
  8. use App\Http\Api\Mq;
  9. use App\Http\Api\ChannelApi;
  10. use Illuminate\Support\Facades\Log;
  11. class AiTaskPrepare
  12. {
  13. /**
  14. * 读取task信息,将任务拆解为单句小任务
  15. *
  16. * @param string $taskId 任务uuid
  17. * @return array 拆解后的提示词数组
  18. */
  19. public static function translate(string $taskId, bool $send = true)
  20. {
  21. $task = Task::findOrFail($taskId);
  22. $description = $task->description;
  23. $rows = explode("\n", $description);
  24. $params = [];
  25. foreach ($rows as $key => $row) {
  26. if (strpos($row, '=') !== false) {
  27. $param = explode('=', trim($row, '|'));
  28. $params[$param[0]] = $param[1];
  29. }
  30. }
  31. if (!isset($params['type'])) {
  32. Log::error('no $params.type');
  33. return false;
  34. }
  35. //get sentences in article
  36. $sentences = array();
  37. $totalLen = 0;
  38. switch ($params['type']) {
  39. case 'sentence':
  40. if (!isset($params['id'])) {
  41. Log::error('no $params.id');
  42. return false;
  43. }
  44. $sentences[] = explode('-', $params['id']);
  45. break;
  46. case 'para':
  47. if (!isset($params['book']) || !isset($params['paragraphs'])) {
  48. Log::error('no $params.book or paragraphs');
  49. return false;
  50. }
  51. $sent = PaliSentence::where('book', $params['book'])
  52. ->where('paragraph', $params['paragraphs'])->orderBy('word_begin')->get();
  53. foreach ($sent as $key => $value) {
  54. $sentences[] = [
  55. 'id' => [
  56. $value->book,
  57. $value->paragraph,
  58. $value->word_begin,
  59. $value->word_end,
  60. ],
  61. 'strlen' => $value->length
  62. ];
  63. $totalLen += $value->length;
  64. }
  65. break;
  66. case 'chapter':
  67. if (!isset($params['book']) || !isset($params['paragraphs'])) {
  68. Log::error('no $params.book or paragraphs');
  69. return false;
  70. }
  71. $chapterLen = PaliText::where('book', $params['book'])
  72. ->where('paragraph', $params['paragraphs'])->value('chapter_len');
  73. $sent = PaliSentence::where('book', $params['book'])
  74. ->whereBetween('paragraph', [$params['paragraphs'], $params['paragraphs'] + $chapterLen - 1])
  75. ->orderBy('paragraph')
  76. ->orderBy('word_begin')->get();
  77. foreach ($sent as $key => $value) {
  78. $sentences[] = [
  79. 'id' => [
  80. $value->book,
  81. $value->paragraph,
  82. $value->word_begin,
  83. $value->word_end,
  84. ],
  85. 'strlen' => $value->length
  86. ];
  87. $totalLen += $value->length;
  88. }
  89. break;
  90. default:
  91. return false;
  92. break;
  93. }
  94. //render prompt
  95. $mdRender = new MdRender([
  96. 'format' => 'prompt',
  97. 'footnote' => false,
  98. 'paragraph' => false,
  99. ]);
  100. $m = new \Mustache_Engine(array(
  101. 'entity_flags' => ENT_QUOTES,
  102. 'escape' => function ($value) {
  103. return $value;
  104. }
  105. ));
  106. # ai model
  107. $aiModel = AiModel::findOrFail($task->executor_id);
  108. $sumLen = 0;
  109. $mqData = [];
  110. foreach ($sentences as $key => $sentence) {
  111. $sumLen += $sentence['strlen'];
  112. $sid = implode('-', $sentence['id']);
  113. Log::debug($sid);
  114. $sentChannelInfo = explode('@', $params['channel']);
  115. $channelId = $sentChannelInfo[0];
  116. $data = [];
  117. $data['origin'] = '{{' . $sid . '}}';
  118. $data['translation'] = '{{sent|id=' . $sid;
  119. $data['translation'] .= '|channel=' . $channelId;
  120. $data['translation'] .= '|text=translation}}';
  121. if (isset($params['nissaya']) && !empty($params['nissaya'])) {
  122. $nissayaChannel = explode('@', $params['nissaya']);
  123. $channelInfo = ChannelApi::getById($nissayaChannel[0]);
  124. if ($channelInfo) {
  125. //查看句子是否存在
  126. $nissayaSent = Sentence::where('book_id', $sentence['id'][0])
  127. ->where('paragraph', $sentence['id'][1])
  128. ->where('word_start', $sentence['id'][2])
  129. ->where('word_end', $sentence['id'][3])
  130. ->where('channel_uid', $nissayaChannel[0])->first();
  131. if ($nissayaSent && !empty($nissayaSent->content)) {
  132. $nissayaData = [];
  133. $nissayaData['channel'] = $channelInfo;
  134. $nissayaData['data'] = '{{sent|id=' . $sid;
  135. $nissayaData['data'] .= '|channel=' . $nissayaChannel[0];
  136. $nissayaData['data'] .= '|text=translation}}';
  137. $data['nissaya'] = $nissayaData;
  138. }
  139. }
  140. }
  141. Log::debug('mustache render', ['tpl' => $description, 'data' => $data]);
  142. $content = $m->render($description, $data);
  143. $prompt = $mdRender->convert($content, []);
  144. //gen mq
  145. $aiMqData = [
  146. 'model' => $aiModel,
  147. 'task' => [
  148. 'info' => $task,
  149. 'progress' => [
  150. 'current' => $sumLen,
  151. 'total' => $totalLen
  152. ],
  153. ],
  154. 'prompt' => $prompt,
  155. 'sentence' => [
  156. 'book_id' => $sentence['id'][0],
  157. 'paragraph' => $sentence['id'][1],
  158. 'word_start' => $sentence['id'][2],
  159. 'word_end' => $sentence['id'][3],
  160. 'channel_uid' => $channelId,
  161. 'content' => $prompt,
  162. 'content_type' => 'markdown',
  163. 'access_token' => $sentChannelInfo[1] ?? $params['token'],
  164. ],
  165. ];
  166. array_push($mqData, $aiMqData);
  167. }
  168. if ($send) {
  169. Mq::publish('ai_translate', $mqData);
  170. }
  171. return $mqData;
  172. }
  173. }