ChapterService.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <?php
  2. namespace App\Services;
  3. use App\Models\Sentence;
  4. use App\Models\Channel;
  5. use App\Models\PaliText;
  6. use Illuminate\Support\Str;
  7. use App\Http\Api\MdRender;
  8. use App\Http\Api\ChannelApi;
  9. use App\Http\Api\StudioApi;
  10. use App\Http\Api\AuthApi;
  11. use App\Http\Resources\TocResource;
  12. use App\Services\PaliContentService;
  13. use Illuminate\Support\Facades\Log;
  14. class ChapterService
  15. {
  16. protected $result = [
  17. "uid" => '',
  18. "title" => '',
  19. "path" => [],
  20. "sub_title" => '',
  21. "summary" => '',
  22. "content" => '',
  23. "content_type" => "html",
  24. "toc" => [],
  25. "status" => 30,
  26. "lang" => "",
  27. "created_at" => "",
  28. "updated_at" => "",
  29. ];
  30. protected $selectCol = [
  31. 'uid',
  32. 'book_id',
  33. 'paragraph',
  34. 'word_start',
  35. "word_end",
  36. 'channel_uid',
  37. 'content',
  38. 'content_type',
  39. 'editor_uid',
  40. 'acceptor_uid',
  41. 'pr_edit_at',
  42. 'fork_at',
  43. 'create_time',
  44. 'modify_time',
  45. 'created_at',
  46. 'updated_at',
  47. ];
  48. private $MaxStrLen = 3000;
  49. public function setMaxSize(int $size)
  50. {
  51. $this->MaxStrLen = $size;
  52. }
  53. public function chapterWithContent(string $id)
  54. {
  55. //getChannels
  56. //chapter info
  57. //chapter rang
  58. //chapter content
  59. }
  60. public function paraWithContent(string $id) {}
  61. public function csParaWithContent(string $id) {}
  62. public function paraContent(int $book, int $from, int $to) {}
  63. private function currChapter() {}
  64. private function getChannels(array|null $input, string $mode)
  65. {
  66. $channels = [];
  67. if (is_array($input)) {
  68. foreach ($input as $channel) {
  69. if (Str::isUuid($channel)) {
  70. $channels[] = $channel;
  71. }
  72. }
  73. }
  74. if ($mode === 'read') {
  75. //阅读模式加载html格式原文
  76. $channelId = ChannelApi::getSysChannel('_System_Pali_VRI_');
  77. } else {
  78. //翻译模式加载json格式原文
  79. $channelId = ChannelApi::getSysChannel('_System_Wbw_VRI_');
  80. }
  81. if ($channelId !== false) {
  82. $channels[] = $channelId;
  83. }
  84. #获取channel索引表
  85. $tranChannels = [];
  86. $channelInfo = Channel::whereIn("uid", $channels)
  87. ->select(['uid', 'type', 'lang', 'name'])->get();
  88. foreach ($channelInfo as $key => $value) {
  89. # code...
  90. if ($value->type === "translation") {
  91. $tranChannels[] = $value->uid;
  92. }
  93. }
  94. $indexChannel = [];
  95. $paliService = app(PaliContentService::class);
  96. $indexChannel = $paliService->getChannelIndex($channels);
  97. return [
  98. 'channels' => $channels,
  99. 'index' => $indexChannel,
  100. 'translations' => $tranChannels,
  101. 'request' => $input,
  102. ];
  103. }
  104. private function chapterInfo(int $book, int $para, array $channelInfo)
  105. {
  106. $result = [];
  107. $chapter = PaliText::where('book', $book)->where('paragraph', $para)->first();
  108. if (!$chapter) {
  109. //FIXME throw
  110. }
  111. if (empty($chapter->toc)) {
  112. $this->result['title'] = "unknown";
  113. } else {
  114. $result['title'] = $chapter->toc;
  115. $result['sub_title'] = $chapter->toc;
  116. $result['path'] = json_decode($chapter->path);
  117. }
  118. $title = Sentence::select($this->selectCol)
  119. ->where('book_id', $book)
  120. ->where('paragraph', $para)
  121. ->whereIn('channel_uid', $channelInfo['translation'])
  122. ->first();
  123. if ($title) {
  124. $result['title'] = MdRender::render($title->content, [$title->channel_uid]);
  125. $mdRender = new MdRender(['format' => 'simple']);
  126. $result['title_text'] = $mdRender->convert($title->content, [$title->channel_uid]);
  127. }
  128. return $result;
  129. }
  130. private function chapterContentRang($book, $para, $from, $to)
  131. {
  132. /**
  133. * 获取句子数据
  134. * 算法:
  135. * 1. 如果标题和下一级第一个标题之间有段落。只输出这些段落和子目录
  136. * 2. 如果标题和下一级第一个标题之间没有间隔 且 chapter 长度大于10000个字符 且有子目录,只输出子目录
  137. * 3. 如果二者都不是,lazy load
  138. */
  139. //1. 计算 标题和下一级第一个标题之间 是否有间隔
  140. $chapter = PaliText::where('book', $book)->where('paragraph', $para)->first();
  141. $paraFrom = $para;
  142. $paraTo = $para + $chapter->chapter_len - 1;
  143. $nextChapter = PaliText::where('book', $book)
  144. ->where('paragraph', ">", $para)
  145. ->where('level', '<', 8)
  146. ->orderBy('paragraph')
  147. ->value('paragraph');
  148. $between = $nextChapter - $para;
  149. //查找子目录
  150. $chapterLen = $chapter->chapter_len;
  151. $toc = PaliText::where('book', $book)
  152. ->whereBetween('paragraph', [$paraFrom + 1, $paraFrom + $chapterLen - 1])
  153. ->where('level', '<', 8)
  154. ->orderBy('paragraph')
  155. ->select(['book', 'paragraph', 'level', 'toc'])
  156. ->get();
  157. if ($between > 1) {
  158. //有间隔
  159. $paraTo = $nextChapter - 1;
  160. } else {
  161. if ($chapter->chapter_strlen > $this->MaxStrLen) {
  162. if (count($toc) > 0) {
  163. //有子目录只输出标题和目录
  164. $paraTo = $paraFrom;
  165. } else {
  166. //没有子目录 全部输出
  167. }
  168. } else {
  169. //章节小。全部输出 不输出子目录
  170. $toc = [];
  171. }
  172. }
  173. $pFrom = $from ?? $paraFrom;
  174. $pTo = $to ?? $paraTo;
  175. //根据句子的长度找到这次应该加载的段落
  176. $paliText = PaliText::select(['paragraph', 'lenght'])
  177. ->where('book', $book)
  178. ->whereBetween('paragraph', [$pFrom, $pTo])
  179. ->orderBy('paragraph')
  180. ->get();
  181. $sumLen = 0;
  182. $currTo = $pTo;
  183. foreach ($paliText as $para) {
  184. $sumLen += $para->lenght;
  185. if ($sumLen > $this->MaxStrLen) {
  186. $currTo = $para->paragraph;
  187. break;
  188. }
  189. }
  190. return ['toc' => $toc, 'from' => $pFrom, 'to' => $currTo];
  191. }
  192. private function subChapterToc($toc)
  193. {
  194. //第一次才显示toc
  195. return TocResource::collection($toc);
  196. }
  197. private function chapterContent($book, $para, $rang, $channelInfo, $mode)
  198. {
  199. $result = [];
  200. $paliService = app(PaliContentService::class);
  201. $record = Sentence::select($this->selectCol)
  202. ->where('book_id', $book)
  203. ->whereBetween('paragraph', [$rang['from'], $rang['to']])
  204. ->whereIn('channel_uid', $channelInfo['channels'])
  205. ->orderBy('paragraph')
  206. ->orderBy('word_start')
  207. ->get();
  208. if (count($record) === 0) {
  209. Log::warning('no data');
  210. }
  211. $result['content'] = json_encode($paliService->makeContentObj(
  212. $record,
  213. $mode,
  214. $channelInfo['index']
  215. ), JSON_UNESCAPED_UNICODE);
  216. $result['content_type'] = 'json';
  217. if ($rang['to'] < $para) {
  218. $result['from'] = $rang['to'] + 1;
  219. $result['to'] = $para;
  220. $result['paraId'] = "{$book}-{$para}";
  221. $result['channels'] = implode(',', $channelInfo['request']);
  222. $result['mode'] = $mode;
  223. }
  224. return $result;
  225. }
  226. }