AiTranslate.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <?php
  2. namespace App\Console\Commands;
  3. use Illuminate\Console\Command;
  4. use App\Models\Sentence;
  5. use App\Models\PaliSentence;
  6. use App\Models\PaliText;
  7. use Illuminate\Support\Facades\Log;
  8. use Illuminate\Support\Facades\Http;
  9. class AiTranslate extends Command
  10. {
  11. /**
  12. * The name and signature of the console command.
  13. * php artisan ai:sentence.translate --type=chapter --api=deepseek --model=deepseek-chat --sid=107-2357
  14. * @var string
  15. */
  16. protected $signature = <<<command
  17. ai:sentence.translate
  18. {--type=sentence : sentence|paragraph|chapter}
  19. {--api= : ai engin url}
  20. {--model= : ai model }
  21. {--sid= : 句子编号 }
  22. {--nissaya= : nissaya channel }
  23. {--result= : result channel }
  24. command;
  25. /**
  26. * The console command description.
  27. *
  28. * @var string
  29. */
  30. protected $description = '使用LLM 和nissaya数据翻译句子';
  31. /**
  32. * Create a new command instance.
  33. *
  34. * @return void
  35. */
  36. public function __construct()
  37. {
  38. parent::__construct();
  39. }
  40. /**
  41. * Execute the console command.
  42. *
  43. * @return int
  44. */
  45. public function handle()
  46. {
  47. //句子号列表
  48. $sentences = array();
  49. $totalLen = 0;
  50. switch ($this->option('type')) {
  51. case 'sentence':
  52. $sentences[] = explode('-', $this->option('sid'));
  53. break;
  54. case 'paragraph':
  55. $para = explode('-', $this->option('sid'));
  56. $sent = PaliSentence::where('book', $para[0])
  57. ->where('paragraph', $para[1])->orderBy('word_begin')->get();
  58. foreach ($sent as $key => $value) {
  59. $sentences[] = [$para[0], $para[1], $value->word_begin, $value->word_end];
  60. }
  61. break;
  62. case 'chapter':
  63. $para = explode('-', $this->option('sid'));
  64. $chapterLen = PaliText::where('book', $para[0])
  65. ->where('paragraph', $para[1])->value('chapter_len');
  66. $sent = PaliSentence::where('book', $para[0])
  67. ->whereBetween('paragraph', [$para[1], $para[1] + $chapterLen - 1])
  68. ->orderBy('paragraph')
  69. ->orderBy('word_begin')->get();
  70. foreach ($sent as $key => $value) {
  71. $sentences[] = [$para[0], $para[1], $value->word_begin, $value->word_end];
  72. }
  73. break;
  74. default:
  75. return 1;
  76. break;
  77. }
  78. //获取句子总长度
  79. foreach ($sentences as $key => $sentence) {
  80. $totalLen += $this->sentLen($sentence);
  81. }
  82. //
  83. foreach ($sentences as $key => $sentence) {
  84. # 获取巴利句子
  85. $pali = PaliSentence::where('book', $sentence[0])
  86. ->where('paragraph', $sentence[1])
  87. ->where('word_begin', $sentence[2])
  88. ->where('word_end', $sentence[3])
  89. ->value('text');
  90. //获取nissaya
  91. $nissaya = Sentence::where('channel_uid', $this->option('nissaya'))
  92. ->where('book_id', $sentence[0])
  93. ->where('paragraph', $sentence[1])
  94. ->where('word_start', $sentence[2])
  95. ->where('word_end', $sentence[3])
  96. ->value('content');
  97. //获取ai结果
  98. $api = $this->getEngin($this->option('api'));
  99. if (!$api) {
  100. $this->error('ai translate no api');
  101. return 1;
  102. }
  103. $json = $this->fetch($api, $this->option('model'), $pali, $nissaya);
  104. $this->info('ai translate', ['json' => $json]);
  105. //写入
  106. }
  107. return 0;
  108. }
  109. private function sentLen($id)
  110. {
  111. return PaliSentence::where('book', $id[0])
  112. ->where('paragraph', $id[1])
  113. ->where('word_begin', $id[2])
  114. ->where('word_end', $id[3])
  115. ->value('length');
  116. }
  117. private function getEngin($engin)
  118. {
  119. $api = config('mint.ai.accounts');
  120. $selected = array_filter($api, function ($value) use ($engin) {
  121. return $value['name'] === $engin;
  122. });
  123. if (!is_array($selected) || count($selected) === 0) {
  124. return null;
  125. }
  126. return $selected[0];
  127. }
  128. private function fetch($api, $model, $origin, $nissaya = null)
  129. {
  130. $prompt = '翻译上面的巴利文为中文';
  131. if ($nissaya) {
  132. $prompt = '根据下面的解释,' . $prompt;
  133. }
  134. $message = "{$origin}\n\n{$prompt}\n\n{$nissaya}";
  135. $url = $api['api_url'];
  136. $param = [
  137. "model" => $model,
  138. "messages" => [
  139. ["role" => "system", "content" => "你是翻译人工智能助手.bhikkhu 为专有名词,不可翻译成其他语言。"],
  140. ["role" => "user", "content" => $message],
  141. ],
  142. "temperature" => 0.3,
  143. "stream" => false
  144. ];
  145. $response = Http::withToken($api['token'])
  146. ->post($url, $param);
  147. if ($response->failed()) {
  148. $this->error('http request error' . $response->json('message'));
  149. Log::error('http request error', ['data' => $response->json()]);
  150. return null;
  151. } else {
  152. return $response->json();
  153. }
  154. }
  155. }