Browse Source

:fire: remove api-v12 sub-project

Jeremy Zheng 1 day ago
parent
commit
6f8616c33b
100 changed files with 0 additions and 11351 deletions
  1. 0 18
      api-v12/.editorconfig
  2. 0 74
      api-v12/.env.example
  3. 0 11
      api-v12/.gitattributes
  4. 0 28
      api-v12/.gitignore
  5. 0 9
      api-v12/README.md
  6. 0 168
      api-v12/app/Console/Commands/AiTranslate.php
  7. 0 77
      api-v12/app/Console/Commands/CacheDictPreference.php
  8. 0 120
      api-v12/app/Console/Commands/CacheWbwPreference.php
  9. 0 45
      api-v12/app/Console/Commands/ClearEmbeddingsCache.php
  10. 0 180
      api-v12/app/Console/Commands/CopyUserBook.php
  11. 0 114
      api-v12/app/Console/Commands/CreateMyHanCrop.php
  12. 0 75
      api-v12/app/Console/Commands/CreateOpenSearchIndex.php
  13. 0 100
      api-v12/app/Console/Commands/ExportAiPaliWordToken.php
  14. 0 209
      api-v12/app/Console/Commands/ExportAiTrainingData.php
  15. 0 165
      api-v12/app/Console/Commands/ExportArticle.php
  16. 0 87
      api-v12/app/Console/Commands/ExportChannel.php
  17. 0 314
      api-v12/app/Console/Commands/ExportChapter.php
  18. 0 100
      api-v12/app/Console/Commands/ExportChapterIndex.php
  19. 0 69
      api-v12/app/Console/Commands/ExportCreateDb.php
  20. 0 259
      api-v12/app/Console/Commands/ExportDiscussion.php
  21. 0 109
      api-v12/app/Console/Commands/ExportFtsPali.php
  22. 0 102
      api-v12/app/Console/Commands/ExportGlossary.php
  23. 0 68
      api-v12/app/Console/Commands/ExportIKPaliTeam.php
  24. 0 219
      api-v12/app/Console/Commands/ExportNissaya.php
  25. 0 125
      api-v12/app/Console/Commands/ExportOffline.php
  26. 0 91
      api-v12/app/Console/Commands/ExportPaliSynonyms.php
  27. 0 87
      api-v12/app/Console/Commands/ExportPalitext.php
  28. 0 131
      api-v12/app/Console/Commands/ExportSentence.php
  29. 0 80
      api-v12/app/Console/Commands/ExportTag.php
  30. 0 75
      api-v12/app/Console/Commands/ExportTagmap.php
  31. 0 100
      api-v12/app/Console/Commands/ExportTerm.php
  32. 0 203
      api-v12/app/Console/Commands/ExportZip.php
  33. 0 277
      api-v12/app/Console/Commands/ExportZip2.php
  34. 0 147
      api-v12/app/Console/Commands/ImportArticle.php
  35. 0 213
      api-v12/app/Console/Commands/ImportArticleMap.php
  36. 0 41
      api-v12/app/Console/Commands/IndexOpenSearch.php
  37. 0 202
      api-v12/app/Console/Commands/IndexTerm.php
  38. 0 444
      api-v12/app/Console/Commands/IndexTipitaka.php
  39. 0 93
      api-v12/app/Console/Commands/InitCommentary.php
  40. 0 156
      api-v12/app/Console/Commands/InitCs6sentence.php
  41. 0 58
      api-v12/app/Console/Commands/InitDependence.php
  42. 0 148
      api-v12/app/Console/Commands/InitSystemChannel.php
  43. 0 103
      api-v12/app/Console/Commands/InitSystemDict.php
  44. 0 66
      api-v12/app/Console/Commands/Install.php
  45. 0 42
      api-v12/app/Console/Commands/InstallPaliSent.php
  46. 0 83
      api-v12/app/Console/Commands/InstallPaliSeries.php
  47. 0 42
      api-v12/app/Console/Commands/InstallPaliSim.php
  48. 0 156
      api-v12/app/Console/Commands/InstallPaliText.php
  49. 0 118
      api-v12/app/Console/Commands/InstallWbwTemplate.php
  50. 0 95
      api-v12/app/Console/Commands/InstallWordAll.php
  51. 0 107
      api-v12/app/Console/Commands/InstallWordBook.php
  52. 0 89
      api-v12/app/Console/Commands/InstallWordIndex.php
  53. 0 91
      api-v12/app/Console/Commands/InstallWordStatistics.php
  54. 0 360
      api-v12/app/Console/Commands/MqAiTranslate.php
  55. 0 313
      api-v12/app/Console/Commands/MqDiscussion.php
  56. 0 61
      api-v12/app/Console/Commands/MqEmpty.php
  57. 0 71
      api-v12/app/Console/Commands/MqExport.php
  58. 0 75
      api-v12/app/Console/Commands/MqExportArticle.php
  59. 0 74
      api-v12/app/Console/Commands/MqExportPaliChapter.php
  60. 0 53
      api-v12/app/Console/Commands/MqIssues.php
  61. 0 174
      api-v12/app/Console/Commands/MqPr.php
  62. 0 70
      api-v12/app/Console/Commands/MqProgress.php
  63. 0 57
      api-v12/app/Console/Commands/MqTask.php
  64. 0 63
      api-v12/app/Console/Commands/MqWbwAnalyses.php
  65. 0 44
      api-v12/app/Console/Commands/PatchWbwPageNumber.php
  66. 0 33
      api-v12/app/Console/Commands/PostInstall.php
  67. 0 92
      api-v12/app/Console/Commands/ProcessDeadLetterQueue.php
  68. 0 313
      api-v12/app/Console/Commands/RabbitMQWorker.php
  69. 0 61
      api-v12/app/Console/Commands/RemoveTermCache.php
  70. 0 80
      api-v12/app/Console/Commands/StatisticsDict.php
  71. 0 77
      api-v12/app/Console/Commands/StatisticsExp.php
  72. 0 90
      api-v12/app/Console/Commands/StatisticsNissaya.php
  73. 0 355
      api-v12/app/Console/Commands/StatisticsNissayaCover.php
  74. 0 77
      api-v12/app/Console/Commands/StatisticsWbw.php
  75. 0 60
      api-v12/app/Console/Commands/TestAI.php
  76. 0 58
      api-v12/app/Console/Commands/TestAIArticleTranslate.php
  77. 0 40
      api-v12/app/Console/Commands/TestAITerm.php
  78. 0 55
      api-v12/app/Console/Commands/TestAiTask.php
  79. 0 69
      api-v12/app/Console/Commands/TestCaseMan.php
  80. 0 53
      api-v12/app/Console/Commands/TestJsonToXml.php
  81. 0 83
      api-v12/app/Console/Commands/TestMarkdownToTpl.php
  82. 0 200
      api-v12/app/Console/Commands/TestMdRender.php
  83. 0 68
      api-v12/app/Console/Commands/TestMq.php
  84. 0 46
      api-v12/app/Console/Commands/TestMqExit.php
  85. 0 131
      api-v12/app/Console/Commands/TestMqWorker.php
  86. 0 126
      api-v12/app/Console/Commands/TestProjectCopyTask.php
  87. 0 117
      api-v12/app/Console/Commands/TestRedis.php
  88. 0 48
      api-v12/app/Console/Commands/TestSchedule.php
  89. 0 77
      api-v12/app/Console/Commands/TestSearchPali.php
  90. 0 102
      api-v12/app/Console/Commands/TestTex.php
  91. 0 76
      api-v12/app/Console/Commands/TestWorkerStartProject.php
  92. 0 71
      api-v12/app/Console/Commands/UpdateOpenSearchIndex.php
  93. 0 62
      api-v12/app/Console/Commands/UpdateRelationTo.php
  94. 0 89
      api-v12/app/Console/Commands/UpdateSentenceUnique.php
  95. 0 58
      api-v12/app/Console/Commands/UpdateSentenceVer.php
  96. 0 30
      api-v12/app/Console/Commands/Upgrade.php
  97. 0 81
      api-v12/app/Console/Commands/UpgradeAITerm.php
  98. 0 342
      api-v12/app/Console/Commands/UpgradeAITranslation.php
  99. 0 60
      api-v12/app/Console/Commands/UpgradeAt20230227.php
  100. 0 173
      api-v12/app/Console/Commands/UpgradeChapterDynamic.php

+ 0 - 18
api-v12/.editorconfig

@@ -1,18 +0,0 @@
-root = true
-
-[*]
-charset = utf-8
-end_of_line = lf
-indent_size = 4
-indent_style = space
-insert_final_newline = true
-trim_trailing_whitespace = true
-
-[*.md]
-trim_trailing_whitespace = false
-
-[*.{yml,yaml}]
-indent_size = 2
-
-[docker-compose.yml]
-indent_size = 4

+ 0 - 74
api-v12/.env.example

@@ -1,74 +0,0 @@
-APP_NAME=Laravel
-APP_ENV=local
-APP_KEY=
-APP_DEBUG=true
-APP_URL=http://localhost
-
-APP_LOCALE=en
-APP_FALLBACK_LOCALE=en
-APP_FAKER_LOCALE=en_US
-
-APP_MAINTENANCE_DRIVER=file
-# APP_MAINTENANCE_STORE=database
-
-PHP_CLI_SERVER_WORKERS=4
-
-BCRYPT_ROUNDS=12
-
-LOG_CHANNEL=stack
-LOG_STACK=single
-LOG_DEPRECATIONS_CHANNEL=null
-LOG_LEVEL=debug
-
-DB_CONNECTION=pgsql
-DB_HOST=127.0.0.1
-DB_PORT=5432
-DB_DATABASE=mint
-DB_USERNAME=root
-DB_PASSWORD=
-
-SESSION_DRIVER=database
-SESSION_LIFETIME=120
-SESSION_ENCRYPT=false
-SESSION_PATH=/
-SESSION_DOMAIN=null
-
-BROADCAST_CONNECTION=log
-FILESYSTEM_DISK=local
-QUEUE_CONNECTION=database
-
-CACHE_STORE=database
-# CACHE_PREFIX=
-
-MEMCACHED_HOST=127.0.0.1
-
-REDIS_CLIENT=phpredis
-REDIS_HOST=127.0.0.1
-REDIS_PASSWORD=null
-REDIS_PORT=6379
-
-MAIL_MAILER=log
-MAIL_SCHEME=null
-MAIL_HOST=127.0.0.1
-MAIL_PORT=2525
-MAIL_USERNAME=null
-MAIL_PASSWORD=null
-MAIL_FROM_ADDRESS="hello@example.com"
-MAIL_FROM_NAME="${APP_NAME}"
-
-AWS_ACCESS_KEY_ID=
-AWS_SECRET_ACCESS_KEY=
-AWS_DEFAULT_REGION=us-east-1
-AWS_BUCKET=
-AWS_USE_PATH_STYLE_ENDPOINT=false
-
-VITE_APP_NAME="${APP_NAME}"
-
-OPENSEARCH_SCHEME=http
-OPENSEARCH_HOST=127.0.0.1
-OPENSEARCH_PORT=9200
-OPENSEARCH_USERNAME=""
-OPENSEARCH_PASSWORD=""
-OPENSEARCH_SSL_VERIFICATION=false
-
-JWT_SECRETS_KEY=

+ 0 - 11
api-v12/.gitattributes

@@ -1,11 +0,0 @@
-* text=auto eol=lf
-
-*.blade.php diff=html
-*.css diff=css
-*.html diff=html
-*.md diff=markdown
-*.php diff=php
-
-/.github export-ignore
-CHANGELOG.md export-ignore
-.styleci.yml export-ignore

+ 0 - 28
api-v12/.gitignore

@@ -1,28 +0,0 @@
-*.log
-.DS_Store
-.env
-.env.backup
-.env.production
-.phpactor.json
-.phpunit.result.cache
-/.fleet
-/.idea
-/.nova
-/.phpunit.cache
-/.vscode
-/.zed
-/auth.json
-/node_modules
-/public/build
-/public/hot
-/public/storage
-/storage/*.key
-/storage/pail
-/vendor
-Homestead.json
-Homestead.yaml
-Thumbs.db
-
-composer.lock
-package-lock.json
-yarn.lock

+ 0 - 9
api-v12/README.md

@@ -1,9 +0,0 @@
-# Usage
-
-```bash
-cd ~/workspace/mint/api-v12
-npm install
-npm run build
-# start your local development server
-composer run dev
-```

+ 0 - 168
api-v12/app/Console/Commands/AiTranslate.php

@@ -1,168 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\Sentence;
-use App\Models\PaliSentence;
-use App\Models\PaliText;
-
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Facades\Http;
-
-class AiTranslate extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan ai:sentence.translate --type=chapter --api=deepseek --model=deepseek-chat --sid=107-2357
-     * php artisan ai:sentence.translate --type=sentence --api=kimi --model=moonshot-v1-8k --sid=107-2357-9-47
-     * @var string
-     */
-    protected $signature = <<<command
-    ai:sentence.translate 
-    {--type=sentence  : sentence|paragraph|chapter} 
-    {--api=  : ai engin url} 
-    {--model=  : ai model } 
-    {--sid=  : 句子编号 } 
-    {--nissaya=  : nissaya channel } 
-    {--result=  : result channel } 
-    command;
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '使用LLM 和nissaya数据翻译句子';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        //句子号列表
-        $sentences = array();
-        $totalLen = 0;
-        switch ($this->option('type')) {
-            case 'sentence':
-                $sentences[] = explode('-', $this->option('sid'));
-                break;
-            case 'paragraph':
-                $para = explode('-', $this->option('sid'));
-                $sent = PaliSentence::where('book', $para[0])
-                    ->where('paragraph', $para[1])->orderBy('word_begin')->get();
-                foreach ($sent as $key => $value) {
-                    $sentences[] = [$para[0], $para[1], $value->word_begin, $value->word_end];
-                }
-                break;
-            case 'chapter':
-                $para = explode('-', $this->option('sid'));
-                $chapterLen = PaliText::where('book', $para[0])
-                    ->where('paragraph', $para[1])->value('chapter_len');
-                $sent = PaliSentence::where('book', $para[0])
-                    ->whereBetween('paragraph', [$para[1], $para[1] + $chapterLen - 1])
-                    ->orderBy('paragraph')
-                    ->orderBy('word_begin')->get();
-                foreach ($sent as $key => $value) {
-                    $sentences[] = [$para[0], $para[1], $value->word_begin, $value->word_end];
-                }
-                break;
-            default:
-                return 1;
-                break;
-        }
-        //获取句子总长度
-
-        foreach ($sentences as $key => $sentence) {
-            $totalLen += $this->sentLen($sentence);
-        }
-        //
-        foreach ($sentences as $key => $sentence) {
-            # 获取巴利句子
-            $pali = PaliSentence::where('book', $sentence[0])
-                ->where('paragraph', $sentence[1])
-                ->where('word_begin', $sentence[2])
-                ->where('word_end', $sentence[3])
-                ->value('text');
-            //获取nissaya
-            $nissaya = Sentence::where('channel_uid', $this->option('nissaya'))
-                ->where('book_id', $sentence[0])
-                ->where('paragraph', $sentence[1])
-                ->where('word_start', $sentence[2])
-                ->where('word_end', $sentence[3])
-                ->value('content');
-            //获取ai结果
-            $api = $this->getEngin($this->option('api'));
-            if (!$api) {
-                $this->error('ai translate no api');
-                return 1;
-            }
-            $json = $this->fetch($api, $this->option('model'), $pali, $nissaya);
-            Log::info('ai translate', ['json' => $json]);
-            $this->info($json['choices'][0]['message']['content']);
-            //写入
-        }
-        return 0;
-    }
-
-    private function sentLen($id)
-    {
-        return PaliSentence::where('book', $id[0])
-            ->where('paragraph', $id[1])
-            ->where('word_begin', $id[2])
-            ->where('word_end', $id[3])
-            ->value('length');
-    }
-    private function getEngin($engin)
-    {
-        $api = config('mint.ai.accounts');
-        $selected = array_filter($api, function ($value) use ($engin) {
-            return $value['name'] === $engin;
-        });
-        if (!is_array($selected) || count($selected) === 0) {
-            return null;
-        }
-        return $selected[0];
-    }
-
-    private function fetch($api, $model, $origin,  $nissaya = null)
-    {
-        $prompt = '翻译上面的巴利文为中文';
-        if ($nissaya) {
-            $prompt = '根据下面的解释,' . $prompt;
-        }
-        $message = "{$origin}\n\n{$prompt}\n\n{$nissaya}";
-
-        $url = $api['api_url'];
-        $param = [
-            "model" => $model,
-            "messages" => [
-                ["role" => "system", "content" => "你是翻译人工智能助手.bhikkhu 为专有名词,不可翻译成其他语言。"],
-                ["role" => "user", "content" => $message],
-            ],
-            "temperature" => 0.3,
-            "stream" => false
-        ];
-        $response = Http::withToken($api['token'])
-            ->post($url, $param);
-        if ($response->failed()) {
-            $this->error('http request error' . $response->json('message'));
-            Log::error('http request error', ['data' => $response->json()]);
-            return null;
-        } else {
-            return $response->json();
-        }
-    }
-}

+ 0 - 77
api-v12/app/Console/Commands/CacheDictPreference.php

@@ -1,77 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\UserDict;
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Cache;
-
-class CacheDictPreference extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'cache:dict.preference';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '从第三方字典中提取首选项';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $prefix = 'dict-preference';
-        $words = UserDict::select(['word', 'language'])
-            ->groupBy(['word', 'language'])
-            ->cursor();
-        $wordCount = DB::select('SELECT count(*) from (
-                     SELECT word,language from user_dicts group by word,language) T');
-        $bar = $this->output->createProgressBar($wordCount[0]->count);
-        $count = 0;
-        foreach ($words as $key => $word) {
-            $meaning = UserDict::where('word', $word->word)
-                ->where('language', $word->language)
-                ->where('source', '_PAPER_RICH_')
-                ->whereNotNull('mean')
-                ->value('mean');
-            $meaning = trim($meaning, " $");
-            if (!empty($meaning)) {
-                $m = explode('$', $meaning);
-                Cache::put("{$prefix}/{$word->word}/{$word->language}", $m[0]);
-            }
-            $bar->advance();
-            $count++;
-            if ($count % 1000 === 0) {
-                if (\App\Tools\Tools::isStop()) {
-                    return 0;
-                }
-            }
-        }
-        $bar->finish();
-
-        return 0;
-    }
-}

+ 0 - 120
api-v12/app/Console/Commands/CacheWbwPreference.php

@@ -1,120 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Facades\Cache;
-use App\Models\WbwAnalysis;
-use Illuminate\Support\Facades\DB;
-
-class CacheWbwPreference extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'cache:wbw.preference {--editor=} {--view=all}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '逐词解析的首选项预热';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $prefix = 'wbw-preference';
-        if (
-            $this->option('view') === 'all' ||
-            $this->option('view') === 'my'
-        ) {
-            $this->info('个人数据');
-            /**
-             * 个人数据算法
-             * 最新优先
-             */
-            $wbw = WbwAnalysis::select(['wbw_word', 'type', 'editor_id']);
-            $wbwCount = DB::select('SELECT count(*) from (
-                SELECT wbw_word,type,editor_id from wbw_analyses group by wbw_word,type,editor_id) T');
-            if ($this->option('editor')) {
-                $wbw = $wbw->where('editor_id', $this->option('editor'));
-                $wbwCount = DB::select(
-                    'SELECT count(*) from (
-                    SELECT wbw_word,type,editor_id from wbw_analyses where editor_id=? group by wbw_word,type,editor_id) T',
-                    [$this->option('editor')]
-                );
-            }
-            $wbw = $wbw->groupBy(['wbw_word', 'type', 'editor_id'])->cursor();
-            $bar = $this->output->createProgressBar($wbwCount[0]->count);
-            $count = 0;
-            foreach ($wbw as $key => $value) {
-                $data = WbwAnalysis::where('wbw_word', $value->wbw_word)
-                    ->where('type', $value->type)
-                    ->where('editor_id', $value->editor_id)
-                    ->orderBy('updated_at', 'desc')
-                    ->value('data');
-                Cache::put("{$prefix}/{$value->wbw_word}/{$value->type}/{$value->editor_id}", $data);
-                $bar->advance();
-                $count++;
-                if ($count % 1000 === 0) {
-                    if (\App\Tools\Tools::isStop()) {
-                        return 0;
-                    }
-                }
-            }
-            $bar->finish();
-        }
-
-        if (
-            $this->option('view') === 'all' ||
-            $this->option('view') === 'community'
-        ) {
-            $this->info('社区通用');
-            /**
-             * 社区数据算法
-             * 多的优先
-             */
-            $wbw = WbwAnalysis::select(['wbw_word', 'type']);
-            $count = DB::select('SELECT count(*) from (
-                SELECT wbw_word,type from wbw_analyses group by wbw_word,type) T');
-            $wbw = $wbw->groupBy(['wbw_word', 'type'])->cursor();
-
-            $bar = $this->output->createProgressBar($count[0]->count);
-            foreach ($wbw as $key => $value) {
-                $data = WbwAnalysis::where('wbw_word', $value->wbw_word)
-                    ->where('type', $value->type)
-                    ->selectRaw('data,count(*)')
-                    ->groupBy("data")
-                    ->orderBy("count", "desc")
-                    ->first();
-
-                Cache::put("{$prefix}/{$value->wbw_word}/{$value->type}/0", $data->data);
-                $bar->advance();
-            }
-            $bar->finish();
-        }
-
-        return 0;
-    }
-}

+ 0 - 45
api-v12/app/Console/Commands/ClearEmbeddingsCache.php

@@ -1,45 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Services\OpenSearchService;
-
-class ClearEmbeddingsCache extends Command
-{
-    /**
-     * 命令名称
-     *
-     * @var string
-     */
-    protected $signature = 'embeddings:clear {text? : 指定要清理的文本,不传则清理全部缓存}';
-
-    /**
-     * 命令描述
-     *
-     * @var string
-     */
-    protected $description = '清理 Redis 中的 embedding 缓存';
-
-    /**
-     * 执行命令
-     */
-    public function handle(OpenSearchService $service)
-    {
-        $text = $this->argument('text');
-
-        if ($text) {
-            $ok = $service->clearEmbeddingCache($text);
-            if ($ok) {
-                $this->info("已清理指定文本的缓存: \"{$text}\"");
-            } else {
-                $this->warn("缓存不存在: \"{$text}\"");
-            }
-        } else {
-            $count = $service->clearAllEmbeddingCache();
-            $this->info("已清理所有 embedding 缓存,共 {$count} 条");
-        }
-
-        return 0;
-    }
-}

+ 0 - 180
api-v12/app/Console/Commands/CopyUserBook.php

@@ -1,180 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\CustomBookSentence;
-use App\Models\CustomBook;
-
-use App\Models\Channel;
-use App\Models\Sentence;
-use Illuminate\Support\Str;
-use Illuminate\Support\Facades\Log;
-
-class CopyUserBook extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan copy:user.book
-     * @var string
-     */
-    protected $signature = 'copy:user.book {--lang} {--book=} {--test}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '复制用户自定书到sentence表';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        //获取全部语言列表
-        $lang = CustomBookSentence::select('lang')->groupBy('lang')->get();
-        foreach ($lang as $key => $value) {
-            $this->info('language:'.$value->lang);
-        }
-        if($this->option('lang')){
-            return 0;
-        }
-
-        if($this->option('test')){
-            $this->info('run in test mode');
-        }
-
-        $this->info('给CustomBook 添加channel');
-        $newChannel = 0;
-
-        foreach (CustomBook::get() as $key => $customBook) {
-            $this->info('doing book='.$customBook->book_id);
-            if(empty($customBook->channel_id)){
-                $bookLang = $customBook->lang;
-                if(empty($bookLang) || $bookLang === 'false' || $bookLang === 'null'  || $bookLang === 'none'){
-                    $this->info('language can not be empty change to pa, book='.$customBook->book_id);
-                    Log::warning('copy:user.book language can not be empty ,change to pa, book='.$customBook->book_id);
-                    $bookLang = 'pa';
-                }
-                $customBook->lang = $bookLang;
-                $channelName = '_user_book_'.$bookLang;
-                $channel = Channel::where('owner_uid',$customBook->owner)
-                                ->where('name',$channelName)->first();
-                if($channel === null){
-                    $this->info('create new channel');
-                    $channelUuid = Str::uuid();
-                    $channel = new Channel;
-                    $channel->id = app('snowflake')->id();
-                    $channel->uid = $channelUuid;
-                    $channel->owner_uid = $customBook->owner;
-                    $channel->name = $channelName;
-                    $channel->type = 'original';
-                    $channel->lang = $bookLang;
-                    $channel->editor_id = 0;
-                    $channel->is_system = true;
-                    $channel->create_time = time()*1000;
-                    $channel->modify_time = time()*1000;
-                    $channel->status = $customBook->status;
-                    if(!$this->option('test')){
-                        $saveOk = $channel->save();
-                        if($saveOk){
-                            $newChannel++;
-                            Log::debug('copy user book : create channel success name='.$channelName);
-                        }else{
-                            Log::error('copy user book : create channel fail.',['channel'=>$channelName,'book'=>$customBook->book_id]);
-                            $this->error('copy user book : create channel fail.  name='.$channelName);
-                            continue;
-                        }
-                    }
-                }
-                if(!Str::isUuid($channel->uid)){
-                    Log::error('copy user book : channel id error.',['channel'=>$channelName,'book'=>$customBook->book_id]);
-                    $this->error('copy user book : channel id error.  name='.$channelName);
-                    continue;
-                }
-                $customBook->channel_id = $channel->uid;
-                if(!$this->option('test')){
-                    $ok = $customBook->save();
-                    if(!$ok){
-                        Log::error('copy user book : create channel fail.',['book'=>$customBook->book_id]);
-                        continue;
-                    }
-                }
-            }
-        }
-        $this->info('给CustomBook 添加channel 结束');
-
-        $userBooks = CustomBook::get();
-        $this->info('book '. count($userBooks));
-        $copySent = 0;
-        foreach ($userBooks as $key => $book) {
-
-            $queryBook = $this->option('book');
-            if(!empty($queryBook)){
-                if($book->book_id != $queryBook){
-                    continue;
-                }
-            }
-            if(empty($book->channel_id)){
-                $this->error('book channel is empty');
-                continue;
-            }
-            $this->info('doing book '. $book->book_id);
-
-            $bookSentence = CustomBookSentence::where('book',$book->book_id)->cursor();
-            foreach ($bookSentence as $key => $sentence) {
-                $newRow = Sentence::firstOrNew(
-                    [
-                        "book_id" => $sentence->book,
-                        "paragraph" => $sentence->paragraph,
-                        "word_start" => $sentence->word_start,
-                        "word_end" => $sentence->word_end,
-                        "channel_uid" => $book->channel_id,
-                    ],
-                    [
-                        'id' => app('snowflake')->id(),
-                        'uid' => Str::uuid(),
-                        'create_time' => $sentence->create_time,
-                        'modify_time' => $sentence->modify_time,
-                    ]
-                    );
-                $newRow->editor_uid = $sentence->owner;
-                $newRow->content = $sentence->content;
-                $newRow->strlen = mb_strlen($sentence->content,"UTF-8");
-                $newRow->status = $sentence->status;
-                $newRow->content_type = $sentence->content_type;
-                $newRow->language = $book->lang;
-                if(empty($newRow->channel_uid)){
-                    $this->error('channel uuid is null book='.$sentence->book .' para='.$sentence->paragraph);
-                    Log::error('channel uuid is null ',['sentence'=>$sentence->book]);
-                }else{
-                    if(!$this->option('test')){
-                        $ok = $newRow->save();
-                        if(!$ok){
-                            Log::error('copy fail ',['sentence'=>$sentence->id]);
-                        }
-                        $copySent++;
-                    }
-                }
-            }
-            $this->info("book {$book->book} finished");
-        }
-        $this->info('all done ');
-        $this->info('channel create '.$newChannel);
-        $this->info('sentence copy '.$copySent);
-        return 0;
-    }
-}

+ 0 - 114
api-v12/app/Console/Commands/CreateMyHanCrop.php

@@ -1,114 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-
-class CreateMyHanCrop extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan create:my.han.crop --page=10
-     * @var string
-     */
-    protected $signature = 'create:my.han.crop {--page=}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '建立缅汉字典切图工作文件';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $csvFile = config("mint.path.dict_text") . '/zh/my-han/index.csv';
-        if (($fp = fopen($csvFile, "r")) !== false) {
-            $row = 0;
-            $currPage = 0;
-            $currPageWords = [];
-            while (($data = fgetcsv($fp, 0, ',')) !== false) {
-                $row++;
-                if ($row === 1) {
-                    continue;
-                }
-                if ($this->option('page')) {
-                    if ($currPage >= (int)$this->option('page')) {
-                        break;
-                    }
-                }
-                $page = (int)$data[1];
-                $word = $data[2];
-                if ($page !== $currPage) {
-                    //保存上一页数据
-                    $this->save($currPage, $currPageWords);
-                    $currPage = $page;
-                    //清空单词缓存
-                    $currPageWords = [];
-                }
-                $currPageWords[] = $word;
-            }
-            fclose($fp);
-            $this->save($currPage, $currPageWords);
-        }
-        $this->info('done');
-        return 0;
-    }
-    private function save($page, $words)
-    {
-        $basicUrl = 'https://ftp.wikipali.org/kosalla/%E7%BC%85%E6%96%87%E8%AF%8D%E5%85%B8/';
-        if (count($words) > 0) {
-            $m = new \Mustache_Engine(array(
-                'entity_flags' => ENT_QUOTES,
-                'escape' => function ($value) {
-                    return $value;
-                }
-            ));
-            $tplFile = resource_path("/mustache/my_han_crop.tpl");
-            $tpl = file_get_contents($tplFile);
-            $wordWithIndex = [];
-            foreach ($words as $key => $value) {
-                $wordWithIndex[] = [
-                    'index' => $key + 1,
-                    'word' => trim($value),
-                ];
-            }
-            $data = [
-                'dict' => [
-                    ['index' => 'a', 'img' => "{$basicUrl}{$page}A.jpg"],
-                    ['index' => 'b', 'img' => "{$basicUrl}{$page}B.jpg"],
-                    ['index' => 'a', 'img' => "{$basicUrl}" . ($page + 1) . "A.jpg"],
-                ],
-                'words' => $wordWithIndex
-            ];
-            $content = $m->render($tpl, $data);
-            //保存到临时文件夹
-            // 使用本地磁盘
-            // 创建目录]
-            $dir = '/tmp/export/myhan_crop/' . $page;
-            Storage::disk('local')->makeDirectory($dir);
-            Storage::disk('local')->makeDirectory($dir . '/img');
-            Storage::disk('local')->put($dir . "/index.html", $content);
-            Storage::disk('local')->put($dir . "/img/{$page}", $page);
-            $this->info("page={$page} word=" . count($words));
-        } else {
-            $this->error('page' . $page . 'no words');
-        }
-    }
-}

+ 0 - 75
api-v12/app/Console/Commands/CreateOpenSearchIndex.php

@@ -1,75 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Services\OpenSearchService;
-use Illuminate\Console\Command;
-
-class CreateOpenSearchIndex extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan create:opensearch.index
-     * @var string
-     */
-    protected $signature = 'create:opensearch.index';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $openSearch = app(OpenSearchService::class);
-
-        // Test OpenSearch connection
-        $open = $openSearch->testConnection();
-        if ($open[0]) {
-            $this->info($open[1]);
-        } else {
-            $this->error($open[1]);
-            return 1; // Exit with error code
-        }
-
-        // Attempt to create or update index
-        try {
-            $crate = $openSearch->createIndex();
-            if ($crate['acknowledged']) {
-                $this->info('Index created successfully: ' . $crate['index']);
-            }
-            if ($crate['shards_acknowledged']) {
-                $this->info('Shards initialized successfully for index: ' . $crate['index']);
-            } else {
-                $this->error('Shard initialization failed for index: ' . $crate['index']);
-                return 1;
-            }
-        } catch (\Exception $e) {
-            if (str_contains($e->getMessage(), 'exists')) {
-                $this->warn('Index already exists, attempting to update...');
-            } else {
-                $this->error('Failed to create index: ' . $e->getMessage());
-            }
-            return 1;
-        }
-
-        return 0;
-    }
-}

+ 0 - 100
api-v12/app/Console/Commands/ExportAiPaliWordToken.php

@@ -1,100 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\DictApi;
-use Illuminate\Support\Facades\Log;
-use App\Models\UserDict;
-
-class ExportAiPaliWordToken extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan export:ai.pali.word.token
-     * @var string
-     */
-    protected $signature = 'export:ai.pali.word.token {--format=gz  : zip file format 7z,lzma,gz }';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'export ai pali word token';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        Log::debug('export ai pali word token');
-
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $exportDir = storage_path('app/tmp/export/offline');
-        if (!is_dir($exportDir)) {
-            $res = mkdir($exportDir, 0755, true);
-            if (!$res) {
-                Log::error('mkdir fail path=' . $exportDir);
-                return 1;
-            } else {
-                Log::info('make dir successful ' . $exportDir);
-            }
-        }
-
-        $dict_id = DictApi::getSysDict('system_preference');
-        if (!$dict_id) {
-            Log::error('没有找到 system_preference 字典');
-            return 1;
-        }
-
-        $filename = 'ai-pali-word-token-' . date("Y-m-d") . '.tsv';
-        $exportFile = $exportDir . '/' . $filename;
-        $fp = fopen($exportFile, 'w');
-        if ($fp === false) {
-            Log::error('无法创建文件');
-            return 1;
-        }
-
-        $start = time();
-        $total = UserDict::where('dict_id', $dict_id)->count();
-        $words = UserDict::where('dict_id', $dict_id)
-            ->select([
-                'word',
-                'factors',
-            ])->cursor();
-        foreach ($words as $key => $word) {
-            $output = array($word->word, $word->factors);
-            fwrite($fp, implode("\t", $output) . "\n");
-            if ($key % 100 === 0) {
-                $present = (int)($key * 100 / $total);
-                $this->info("[{$present}%]-{$key}");
-            }
-        }
-        fclose($fp);
-        Log::info((time() - $start) . ' seconds');
-
-        $this->call('export:zip', [
-            'id' => 'ai-pali-word-token',
-            'filename' => $exportFile,
-            'title' => 'ai pali word token',
-            'format' => $this->option('format'),
-        ]);
-
-        return 0;
-    }
-}

+ 0 - 209
api-v12/app/Console/Commands/ExportAiTrainingData.php

@@ -1,209 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Log;
-use App\Models\Sentence;
-use App\Models\PaliSentence;
-use App\Http\Api\MdRender;
-use Illuminate\Support\Facades\File;
-use App\Http\Api\ChannelApi;
-use App\Services\PaliTextService;
-
-class ExportAiTrainingData extends Command
-{
-    private $ShortTrans = 0.17;
-    /**
-     * The name and signature of the console command.
-     * php artisan export:ai.training.data
-     * @var string
-     */
-    protected $signature = 'export:ai.training.data {--format=gz  : zip file format 7z,lzma,gz } {--test}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'export ai training data';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        Log::info('task export offline sentence-table start');
-        //创建文件夹
-        $base = 'app/tmp/export/offline';
-        $exportDir = storage_path($base);
-        if (!is_dir($exportDir)) {
-            $res = mkdir($exportDir, 0755, true);
-            if (!$res) {
-                $this->error('mkdir fail path=' . $exportDir);
-                return 1;
-            } else {
-                $this->info('make dir successful ' . $exportDir);
-            }
-        }
-
-        //创建临时文件夹\
-        $dirname = $exportDir . '/' . 'wikipali-offline-ai-training-' . date("YmdHis");
-
-        $tmp = mkdir($dirname, 0755, true);
-        if (!$tmp) {
-            $this->error('mkdir fail path=' . $dirname);
-            return 1;
-        } else {
-            $this->info('make dir successful ' . $dirname);
-        }
-
-        $fpIndex = fopen($dirname . '/index.md', 'w');
-        if ($fpIndex === false) {
-            die('无法创建索引文件');
-        }
-
-        $channels = [
-            '7ac4d13b-a43d-4409-91b5-5f2a82b916b3',
-            'e5bc5c97-a6fb-4ccb-b7df-be6dcfee9c43',
-            '74ebf4c5-c243-4948-955d-6c277e29276a',
-            '3b0cb0aa-ea88-4ce5-b67d-00a3e76220cc',
-            '5310999c-0b0c-4bb0-9bb9-9cdd176e9ef0',
-            '331447b6-39bb-4b49-ac10-6206db93a050',
-        ];
-
-        $start = time();
-        foreach ($channels as $key => $channel) {
-            if ($this->option('test') && $key > 0) {
-                // test mode 只跑一个
-                break;
-            }
-            fwrite($fpIndex, "# {$channel}\n");
-            $channelInfo = ChannelApi::getById($channel);
-            if ($channelInfo) {
-                fwrite($fpIndex, "- 版本名称:{$channelInfo['name']}\n");
-                fwrite($fpIndex, "- 语言:{$channelInfo['lang']}\n");
-            }
-            // 创建文件
-            $this->info('export start' . $channel);
-            $filename = $channel . '.jsonl';
-            $exportFile = $dirname . '/' . $filename;
-            $fp = fopen($exportFile, 'w');
-            if ($fp === false) {
-                die('无法创建文件');
-            }
-
-            $db = Sentence::where('channel_uid', $channel);
-            $bar = $this->output->createProgressBar($db->count());
-
-            $srcDb = $db->select([
-                'book_id',
-                'paragraph',
-                'word_start',
-                'word_end',
-                'content',
-                'content_type'
-            ])
-                ->whereNotNull('content')
-                ->orderBy('book_id')
-                ->orderBy('paragraph')
-                ->orderBy('word_start')->cursor();
-            $done = [];
-            foreach ($srcDb as $sent) {
-                $id = "{$sent->book_id}-{$sent->paragraph}-{$sent->word_start}-{$sent->word_end}";
-                if (isset($done[$id])) {
-                    continue;
-                }
-                //获取原文
-                $origin = PaliSentence::where('book', $sent->book_id)
-                    ->where('paragraph', $sent->paragraph)
-                    ->where('word_begin', $sent->word_start)
-                    ->where('word_end', $sent->word_end)
-                    ->value('text');
-                //忽略空的原文
-                if (self::isEmpty($origin)) {
-                    Log::warning('origin is empty id=' . $id);
-                    continue;
-                }
-                // 渲染译文
-                $translation = MdRender::render(
-                    $sent->content,
-                    [$channel],
-                    null,
-                    'read',
-                    'translation',
-                    $sent->content_type,
-                    'text',
-                );
-                $translation = trim($translation);
-                // 忽略空的译文
-                if (self::isEmpty($translation)) {
-                    Log::warning('translation is empty id=' . $id);
-                    continue;
-                }
-
-                //忽略过短的译文
-                if (mb_strlen($translation) / mb_strlen($origin) < $this->ShortTrans) {
-                    Log::warning('translation is short id=' . $id);
-                    continue;
-                }
-                //原文与翻译完全相同
-                if ($translation === $origin) {
-                    Log::warning('translation is same id=' . $id);
-                    continue;
-                }
-                // 获取分类标签
-                $paliTextService = app(PaliTextService::class);
-                $tags = $paliTextService->getParaCategoryTags($sent->book_id, $sent->paragraph);
-                $path = $paliTextService->getParaPathTitle($sent->book_id, $sent->paragraph);
-                $currData = [
-                    'id' => $id,
-                    'original' => $origin,
-                    'translation' => $translation,
-                    'category' => $tags,
-                    'path' => $path,
-                ];
-
-                fwrite($fp, json_encode($currData, JSON_UNESCAPED_UNICODE) . "\n");
-                $bar->advance();
-                $done[$id] = 1;
-            }
-            fclose($fp);
-        }
-        fclose($fpIndex);
-
-        $this->info((time() - $start) . ' seconds');
-        $this->call('export:zip2', [
-            'id' => 'ai-translating-training-data',
-            'filename' => $dirname,
-            'title' => 'wikipali ai translating training data',
-            'format' => $this->option('format'),
-        ]);
-
-        sleep(5);
-        File::deleteDirectory($dirname);
-
-        return 0;
-    }
-
-    private function isEmpty(?string $input): bool
-    {
-        if (empty($input)) {
-            return true;
-        }
-        $result = preg_replace('/[\s\d\p{P}]/u', '', $input);
-        return empty($result);
-    }
-}

+ 0 - 165
api-v12/app/Console/Commands/ExportArticle.php

@@ -1,165 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Http;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Str;
-use Illuminate\Support\Facades\Storage;
-
-use Illuminate\Support\Facades\Cache;
-use App\Tools\ExportDownload;
-use App\Http\Api\MdRender;
-
-
-class ExportArticle extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan export:article 78c22ad3-58e2-4cf0-b979-67783ca3a375 123 --channel=7fea264d-7a26-40f8-bef7-bc95102760fb --format=html
-     * php artisan export:article df6c6609-6fc1-42d0-9ef1-535ef3e702c9 1234 --origin=true --channel=7fea264d-7a26-40f8-bef7-bc95102760fb  --format=docx --anthology=697c9169-cb9d-4a60-8848-92745e467bab --token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJuYmYiOjE2OTc3Mjg2ODUsImV4cCI6MTcyOTI2NDY4NSwidWlkIjoiYmE1NDYzZjMtNzJkMS00NDEwLTg1OGUtZWFkZDEwODg0NzEzIiwiaWQiOjR9.fiXhnY2LczZ9kKVHV0FfD3AJPZt-uqM5wrDe4EhToVexdd007ebPFYssZefmchfL0mx9nF0rgHSqjNhx4P0yDA
-     * @var string
-     */
-    protected $signature = 'export:article {id} {query_id} {--token=} {--anthology=} {--channel=}  {--origin=false} {--translation=true} {--format=tex} {--debug}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $this->info('task export chapter start');
-        Log::debug('task export chapter start');
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $options = [
-            'queryId' => $this->argument('query_id'),
-            'format' => $this->option('format'),
-            'debug' => $this->option('debug'),
-            'filename' => 'article',
-        ];
-        $upload = new ExportDownload($options);
-
-        MdRender::init();
-        $m = new \Mustache_Engine(array(
-            'entity_flags' => ENT_QUOTES,
-            'delimiters' => '[[ ]]',
-            'escape' => function ($value) {
-                return $value;
-            }
-        ));
-
-        $sections = array();
-        $articles = array();
-
-
-        $article = $this->fetch($this->argument('id'));
-        if (!$article) {
-            return 1;
-        }
-
-        $bookMeta = array();
-        $bookMeta['book_author'] = "";
-        $bookMeta['book_title'] = $article['title_text'];
-
-        $articles[] = [
-            'level' => 1,
-            'title' => $article['title_text'],
-            'content' => isset($article['html']) ? $article['html'] : '',
-        ];
-        $progress = 0.1;
-        $this->info($upload->setStatus($progress, 'export article content title=' . $article['title_text']));
-
-        if (isset($article['toc']) && count($article['toc']) > 0) {
-            $this->info('has sub article ' . count($article['toc']));
-            $step = 0.8 / count($article['toc']);
-            $baseLevel = 0;
-            foreach ($article['toc'] as $key => $value) {
-                if ($baseLevel === 0) {
-                    $baseLevel = $value['level'] - 2;
-                }
-                $progress += $step;
-                $this->info($upload->setStatus($progress, 'exporting article title=' . $value['title']));
-                $article = $this->fetch($value['key']);
-                if (!$article) {
-                    $this->info($upload->setStatus($progress, 'exporting article fail title=' . $value['title']));
-                    continue;
-                }
-                $this->info($upload->setStatus($progress, 'exporting article success title=' . $article['title_text']));
-                $articles[] = [
-                    'level' => $value['level'] - $baseLevel,
-                    'title' => $article['title_text'],
-                    'content' => isset($article['html']) ? $article['html'] : '',
-                ];
-            }
-        }
-
-        $sections[] = [
-            'name' => 'articles',
-            'body' => ['articles' => $articles],
-        ];
-        $this->info($upload->setStatus(0.9, 'export article content done'));
-        Log::debug('导出结束');
-
-
-        $upload->upload('article', $sections, $bookMeta);
-        $this->info($upload->setStatus(1, 'export article done'));
-        return 0;
-    }
-
-    private function fetch($articleId)
-    {
-        $api = config('mint.server.api.bamboo');
-        $basicUrl = $api . '/v2/article/';
-        $url =  $basicUrl . $articleId;;
-        $this->info('http request url=' . $url);
-
-        $urlParam = [
-            'mode' => 'read',
-            'format' => 'markdown',
-            'anthology' => $this->option('anthology'),
-            'channel' => $this->option('channel'),
-            'origin' => 'true' /*$this->option('origin')*/,
-            'paragraph' => true,
-        ];
-
-        Log::debug('export article http request', ['url' => $url, 'param' => $urlParam]);
-        if ($this->option('token')) {
-            $response = Http::withToken($this->option('token'))->get($url, $urlParam);
-        } else {
-            $response = Http::get($url, $urlParam);
-        }
-
-        if ($response->failed()) {
-            $this->error('http request error' . $response->json('message'));
-            Log::error('http request error', ['error' => $response->json('message')]);
-            return false;
-        }
-        if (!$response->json('ok')) {
-            $this->error('http request error' . $response->json('message'));
-            return false;
-        }
-        $article = $response->json('data');
-        return $article;
-    }
-}

+ 0 - 87
api-v12/app/Console/Commands/ExportChannel.php

@@ -1,87 +0,0 @@
-<?php
-/**
- * 导出离线用的channel数据
- */
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use App\Models\Channel;
-use Illuminate\Support\Facades\Log;
-
-class ExportChannel extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'export:channel {db}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '导出离线用的channel数据';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        Log::debug('task export offline channel-table start');
-        $exportFile = storage_path('app/public/export/offline/'.$this->argument('db').'-'.date("Y-m-d").'.db3');
-        $dbh = new \PDO('sqlite:'.$exportFile, "", "", array(\PDO::ATTR_PERSISTENT => true));
-        $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
-        $dbh->beginTransaction();
-
-        $query = "INSERT INTO channel ( id , name , type , language ,
-                                    summary , owner_id , setting,created_at )
-                                    VALUES ( ? , ? , ? , ? , ? , ? , ? , ?  )";
-        try{
-            $stmt = $dbh->prepare($query);
-        }catch(PDOException $e){
-            Log::info($e);
-            return 1;
-        }
-
-        $bar = $this->output->createProgressBar(Channel::where('status',30)->count());
-        foreach (Channel::where('status',30)
-                ->select(['uid','name','type','lang',
-                          'summary','owner_uid','setting','created_at'])
-                          ->cursor() as $row) {
-                $currData = array(
-                            $row->uid,
-                            $row->name,
-                            $row->type,
-                            $row->lang,
-                            $row->summary,
-                            $row->owner_uid,
-                            $row->setting,
-                            $row->created_at,
-                            );
-            $stmt->execute($currData);
-            $bar->advance();
-        }
-        $dbh->commit();
-        $bar->finish();
-        Log::debug('task export offline channel-table finished');
-        return 0;
-    }
-}

+ 0 - 314
api-v12/app/Console/Commands/ExportChapter.php

@@ -1,314 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Str;
-
-use App\Models\ProgressChapter;
-use App\Models\Channel;
-use App\Models\PaliText;
-use App\Models\Sentence;
-
-use App\Http\Api\ChannelApi;
-use App\Http\Api\MdRender;
-use App\Tools\Export;
-use Illuminate\Support\Facades\Cache;
-use App\Tools\ExportDownload;
-
-
-class ExportChapter extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan export:chapter 213 3 a19eaf75-c63f-4b84-8125-1bce18311e23 213-3.html --format=html --origin=true
-     * php artisan export:chapter 168 915 7fea264d-7a26-40f8-bef7-bc95102760fb 168-915.html --format=html --debug
-     * php artisan export:chapter 168 915 7fea264d-7a26-40f8-bef7-bc95102760fb 168-915.html --format=html --origin=true
-     * @var string
-     */
-    protected $signature = 'export:chapter {book} {para} {channel} {query_id} {--token=} {--origin=false} {--translation=true} {--debug} {--format=markdown} ';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $this->info('task export chapter start');
-        Log::debug('task export chapter start');
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $book = $this->argument('book');
-        $para = $this->argument('para');
-
-        $upload = new ExportDownload([
-            'queryId' => $this->argument('query_id'),
-            'format' => $this->option('format'),
-            'debug' => $this->option('debug'),
-            'filename' => $book . '-' . $para,
-        ]);
-
-        $m = new \Mustache_Engine(array(
-            'entity_flags' => ENT_QUOTES,
-            'delimiters' => '[[ ]]',
-            'escape' => function ($value) {
-                return $value;
-            }
-        ));
-        $tplFile = resource_path("mustache/chapter/md/paragraph.md");
-        $tplParagraph = file_get_contents($tplFile);
-
-        MdRender::init();
-
-        $renderFormat = 'markdown';
-
-        //获取原文channel
-        $orgChannelId = ChannelApi::getSysChannel('_System_Pali_VRI_');
-
-        $tranChannelsId = explode('_', $this->argument('channel'));
-
-        $channelsId = array_merge([$orgChannelId], $tranChannelsId);
-
-        $channels = array();
-        $channelsIndex = array();
-        foreach ($channelsId as $key => $id) {
-            $channels[] = ChannelApi::getById($id);
-            $channelsIndex[$id] = ChannelApi::getById($id);
-        }
-
-        $bookMeta = array();
-        $bookMeta['book_author'] = "";
-        foreach ($channels as $key => $channel) {
-            $bookMeta['book_author'] .= $channel['name'] . ' ';
-        }
-
-        $chapter = PaliText::where('book', $book)
-            ->where('paragraph', $para)->first();
-        if (!$chapter) {
-            return $this->error("no data");
-        }
-
-        $currProgress = 0;
-        $this->info($upload->setStatus($currProgress, 'start'));
-
-
-        if (empty($chapter->toc)) {
-            $bookMeta['title'] = "unknown";
-        } else {
-            $bookMeta['book_title'] = '';
-            foreach ($channelsId as $key => $id) {
-                $title = ProgressChapter::where('book', $book)->where('para', $para)
-                    ->where('channel_id', $id)
-                    ->value('title');
-                $bookMeta['book_title'] .= $title;
-            }
-            $bookMeta['sub_title'] = $chapter->toc;
-        }
-
-        $subChapter = PaliText::where('book', $book)->where('parent', $para)
-            ->where('level', '<', 8)
-            ->orderBy('paragraph')
-            ->get();
-        if (count($subChapter) === 0) {
-            //没有子章节
-            $subChapter = PaliText::where('book', $book)->where('paragraph', $para)
-                ->where('level', '<', 8)
-                ->orderBy('paragraph')
-                ->get();
-        }
-
-        $chapterParagraph = PaliText::where('book', $book)->where('paragraph', $para)->value('chapter_len');
-        if ($chapterParagraph > 0) {
-            $step = 0.9 / $chapterParagraph;
-        } else {
-            $step = 0.9;
-            Log::error('段落长度不能为0', ['book' => $book, 'para' => $para]);
-        }
-
-        $outputChannelsId = [];
-        if ($this->option('origin') === 'true') {
-            $outputChannelsId[] = $orgChannelId;
-        }
-        if ($this->option('translation') === 'true') {
-            $outputChannelsId = array_merge($outputChannelsId, $tranChannelsId);
-        }
-
-        $sections = array();
-        foreach ($subChapter as $key => $sub) {
-            # 看这个章节是否存在译文
-            $hasChapter = false;
-            if ($this->option('origin') === 'true') {
-                $hasChapter = true;
-            }
-            if ($this->option('translation') === 'true') {
-                foreach ($tranChannelsId as $id) {
-                    if (ProgressChapter::where('book', $book)->where('para', $sub->paragraph)
-                        ->where('channel_id', $id)
-                        ->exists()
-                    ) {
-                        $hasChapter = true;
-                    }
-                }
-            }
-            if (!$hasChapter) {
-                //不存在需要导出的数据
-                continue;
-            }
-            $filename = "{$sub->paragraph}." . $this->option('format');
-            $bookMeta['sections'][] = ['filename' => $filename];
-            $paliTitle = PaliText::where('book', $book)
-                ->where('paragraph', $sub->paragraph)
-                ->value('toc');
-            $sectionTitle = $paliTitle;
-            if ($this->option('translation') === 'true') {
-                $chapter = ProgressChapter::where('book', $book)->where('para', $sub->paragraph)
-                    ->where('channel_id', $tranChannelsId[0])
-                    ->first();
-                if ($chapter && !empty($chapter->title)) {
-                    $sectionTitle = $chapter->title;
-                }
-            }
-
-
-            $content = array();
-
-            $chapterStart = $sub->paragraph + 1;
-            $chapterEnd = $sub->paragraph + $sub->chapter_len;
-            $chapterBody = PaliText::where('book', $book)
-                ->whereBetween('paragraph', [$chapterStart, $chapterEnd])
-                ->orderBy('paragraph')->get();
-
-
-
-            foreach ($chapterBody as $body) {
-                $currProgress += $step;
-                $this->info($upload->setStatus($currProgress, 'export chapter ' . $body->paragraph));
-                $paraData = array();
-                $paraData['translations'] = array();
-                foreach ($outputChannelsId as $key => $channelId) {
-                    $translationData = Sentence::where('book_id', $book)
-                        ->where('paragraph', $body->paragraph)
-                        ->where('channel_uid', $channelId)
-                        ->orderBy('word_start')->get();
-                    $sentContent = array();
-                    foreach ($translationData as $sent) {
-                        $texText = MdRender::render(
-                            $sent->content,
-                            [$sent->channel_uid],
-                            null,
-                            'read',
-                            $channelsIndex[$channelId]['type'],
-                            $sent->content_type,
-                            $renderFormat
-                        );
-                        $sentContent[] = trim($texText);
-                    }
-                    $paraContent = implode(' ', $sentContent);
-                    if ($channelsIndex[$channelId]['type'] === 'original') {
-                        $paraData['origin'] = $paraContent;
-                    } else {
-                        $paraData['translations'][] = ['content' => $paraContent];
-                    }
-                }
-                if ($body->level > 7) {
-                    $content[] = $m->render($tplParagraph, $paraData);
-                } else {
-                    $currLevel = $body->level - $sub->level;
-                    if ($currLevel <= 0) {
-                        $currLevel = 1;
-                    }
-
-                    if (count($paraData['translations']) === 0) {
-                        $subSessionTitle = PaliText::where('book', $book)
-                            ->where('paragraph', $body->paragraph)
-                            ->value('toc');
-                    } else {
-                        $subSessionTitle = $paraData['translations'][0]['content'];
-                    }
-
-                    //标题
-                    $subStr = array_fill(0, $currLevel, '#');
-                    $content[] = implode('', $subStr) . " " . $subSessionTitle;
-                }
-                $content[] = "\n\n";
-            }
-
-            $sections[] = [
-                'name' => $filename,
-                'body' => [
-                    'title' => $sectionTitle,
-                    'content' => implode('', $content)
-                ]
-            ];
-        }
-
-        //导出术语表
-        $keyPali = array();
-        $keyMeaning = array();
-        if (isset($GLOBALS['glossary'])) {
-            $glossary = $GLOBALS['glossary'];
-            foreach ($glossary as $word => $meaning) {
-                $keyMeaning[$meaning] = $word;
-                $keyPali[$word] = $meaning;
-            }
-        }
-
-        ksort($keyPali);
-        krsort($keyMeaning);
-        $glossaryData = [];
-        $glossaryData['pali'] = [];
-        $glossaryData['meaning'] = [];
-        foreach ($keyPali as $word => $meaning) {
-            $glossaryData['pali'][] = ['pali' => $word, 'meaning' => $meaning];
-        }
-        foreach ($keyMeaning as $meaning => $word) {
-            $glossaryData['meaning'][] = ['pali' => $word, 'meaning' => $meaning];
-        }
-
-        Log::debug('glossary', ['data' => $glossaryData]);
-
-        $tplFile = resource_path("mustache/chapter/" . $this->option('format') . "/glossary." . $this->option('format'));
-        $tplGlossary = file_get_contents($tplFile);
-
-        $glossaryContent = $m->render($tplGlossary, $glossaryData);
-
-        $sections[] = [
-            'name' => 'glossary.' . $this->option('format'),
-            'body' => [
-                'title' => 'glossary',
-                'content' => $glossaryContent
-            ]
-        ];
-        $this->info($upload->setStatus($currProgress, 'export glossary ' . count($keyPali)));
-
-        $this->info($upload->setStatus(0.9, 'export content done sections=' . count($sections)));
-
-        Log::debug('导出结束', ['sections' => count($sections)]);
-
-        $upload->upload('chapter', $sections, $bookMeta);
-        $this->info($upload->setStatus(1, 'export chapter done'));
-
-        return 0;
-    }
-}

+ 0 - 100
api-v12/app/Console/Commands/ExportChapterIndex.php

@@ -1,100 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use App\Models\ProgressChapter;
-use App\Models\Channel;
-use Illuminate\Support\Facades\Cache;
-use Illuminate\Support\Facades\Log;
-
-class ExportChapterIndex extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'export:chapter.index {db : db file name wikipali-offline or wikipali-offline-index}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'export chapter index';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        Log::debug('task export offline chapter-index-table start');
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-
-        $exportFile = storage_path('app/public/export/offline/' . $this->argument('db') . '-' . date("Y-m-d") . '.db3');
-        $dbh = new \PDO('sqlite:' . $exportFile, "", "", array(\PDO::ATTR_PERSISTENT => true));
-        $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
-        $dbh->beginTransaction();
-
-        $query = "INSERT INTO chapter ( id , book , paragraph,
-                                    language , title , channel_id , progress,updated_at  )
-                                    VALUES ( ? , ? , ? , ? , ? , ? , ? , ?  )";
-        try {
-            $stmt = $dbh->prepare($query);
-        } catch (\PDOException $e) {
-            Log::info($e);
-            return 1;
-        }
-
-        $publicChannels = Channel::where('status', 30)->select('uid')->get();
-        $rows = ProgressChapter::whereIn('channel_id', $publicChannels)->count();
-        Cache::put("/export/chapter/count", $rows, 3600 * 10);
-        $bar = $this->output->createProgressBar($rows);
-        foreach (
-            ProgressChapter::whereIn('channel_id', $publicChannels)
-                ->select([
-                    'uid',
-                    'book',
-                    'para',
-                    'lang',
-                    'title',
-                    'channel_id',
-                    'progress',
-                    'updated_at'
-                ])->cursor() as $row
-        ) {
-            $currData = array(
-                $row->uid,
-                $row->book,
-                $row->para,
-                $row->lang,
-                $row->title,
-                $row->channel_id,
-                $row->progress,
-                $row->updated_at,
-            );
-            $stmt->execute($currData);
-            $bar->advance();
-        }
-        $dbh->commit();
-        $bar->finish();
-        Log::debug('task export offline chapter-index-table finished');
-        return 0;
-    }
-}

+ 0 - 69
api-v12/app/Console/Commands/ExportCreateDb.php

@@ -1,69 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use Illuminate\Support\Facades\Log;
-
-class ExportCreateDb extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'export:create.db';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        Log::debug('task export offline create-db start');
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $this->create('sentence.sql','wikipali-offline');
-        $this->create('sentence.sql','wikipali-offline-index');
-
-        return 0;
-    }
-
-    private function create($sqlFile,$dbFile){
-        $sqlPath = database_path('export/'.$sqlFile);
-        $exportDir = storage_path('app/public/export/offline');
-        $exportFile = $exportDir.'/'.$dbFile.'-'.date("Y-m-d").'.db3';
-        $file = fopen($exportFile,'w');
-        fclose($file);
-        $dbh = new \PDO('sqlite:'.$exportFile, "", "", array(\PDO::ATTR_PERSISTENT => true));
-        $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
-        //建立数据库
-        $_sql = file_get_contents($sqlPath);
-        $_arr = explode(';', $_sql);
-        //执行sql语句
-        foreach ($_arr as $_value) {
-            $dbh->query($_value . ';');
-        }
-        Log::debug('task export offline create-db finished');
-    }
-}

+ 0 - 259
api-v12/app/Console/Commands/ExportDiscussion.php

@@ -1,259 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\DB;
-use App\Http\Api\ChannelApi;
-use Carbon\Carbon;
-
-class ExportDiscussion extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan export:discussion
-     */
-    protected $signature = 'export:discussion {editor : The editor UID to export discussions for}';
-
-    /**
-     * The console command description.
-     */
-    protected $description = 'Export discussions made by a specific editor to a Markdown file';
-
-    /** @var string 巴利原文 channel_uid */
-    private string $orgChannelId;
-
-    /** @var resource 输出文件句柄(流式写入,避免大字符串堆积在内存) */
-    private $fileHandle;
-
-    /** @var string 输出文件路径 */
-    private string $outputPath;
-
-    /**
-     * Execute the console command.
-     */
-    public function handle(): int
-    {
-        $editorUid = $this->argument('editor');
-
-        $this->info("Fetching discussions for editor: {$editorUid}");
-
-        // 1. 获取巴利原文 channel_uid
-        $this->orgChannelId = ChannelApi::getSysChannel('_System_Pali_VRI_');
-        if (!$this->orgChannelId) {
-            $this->error('Failed to retrieve Pali source channel ID.');
-            return self::FAILURE;
-        }
-        $this->info("Pali channel ID: {$this->orgChannelId}");
-
-        // 2. 统计总数(用于进度条)
-        $total = DB::table('discussions')
-            ->where('editor_uid', $editorUid)
-            ->where('status', 'active')
-            ->count();
-
-        if ($total === 0) {
-            $this->warn("No discussions found for editor: {$editorUid}");
-            return self::SUCCESS;
-        }
-
-        $this->info("Found {$total} discussion(s). Processing...");
-
-        // 3. 打开文件句柄(流式写入,不在内存中拼接整个 Markdown)
-        $filename = "discussion_export_{$editorUid}_" . now()->format('YmdHis') . '.md';
-        $this->outputPath = storage_path("app/tmp/{$filename}");
-        $this->fileHandle = fopen($this->outputPath, 'w');
-        if (!$this->fileHandle) {
-            $this->error("Cannot open file for writing: {$this->outputPath}");
-            return self::FAILURE;
-        }
-
-        // 写文件头
-        $this->writeLine("# 讨论导出报告\n");
-        $this->writeLine("- **Editor UID**: {$editorUid}");
-        $this->writeLine("- **导出时间**: " . now()->toDateTimeString());
-        $this->writeLine("\n---\n");
-
-        // 4. 分批处理(每批 50 条),避免内存溢出
-        $progressBar = $this->output->createProgressBar($total);
-        $progressBar->start();
-
-        DB::table('discussions')
-            ->where('editor_uid', $editorUid)
-            ->where('status', 'active')
-            ->orderBy('created_at', 'asc')
-            ->select(['id', 'res_id', 'res_type', 'content', 'created_at'])
-            ->chunk(50, function ($discussions) use ($progressBar) {
-                $this->processChunk($discussions);
-                $progressBar->advance($discussions->count());
-
-                // 每批处理完后主动释放内存
-                gc_collect_cycles();
-            });
-
-        $progressBar->finish();
-        $this->newLine();
-
-        fclose($this->fileHandle);
-
-        $this->info("\n✅ 导出完成!文件已保存到: {$this->outputPath}");
-
-        return self::SUCCESS;
-    }
-
-    /**
-     * 处理一批 discussions。
-     */
-    private function processChunk(\Illuminate\Support\Collection $discussions): void
-    {
-        // --- 批量查译文 sentences ---
-        $resIds = $discussions->pluck('res_id')->unique()->values()->all();
-
-        $translationMap = DB::table('sentences')
-            ->whereIn('uid', $resIds)
-            ->select([
-                'uid',
-                'book_id',
-                'paragraph',
-                'word_start',
-                'word_end',
-                'content',
-                'channel_uid',
-            ])
-            ->get()
-            ->keyBy('uid');
-
-        // --- 批量查 sent_histories(分小批,避免超大 IN) ---
-        $historiesMap = [];
-        foreach (array_chunk($resIds, 100) as $batch) {
-            DB::table('sent_histories')
-                ->whereIn('sent_uid', $batch)
-                ->orderBy('create_time', 'asc')
-                ->select(['sent_uid', 'content', 'create_time'])
-                ->each(function ($row) use (&$historiesMap) {
-                    $historiesMap[$row->sent_uid][] = $row;
-                });
-        }
-
-        // --- 收集本批所有唯一坐标,批量查巴利原文 ---
-        $coordKeys = [];
-        foreach ($translationMap as $t) {
-            $key = "{$t->book_id}_{$t->paragraph}_{$t->word_start}_{$t->word_end}";
-            $coordKeys[$key] = $t;
-        }
-        $paliMap = $this->fetchPaliSentences($coordKeys);
-
-        // --- 写 Markdown ---
-        foreach ($discussions as $discussion) {
-            $sentUid     = $discussion->res_id;
-            $translation = $translationMap->get($sentUid);
-            if (!$translation) {
-                continue;
-            }
-
-            $coordKey    = "{$translation->book_id}_{$translation->paragraph}_{$translation->word_start}_{$translation->word_end}";
-            $pali        = $paliMap[$coordKey] ?? null;
-            $paliContent = $pali ? trim($pali->content ?? '(无原文)') : '(未找到巴利原文)';
-
-            $discussionCreatedAt = $discussion->created_at
-                ? Carbon::parse($discussion->created_at)
-                : null;
-
-            $histories      = $historiesMap[$sentUid] ?? [];
-            $matchedHistory = $this->findClosestHistory($histories, $discussionCreatedAt);
-            $translationAtTime = $matchedHistory
-                ? trim($matchedHistory->content)
-                : trim($translation->content ?? '(无译文内容)');
-
-            $this->writeLine("# {$paliContent}\n");
-            $this->writeLine("  - **历史译文**: {$translationAtTime}");
-            $this->writeLine("  - **评论**: " . trim($discussion->title ?? '') . trim($discussion->content ?? ''));
-            $this->writeLine("  - **当前译文**: {$translation->content}");
-            $this->writeLine('');
-        }
-
-        // 显式释放本批数据
-        unset($translationMap, $historiesMap, $coordKeys, $paliMap);
-    }
-
-    /**
-     * 批量查询巴利原文,每组最多 30 个坐标,避免超大 SQL。
-     *
-     * @param array<string, object> $coordKeys  key="{book_id}_{paragraph}_{word_start}_{word_end}"
-     * @return array<string, object>
-     */
-    private function fetchPaliSentences(array $coordKeys): array
-    {
-        $paliMap = [];
-
-        foreach (array_chunk(array_values($coordKeys), 30) as $group) {
-            $results = DB::table('sentences')
-                ->where('channel_uid', $this->orgChannelId)
-                ->where(function ($q) use ($group) {
-                    foreach ($group as $t) {
-                        $q->orWhere(function ($sub) use ($t) {
-                            $sub->where('book_id',    $t->book_id)
-                                ->where('paragraph',  $t->paragraph)
-                                ->where('word_start', $t->word_start)
-                                ->where('word_end',   $t->word_end);
-                        });
-                    }
-                })
-                ->select(['book_id', 'paragraph', 'word_start', 'word_end', 'content'])
-                ->get();
-
-            foreach ($results as $ps) {
-                $key = "{$ps->book_id}_{$ps->paragraph}_{$ps->word_start}_{$ps->word_end}";
-                $paliMap[$key] = $ps;
-            }
-
-            unset($results);
-        }
-
-        return $paliMap;
-    }
-
-    /**
-     * 流式写入一行到文件。
-     */
-    private function writeLine(string $line): void
-    {
-        fwrite($this->fileHandle, $line . "\n");
-    }
-
-    /**
-     * 在历史记录中找评论发布时间之前最近的那条。
-     * 若全部在评论之后,则退而取最早一条。
-     *
-     * @param array       $histories           sent_histories(已按 create_time ASC 排序)
-     * @param Carbon|null $discussionCreatedAt 评论发布时间
-     */
-    private function findClosestHistory(array $histories, ?Carbon $discussionCreatedAt): ?object
-    {
-        if (empty($histories)) {
-            return null;
-        }
-
-        if (!$discussionCreatedAt) {
-            return end($histories) ?: null;
-        }
-
-        $discussionTimestamp = $discussionCreatedAt->timestamp;
-        $best     = null;
-        $bestDiff = PHP_INT_MAX;
-
-        foreach ($histories as $h) {
-            $historyTime = (int) $h->create_time;
-            if ($historyTime <= $discussionTimestamp) {
-                $diff = $discussionTimestamp - $historyTime;
-                if ($diff < $bestDiff) {
-                    $bestDiff = $diff;
-                    $best     = $h;
-                }
-            }
-        }
-
-        // 所有历史都在评论之后 → 取最早一条
-        return $best ?? $histories[0];
-    }
-}

+ 0 - 109
api-v12/app/Console/Commands/ExportFtsPali.php

@@ -1,109 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\DictApi;
-use App\Models\UserDict;
-use Illuminate\Support\Facades\Redis;
-use Illuminate\Support\Facades\Log;
-
-class ExportFtsPali extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'export:fts.pali';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '导出全文搜索用的巴利语词汇表';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        //irregular
-        $dictId = ['4d3a0d92-0adc-4052-80f5-512a2603d0e8'];
-        //regular
-        $dictId[] = DictApi::getSysDict('system_regular');
-        $long = ["ā", "ī", "ū"];
-        $path = storage_path('app/export/fts');
-        if (!is_dir($path)) {
-            $res = mkdir($path, 0700, true);
-            if (!$res) {
-                Log::error('mkdir fail path=' . $path);
-                return 1;
-            }
-        }
-
-        $pageSize = 10000;
-        $currPage = 1;
-        $filename = "/pali-{$currPage}.syn";
-        $fp = fopen($path . $filename, 'w') or die("Unable to open file!");
-        $count = 0;
-        foreach ($dictId as $key => $value) {
-            $words = UserDict::where('dict_id', $value)
-                ->select('word')
-                ->groupBy('word')->cursor();
-            $this->info('word count=' . count($words));
-            foreach ($words as $key => $word) {
-                $count++;
-                if ($count % 1000 === 0) {
-                    $this->info($count);
-                }
-                if ($count % 10000 === 0) {
-                    fclose($fp);
-                    $redisKey = 'export/fts/pali' . $filename;
-                    $content = file_get_contents($path . $filename);
-                    Redis::set($redisKey, $content);
-                    Redis::expire($redisKey, 3600 * 24 * 10);
-                    $currPage++;
-                    $filename = "/pali-{$currPage}.syn";
-                    $this->info('new file filename=' . $filename);
-                    $fp = fopen($path . $filename, 'w') or die("Unable to open file!");
-                }
-                $parent = UserDict::where('dict_id', $value)
-                    ->where('word', $word->word)
-                    ->selectRaw('parent,char_length("parent")')
-                    ->groupBy('parent')->orderBy('char_length', 'asc')->first();
-
-                if ($parent && !empty($parent->parent)) {
-                    $end = mb_substr($parent->parent, -1, null, "UTF-8");
-                    if (in_array($end, ["ā", "ī", "ū"])) {
-                        $head = mb_substr($parent->parent, 0, mb_strlen($parent->parent) - 1, "UTF-8");
-                        $newEnd = str_replace(["ā", "ī", "ū"], ["a", "i", "u"], $end);
-                        $parentWord = $head . $newEnd;
-                    } else {
-                        $parentWord = $parent->parent;
-                    }
-                    fwrite($fp, $word->word . ' ' . $parentWord . PHP_EOL);
-                } else {
-                    $this->error('word no parent word=' . $word->word);
-                }
-            }
-        }
-        fclose($fp);
-
-
-        return 0;
-    }
-}

+ 0 - 102
api-v12/app/Console/Commands/ExportGlossary.php

@@ -1,102 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Facades\File;
-use App\Services\TermService;
-
-
-class ExportGlossary extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan export:export-glossary zh-Hans
-     * @var string
-     */
-    protected $signature = 'export:export-glossary {lang}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '导出术语表';
-
-    protected TermService $termService;
-
-    public function __construct(TermService $termService)
-    {
-        $this->termService = $termService;
-        parent::__construct();
-    }
-    /**
-     * Execute the console command.
-     */
-    public function handle()
-    {
-        Log::info('task export offline sentence-table start');
-        $lang = $this->argument('lang');
-        //创建文件夹
-        $base = 'app/tmp/export/offline';
-        $exportDir = storage_path($base);
-        if (!is_dir($exportDir)) {
-            $res = mkdir($exportDir, 0755, true);
-            if (!$res) {
-                $this->error('mkdir fail path=' . $exportDir);
-                return 1;
-            } else {
-                $this->info('make dir successful ' . $exportDir);
-            }
-        }
-
-        //创建临时文件夹\
-        $dirname = $exportDir . '/' . 'wikipali_glossary_' . date("YmdHis");
-
-        $tmp = mkdir($dirname, 0755, true);
-        if (!$tmp) {
-            $this->error('mkdir fail path=' . $dirname);
-            return 1;
-        } else {
-            $this->info('make dir successful ' . $dirname);
-        }
-
-        $fpIndex = fopen($dirname . '/index.md', 'w');
-        if ($fpIndex === false) {
-            die('无法创建索引文件');
-        }
-
-        // 创建json文件
-        $this->info('export start' . $lang);
-        $filename = 'glossary_' . $lang . '.jsonl';
-        $exportFile = $dirname . '/' . $filename;
-        $fp = fopen($exportFile, 'w');
-        if ($fp === false) {
-            die('无法创建文件');
-        }
-        $start = time();
-
-        //**业务逻辑 */
-
-        $data = $this->termService->getCommunityGlossary($lang);
-        foreach ($data['items'] as $key => $value) {
-            fwrite($fp, json_encode($value, JSON_UNESCAPED_UNICODE) . "\n");
-        }
-
-        fclose($fpIndex);
-
-        $this->info((time() - $start) . ' seconds');
-        $this->call('export:zip2', [
-            'id' => 'wikipali_glossary',
-            'filename' => $dirname,
-            'title' => 'wikipali glossary of community',
-            'format' => 'jsonl',
-        ]);
-
-        sleep(5);
-        File::deleteDirectory($dirname);
-
-        return 0;
-    }
-}

+ 0 - 68
api-v12/app/Console/Commands/ExportIKPaliTeam.php

@@ -1,68 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\DhammaTerm;
-use Illuminate\Support\Facades\Redis;
-use Illuminate\Support\Facades\Log;
-
-class ExportIKPaliTeam extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan export:ik.pali.team
-     * @var string
-     */
-    protected $signature = 'export:ik.pali.team';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $path = storage_path('app/export/fts');
-        if (!is_dir($path)) {
-            $res = mkdir($path, 0700, true);
-            if (!$res) {
-                Log::error('mkdir fail path=' . $path);
-                return 1;
-            }
-        }
-        $filename = "/pali_term.txt";
-        $fp = fopen($path . $filename, 'w') or die("Unable to open file!");
-        $wordsList = [];
-        $teams = DhammaTerm::select(['meaning', 'other_meaning'])->get();
-        foreach ($teams as $term) {
-            if (!empty($term->meaning)) {
-                $wordsList[$term->meaning] = 1;
-            }
-        }
-        foreach ($wordsList as $word => $value) {
-            fwrite($fp, $word . PHP_EOL);
-        }
-        // 关闭文件
-        fclose($fp);
-        $this->info('done');
-        return 0;
-    }
-}

+ 0 - 219
api-v12/app/Console/Commands/ExportNissaya.php

@@ -1,219 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use App\Models\Channel;
-use App\Models\Sentence;
-use App\Models\NissayaEnding;
-use App\Models\UserDict;
-use App\Http\Api\DictApi;
-
-class SuttaType
-{
-    public static function types(){
-        return     [
-            'mula'=>[
-                69,70,71,72,73,74,
-                75,76,77,78,79,80,
-                81,82,83,84,85,86,
-                87,88,89,90,91,92,
-                93,94,95,143,144,145,
-                146,147,148,149,150,151,
-                152,153,154,155,156,157,
-                158,159,160,161,162,163,
-                164,165,166,167,168,169,
-                170,171,213,214,215,216,217,
-            ],
-            'atthakatha' => [
-                64,65,96,97,98,99,
-                100,101,102,103,104,105,
-                106,107,108,109,110,111,
-                112,113,114,115,116,117,
-                118,119,120,121,122,123,
-                124,125,126,127,128,129,
-                130,131,132,133,134,135,
-                136,137,138,139,140,141,142,
-            ],
-            'tika' => [
-                66,67,68,172,173,174,
-                175,176,177,178,179,180,
-                181,182,183,184,185,186,
-                187,188,189,190,191,192,
-                193,194,195,196,197,198,
-                199,200,201,202,203,204,
-                205,206,207,208,209,210,211,212,
-            ],
-            'vinaya' => [138,139,140,141,142,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,],
-            'sutta' => [
-                82,83,84,85,86,
-                87,88,89,90,91,92,93,
-                94,95,99,100,101,102,
-                103,104,105,106,107,108,
-                109,110,111,112,113,114,
-                115,116,117,118,119,120,
-                121,122,123,124,125,126,
-                127,128,129,130,131,132,
-                133,134,135,136,137,143,
-                144,145,146,147,148,149,
-                150,151,152,153,154,155,
-                156,157,158,159,160,161,
-                162,163,164,165,166,167,
-                168,169,170,171,181,182,
-                183,184,185,186,187,188,
-                189,190,191,192,193,194,
-                195,196,197,198,199,
-            ],
-            'abhidhamma' => [69,70,71,72,73,74,75,76,77,78,79,80,81,96,97,98,172,173,174,175,176,177,178,179,180,],
-        ];
-    }
-
-    public static function getTypeByBook($bookId){
-        $types = [];
-        foreach (SuttaType::types() as $type => $books) {
-            if(in_array($bookId,$books)){
-                $types[] = $type;
-            }
-        }
-        return $types;
-    }
-}
-
-class ExportNissaya extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan export:nissaya
-     * @var string
-     */
-    protected $signature = 'export:nissaya';
-    protected $my = ["ႁႏၵ","ခ္","ဃ္","ဆ္","ဈ္","ည္","ဌ္","ဎ္","ထ္","ဓ္","ဖ္","ဘ္","က္","ဂ္","စ္","ဇ္","ဉ္","ဠ္","ဋ္","ဍ္","ဏ္","တ္","ဒ္","န္","ဟ္","ပ္","ဗ္","မ္","ယ္","ရ္","လ္","ဝ္","သ္","င္","င်္","ဿ","ခ","ဃ","ဆ","ဈ","စျ","ည","ဌ","ဎ","ထ","ဓ","ဖ","ဘ","က","ဂ","စ","ဇ","ဉ","ဠ","ဋ","ဍ","ဏ","တ","ဒ","န","ဟ","ပ","ဗ","မ","ယ","ရ","႐","လ","ဝ","သ","aျ္","aွ္","aြ္","aြ","ၱ","ၳ","ၵ","ၶ","ၬ","ၭ","ၠ","ၡ","ၢ","ၣ","ၸ","ၹ","ၺ","႓","ၥ","ၧ","ၨ","ၩ","်","ျ","ႅ","ၼ","ွ","ႇ","ႆ","ၷ","ၲ","႒","႗","ၯ","ၮ","႑","kaၤ","gaၤ","khaၤ","ghaၤ","aှ","aိံ","aုံ","aော","aေါ","aအံ","aဣံ","aဥံ","aံ","aာ","aါ","aိ","aီ","aု","aဳ","aူ","aေ","အါ","အာ","အ","ဣ","ဤ","ဥ","ဦ","ဧ","ဩ","ႏ","ၪ","a္","္","aံ","ေss","ေkh","ေgh","ေch","ေjh","ေññ","ေṭh","ေḍh","ေth","ေdh","ေph","ေbh","ေk","ေg","ေc","ေj","ေñ","ေḷ","ေṭ","ေḍ","ေṇ","ေt","ေd","ေn","ေh","ေp","ေb","ေm","ေy","ေr","ေl","ေv","ေs","ေy","ေv","ေr","ea","eā","၁","၂","၃","၄","၅","၆","၇","၈","၉","၀","း","့","။","၊"];
-    protected $en = ["ndra","kh","gh","ch","jh","ññ","ṭh","ḍh","th","dh","ph","bh","k","g","c","j","ñ","ḷ","ṭ","ḍ","ṇ","t","d","n","h","p","b","m","y","r","l","v","s","ṅ","ṅ","ssa","kha","gha","cha","jha","jha","ñña","ṭha","ḍha","tha","dha","pha","bha","ka","ga","ca","ja","ña","ḷa","ṭa","ḍa","ṇa","ta","da","na","ha","pa","ba","ma","ya","ra","ra","la","va","sa","ya","va","ra","ra","္ta","္tha","္da","္dha","္ṭa","္ṭha","္ka","္kha","္ga","္gha","္pa","္pha","္ba","္bha","္ca","္cha","္ja","္jha","္a","္ya","္la","္ma","္va","္ha","ssa","na","ta","ṭṭha","ṭṭa","ḍḍha","ḍḍa","ṇḍa","ṅka","ṅga","ṅkha","ṅgha","ha","iṃ","uṃ","o","o","aṃ","iṃ","uṃ","aṃ","ā","ā","i","ī","u","u","ū","e","ā","ā","a","i","ī","u","ū","e","o","n","ñ","","","aṃ","sse","khe","ghe","che","jhe","ññe","ṭhe","ḍhe","the","dhe","phe","bhe","ke","ge","ce","je","ñe","ḷe","ṭe","ḍe","ṇe","te","de","ne","he","pe","be","me","ye","re","le","ve","se","ye","ve","re","e","o","1","2","3","4","5","6","7","8","9","0","”","’",".",","];
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '导出nissaya统计数据';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $nissaya_channels = Channel::where('type','nissaya')
-                            ->where('lang','my')
-                            ->select('uid')->get();
-        $this->info('channel:'.count($nissaya_channels));
-        //system regular
-        $dict_id = DictApi::getSysDict('system_regular');
-        if(!$dict_id){
-            $this->error('没有找到 system_regular 字典');
-            return 1;
-        }else{
-            $this->info("system_regular :{$dict_id}");
-        }
-
-        //获取缅文语尾表
-        $nissayaEndings = NissayaEnding::select('ending')->groupBy('ending')->get();
-        $endings = [];
-        $maxLen = 0;
-        foreach ($nissayaEndings as $key => $ending) {
-            $endings[] = $ending->ending;
-            if(mb_strlen($ending->ending,'UTF-8')>$maxLen){
-                $maxLen = mb_strlen($ending->ending,'UTF-8');
-            }
-        }
-        $this->info(count($endings).' ending');
-
-        $filename = "public/export/nissaya.csv";
-        Storage::disk('local')->put($filename, "");
-        $file = fopen(storage_path("app/$filename"),"w");
-        $bar = $this->output->createProgressBar(Sentence::whereIn('channel_uid',$nissaya_channels)->count());
-        foreach (Sentence::whereIn('channel_uid',$nissaya_channels)->select(['content','book_id'])->cursor() as $sent) {
-            $lines = explode("\n",$sent->content);
-            foreach ($lines as $key => $line) {
-                # code...
-                if(substr_count(trim($line),'=') === 1){
-                    $nissaya_str = explode('=',$line);
-                    $pali = $this->my2en($nissaya_str[0]);
-                    $types = SuttaType::getTypeByBook($sent->book_id);
-                    $strTypes = implode(",",$types);
-                    //拆分
-                    $factors = UserDict::where('dict_id',$dict_id)->where('word',$pali)->value('factors');
-                    $factors = explode('+',$factors);
-                    if(count($factors)>1){
-                        $paliEnding = end($factors);
-                    }else{
-                        $paliEnding = '';
-                    }
-                    $nissaya_my = trim($nissaya_str[1]);
-                    $mEnding1 = $this->matchEnding($nissaya_my,$endings,$maxLen);
-                    if(!empty($paliEnding) && !empty($mEnding1[1])){
-                        $mixed = $paliEnding.$mEnding1[1];
-                        fputcsv($file,[$strTypes, $pali,$paliEnding,$nissaya_my,$mEnding1[1],$mixed]);
-                    }
-                    $mEnding2= ['',''];
-                    if(!empty($mEnding1[1])){
-                        $mEnding2 = $this->matchEnding($mEnding1[0],$endings,$maxLen);
-                        if(!empty($paliEnding) && !empty($mEnding2[1])){
-                            $mixed = $paliEnding.$mEnding2[1];
-                            fputcsv($file,[$strTypes, $pali,$paliEnding,$nissaya_my,$mEnding2[1],$mixed]);
-                        }
-                    }
-                    $mEnding3= ['',''];
-                    if(!empty($mEnding2[1])){
-                        $mEnding3 = $this->matchEnding($mEnding2[0],$endings,$maxLen);
-                        if(!empty($paliEnding) && !empty($mEnding3[1])){
-                            $mixed = $paliEnding.$mEnding3[1];
-                            fputcsv($file,[$strTypes, $pali,$paliEnding,$nissaya_my,$mEnding3[1],$mixed]);
-                        }
-                    }
-
-                    //fputcsv($file,[$strTypes, $pali,$paliEnding,$nissaya_my,$mEnding1[1],$mEnding2[1],$mEnding3[1]]);
-                }
-            }
-            $bar->advance();
-        }
-        fclose($file);
-        $bar->finish();
-        $this->info('done');
-        $this->info($filename);
-        return 0;
-    }
-
-    public function my2en($my){
-        return str_replace($this->my,$this->en,$my);
-    }
-
-    private function matchEnding($needle,$endings,$maxLen){
-        $needle = trim($needle);
-        if(mb_substr($needle,-1,1,'UTF-8') === '။'){
-            $needle = mb_substr($needle,0,-1);
-        }
-        for ($i=1; $i <= $maxLen ; $i++) {
-            $mEnding = mb_substr($needle,-$i);
-            if(in_array($mEnding,$endings)){
-                return [mb_substr($needle,0,mb_strlen($needle,'UTF-8')-$i),$mEnding];
-            }
-        }
-        return [$needle,''];
-    }
-}

+ 0 - 125
api-v12/app/Console/Commands/ExportOffline.php

@@ -1,125 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use Illuminate\Support\Facades\Cache;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Facades\Redis;
-
-class ExportOffline extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan export:offline lzma
-     * @var string
-     */
-    protected $signature = 'export:offline {format?  : zip file format 7z,lzma,gz } {--shortcut}  {--driver=morus}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'export  offline data for app';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $exportDir = storage_path('app/public/export/offline');
-        if (!is_dir($exportDir)) {
-            $res = mkdir($exportDir, 0755, true);
-            if (!$res) {
-                Log::error('mkdir fail path=' . $exportDir);
-                return 1;
-            }
-        }
-
-        //清空redis
-        Cache::put('/offline/index', []);
-
-        //删除全部的旧文件
-        foreach (scandir($exportDir) as $key => $file) {
-            if (is_file($exportDir . '/' . $file)) {
-                unlink($exportDir . '/' . $file);
-            }
-        }
-        //添加 .stop
-        $exportStop = $exportDir . '/.stop';
-        $file = fopen($exportStop, 'w');
-        fclose($file);
-
-        //建表
-        $this->info('create db');
-        $this->call('export:create.db');
-
-        //term
-        $this->info('export term start');
-        $this->call('export:term');
-
-        //导出channel
-        $this->info('export channel start');
-        $this->call('export:channel', ['db' => 'wikipali-offline']);
-        $this->call('export:channel', ['db' => 'wikipali-offline-index']);
-
-        if (!$this->option('shortcut')) {
-            //tag
-            $this->info('export tag start');
-            $this->call('export:tag', ['db' => 'wikipali-offline']);
-            $this->call('export:tag.map', ['db' => 'wikipali-offline']);
-            //
-            $this->info('export pali text start');
-            $this->call('export:pali.text');
-            //导出章节索引
-            $this->info('export chapter start');
-            $this->call('export:chapter.index', ['db' => 'wikipali-offline']);
-            $this->call('export:chapter.index', ['db' => 'wikipali-offline-index']);
-            //导出译文
-            $this->info('export sentence start');
-            $this->call('export:sentence', ['--type' => 'translation', '--driver' => $this->option('driver')]);
-            $this->call('export:sentence', ['--type' => 'nissaya', '--driver' => $this->option('driver')]);
-            //导出原文
-            $this->call('export:sentence', ['--type' => 'original', '--driver' => $this->option('driver')]);
-        }
-
-        $this->info('zip');
-        Log::info('export offline: db写入完毕 开始压缩');
-
-        sleep(5);
-        $this->call('export:zip', [
-            'id' => 'index',
-            'filename' => 'wikipali-offline-index' . '-' . date("Y-m-d") . '.db3',
-            'title' => 'wikipali 离线包索引',
-            'format' => $this->argument('format'),
-        ]);
-        $this->call('export:zip', [
-            'id' => 'date-package',
-            'filename' => 'wikipali-offline' . '-' . date("Y-m-d") . '.db3',
-            'title' => 'wikipali 离线包',
-            'format' => $this->argument('format'),
-        ]);
-
-        $this->call('export:ai.training.data');
-        $this->call('export:ai.pali.word.token');
-        unlink($exportStop);
-        return 0;
-    }
-}

+ 0 - 91
api-v12/app/Console/Commands/ExportPaliSynonyms.php

@@ -1,91 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\DictApi;
-use App\Models\UserDict;
-use App\Models\DhammaTerm;
-
-class ExportPaliSynonyms extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan export:pali.synonyms --output=
-     * @var string
-     */
-    protected $signature = 'export:pali.synonyms {--output=}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '导出openSearch用的巴利语变格表';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (!$this->option('output')) {
-            $this->error('please set output file option --output=file');
-            return 1;
-        }
-        //irregular
-        $dictId = ['4d3a0d92-0adc-4052-80f5-512a2603d0e8'];
-        //regular
-        $dictId[] = DictApi::getSysDict('system_regular');
-
-        $filename = $this->option('output');
-        $fp = fopen($filename, 'w') or die("Unable to open file!");
-        foreach ($dictId as  $dict) {
-            $parents = UserDict::where('dict_id', $dict)
-                ->select('parent')
-                ->groupBy('parent')->cursor();
-
-            foreach ($parents as  $parent) {
-                $words = UserDict::where('dict_id', $dict)
-                    ->where('parent', $parent->parent)
-                    ->select('word')
-                    ->groupBy('word')->get();
-                $wordsList = [];
-                foreach ($words as $word) {
-                    $wordsList[$word->word] = 1;
-                }
-                $teams = DhammaTerm::where('word', $parent->parent)
-                    ->select(['meaning'])->get();
-                foreach ($teams as $term) {
-                    $wordsList[$term->meaning] = 1;
-                }
-                $this->info("[{$parent->parent}] " . count($words) . " team=" . count($teams));
-                // 合并 $parent->parent, $words->word, $team->meaning 为一个字符串数组
-                $combinedArray = [];
-                $combinedArray[] = $parent->parent;
-                foreach ($wordsList as $word => $value) {
-                    $combinedArray[] = $word;
-                }
-
-                // 将 $combinedArray 写入 CSV 文件
-                fputcsv($fp, $combinedArray);
-            }
-        }
-
-        // 关闭文件
-        fclose($fp);
-        $this->info('done');
-        return 0;
-    }
-}

+ 0 - 87
api-v12/app/Console/Commands/ExportPalitext.php

@@ -1,87 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use App\Models\PaliText;
-use Illuminate\Support\Facades\Log;
-
-class ExportPalitext extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'export:pali.text';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '导出离线用的巴利段落数据';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        Log::debug('task export offline palitext-table start');
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $exportFile = storage_path('app/public/export/offline/wikipali-offline-'.date("Y-m-d").'.db3');
-        $dbh = new \PDO('sqlite:'.$exportFile, "", "", array(\PDO::ATTR_PERSISTENT => true));
-        $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
-        $dbh->beginTransaction();
-
-        $query = "INSERT INTO pali_text ( id , book , paragraph, level, toc,
-                                    chapter_len , parent   )
-                                    VALUES ( ? , ? , ? , ? , ? , ? , ? )";
-        try{
-            $stmt = $dbh->prepare($query);
-        }catch(PDOException $e){
-            Log::info($e);
-            return 1;
-        }
-
-        $bar = $this->output->createProgressBar(PaliText::count());
-        foreach (PaliText::select(['uid','book','paragraph',
-                    'level','toc','lenght','chapter_len',
-                    'next_chapter','prev_chapter','parent','chapter_strlen'])
-                    ->orderBy('book')
-                    ->orderBy('paragraph')
-                    ->cursor() as $chapter) {
-            $currData = array(
-                            $chapter->uid,
-                            $chapter->book,
-                            $chapter->paragraph,
-                            $chapter->level,
-                            $chapter->toc,
-                            $chapter->chapter_len,
-                            $chapter->parent,
-                            );
-            $stmt->execute($currData);
-            $bar->advance();
-        }
-        $dbh->commit();
-        $bar->finish();
-        Log::debug('task: export offline palitext-table finished');
-
-        return 0;
-    }
-}

+ 0 - 131
api-v12/app/Console/Commands/ExportSentence.php

@@ -1,131 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use App\Models\Sentence;
-use App\Models\Channel;
-use App\Http\Api\ChannelApi;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Str;
-use App\Http\Api\MdRender;
-
-class ExportSentence extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'export:sentence {--channel=} {--type=translation} {--driver=morus}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        Log::debug('task export offline sentence-table start');
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        \App\Tools\Markdown::driver($this->option('driver'));
-        $channels = [];
-        $channel_id = $this->option('channel');
-        if($channel_id){
-            $file_suf = $channel_id;
-            $channels[] = $channel_id;
-        }else{
-            $channel_type = $this->option('type');
-            $file_suf = $channel_type;
-            if($channel_type === "original"){
-                $pali_channel = ChannelApi::getSysChannel("_System_Pali_VRI_");
-                if($pali_channel === false){
-                    return 0;
-                }
-                $channels[] = $pali_channel;
-            }else{
-                $nissaya_channel = Channel::where('type',$channel_type)->where('status',30)->select('uid')->get();
-                foreach ($nissaya_channel as $key => $value) {
-                    # code...
-                    $channels[] = $value->uid;
-                }
-            }
-        }
-
-
-        $exportFile = storage_path('app/public/export/offline/wikipali-offline-'.date("Y-m-d").'.db3');
-        $dbh = new \PDO('sqlite:'.$exportFile, "", "", array(\PDO::ATTR_PERSISTENT => true));
-        $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
-        $dbh->beginTransaction();
-
-        if($channel_type === "original"){
-            $table = 'sentence';
-        }else{
-            $table = 'sentence_translation';
-        }
-
-        $query = "INSERT INTO {$table} ( book , paragraph ,
-                                    word_start , word_end , content , channel_id  )
-                                    VALUES ( ? , ? , ? , ? , ? , ? )";
-        try{
-            $stmt = $dbh->prepare($query);
-        }catch(PDOException $e){
-            Log::info($e);
-            return 1;
-        }
-
-        $db = Sentence::whereIn('channel_uid',$channels);
-        $bar = $this->output->createProgressBar($db->count());
-        $srcDb = $db->select(['uid','book_id','paragraph',
-                                'word_start','word_end',
-                                'content','content_type','channel_uid',
-                                'editor_uid','language','updated_at'])->cursor();
-        foreach ($srcDb as $sent) {
-            if(Str::isUuid($sent->channel_uid)){
-                $channel = ChannelApi::getById($sent->channel_uid);
-                $currData = array(
-                        $sent->book_id,
-                        $sent->paragraph,
-                        $sent->word_start,
-                        $sent->word_end,
-                        MdRender::render($sent->content,
-                                        [$sent->channel_uid],
-                                        null,
-                                        'read',
-                                        $channel['type'],
-                                        $sent->content_type,
-                                        'unity',
-                                        ),
-                        $sent->channel_uid,
-                    );
-                $stmt->execute($currData);
-
-            }
-            $bar->advance();
-        }
-        $dbh->commit();
-        $bar->finish();
-        Log::debug('task export sentence finished');
-        return 0;
-    }
-}

+ 0 - 80
api-v12/app/Console/Commands/ExportTag.php

@@ -1,80 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use App\Models\Tag;
-use Illuminate\Support\Facades\Log;
-
-class ExportTag extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'export:tag {db}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        Log::debug('task: export offline data tag-table start');
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $exportFile = storage_path('app/public/export/offline/'.$this->argument('db').'-'.date("Y-m-d").'.db3');
-        $dbh = new \PDO('sqlite:'.$exportFile, "", "", array(\PDO::ATTR_PERSISTENT => true));
-        $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
-        $dbh->beginTransaction();
-
-        $query = "INSERT INTO tag ( id , name ,
-                                    description , color , owner_id  )
-                                    VALUES ( ? , ? , ? , ? , ?  )";
-        try{
-            $stmt = $dbh->prepare($query);
-        }catch(PDOException $e){
-            Log::info($e);
-            return 1;
-        }
-
-        $bar = $this->output->createProgressBar(Tag::count());
-        foreach (Tag::select(['id','name','description','color','owner_id'])->cursor() as $row) {
-            $currData = array(
-                $row->id,
-                $row->name,
-                $row->description,
-                $row->color,
-                $row->owner_id,
-            );
-            $stmt->execute($currData);
-            $bar->advance();
-        }
-        $dbh->commit();
-        $bar->finish();
-        Log::debug('task: export offline data tag-table start');
-
-        return 0;
-    }
-}

+ 0 - 75
api-v12/app/Console/Commands/ExportTagmap.php

@@ -1,75 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use App\Models\TagMap;
-use Illuminate\Support\Facades\Log;
-
-class ExportTagmap extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'export:tag.map {db}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        Log::debug('task: export offline tagmap-table start');
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $exportFile = storage_path('app/public/export/offline/'.$this->argument('db').'-'.date("Y-m-d").'.db3');
-        $dbh = new \PDO('sqlite:'.$exportFile, "", "", array(\PDO::ATTR_PERSISTENT => true));
-        $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
-        $dbh->beginTransaction();
-
-        $query = "INSERT INTO tag_map ( anchor_id , tag_id )
-                                    VALUES ( ? , ? )";
-        try{
-            $stmt = $dbh->prepare($query);
-        }catch(PDOException $e){
-            Log::info($e);
-            return 1;
-        }
-
-        $bar = $this->output->createProgressBar(TagMap::count());
-        foreach (TagMap::select(['id','table_name','anchor_id','tag_id'])->cursor() as $row) {
-            $currData = array(
-                            $row->anchor_id,
-                            $row->tag_id,
-                            );
-            $stmt->execute($currData);
-            $bar->advance();
-        }
-        $dbh->commit();
-        $bar->finish();
-        Log::debug('task: export offline tagmap-table finished');
-        return 0;
-    }
-}

+ 0 - 100
api-v12/app/Console/Commands/ExportTerm.php

@@ -1,100 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use App\Models\DhammaTerm;
-use Illuminate\Support\Facades\Log;
-
-class ExportTerm extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'export:term';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        Log::info('task export offline term-table start');
-        $startAt = time();
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $exportFile = storage_path('app/public/export/offline/wikipali-offline-'.date("Y-m-d").'.db3');
-        $dbh = new \PDO('sqlite:'.$exportFile, "", "", array(\PDO::ATTR_PERSISTENT => true));
-        $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
-        $dbh->beginTransaction();
-
-        $query = "INSERT INTO dhamma_terms ( uuid , word , word_en , meaning ,
-                                    other_meaning , note , tag , channel_id,
-                                    language, owner, editor_id,
-                                    created_at,updated_at,deleted_at)
-                                    VALUES ( ? , ? , ? , ? ,
-                                            ? , ? , ? , ? ,
-                                            ?, ?, ?,
-                                            ?, ?, ? )";
-        try{
-            $stmt = $dbh->prepare($query);
-        }catch(PDOException $e){
-            Log::info($e);
-            return 1;
-        }
-
-        $bar = $this->output->createProgressBar(DhammaTerm::count());
-        foreach (DhammaTerm::select(['guid','word','word_en','meaning',
-                          'other_meaning','note','tag','channal',
-                          'language',"owner","editor_id",
-                          "created_at","updated_at","deleted_at"
-                          ])
-                          ->cursor() as $row) {
-                $currData = array(
-                            $row->guid,
-                            $row->word,
-                            $row->word_en,
-                            $row->meaning,
-                            $row->other_meaning,
-                            $row->note,
-                            $row->tag,
-                            $row->channal,
-                            $row->language,
-                            $row->owner,
-                            $row->editor_id,
-                            $row->created_at,
-                            $row->updated_at,
-                            $row->deleted_at,
-                            );
-            $stmt->execute($currData);
-            $bar->advance();
-        }
-        $dbh->commit();
-        $bar->finish();
-        $this->info(' time='.(time()-$startAt).'s');
-        Log::info('task export offline term-table finished');
-        return 0;
-    }
-}

+ 0 - 203
api-v12/app/Console/Commands/ExportZip.php

@@ -1,203 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Facades\Cache;
-use Illuminate\Support\Facades\App;
-
-use Symfony\Component\Process\Process;
-use Symfony\Component\Process\Exception\ProcessFailedException;
-
-class ExportZip extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'export:zip {filename : filename} {title : title} {id : 标识符} {format?  : zip file format 7z,lzma,gz }';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '压缩导出的文件';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        Log::debug('export offline: 开始压缩');
-        $defaultExportPath = storage_path('app/public/export/offline');
-        $exportFile = $this->argument('filename');
-        $filename = basename($exportFile);
-        if ($filename === $exportFile) {
-            $exportFullFileName = $defaultExportPath . '/' . $filename;
-            $exportPath = $defaultExportPath;
-        } else {
-            $exportFullFileName = $exportFile;
-            $exportPath = dirname($exportFile);
-        }
-        Log::debug(
-            'export offline: zip file {filename} {format}',
-            [
-                'filename' => $exportFile,
-                'format' => $this->argument('format'),
-                'exportFullFileName' => $exportFullFileName,
-                'exportPath' => $exportPath,
-            ]
-        );
-        switch ($this->argument('format')) {
-            case '7z':
-                $zipFile = $filename . ".7z";
-                break;
-            case 'lzma':
-                $zipFile = $filename . ".lzma";
-                break;
-            default:
-                $zipFile = $filename . ".gz";
-                break;
-        }
-        //
-        if (!file_exists($exportFullFileName)) {
-            Log::error('export offline: no  file {filename}', ['filename' => $exportFullFileName]);
-            $this->error('export offline: no  file {filename}' . $exportFullFileName);
-            return 1;
-        }
-
-        $zipFullFileName = $exportPath . '/' . $zipFile;
-        if (file_exists($zipFullFileName)) {
-            Log::debug('export offline: delete old zip file:' . $zipFullFileName);
-            unlink($zipFullFileName);
-        }
-
-        shell_exec("cd " . $exportPath);
-        switch ($this->argument('format')) {
-            case '7z':
-                $command = [
-                    '7z',
-                    'a',
-                    '-t7z',
-                    '-m0=lzma',
-                    '-mx=9',
-                    '-mfb=64',
-                    '-md=32m',
-                    '-ms=on',
-                    $zipFullFileName,
-                    $exportFullFileName
-                ];
-                break;
-            case 'lzma':
-                $command = ['xz', '-k', '-9', '--format=lzma', $exportFullFileName];
-                break;
-            default:
-                $command = ['gzip', $exportFullFileName];
-                break;
-        }
-
-        $this->info(implode(' ', $command));
-        Log::debug('export offline zip start', ['command' => $command, 'format' => $this->argument('format')]);
-        $process = new Process($command);
-        $process->setTimeout(60 * 60 * 6);
-        $process->run();
-        $this->info($process->getOutput());
-        $this->info('压缩完成');
-        Log::debug(
-            'zip file {filename} in {format} saved.',
-            [
-                'filename' => $exportFile,
-                'format' => $this->argument('format')
-            ]
-        );
-
-        $url = array();
-        foreach (config('mint.server.cdn_urls') as $key => $cdn) {
-            $url[] = [
-                'link' => $cdn . '/' . $zipFile,
-                'hostname' => 'china cdn-' . $key,
-            ];
-        }
-
-        $bucket = config('mint.attachments.bucket_name.temporary');
-        $tmpFile =  $bucket . '/' . $zipFile;
-
-        $this->info('upload file=' . $tmpFile);
-        Log::debug('export offline: upload file {filename}', ['filename' => $tmpFile]);
-
-        Storage::put($tmpFile, file_get_contents($zipFullFileName));
-
-        $this->info('upload done file=' . $tmpFile);
-        Log::debug('export offline: upload done {filename}', ['filename' => $tmpFile]);
-
-        if (App::environment('local')) {
-            $link = Storage::url($tmpFile);
-        } else {
-            try {
-                $link = Storage::temporaryUrl($tmpFile, now()->addDays(2));
-            } catch (\Exception $e) {
-                $this->error('generate temporaryUrl fail');
-                Log::error(
-                    'export offline: generate temporaryUrl fail {Exception}',
-                    [
-                        'exception' => $e,
-                        'file' => $tmpFile
-                    ]
-                );
-                return 1;
-            }
-        }
-        $this->info('link = ' . $link);
-        Log::info('export offline: link=' . $link);
-
-        $url[] = [
-            'link' => $link,
-            'hostname' => 'Amazon cloud storage(Hongkong)',
-        ];
-        $info = Cache::get('/offline/index');
-        if (!is_array($info)) {
-            $info = array();
-        }
-        $info[] = [
-            'id' => $this->argument('id'),
-            'title' => $this->argument('title'),
-            'filename' => $zipFile,
-            'url' => $url,
-            'create_at' => date("Y-m-d H:i:s"),
-            'chapter' => Cache::get("/export/chapter/count"),
-            'filesize' => filesize($zipFullFileName),
-            'min_app_ver' => '1.3',
-        ];
-        Cache::put('/offline/index', $info);
-        sleep(5);
-        try {
-            unlink($exportFullFileName);
-        } catch (\Throwable $th) {
-            Log::error(
-                'export offline: delete  file fail {Exception}',
-                [
-                    'exception' => $th,
-                    'file' => $exportFullFileName
-                ]
-            );
-        }
-
-        return 0;
-    }
-}

+ 0 - 277
api-v12/app/Console/Commands/ExportZip2.php

@@ -1,277 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Facades\Cache;
-use Illuminate\Support\Facades\App;
-
-use Symfony\Component\Process\Process;
-
-class ExportZip2 extends Command
-{
-    protected $signature = 'export:zip2
-        {filename : filename}
-        {title : title}
-        {id : 标识符}
-        {format? : zip file format 7z,lzma,gz }';
-
-    protected $description = '压缩导出的文件';
-
-    public function handle()
-    {
-        Log::debug('export offline: 开始压缩');
-
-        $defaultExportPath = storage_path('app/public/export/offline');
-        $exportFile = $this->argument('filename');
-
-        $filename = basename($exportFile);
-
-        if ($filename === $exportFile) {
-            $exportFullFileName = $defaultExportPath . '/' . $filename;
-            $exportPath = $defaultExportPath;
-        } else {
-            $exportFullFileName = $exportFile;
-            $exportPath = dirname($exportFile);
-        }
-
-        $format = $this->argument('format') ?? 'gz';
-
-        if (!file_exists($exportFullFileName)) {
-
-            Log::error('export offline: file not exists', [
-                'file' => $exportFullFileName
-            ]);
-
-            $this->error('file not exists: ' . $exportFullFileName);
-
-            return 1;
-        }
-
-        $zipFile = $this->getZipFileName($filename, $format);
-        $zipFullFileName = $exportPath . '/' . $zipFile;
-
-        if (file_exists($zipFullFileName)) {
-            unlink($zipFullFileName);
-        }
-
-        $this->info("start compress: {$exportFullFileName}");
-        Log::debug('export offline zip start', [
-            'file' => $exportFullFileName,
-            'format' => $format
-        ]);
-
-        $this->compress($exportFullFileName, $zipFullFileName, $format);
-
-        $this->info('压缩完成');
-
-        Log::debug('zip done', [
-            'zip' => $zipFullFileName
-        ]);
-
-        /*
-        |--------------------------------------------------------------------------
-        | 上传 S3
-        |--------------------------------------------------------------------------
-        */
-
-        $bucket = config('mint.attachments.bucket_name.temporary');
-        $tmpFile = $bucket . '/' . $zipFile;
-
-        $this->info('upload file=' . $tmpFile);
-
-        Log::debug('export offline upload', [
-            'file' => $tmpFile
-        ]);
-
-        Storage::put($tmpFile, fopen($zipFullFileName, 'r'));
-
-        $this->info('upload done');
-
-        Log::debug('upload done');
-
-        /*
-        |--------------------------------------------------------------------------
-        | 生成下载链接
-        |--------------------------------------------------------------------------
-        */
-
-        if (App::environment('local')) {
-            $link = Storage::url($tmpFile);
-        } else {
-            try {
-                $link = Storage::temporaryUrl(
-                    $tmpFile,
-                    now()->addDays(2)
-                );
-            } catch (\Exception $e) {
-                Log::error('temporaryUrl fail', [
-                    'exception' => $e
-                ]);
-                $this->error('generate temporaryUrl fail');
-                return 1;
-            }
-        }
-
-        $this->info('link=' . $link);
-
-        /*
-        |--------------------------------------------------------------------------
-        | CDN 列表
-        |--------------------------------------------------------------------------
-        */
-
-        $url = [];
-        foreach (config('mint.server.cdn_urls') as $key => $cdn) {
-            $url[] = [
-                'link' => $cdn . '/' . $zipFile,
-                'hostname' => 'china cdn-' . $key
-            ];
-        }
-
-        $url[] = [
-            'link' => $link,
-            'hostname' => 'Amazon cloud storage(Hongkong)'
-        ];
-
-        /*
-        |--------------------------------------------------------------------------
-        | Cache 写入
-        |--------------------------------------------------------------------------
-        */
-
-        $info = Cache::get('/offline/index', []);
-        if (!is_array($info)) {
-            $info = [];
-        }
-        $id = $this->argument('id');
-        // 先移除已有相同 id 的记录
-        $info = array_values(array_filter($info, function ($item) use ($id) {
-            return !isset($item['id']) || $item['id'] != $id;
-        }));
-        // 再追加新数据
-        $info[] = [
-            'id' => $id,
-            'title' => $this->argument('title'),
-            'filename' => $zipFile,
-            'url' => $url,
-            'create_at' => now()->toDateTimeString(),
-            'chapter' => Cache::get("/export/chapter/count"),
-            'filesize' => filesize($zipFullFileName),
-            'min_app_ver' => '1.3',
-        ];
-
-        Cache::put('/offline/index', $info);
-
-        /*
-        |--------------------------------------------------------------------------
-        | 删除原始文件
-        |--------------------------------------------------------------------------
-        */
-
-        sleep(5);
-        try {
-            if (is_file($exportFullFileName)) {
-                unlink($exportFullFileName);
-            }
-            if (file_exists($zipFullFileName)) {
-                unlink($zipFullFileName);
-            }
-        } catch (\Throwable $e) {
-            Log::error('delete source fail', [
-                'exception' => $e
-            ]);
-        }
-
-        return 0;
-    }
-
-    /*
-    |--------------------------------------------------------------------------
-    | 生成压缩文件名
-    |--------------------------------------------------------------------------
-    */
-
-    protected function getZipFileName(string $filename, string $format): string
-    {
-        return match ($format) {
-            '7z' => $filename . '.7z',
-            'lzma' => $filename . '.lzma',
-            default => $filename . '.tar.gz'
-        };
-    }
-
-    /*
-    |--------------------------------------------------------------------------
-    | 压缩函数
-    |--------------------------------------------------------------------------
-    */
-
-    protected function compress($source, $target, $format)
-    {
-        $isDir = is_dir($source);
-        switch ($format) {
-            case '7z':
-                $command = [
-                    '7z',
-                    'a',
-                    '-t7z',
-                    '-mx=9',
-                    $target,
-                    $source
-                ];
-                break;
-
-            case 'lzma':
-                if ($isDir) {
-                    $tmpTar = $source . '.tar';
-                    $tar = new Process([
-                        'tar',
-                        '-cf',
-                        $tmpTar,
-                        '-C',
-                        dirname($source),
-                        basename($source)
-                    ]);
-                    $tar->run();
-                    $source = $tmpTar;
-                }
-                $command = [
-                    'xz',
-                    '-k',
-                    '-9',
-                    '--format=lzma',
-                    $source
-                ];
-                break;
-
-            default:
-                $command = [
-                    'tar',
-                    '-czf',
-                    $target,
-                    '-C',
-                    dirname($source),
-                    basename($source)
-                ];
-        }
-
-        $this->info(implode(' ', $command));
-        $process = new Process($command);
-        $process->setTimeout(60 * 60 * 6);
-        $process->run();
-
-        $this->info($process->getOutput());
-
-        if (!$process->isSuccessful()) {
-
-            Log::error('compress fail', [
-                'error' => $process->getErrorOutput()
-            ]);
-
-            throw new \RuntimeException($process->getErrorOutput());
-        }
-    }
-}

+ 0 - 147
api-v12/app/Console/Commands/ImportArticle.php

@@ -1,147 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Http;
-use Illuminate\Support\Facades\Log;
-use App\Http\Api\StudioApi;
-use App\Models\Article;
-
-class ImportArticle extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan import:article --studio=visuddhinanda --anthology=eb9e3f7f-b942-4ca4-bd6f-b7876b59a523 --token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJuYmYiOjE2OTc3Mjg2ODUsImV4cCI6MTcyOTI2NDY4NSwidWlkIjoiYmE1NDYzZjMtNzJkMS00NDEwLTg1OGUtZWFkZDEwODg0NzEzIiwiaWQiOjR9.fiXhnY2LczZ9kKVHV0FfD3AJPZt-uqM5wrDe4EhToVexdd007ebPFYssZefmchfL0mx9nF0rgHSqjNhx4P0yDA
-     * @var string
-     */
-    protected $signature = 'import:article {--studio=} {--anthology=} {--token=}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '导入缅文tipitaka sarupa文章';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     * 分两个步骤导入
-     * 1. 导入文章到文集
-     * 2. 重新生成目录结构
-     * @return int
-     */
-    public function handle()
-    {
-        if (!$this->confirm('Do you wish to continue?')) {
-            return 0;
-        }
-        $token = $this->option('token');
-        $studioName = $this->option('studio');
-        $anthologyId = $this->option('anthology');
-
-        //先获取文章列表,建立全部目录
-        $head = array();
-        $strFileName = __DIR__."/tipitaka-sarupa.csv";
-        if(!file_exists($strFileName)){
-            $this->error($strFileName.'文件不存在');
-            return 1;
-        }
-
-        if (($fp = fopen($strFileName, "r")) === false) {
-            $this->error("can not open csv {$strFileName}");
-            return 0;
-        }
-        $this->info('打开csv文件成功');
-
-        $studioId = StudioApi::getIdByName($studioName);
-        if(!$studioId){
-            $this->error("can not found studio name {$studioName}");
-            return 0;
-        }
-        //导入文章
-        $url = config('app.url').'/api/v2/article';
-        $inputRow = 0;
-        fseek($fp, 0);
-        $count = 0;
-        $success = 0;
-        $fail = 0;
-        while (($data = fgetcsv($fp, 0, ',')) !== false) {
-            if($inputRow>0){
-                $id = $data[0];
-                $dir = $data[1];
-                $title = $data[2];
-                $realTitle = "[{$id}]{$title}";
-                $content = str_replace('\n',"\n",$data[4]) ;
-                $reference = str_replace(['(',')'],['({{ql|type=m|title=','}})'],$data[5]);
-                $contentCombine = "{$title}\n\n{$content}\n\n{$reference}";
-                $percent = (int)($inputRow*100/7000);
-                $this->info("[{$percent}%] doing ".$realTitle);
-                //先查是否有
-                $hasArticle = Article::where('owner',$studioId)
-                              ->where('title',$realTitle)
-                              ->exists();
-                if($hasArticle){
-                    $this->error('文章已经存在 title='.$realTitle);
-                    continue;
-                }
-                $count++;
-                $this->info('新建 title='.$realTitle);
-                sleep(2);
-                $response = Http::withToken($token)->post($url,
-                                [
-                                    'title'=> $realTitle,
-                                    'lang'=> 'my',
-                                    'studio'=> $studioName,
-                                    'anthologyId'=> $anthologyId,
-                                ]);
-                if($response->ok()){
-                    $this->info('create ok');
-                    $articleId = $response->json('data')['uid'];
-                }else{
-                    $this->error('create article fail.'.$realTitle);
-                    Log::error('create article fail title='.$realTitle);
-                    $fail++;
-                    continue;
-                }
-                sleep(2);
-                $this->info('修改 id='.$articleId);
-                $response = Http::withToken($token)->put($url.'/'.$articleId,
-                                    [
-                                        'title'=> $realTitle,
-                                        'summary'=> $title.'#'.$id,
-                                        'lang'=> 'my',
-                                        'content'=> $contentCombine,
-                                        'anthology_id'=>$anthologyId,
-                                        'to_tpl'=>true,
-                                        'status'=>30,
-                                    ]);
-
-                if($response->ok()){
-                    $this->info('edit ok');
-                    $success++;
-                }else{
-                    $this->error('edit article fail');
-                    Log::error('edit article fail ',['id'=>$articleId,'title'=>$realTitle]);
-                    $fail++;
-                }
-            }
-            $inputRow++;
-        }
-
-        fclose($fp);
-
-        $this->info('成功='.$success.' 失败='.$fail);
-        return 0;
-    }
-}

+ 0 - 213
api-v12/app/Console/Commands/ImportArticleMap.php

@@ -1,213 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Http;
-use Illuminate\Support\Facades\Log;
-use App\Http\Api\StudioApi;
-use App\Models\Article;
-use App\Models\Collection;
-
-class ImportArticleMap extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan import:article.map visuddhinanda --studio=visuddhinanda --size=30000 --anthology=4c6b661b-fd68-44c5-8918-2e327c870b9a --token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJuYmYiOjE2OTc3Mjg2ODUsImV4cCI6MTcyOTI2NDY4NSwidWlkIjoiYmE1NDYzZjMtNzJkMS00NDEwLTg1OGUtZWFkZDEwODg0NzEzIiwiaWQiOjR9.fiXhnY2LczZ9kKVHV0FfD3AJPZt-uqM5wrDe4EhToVexdd007ebPFYssZefmchfL0mx9nF0rgHSqjNhx4P0yDA
-     *
-     * @var string
-     */
-    protected $signature = 'import:article.map {src_studio} {--token=} {--studio=} {--anthology=} {--size=}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '重置缅文tipitaka sarupa文章目录';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $token = $this->option('token');
-        $studioName = $this->option('studio');
-        $anthologyId = $this->option('anthology');
-        $srcStudio = $this->argument('src_studio');
-        if (!$this->confirm('Do you wish to continue?')) {
-            return 0;
-        }
-        $studioId = StudioApi::getIdByName($studioName);
-        if(!$studioId){
-            $this->error("can not found studio name {$studioName}");
-            return 0;
-        }
-        $srcStudioId = StudioApi::getIdByName($srcStudio);
-        if(!$srcStudioId){
-            $this->error("can not found src studio name {$srcStudio}");
-            return 0;
-        }
-
-        //先获取文章列表,建立全部目录
-        $url = config('app.url').'/api/v2/article-map';
-
-        $this->info('打开csv文件并读取数据');
-        $head = array();
-        $strFileName = __DIR__."/tipitaka-sarupa.csv";
-        if(!file_exists($strFileName)){
-            $this->error($strFileName.'文件不存在');
-            return 1;
-        }
-
-        if (($fp = fopen($strFileName, "r")) === false) {
-            $this->error("can not open csv {$strFileName}");
-            return 0;
-        }
-        //查询文集语言
-        $srcAnthology = Collection::where('uid',$anthologyId)->first();
-        if(!$srcAnthology){
-            $this->error("文集不存在 anthologyId=".$anthologyId);
-            return 0;
-        }
-        $lang = $srcAnthology->lang;
-        if(empty($lang)){
-            $this->error("文集语言不能为空 anthologyId=".$anthologyId);
-            return 0;
-        }
-        $inputRow = 0;
-        $currSize=0;
-        $currBlock=1;
-        $currDir='';
-        $success = 0;
-        $fail = 0;
-        $articleMap = array();
-        while (($data = fgetcsv($fp, 0, ',')) !== false) {
-            if($inputRow>0){
-                $id = $data[0];
-                $dir = $data[1];
-                $title = $data[2];
-                $realTitle = "[{$id}]{$title}";
-                $realTitle = mb_substr($realTitle,0,128,'UTF-8');
-                $reference = $data[5];
-
-                $percent = (int)($inputRow*100/6984);
-                $this->info("[{$percent}%] doing ".$realTitle);
-
-                if($this->option('size')){
-                    $currDir = $srcAnthology->title . '-' . $currBlock;
-                    if($currSize > $this->option('size')){
-                        $currBlock++;
-                        $currSize=0;
-                    }
-                }else{
-                    $currDir = $dir;
-                }
-                //查找目录文章是否存在
-                $dirArticle = Article::where('owner',$studioId)
-                              ->where('title',$currDir)
-                              ->first();
-                if($dirArticle){
-                    $dirId = $dirArticle->uid;
-                }else{
-                    $this->info('不存在目录'.$currDir.'新建');
-                    $url = config('app.url').'/api/v2/article';
-                    sleep(2);
-                    $response = Http::withToken($token)->post($url,
-                    [
-                        'title'=> $currDir,
-                        'lang'=> $lang,
-                        'studio'=> $studioName,
-                        'anthologyId'=> $anthologyId,
-                    ]);
-                    if($response->ok()){
-                        $this->info('dir create ok title='.$currDir);
-                        $dirId = $response->json('data.uid');
-                    }else{
-                        $this->error('create dir fail.'.$currDir);
-                        Log::error('create dir fail title='.$currDir);
-                        $fail++;
-                        continue;
-                    }
-                }
-                //创建目录结束
-                if(!isset($articleMap[$dirId])){
-                    $articleMap[$dirId] = ['name'=>$currDir,'children'=>[]];
-                }
-                //查找文章
-                $article = Article::where('owner',$srcStudioId)
-                              ->where('title',$realTitle)
-                              ->first();
-                if(!$article){
-                    $this->error('文章没找到.'.$realTitle);
-                    Log::error('文章没找到 title='.$realTitle);
-                    $fail++;
-                    continue;
-                }
-                $articleMap[$dirId]['children'][] = [
-                    'id'=>$article->uid,
-                    'title'=>$article->title,
-                ];
-                if($this->option('size')){
-                    $currSize += mb_strlen($title,'UTF-8') +
-                                mb_strlen($data[4],'UTF-8') +
-                                mb_strlen($reference,'UTF-8');
-                }
-                $success++;
-            }
-            $inputRow++;
-        }
-        $this->info("找到文章=" .$success);
-        $this->info("目录=" .count($articleMap));
-
-        $this->info('正在准备map数据');
-
-        $data = array();
-        foreach ($articleMap as $dirId => $dir) {
-            $data[] = [
-                    'article_id'=> $dirId,
-                    'level'=> 1,
-                    'title'=> $dir['name'],
-                    'children'=> count($dir['children']),
-                    'deleted_at'=> null,
-            ];
-            foreach ($dir['children'] as $key => $child) {
-                $data[] = [
-                        'article_id'=> $child['id'],
-                        'level'=> 2,
-                        'title'=> $child['title'],
-                        'children'=> 0,
-                        'deleted_at'=> null,
-                ];
-            }
-        }
-        $this->info('map data='.count($data));
-
-        //目录写入db
-        $url = config('app.url').'/api/v2/article-map/'.$anthologyId;
-        $response = Http::withToken($token)->put($url,
-        [
-            'data'=> $data,
-            'operation' => "anthology",
-        ]);
-        if($response->ok()){
-            $this->info('map update ok ');
-        }else{
-            $this->error('map update  fail.');
-            Log::error('map update  fail ');
-        }
-        return 0;
-    }
-}

+ 0 - 41
api-v12/app/Console/Commands/IndexOpenSearch.php

@@ -1,41 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Services\OpenSearchService;
-use Illuminate\Support\Facades\App;
-
-
-class IndexOpenSearch extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'app:index-open-search';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '如果是新的索引 全量更新openSearch';
-
-    /**
-     * Execute the console command.
-     */
-    public function handle()
-    {
-        //
-        $service = app(OpenSearchService::class);
-        if ($service->count() === 0) {
-            $this->call('opensearch:index-pali');
-        } else {
-            if (App::environment('local')) {
-                $this->info('data exist');
-            }
-        }
-    }
-}

+ 0 - 202
api-v12/app/Console/Commands/IndexTerm.php

@@ -1,202 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Models\DhammaTerm;
-use Illuminate\Console\Command;
-use App\Services\OpenSearchService;
-use App\Services\TermService;
-use Illuminate\Support\Facades\Log;
-
-class IndexTerm extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     *
-     * @example
-     *   php artisan opensearch:index-term
-     *   php artisan opensearch:index-term --word=anomadassī
-     *   php artisan opensearch:index-term --test
-     */
-    protected $signature = 'opensearch:index-term
-        {--test}
-        {--word= : 指定单个词条进行索引,省略则索引全部}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Index Term data into OpenSearch';
-
-    /** @var bool 是否为测试模式(只打印,不写入 OpenSearch) */
-    private bool $isTest = false;
-
-    /**
-     * Create a new command instance.
-     */
-    public function __construct(
-        protected OpenSearchService $openSearchService,
-        protected TermService $termService,
-    ) {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * 遍历所有(或指定)DhammaTerm,逐条构建文档并写入 OpenSearch。
-     * 测试模式下(--test)只打印文档内容,不执行写入。
-     *
-     * @return int  0 表示成功,1 表示失败
-     */
-    public function handle(): int
-    {
-        $word = $this->option('word');
-
-        if ($this->option('test')) {
-            $this->isTest = true;
-            $this->info('test mode');
-        }
-
-        try {
-            [$connected, $message] = $this->openSearchService->testConnection();
-            if (!$connected) {
-                $this->error($message);
-                Log::error($message);
-                return 1;
-            }
-
-            $total = DhammaTerm::count();
-            $terms = DhammaTerm::select(['guid', 'word'])->orderBy('updated_at', 'asc');
-
-            if ($word) {
-                $terms = $terms->where('word', $word);
-            }
-
-            $overallStatus = 0;
-
-            foreach ($terms->cursor() as $key => $term) {
-                $percent = (int) (($key * 100) / $total);
-                $this->info("[{$percent}%]-{$key}  " . $term->word);
-                $this->indexTerm($term->guid);
-            }
-
-            return $overallStatus;
-        } catch (\Exception $e) {
-            $this->error('Failed to index Term data: ' . $e->getMessage());
-            Log::error('Failed to index Term data', ['error' => $e]);
-            return 1;
-        }
-    }
-
-    /**
-     * 构建单条词条文档并写入 OpenSearch
-     *
-     * 文档结构遵循新版 mapping:
-     *   title.text.pali / title.text.zh  → 全文检索
-     *   title.suggest.pali / title.suggest.zh → 自动建议
-     *   content.text.pali / content.text.zh   → 正文内容
-     *
-     * @param  string  $id  DhammaTerm 的 guid
-     * @return void
-     */
-    protected function indexTerm(string $id): void
-    {
-        $termData    = $this->termService->find($id, 'text');
-        $channelName = $termData['channel']['name'] ?? '';
-        $isCommunity = $this->termService->isCommunity($termData['channel_id']);
-        $content     = $termData['html'] ?? $termData['meaning'];
-
-        $categories = $this->extractCategories($termData['note'] ?? '');
-        $quality = $this->extractFirstQuality($termData['note'] ?? '');
-        $tags = [];
-        foreach ($categories as $key => $category) {
-            $tags[] = "category:{$category}";
-        }
-        if (!empty($quality)) {
-            $tags[] = "quality:{$quality}";
-        }
-        $document = [
-            'id'            => "term_{$id}",
-            'resource_id'   => $id,
-            'resource_type' => 'term',
-            'title'         => [
-                'text' => [
-                    'pali' => $termData['word'],
-                    'zh'   => $termData['meaning'],
-                ],
-                'suggest' => [
-                    'pali' => [$termData['word']],
-                    'zh'   => [$termData['meaning']],
-                ],
-            ],
-            'summary' => [
-                'text' => $termData['summary'] ?? '',
-            ],
-            'content'     => [],
-            'bold_single' => [$termData['meaning'], $termData['word']],
-            'related_id'  => $termData['word'],
-            'category'    => null,
-            'tags'        => $tags,
-            'language'    => $termData['language'],
-            'updated_at'  => now()->toIso8601String(),
-            'path'        => $termData['studio']['realName'] . "/{$channelName}",
-            'metadata' => ['channel' => $termData['channel_id']],
-        ];
-
-        // TODO: 补充语言判断,将内容放入对应的 text.pali 或 text.zh 字段
-        $plainText = strip_tags($content);
-        if (str_contains($termData['language'], 'zh')) {
-            $document['content']['text']['zh'] = $plainText;
-        } else {
-            $document['content']['text']['zh'] = $plainText;
-        }
-        $document['content']['display']    = $content;             // 展示
-
-        if ($this->isTest) {
-            $this->info($document['title']['text']['pali']);
-            $this->info($document['summary']['text']);
-        } else {
-            $this->openSearchService->create($document['id'], $document);
-        }
-    }
-
-    /**
-     * 提取 Markdown 中的 {{category|...}} 分类标签
-     *
-     * @param string $content
-     * @return array
-     */
-    private function extractCategories(string $content): array
-    {
-        if (empty($content)) {
-            return [];
-        }
-        preg_match_all('/\{\{category\|([^}]+)\}\}/u', $content, $matches);
-
-        return array_values(array_filter(array_map(
-            fn($item) => trim($item),
-            $matches[1] ?? []
-        )));
-    }
-
-    /**
-     * 提取 Markdown 中第一个 {{quality|...}} 标签内的内容
-     *
-     * @param string $content
-     * @return string
-     */
-    private function extractFirstQuality(string $content): string
-    {
-        if (empty($content)) {
-            return '';
-        }
-
-        preg_match('/\{\{quality\|([^}]+)\}\}/u', $content, $matches);
-
-        return isset($matches[1]) ? trim($matches[1]) : '';
-    }
-}

+ 0 - 444
api-v12/app/Console/Commands/IndexTipitaka.php

@@ -1,444 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Services\SearchPaliDataService;
-use App\Services\OpenSearchService;
-use App\Services\SummaryService;
-use App\Services\TagService;
-use Illuminate\Support\Facades\Log;
-use App\Models\PaliText;
-use App\Models\Sentence;
-use App\Services\PaliContentService;
-use App\Http\Api\ChannelApi;
-use App\Models\ProgressChapter;
-
-class IndexTipitaka extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan opensearch:index-tipitaka 93 --para=6 --granularity=chapter
-     * @var string
-     */
-    protected $signature = 'opensearch:index-tipitaka {book : The book ID to index data for}
-    {--test}
-    {--para= : index paragraph No. omit to all}
-    {--summary=on}
-    {--resume}
-    {--granularity=all : The granularity to index (paragraph, sutta, sentence; omit to index all)}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Index Pali data into OpenSearch for a specified book and optional granularity (all granularities if not specified)';
-
-
-    private $isTest = false;
-    private $summary = false;
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct(
-        protected SearchPaliDataService $searchPaliDataService,
-        protected OpenSearchService $openSearchService,
-        protected SummaryService $summaryService,
-        protected TagService $tagService
-    ) {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $book = (int)$this->argument('book');
-        $granularity = $this->option('granularity');
-        $paragraph = $this->option('para');
-        $this->summary = $this->option('summary') === 'on';
-
-        if ($this->option('test')) {
-            $this->isTest = true;
-            $this->info('test mode');
-        }
-
-
-        try {
-            // Test OpenSearch connection
-            [$connected, $message] = $this->openSearchService->testConnection();
-            if (!$connected) {
-                $this->error($message);
-                Log::error($message);
-                return 1;
-            }
-            $overallStatus = 0; // Track overall command status (0 for success, 1 for any failure)
-            $maxBookId = PaliText::max('book');
-            if ($book === 0) {
-                $booksId = range(1, $maxBookId);
-            } else if ($this->option('resume')) {
-                $booksId = range($book, $maxBookId);
-            } else {
-                $booksId = [$book];
-            }
-            foreach ($booksId as $key => $bookId) {
-                if (
-                    $this->option('granularity') === 'chapter' ||
-                    $this->option('granularity') === 'all'
-                ) {
-                    $this->indexChapter($bookId);
-                }
-                if (
-                    $this->option('granularity') === 'paragraph' ||
-                    $this->option('granularity') === 'all'
-                ) {
-                    $this->indexTipitakaParagraph($bookId, $paragraph);
-                }
-            }
-
-            return $overallStatus;
-        } catch (\Exception $e) {
-            $this->error("Failed to index Pali data: " . $e->getMessage());
-            Log::error("Failed to index Pali data for book: $book, granularity: " . ($granularity ?: 'all'), ['error' => $e]);
-            return 1;
-        }
-    }
-
-    /**
-     * Index Pali paragraphs for a given book.
-     *
-     * @param int $book
-     * @return int
-     */
-    protected function indexTipitakaParagraph($book, $paragraph = null)
-    {
-        $this->info("Starting to index paragraphs for book: $book");
-        $total = 0;
-        if ($paragraph) {
-            $paragraphs = PaliText::where('book', $book)
-                ->where('paragraph', $paragraph)
-                ->orderBy('paragraph')->cursor();
-        } else {
-            $paragraphs = PaliText::where('book', $book)
-                ->orderBy('paragraph')->cursor();
-        }
-        $bookUid = PaliText::where('book', $book)->where('level', 1)->first()->uid;
-        $category = $this->tagService->getTagsName($bookUid);
-        $headings = [];
-        $currChapterTitle = '';
-        $commentaryId = '';
-        $currSession = [];
-        foreach ($paragraphs as $key => $para) {
-            $total++;
-            if ($para->level < 8) {
-                $currChapterTitle = $para->toc;
-            }
-            if ($para->class === 'nikaya') {
-                $nikaya = $para->text;
-            }
-            $paraContent = $this->searchPaliDataService
-                ->getParaContent($para['book'], $para['paragraph']);
-            if (!empty($commentaryId)) {
-                $currSession[] = $paraContent;
-            }
-            if (isset($paraContent['commentary'])) {
-                if (!empty($commentaryId)) {
-                    //保存 session
-                    $this->indexPaliSession($para->toArray(), $currSession, $currChapterTitle, $commentaryId);
-                    $currSession = [];
-                }
-                $commentaryId = $paraContent['commentary'];
-            }
-            $this->indexParagraph($para->toArray(), $paraContent, $commentaryId, $category);
-            $this->info("{$para['book']}-[{$para['paragraph']}]-[{$commentaryId}]");
-        }
-
-        $this->info("Successfully indexed $total paragraphs for book: $book");
-        Log::info("Indexed $total paragraphs for book: $book");
-
-        return 0;
-    }
-    /**
-     *
-     */
-    protected function indexParagraph($paraInfo, $paraContent, $related_id, array $category)
-    {
-        $paraId = $paraInfo['book'] . '-' . $paraInfo['paragraph'];
-        $resource_id = $paraInfo['uid'];
-        $path = json_decode($paraInfo['path']);
-        if (is_array($path) && count($path) > 0) {
-            $title = end($path)->title;
-        } else {
-            $title = '';
-        }
-        $document = [
-            'id' => "tipitaka_paragraph_pi_{$paraId}",
-            'resource_id' => $resource_id, // Use uid from getPaliData for resource_id
-            'resource_type' => 'tipitaka',
-            'title' => [
-                'text' => ['pali' => $title,],
-            ],
-            'summary' => [
-                'text' => $this->summary  ? $this->summaryService->summarize($paraContent['markdown']) : ''
-            ],
-            'content' => [
-                'text' => ['pali' => $paraContent['text']],
-                'suggest' => ['pali' => $paraContent['words']],
-            ],
-            'bold_single' => implode(' ', $paraContent['bold1']),
-            'bold_multi' => implode(' ', array_merge($paraContent['bold2'], $paraContent['bold3'])),
-            'related_id' => $paraId,
-            'category' => $category, // Assuming Pali paragraphs are sutta; adjust as needed
-            'language' => 'pi',
-            'updated_at' => now()->toIso8601String(),
-            'granularity' => 'paragraph',
-            'path' => $this->getPathTitle($path),
-        ];
-        if ($paraInfo['level'] < 8) {
-            $document['title']['suggest']['pali'] = $paraContent['words'];
-        }
-        if ($this->isTest) {
-            $this->info($document['title']['text']['pali']);
-            $this->info($document['summary']['text']);
-        } else {
-            $this->openSearchService->create($document['id'], $document);
-        }
-        return;
-    }
-
-    /**
-     *
-     */
-    protected function indexPaliSession($paraInfo, $contents, $currChapter, $related_id)
-    {
-        $markdown = [];
-        $text = [];
-        $bold_single = [];
-        $bold_multi = [];
-        foreach ($contents as $key => $content) {
-            $markdown[] = $content['markdown'];
-            $text[] = $content['text'];
-            $bold_single = array_merge($bold_single, $content['bold1']);
-            $bold_multi = array_merge($bold_multi, $content['bold2'], $content['bold3']);
-        }
-        $document = [
-            'id' => "pali_session_{$related_id}",
-            'resource_id' => $paraInfo['uid'], // Use uid from getPaliData for resource_id
-            'resource_type' => 'original_text',
-            'title' => [
-                'pali' => "{$currChapter} paragraph {$paraInfo['paragraph']}"
-            ],
-            'summary' => [
-                'text' => $this->summary ? $this->summaryService->summarize($content['markdown']) : ''
-            ],
-            'content' => [
-                'pali' => implode("\n\n", $markdown),
-            ],
-            'bold_single' => implode(" ", $bold_single),
-            'bold_multi' => implode(" ", $bold_multi),
-            'related_id' => $related_id,
-            'category' => 'pali', // Assuming Pali paragraphs are sutta; adjust as needed
-            'language' => 'pali',
-            'updated_at' => now()->toIso8601String(),
-            'granularity' => 'session',
-            'path' => $this->getPathTitle(json_decode($paraInfo['path'])),
-        ];
-        if ($this->isTest) {
-            $this->info($document['title']['pali']);
-            $this->info($document['summary']['text']);
-        } else {
-            $this->openSearchService->create($document['id'], $document);
-        }
-        return;
-    }
-
-
-
-    /**
-     * Index Pali suttas for a given book (placeholder for future implementation).
-     *
-     * @param int $book
-     * @return int
-     */
-    protected function indexChapter($book)
-    {
-        $this->info("Starting to index paragraphs for book: $book");
-        $total = 0;
-        $chapters = PaliText::where('book', $book)
-            ->where('level', '<', 8)
-            ->orderBy('paragraph')->get();
-        foreach ($chapters as $key => $chapter) {
-            if ($chapter->level === 1) {
-                $category = $this->tagService->getTagsName($chapter->uid);
-            }
-            /**
-             * 章节的起始位置算法
-             * 从章节的标题,到下一个章节的标题之间
-             */
-            $start = $chapter->paragraph;
-            if ($key === count($chapters) - 1) {
-                $end = PaliText::where('book', $book)
-                    ->orderBy('paragraph', 'desc')->first()
-                    ->value('paragraph');
-            } else {
-                $end = $chapters[$key + 1]->paragraph;
-            }
-            //获取这个段落之间的全部channel
-            $channels = Sentence::where('book_id', $book)
-                ->whereBetween('paragraph', [$start, $end])
-                ->select('channel_uid')
-                ->groupBy('channel_uid')->get();
-            $this->info("index chapter start={$start} end={$end}");
-
-            foreach ($channels as $key => $channel) {
-                $display = [];
-                $content = [];
-                $channelInfo = ChannelApi::getById($channel->channel_uid);
-                $this->info('channel =' . $channelInfo['name']);
-                if ($channelInfo['type'] === 'wbw') {
-                    $this->info('wbw channel skip');
-                    continue;
-                }
-                $paragraphsData = app(PaliContentService::class)->paragraphs(
-                    $book,
-                    $start,
-                    $end,
-                    [$channel->channel_uid],
-                    ['mode' => 'read', 'format' => 'html', 'original' => true]
-                );
-                //生成html数据
-
-                $title = '';
-                foreach ($paragraphsData as $key => $paragraph) {
-                    $translation = [];
-                    $original = [];
-                    foreach ($paragraph['children'] as $key => $sent) {
-                        if (isset($sent['translation'])) {
-                            foreach ($sent['translation'] as $key => $tran) {
-                                $curr = $tran['html'] ?? $tran['content'];
-                                $translation[] = "<span class='sentence'>{$curr}</span>";
-                                if ($tran['para'] === $start && !empty($curr)) {
-                                    $title = $curr;
-                                }
-                            }
-                        }
-                        if (
-                            isset($sent['origin']) ||
-                            is_array($sent['origin']) ||
-                            count($sent['origin']) > 0
-                        ) {
-                            $ori = $sent['origin'][0];
-                            $curr = $ori['html'] ?? $ori['content'];
-                            $original[] = "<span class='sentence origin'>{$curr}</span>";
-                            if (empty($title) && $ori['para'] === $start && !empty($curr)) {
-                                $title = $curr;
-                            }
-                        }
-                    }
-
-
-                    $level = $paragraph['para'] === $start ? $chapter->level : 0;
-                    $strOriginal = implode('', $original);
-                    $strTranslation = implode('', $translation);
-
-                    if ($level > 0) {
-                        $display[] = "<div><h{$level}>{$strOriginal}</h{$level}><h{$level}>{$strTranslation}</h{$level}></div>";
-                    } else {
-                        $display[] = "<div><p>{$strOriginal}</p><p>{$strTranslation}</p></div>";
-                    }
-
-                    if ($channelInfo['type'] === 'original') {
-                        $content[] = $strOriginal;
-                    } else {
-                        $content[] = $strTranslation;
-                    }
-                }
-                $this->chapterSave([
-                    'book' => $book,
-                    'para' => $start,
-                    'level' => $chapter->level,
-                    'channel' => $channel->channel_uid,
-                    'display' => implode('', $display),
-                    'content' => implode('', $content),
-                    'title' => strip_tags($title),
-                    'cat' => $category
-                ]);
-            }
-        }
-
-
-        return 0;
-    }
-
-    protected function chapterSave(array $param)
-    {
-        $progress = ProgressChapter::where('book', $param['book'])
-            ->where('para', $param['para'])
-            ->where('channel_id', $param['channel'])
-            ->first();
-        $channel = ChannelApi::getById($param['channel']);
-        $document = [
-            'id'            => "tipitaka_chapter_{$param['book']}-{$param['para']}_{$param['channel']}",
-            'resource_id'   => $progress ? $progress->uid : "{$param['book']}-{$param['para']}_{$param['channel']}",
-            'resource_type' => 'tipitaka',
-            'title'         => [],
-            'summary' => [
-                'text' => '',
-            ],
-            'content'     => [],
-            'related_id'  => "{$param['book']}-{$param['para']}",
-            'category'    => $param['cat'],
-            'language'    => $channel['lang'],
-            'updated_at'  => now()->toIso8601String(),
-            'granularity' => $param['level'] === 1 ? 'book' : 'chapter',
-        ];
-
-        // TODO: 补充语言判断,将内容放入对应的 text.pali 或 text.zh 字段
-        $plainText = strip_tags($param['content']);
-        $title = strip_tags($param['title']);
-        if (str_contains($channel['lang'], 'zh')) {
-            $document['content']['text']['zh'] = $plainText;
-            $document['title']['text']['zh'] = $title;
-        } else {
-            $document['content']['text']['pali'] = $plainText;
-            $document['title']['text']['pali'] = $title;
-        }
-        $document['content']['display']    = $param['display'];             // 展示
-
-        if ($this->isTest) {
-            $this->info($param['content']);
-        } else {
-            $this->openSearchService->create($document['id'], $document);
-            $this->info("create index {$document['id']} size=" . strlen($param['content']));
-        }
-    }
-    /**
-     * Index Pali sentences for a given book (placeholder for future implementation).
-     *
-     * @param int $book
-     * @return int
-     */
-    protected function indexPaliSentences($book)
-    {
-        $this->warn("Sentence indexing is not yet implemented for book: $book");
-        Log::warning("Sentence indexing not implemented for book: $book");
-        return 1;
-    }
-
-
-    private function getPathTitle(array $input)
-    {
-        $output = [];
-        foreach ($input as $key => $node) {
-            $output[] = $node->title;
-        }
-        return implode('/', $output);
-    }
-}

+ 0 - 93
api-v12/app/Console/Commands/InitCommentary.php

@@ -1,93 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\Tag;
-use App\Models\TagMap;
-use App\Models\PaliText;
-use App\Models\PaliSentence;
-use App\Models\Commentary;
-use App\Models\RelatedParagraph;
-
-class InitCommentary extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan init:commentary
-     * @var string
-     */
-    protected $signature = 'init:commentary {--book=}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'init commentary sentences';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        //查询注释书标签
-        $tags = Tag::whereIn('name', ['aṭṭhakathā', 'ṭīkā'])->select('id')->get();
-        //查询段落编号
-        $paliId = TagMap::whereIn('tag_id', $tags)
-            ->where('table_name', 'pali_texts')
-            ->cursor();
-        foreach ($paliId as $key => $paraId) {
-            $book = PaliText::where('uid', $paraId->anchor_id)
-                ->where('level', 1)->first();
-            if (!$book) {
-                continue;
-            }
-            $paragraphs = PaliText::where('book', $book->book)
-                ->whereBetween('paragraph', [$book->paragraph, $book->paragraph + $book->chapter_len - 1])
-                ->get();
-            foreach ($paragraphs as $key => $para) {
-                $this->info($para->book . '-' . $para->paragraph);
-                $sentences = PaliSentence::where('book', $para->book)
-                    ->where('paragraph', $para->paragraph)
-                    ->get();
-                $del = Commentary::where('book1', $para->book)
-                    ->where('paragraph1', $para->paragraph)
-                    ->where('owner_id', config("mint.admin.root_uuid"))
-                    ->delete();
-                $csPara = RelatedParagraph::where('book', $para->book)
-                    ->where('para', $para->paragraph)
-                    ->first();
-                if ($csPara) {
-                    foreach ($sentences as $key => $sentence) {
-                        $new = new Commentary();
-                        $new->book1 = $sentence->book;
-                        $new->paragraph1 = $sentence->paragraph;
-                        $new->start1 = $sentence->word_begin;
-                        $new->end1 = $sentence->word_end;
-                        $new->editor_id = config("mint.admin.root_uuid");
-                        $new->owner_id = config("mint.admin.root_uuid");
-                        $new->p_number = $csPara->book_name . '-' . $csPara->para;
-                        $new->save();
-                    }
-                } else {
-                    $this->error('no relation paragraph');
-                }
-            }
-        }
-        $this->info('all done');
-        return 0;
-    }
-}

+ 0 - 156
api-v12/app/Console/Commands/InitCs6sentence.php

@@ -1,156 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\PaliSentence;
-use App\Models\WbwTemplate;
-use App\Models\Sentence;
-use Illuminate\Support\Str;
-use App\Http\Api\ChannelApi;
-
-
-class InitCs6sentence extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'init:cs6sentence {book?} {para?}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '按照分句数据库,填充cs6的巴利原文句子';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $start = time();
-        $channelId = ChannelApi::getSysChannel('_System_Pali_VRI_');
-        if ($channelId === false) {
-            $this->error('no channel');
-            return 1;
-        }
-        $this->info($channelId);
-        $pali = new PaliSentence;
-        if (!empty($this->argument('book'))) {
-            $pali = $pali->where('book', $this->argument('book'));
-        }
-        if (!empty($this->argument('para'))) {
-            $pali = $pali->where('paragraph', $this->argument('para'));
-        }
-        $bar = $this->output->createProgressBar($pali->count());
-        $pali = $pali->select('book', 'paragraph', 'word_begin', 'word_end')->cursor();
-        $pageHead = ['M', 'P', 'T', 'V', 'O'];
-        foreach ($pali as $value) {
-            # code...
-            $words = WbwTemplate::where("book", $value->book)
-                ->where("paragraph", $value->paragraph)
-                ->where("wid", ">=", $value->word_begin)
-                ->where("wid", "<=", $value->word_end)
-                ->orderBy('wid', 'asc')
-                ->get();
-            $sent = '';
-            $boldStart = false;
-            $boldCount = 0;
-            $lastWord = null;
-            foreach ($words as $word) {
-                # code...
-                //if($word->style != "note" && $word->type != '.ctl.')
-                if ($word->type != '.ctl.') {
-                    if ($lastWord !== null) {
-                        if ($word->real !== "ti") {
-
-                            if (!(empty($word->real) && empty($lastWord->real))) {
-                                #如果不是标点符号,在词的前面加空格 。
-                                $sent .= " ";
-                            }
-                        }
-                    }
-
-                    if (strpos($word->word, '{') !== false) {
-                        //一个单词里面含有黑体字的
-                        $paliWord = \str_replace("{", "<strong>", $word->word);
-                        $paliWord = \str_replace("}", "</strong>", $paliWord);
-                        $sent .= $paliWord;
-                    } else {
-                        if ($word->style == 'bld') {
-                            $sent .= "<strong>{$word->word}</strong>";
-                        } else {
-                            $sent .= $word->word;
-                        }
-                    }
-                } else {
-                    $type = substr($word->word, 0, 1);
-                    if (in_array($type, $pageHead)) {
-                        $arrPage = explode('.', $word->word);
-                        if (count($arrPage) === 2) {
-                            $pageNumber = $arrPage[0] . '.' . (int)$arrPage[1];
-                            $sent .= "<code>{$pageNumber}</code>";
-                        }
-                    }
-                }
-                $lastWord = $word;
-            }
-
-            #将wikipali风格的引用 改为缅文风格
-            /*
-			$sent = \str_replace('n’’’ ti','’’’nti',$sent);
-			$sent = \str_replace('n’’ ti','’’nti',$sent);
-			$sent = \str_replace('n’ ti','’nti',$sent);
-			$sent = \str_replace('**ti**','**ti',$sent);
-			$sent = \str_replace('‘ ','‘',$sent);
-            */
-            $sent = \str_replace(' ti', 'ti', $sent);
-
-            $newRow = Sentence::firstOrNew(
-                [
-                    "book_id" => $value->book,
-                    "paragraph" => $value->paragraph,
-                    "word_start" => $value->word_begin,
-                    "word_end" => $value->word_end,
-                    "channel_uid" => $channelId,
-                ],
-                [
-                    'id' => app('snowflake')->id(),
-                    'uid' => Str::uuid(),
-                    'create_time' => time() * 1000,
-                ]
-            );
-            $newRow->editor_uid = config("mint.admin.root_uuid");
-            $newRow->content = "<span>{$sent}</span>";
-            $newRow->strlen = mb_strlen($sent, "UTF-8");
-            $newRow->status = 10;
-            $newRow->content_type = "html";
-            $newRow->modify_time = time() * 1000;
-            $newRow->language = 'en';
-            $newRow->save();
-
-            $bar->advance();
-        }
-        $bar->finish();
-        $this->info("finished " . (time() - $start) . "s");
-        return 0;
-    }
-}

+ 0 - 58
api-v12/app/Console/Commands/InitDependence.php

@@ -1,58 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Symfony\Component\Process\Process;
-use Symfony\Component\Process\Exception\ProcessFailedException;
-
-class InitDependence extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'init:dep';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'init dependence date - pali sencence ect.';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-		#克隆依赖的数据仓库到本地
-		$depDir = $this->info(config("mint.path.dependence"));
-		foreach ($this->info(config("mint.dependence")) as $key => $value) {
-			# code...
-			$process = new Process(['git','clone',$value->url,$depDir.'/'.$value->path]);
-			$process->run();
-			if(!$process->isSuccessful()){
-				throw new ProcessFailedException($process);
-			}
-			$this->info($process->getOutput());
-		}
-        return 0;
-    }
-}

+ 0 - 148
api-v12/app/Console/Commands/InitSystemChannel.php

@@ -1,148 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Models\Channel;
-use Illuminate\Console\Command;
-
-class InitSystemChannel extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'init:system.channel';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'create system channel. like pali text , wbw template ect.';
-
-    protected $channels = [
-        [
-            "name" => '_System_Pali_VRI_',
-            'type' => 'original',
-            'lang' => 'pali',
-        ],
-        [
-            "name" => '_System_Wbw_VRI_',
-            'type' => 'wbw',
-            'lang' => 'pali',
-        ],
-        [
-            "name" => '_System_Grammar_Term_zh-hans_',
-            'type' => 'translation',
-            'lang' => 'zh-Hans',
-        ],
-        [
-            "name" => '_System_Grammar_Term_zh-hant_',
-            'type' => 'translation',
-            'lang' => 'zh-Hant',
-        ],
-        [
-            "name" => '_System_Grammar_Term_en_',
-            'type' => 'translation',
-            'lang' => 'en',
-        ],
-        [
-            "name" => '_System_Grammar_Term_my_',
-            'type' => 'translation',
-            'lang' => 'my',
-        ],
-        [
-            "name" => '_community_term_zh-hans_',
-            'type' => 'translation',
-            'lang' => 'zh-Hans',
-        ],
-        [
-            "name" => '_community_term_zh-hant_',
-            'type' => 'translation',
-            'lang' => 'zh-Hant',
-        ],
-        [
-            "name" => '_community_term_en_',
-            'type' => 'translation',
-            'lang' => 'en',
-        ],
-        [
-            "name" => '_community_translation_zh-hans_',
-            'type' => 'translation',
-            'lang' => 'zh-Hans',
-        ],
-        [
-            "name" => '_community_translation_zh-hant_',
-            'type' => 'translation',
-            'lang' => 'zh-Hant',
-        ],
-        [
-            "name" => '_community_translation_en_',
-            'type' => 'translation',
-            'lang' => 'en',
-        ],
-        [
-            "name" => '_System_Quote_',
-            'type' => 'original',
-            'lang' => 'en',
-        ],
-        [
-            "name" => '_community_summary_zh-hans_',
-            'type' => 'translation',
-            'lang' => 'zh-Hans',
-        ],
-        [
-            "name" => '_System_commentary_',
-            'type' => 'commentary',
-            'lang' => 'en',
-            'status' => 30,
-        ],
-    ];
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $this->info("start");
-        foreach ($this->channels as $key => $value) {
-            # code...
-            $channel = Channel::firstOrNew([
-                'name' => $value['name'],
-                'owner_uid' => config("mint.admin.root_uuid"),
-            ]);
-            if (empty($channel->id)) {
-                $channel->id = app('snowflake')->id();
-            }
-            $channel->type = $value['type'];
-            $channel->lang = $value['lang'];
-            $channel->editor_id = 0;
-            $channel->owner_uid = config("mint.admin.root_uuid");
-            $channel->create_time = time() * 1000;
-            $channel->modify_time = time() * 1000;
-            $channel->is_system = true;
-            if (isset($value['status'])) {
-                $channel->status = $value['status'];
-            }
-            $channel->save();
-            $this->info("created" . $value['name']);
-        }
-        return 0;
-    }
-}

+ 0 - 103
api-v12/app/Console/Commands/InitSystemDict.php

@@ -1,103 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Models\DictInfo;
-use Illuminate\Console\Command;
-
-class InitSystemDict extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     * php artisan init:system.dict
-     */
-    protected $signature = 'init:system.dict';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'create system dict. like sys_regular  ect.';
-
-    /**
-     * name 不要修改。因为在程序其他地方,用name 查询词典id
-     */
-    protected $dictionary =[
-        [
-            "name"=>'robot_compound',
-            'shortname'=>'compound',
-            'description'=>'split compound by AI',
-            'src_lang'=>'pa',
-            'dest_lang'=>'cm',
-        ],
-        [
-            "name"=>'system_regular',
-            'shortname'=>'regular',
-            'description'=>'system regular',
-            'src_lang'=>'pa',
-            'dest_lang'=>'cm',
-        ],
-        [
-            "name"=>'community',
-            'shortname'=>'社区',
-            'description'=>'由用户贡献词条的社区字典',
-            'src_lang'=>'pa',
-            'dest_lang'=>'cm',
-        ],
-        [
-            "name"=>'community_extract',
-            'shortname'=>'社区汇总',
-            'description'=>'由用户贡献词条的社区字典汇总统计',
-            'src_lang'=>'pa',
-            'dest_lang'=>'cm',
-        ],
-        [
-            "name"=>'system_preference',
-            'shortname'=>'系统单词首选项',
-            'description'=>'通过系统筛选出的首选项,只包含语法信息',
-            'src_lang'=>'pa',
-            'dest_lang'=>'cm',
-        ],
-    ];
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $this->info("start");
-        foreach ($this->dictionary as $key => $value) {
-            # code...
-            $channel = DictInfo::firstOrNew([
-                'name' => $value['name'],
-                'owner_id' => config("mint.admin.root_uuid"),
-            ]);
-            $channel->shortname = $value['shortname'];
-            $channel->description = $value['description'];
-            $channel->src_lang = $value['src_lang'];
-            $channel->dest_lang = $value['dest_lang'];
-            $channel->meta = json_encode($value,JSON_UNESCAPED_UNICODE);
-            $channel->save();
-            $this->info("updated {$value['name']}");
-        }
-        return 0;
-    }
-}

+ 0 - 66
api-v12/app/Console/Commands/Install.php

@@ -1,66 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-
-class Install extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'install {--test}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'install new host';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-		$isTest = $this->option('test');
-		if($isTest){
-			$this->call('install:wbwtemplate', ['from' => 1]);
-		}else{
-			$this->call('install:wbwtemplate');
-			$this->call('install:palitext');
-			$this->call('install:wordbook');
-			$this->call('install:wordall');
-			$this->call('install:wordindex');
-
-			$this->call('upgrade:palitext');
-			$this->call('upgrade:palitoc',['lang'=>'pali']);
-			$this->call('upgrade:palitoc',['lang'=>'zh-hans']);
-			$this->call('upgrade:palitoc',['lang'=>'zh-hant']);
-
-			$this->call('install:paliseries');
-			$this->call('install:wordstatistics');
-
-		}
-
-        return 0;
-    }
-}

+ 0 - 42
api-v12/app/Console/Commands/InstallPaliSent.php

@@ -1,42 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-
-class InstallPaliSent extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'command:name';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        return 0;
-    }
-}

+ 0 - 83
api-v12/app/Console/Commands/InstallPaliSeries.php

@@ -1,83 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\BookTitle;
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Log;
-
-class InstallPaliSeries extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'install:pali.series';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-		$this->info("upgrade pali serieses");
-		$startTime = time();
-
-		DB::transaction(function () {
-			#删除目标数据库中数据
-			BookTitle::where('book','>',0)->delete();
-
-		// 打开csv文件并读取数据
-			$strFileName = config("mint.path.pali_title") . "/pali_serieses.csv";
-			if(!file_exists($strFileName)){
-				return 1;
-			}
-			$inputRow = 0;
-			if (($fp = fopen($strFileName, "r")) !== false) {
-				while (($data = fgetcsv($fp, 0, ',')) !== false) {
-					if($inputRow>0){
-						$newData = [
-							'sn'=>$data[0],
-							'book'=>$data[1],
-							'paragraph'=>$data[2],
-							'title'=>$data[3],
-						];
-
-						BookTitle::create($newData);
-					}
-					$inputRow++;
-				}
-				fclose($fp);
-				Log::info("res load:" .$strFileName);
-			} else {
-				$this->error("can not open csv $strFileName");
-				Log::error("can not open csv $strFileName");
-			}
-		});
-		$this->info("ok");
-        return 0;
-    }
-}

+ 0 - 42
api-v12/app/Console/Commands/InstallPaliSim.php

@@ -1,42 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-
-class InstallPaliSim extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'command:name';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        return 0;
-    }
-}

+ 0 - 156
api-v12/app/Console/Commands/InstallPaliText.php

@@ -1,156 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\PaliText;
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Log;
-
-class InstallPaliText extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'install:palitext {from?} {to?}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-		$this->info("instert pali text");
-		$startTime = time();
-
-		$_from = $this->argument('from');
-		$_to = $this->argument('to');
-		if(empty($_from) && empty($_to)){
-			$_from = 1;
-			$_to = 217;
-		}else if(empty($_to)){
-			$_to = $_from;
-		}
-		$fileListFileName = config("mint.path.palitext_filelist");
-
-		$filelist = array();
-
-		if (($handle = fopen($fileListFileName, 'r')) !== false) {
-			while (($filelist[] = fgetcsv($handle, 0, ',')) !== false) {
-			}
-		}
-		$bar = $this->output->createProgressBar($_to-$_from+1);
-
-		for ($from=$_from; $from <=$_to ; $from++) {
-			# code...
-
-			$fileSn = $from-1;
-			$FileName = $filelist[$fileSn][1];
-
-			$dirXmlBase = config("mint.path.palicsv") . "/";
-			$GLOBALS['data'] = array();
-
-			// 打开vri html文件并读取数据
-			$pali_text_array = array();
-			$htmlFile = config("mint.path.palitext") .'/'. $FileName.'.htm';
-			if (($fpPaliText = fopen($htmlFile, "r")) !== false) {
-				while (($data = fgets($fpPaliText)) !== false) {
-					if (substr($data, 0, 2) === "<p") {
-						array_push($pali_text_array, $data);
-					}
-				}
-				fclose($fpPaliText);
-				//$this->info("pali text load:" . $htmlFile . PHP_EOL);
-			} else {
-				$this->error( "can not pali text file. filename=" . $htmlFile . PHP_EOL) ;
-				Log::error( "can not pali text file. filename=" . $htmlFile . PHP_EOL) ;
-			}
-
-			$inputRow = 0;
-			$csvFile = config("mint.path.palicsv") .'/'. $FileName .'/'. $FileName.'_pali.csv';
-			if (($fp = fopen($csvFile, "r")) !== false) {
-				while (($data = fgetcsv($fp, 0, ',')) !== false) {
-					if ($inputRow > 0) {
-						if (($inputRow - 1) < count($pali_text_array)) {
-							$data[5] = $pali_text_array[$inputRow - 1];
-						}
-						$data[1] = mb_substr($data[1],1,null,"UTF-8");
-						$GLOBALS['data'][] = $data;
-					}
-					$inputRow++;
-				}
-				fclose($fp);
-				//$this->info("单词表load:" . $csvFile.PHP_EOL);
-			} else {
-				$this->error( "can not open csv file. filename=" . $csvFile. PHP_EOL) ;
-				Log::error( "can not open csv file. filename=" . $csvFile. PHP_EOL) ;
-				continue;
-			}
-
-			if (($inputRow - 1) != count($pali_text_array)) {
-				$this->error( "line count error $FileName ".PHP_EOL);
-				Log::error( "line count error $FileName ".PHP_EOL);
-			}
-
-
-			#删除目标数据库中数据
-			PaliText::where('book', $from)->delete();
-
-
-			// 打开文件并读取数据
-
-
-			DB::transaction(function () {
-				foreach ($GLOBALS['data'] as $oneParam) {
-					if ($oneParam[3] < 100) {
-						$toc = $oneParam[6];
-					} else {
-						$toc = "";
-					}
-					$params = [
-						'book'=>$oneParam[1],
-						'paragraph'=>$oneParam[2],
-						'level'=>$oneParam[3],
-						'class'=> $oneParam[4],
-						'toc'=>$toc,
-						'text'=>$oneParam[6],
-						'html'=>$oneParam[5],
-						'lenght'=>mb_strlen($oneParam[6], "UTF-8"),
-					];
-					PaliText::create($params);
-				}
-
-			});
-
-			$bar->advance();
-		}
-		$bar->finish();
-		$this->info("instert pali text finished. in ". time()-$startTime . "s" .PHP_EOL);
-
-        return 0;
-
-    }
-}

+ 0 - 118
api-v12/app/Console/Commands/InstallWbwTemplate.php

@@ -1,118 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\WbwTemplate;
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Log;
-
-class InstallWbwTemplate extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'install:wbwtemplate {from?} {to?}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-		$this->info("instert wbw template");
-
-
-		$_from = $this->argument('from');
-		$_to = $this->argument('to');
-		if(empty($_from) && empty($_to)){
-			$_from = 1;
-			$_to = 217;
-		}else if(empty($_to)){
-			$_to = $_from;
-		}
-		$fileListFileName = public_path('/palihtml/filelist.csv');
-
-		$filelist = array();
-
-		if (($handle = fopen($fileListFileName, 'r')) !== false) {
-			while (($filelist[] = fgetcsv($handle, 0, ',')) !== false) {
-			}
-		}
-		$bar = $this->output->createProgressBar($_to-$_from+1);
-
-		for ($from=$_from; $from <=$_to ; $from++) {
-			# code...
-
-			$fileSn = $from-1;
-			$outputFileNameHead = $filelist[$fileSn][1];
-
-			$dirXmlBase = public_path('/tmp/palicsv') . "/";
-			$dirXml = $outputFileNameHead . "/";
-
-
-			#删除目标数据库中数据
-			WbwTemplate::where('book', $from)->delete();
-
-
-			// 打开文件并读取数据
-
-			if (($GLOBALS["fp"] = fopen($dirXmlBase . $dirXml . $outputFileNameHead . ".csv", "r")) !== false) {
-				$GLOBALS["row"]=0;
-				DB::transaction(function () {
-					while (($data = fgetcsv($GLOBALS["fp"], 0, ',')) !== false) {
-						$GLOBALS["row"]++;
-						if($GLOBALS["row"]==1){
-							continue;
-						}
-						#或略第一行 标题行
-						$params = [
-							'book'=>mb_substr($data[2], 1),
-							'paragraph'=>$data[3],
-							'wid'=>$data[16],
-							'word'=>$data[4],
-							'real'=>$data[5],
-							'type'=>$data[6],
-							'gramma'=>$data[7],
-							'part'=>$data[10],
-							'style'=>$data[15]
-						];
-						WbwTemplate::insert($params);
-					}
-				});
-				fclose($GLOBALS["fp"]);
-			} else {
-				$this->error("can not open csv file. filename=" . $dirXmlBase . $dirXml . $outputFileNameHead . ".csv".PHP_EOL) ;
-				Log::error("can not open csv file. filename=" . $dirXmlBase . $dirXml . $outputFileNameHead . ".csv".PHP_EOL) ;
-			}
-
-			$bar->advance();
-		}
-		$bar->finish();
-        return 0;
-
-	}
-}

+ 0 - 95
api-v12/app/Console/Commands/InstallWordAll.php

@@ -1,95 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\WordList;
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Log;
-
-class InstallWordAll extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'install:wordall {from?} {to?}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-		$startTime = time();
-
-		$this->info("instert word in palibook ");
-		Log::info("instert word in palibook ");
-
-		$_from = $this->argument('from');
-		$_to = $this->argument('to');
-		if(empty($_from) && empty($_to)){
-			$_from = 1;
-			$_to = 217;
-		}else if(empty($_to)){
-			$_to = $_from;
-		}
-
-		$bar = $this->output->createProgressBar($_to-$_from+1);
-
-		for ($book=$_from; $book <= $_to; $book++) {
-			Log::info("doing ".($book));
-			DB::transaction(function ()use($book) {
-				$fileSn = $book-1;
-				if (($fpoutput = fopen(config("mint.path.paliword_book") . "/{$fileSn}_words.csv", "r")) !== false){
-					#删除目标数据库中数据
-					WordList::where('book', $book)->delete();
-					while (($data = fgetcsv($fpoutput, 0, ',')) !== false)
-					{
-						$newData = [
-							'sn'=>$data[0],
-							'book'=>$data[1],
-							'paragraph'=>$data[2],
-							'wordindex'=>$data[3],
-							'bold'=>$data[4],
-						];
-						WordList::create($newData);
-					}
-					return 0;
-				}else{
-					Log::error("open csv fail");
-					return 1;
-				}
-			});
-			$bar->advance();
-		}
-		$bar->finish();
-
-		$msg = "all done in ". time()-$startTime . "s";
-		$this->info($msg.PHP_EOL);
-		Log::info($msg);
-        return 0;
-    }
-}

+ 0 - 107
api-v12/app/Console/Commands/InstallWordBook.php

@@ -1,107 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\BookWord;
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Log;
-
-class InstallWordBook extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'install:wordbook {from?} {to?}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'install palibook word list in each book';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-		$startTime = time();
-
-		$this->info("instert word in palibook ");
-		Log::info("instert word in palibook ");
-
-		$_from = $this->argument('from');
-		$_to = $this->argument('to');
-		if(empty($_from) && empty($_to)){
-			$_from = 1;
-			$_to = 217;
-		}else if(empty($_to)){
-			$_to = $_from;
-		}
-
-		$bar = $this->output->createProgressBar($_to-$_from+1);
-
-		for ($book=$_from; $book <= $_to; $book++) {
-			Log::info("doing ".($book));
-
-			#删除目标数据库中数据
-			BookWord::where('book', $book)->delete();
-
-			//分类汇总得到单词表
-			$bookword = array();
-			$fileId = $book-1;
-			if (($fpoutput = fopen(config("mint.path.paliword_book") . "/{$fileId}_words.csv", "r")) !== false) {
-				$count = 0;
-				while (($data = fgetcsv($fpoutput, 0, ',')) !== false) {
-					$book = $data[1];
-					if (isset($bookword[$data[3]])) {
-						$bookword[$data[3]]++;
-					} else {
-						$bookword[$data[3]] = 1;
-					}
-
-					$count++;
-				}
-			}else{
-				Log::error("open csv fail");
-				continue;
-			}
-			DB::transaction(function ()use($book,$bookword) {
-				foreach ($bookword as $key => $value) {
-					$newData = [
-						'book'=>$book,
-						'wordindex'=>$key,
-						'count'=>$value,
-					];
-					BookWord::create($newData);
-				}
-			});
-			$bar->advance();
-		}
-		$bar->finish();
-
-		$msg = "all done in ". time()-$startTime . "s";
-		$this->info($msg.PHP_EOL);
-		Log::info($msg);
-
-        return 0;
-    }
-}

+ 0 - 89
api-v12/app/Console/Commands/InstallWordIndex.php

@@ -1,89 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\WordIndex;
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Log;
-
-class InstallWordIndex extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'install:wordindex';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-		$startTime = time();
-
-		$info = "instert word in palibook ";
-		$this->info($info);
-		Log::info($info);
-
-		#删除目标数据库中数据
-		WordIndex::where('id', '>',-1)->delete();
-
-		$scan = scandir(config("mint.path.paliword_index"));
-		$bar = $this->output->createProgressBar(count($scan));
-		foreach($scan as $filename) {
-			$bar->advance();
-			$filename = config("mint.path.paliword_index")."/".$filename;
-			if (is_file($filename)) {
-				Log::info("doing ".$filename);
-				DB::transaction(function ()use($filename) {
-				if (($fpoutput = fopen($filename, "r")) !== false) {
-						$count = 0;
-						while (($data = fgetcsv($fpoutput, 0, ',')) !== false) {
-							$newData = [
-								'id'=>$data[0],
-								'word'=>$data[1],
-								'word_en'=>$data[2],
-								'normal'=>$data[3],
-								'bold'=>$data[4],
-								'is_base'=>$data[5],
-								'len'=>$data[6],
-							];
-							WordIndex::create($newData);
-							$count++;
-						}
-						Log::info("insert ".$count);
-					}
-				});
-			}
-		}
-		$bar->finish();
-		$msg = "all done in ". time()-$startTime . "s";
-		Log::info($msg);
-		$this->info($msg);
-        return 0;
-    }
-}

+ 0 - 91
api-v12/app/Console/Commands/InstallWordStatistics.php

@@ -1,91 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\WordStatistic;
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Log;
-
-class InstallWordStatistics extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'install:wordstatistics';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-		$startTime = time();
-
-		$info = "instert wordstatistics ";
-		$this->info($info.PHP_EOL);
-		Log::info($info);
-
-		#删除目标数据库中数据
-		WordStatistic::where('id', '>',-1)->delete();
-
-		$scan = scandir(config("mint.path.word_statistics"));
-		$bar = $this->output->createProgressBar(count($scan));
-		foreach($scan as $filename) {
-			$bar->advance();
-			$filename = config("mint.path.word_statistics")."/".$filename;
-			if (is_file($filename)) {
-				Log::info("doing ".$filename);
-				DB::transaction(function ()use($filename) {
-				if (($fpoutput = fopen($filename, "r")) !== false) {
-						$count = 0;
-						while (($data = fgetcsv($fpoutput, 0, ',')) !== false) {
-							$newData = [
-								'bookid'=>$data[0],
-								'word'=>$data[1],
-								'count'=>$data[2],
-								'base'=>$data[3],
-								'end1'=>$data[4],
-								'end2'=>$data[5],
-								'type'=>$data[6],
-								'length'=>$data[7],
-							];
-							WordStatistic::create($newData);
-							$count++;
-						}
-						Log::info("insert ".$count);
-					}
-				});
-			}
-		}
-		$bar->finish();
-		$msg = "all done in ". time()-$startTime . "s";
-		Log::info($msg);
-		$this->info($msg);
-        return 0;
-        return 0;
-    }
-}

+ 0 - 360
api-v12/app/Console/Commands/MqAiTranslate.php

@@ -1,360 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\Mq;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Facades\Http;
-use Illuminate\Http\Client\RequestException;
-use Illuminate\Support\Facades\Cache;
-
-class MqAiTranslate extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan mq:ai.translate
-     * @var string
-     */
-    protected $signature = 'mq:ai.translate';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $exchange = 'router';
-        $queue = 'ai_translate';
-        $this->info(" [*] Waiting for {$queue}. To exit press CTRL+C");
-        Log::debug("mq worker {$queue} start.");
-        Mq::worker($exchange, $queue, function ($messages, $messageId) use ($queue) {
-            Log::debug('ai translate start', ['message' => count($messages)]);
-            $this->info('ai translate task start task=' . count($messages));
-            if (!is_array($messages) || count($messages) === 0) {
-                Log::error('message is not array');
-                return 1;
-            }
-
-            //获取model token
-            $first = $messages[0];
-            $taskId = $first->task->info->id;
-            Cache::put("/task/{$taskId}/message_id", $messageId);
-            $pointerKey = "/message/{$messageId}/pointer";
-            $pointer = 0;
-            if (Cache::has($pointerKey)) {
-                //回到上次中断的点
-                $pointer = Cache::get($pointerKey);
-            }
-
-            Log::debug($queue . ' ai assistant token', ['user' => $first->model->uid]);
-            $modelToken = $first->model->token;
-            Log::debug($queue . ' ai assistant token', ['token' => $modelToken]);
-
-            $this->setTaskStatus($first->task->info->id, 'running', $modelToken);
-
-            $discussionUrl = config('app.url') . '/api/v2/discussion';
-            $taskDiscussionData = [
-                'res_id' => $first->task->info->id,
-                'res_type' => 'task',
-                'title' => $first->task->info->title,
-                'content' => $first->task->info->category,
-                'content_type' => 'markdown',
-                'type' => 'discussion',
-                'notification' => false,
-            ];
-            $response = Http::timeout(10)->withToken($modelToken)->post($discussionUrl, $taskDiscussionData);
-            if ($response->failed()) {
-                Log::error($queue . ' discussion create topic error', ['data' => $response->json()]);
-            } else {
-                if (isset($response->json()['data']['id'])) {
-                    $taskDiscussionData['parent'] = $response->json()['data']['id'];
-                }
-            }
-
-            for ($i = $pointer; $i < count($messages); $i++) {
-                Cache::put($pointerKey, $i);
-                $message = $messages[$i];
-                $taskDiscussionContent = [];
-                $param = [
-                    "model" => $message->model->model,
-                    "messages" => [
-                        ["role" => "system", "content" => $message->model->system_prompt ?? ''],
-                        ["role" => "user", "content" => $message->prompt],
-                    ],
-                    "temperature" => 0.7,
-                    "stream" => false
-                ];
-                Log::info($queue . ' LLM request' . $message->model->url);
-                Log::info($queue . ' model:' . $param['model']);
-                Log::debug($queue . ' LLM api request', [
-                    'url' => $message->model->url,
-                    'data' => $param
-                ]);
-
-                //写入 model log
-                $modelLogData = [
-                    'model_id' => $message->model->uid,
-                    'request_at' => now(),
-                    'request_data' => json_encode($param, JSON_UNESCAPED_UNICODE),
-                ];
-
-                try {
-                    $response = Http::withToken($message->model->key)
-                        ->timeout(300)
-                        ->post($message->model->url, $param);
-
-                    $response->throw(); // 触发异常(如果请求失败)
-                    $taskDiscussionContent[] = '- LLM request successful';
-                    Log::info($queue . ' LLM request successful');
-
-                    $modelLogData['request_headers'] = json_encode($response->handlerStats(), JSON_UNESCAPED_UNICODE);
-                    $modelLogData['response_headers'] = json_encode($response->headers(), JSON_UNESCAPED_UNICODE);
-                    $modelLogData['status'] = $response->status();
-                    $modelLogData['response_data'] = json_encode($response->json(), JSON_UNESCAPED_UNICODE);
-                    self::saveModelLog($modelToken, $modelLogData);
-                    /*
-                if ($response->failed()) {
-                    $modelLog->success = false;
-                    $modelLog->save();
-                    Log::error($queue . ' http response error', ['data' => $response->json()]);
-                    return 1;
-                }*/
-                } catch (RequestException $e) {
-                    Log::error($queue . ' LLM request exception: ' . $e->getMessage());
-                    $failResponse = $e->response;
-
-                    $modelLogData['request_headers'] = json_encode($failResponse->handlerStats(), JSON_UNESCAPED_UNICODE);
-                    $modelLogData['response_headers'] = json_encode($failResponse->headers(), JSON_UNESCAPED_UNICODE);
-                    $modelLogData['status'] = $failResponse->status();
-                    $modelLogData['response_data'] = $response->body();
-                    $modelLogData['success'] = false;
-                    self::saveModelLog($modelToken, $modelLogData);
-                    continue;
-                }
-                Log::info($queue . ' model log saved');
-
-                $aiData = $response->json();
-                Log::debug($queue . ' LLM http response', ['data' => $response->json()]);
-                $responseContent = $aiData['choices'][0]['message']['content'];
-                if (isset($aiData['choices'][0]['message']['reasoning_content'])) {
-                    $reasoningContent = $aiData['choices'][0]['message']['reasoning_content'];
-                }
-
-                Log::debug($queue . ' LLM response content=' . $responseContent);
-                if (empty($reasoningContent)) {
-                    Log::debug($queue . ' no reasoningContent');
-                } else {
-                    Log::debug($queue . ' reasoning=' . $reasoningContent);
-                }
-
-
-
-                if ($message->task->info->category === 'translate') {
-                    //写入句子库
-                    $url = config('app.url') . '/api/v2/sentence';
-                    $sentData = [];
-                    $message->sentence->content = $responseContent;
-                    $sentData[] = $message->sentence;
-                    Log::info($queue . " sentence update {$url}");
-                    $response = Http::timeout(10)->withToken($modelToken)->post($url, [
-                        'sentences' => $sentData,
-                    ]);
-                    if ($response->failed()) {
-                        Log::error($queue . ' sentence update failed', [
-                            'url' => $url,
-                            'data' => $response->json(),
-                        ]);
-                        continue;
-                    } else {
-                        $count = $response->json()['data']['count'];
-                        Log::info("{$queue} sentence update {$count} successful");
-                    }
-                }
-                if ($message->task->info->category === 'suggest') {
-                    //写入pr
-                    $url = config('app.url') . '/api/v2/sentpr';
-                    Log::info($queue . " sentence update {$url}");
-                    $response = Http::timeout(10)->withToken($modelToken)->post($url, [
-                        'book' => $message->sentence->book_id,
-                        'para' => $message->sentence->paragraph,
-                        'begin' => $message->sentence->word_start,
-                        'end' => $message->sentence->word_end,
-                        'channel' => $message->sentence->channel_uid,
-                        'text' => $responseContent,
-                        'notification' => false,
-                        'webhook' => false,
-                    ]);
-                    if ($response->failed()) {
-                        Log::error($queue . ' sentence update failed', [
-                            'url' => $url,
-                            'data' => $response->json(),
-                        ]);
-                        continue;
-                    } else {
-                        if ($response->json()['ok']) {
-                            Log::info("{$queue} sentence suggest update successful");
-                        } else {
-                            Log::error("{$queue} sentence suggest update failed", [
-                                'url' => $url,
-                                'data' => $response->json(),
-                            ]);
-                        }
-                    }
-                }
-
-                //写入discussion
-                #获取句子id
-                $url = config('app.url') . '/api/v2/sentence-info/aa';
-                Log::info('ai translate', ['url' => $url]);
-                $response = Http::timeout(10)->withToken($modelToken)->get($url, [
-                    'book' => $message->sentence->book_id,
-                    'par' => $message->sentence->paragraph,
-                    'start' => $message->sentence->word_start,
-                    'end' => $message->sentence->word_end,
-                    'channel' => $message->sentence->channel_uid
-                ]);
-                if ($response->json()['ok']) {
-                    $sUid = $response->json()['data']['id'];
-                } else {
-                    Log::error($queue . ' sentence id error', ['data' => $response->json()]);
-                    return 1;
-                }
-                $url = config('app.url') . '/api/v2/discussion';
-                $data = [
-                    'res_id' => $sUid,
-                    'res_type' => 'sentence',
-                    'title' => $message->task->info->title,
-                    'content' => $message->task->info->category,
-                    'content_type' => 'markdown',
-                    'type' => 'discussion',
-                    'notification' => false,
-                ];
-                $response = Http::timeout(10)->withToken($modelToken)->post($url, $data);
-                if ($response->failed()) {
-                    Log::error($queue . ' discussion create topic error', ['data' => $response->json()]);
-                } else {
-                    if (isset($response->json()['data']['id'])) {
-                        Log::info($queue . ' discussion create topic successful');
-                        $data['parent'] = $response->json()['data']['id'];
-                        unset($data['title']);
-                        $topicChildren = [];
-                        //提示词
-                        $topicChildren[] = $message->prompt;
-                        //任务结果
-                        $topicChildren[] = $responseContent;
-                        //推理过程写入discussion
-                        if (isset($reasoningContent) && !empty($reasoningContent)) {
-                            $topicChildren[] = $reasoningContent;
-                        }
-                        foreach ($topicChildren as  $content) {
-                            $data['content'] = $content;
-                            Log::debug($queue . ' discussion child request', ['url' => $url, 'data' => $data]);
-                            $response = Http::timeout(10)->withToken($modelToken)->post($url, $data);
-                            if ($response->failed()) {
-                                Log::error($queue . ' discussion error', ['data' => $response->json()]);
-                            } else {
-                                Log::info($queue . ' discussion child successful');
-                            }
-                        }
-                    } else {
-                        Log::error($queue . ' discussion create topic response is null');
-                    }
-                }
-
-
-                //修改task 完成度
-                $taskProgress = $message->task->progress;
-                if ($taskProgress->total > 0) {
-                    $progress = (int)($taskProgress->current * 100 / $taskProgress->total);
-                } else {
-                    $progress = 100;
-                    Log::error($queue . ' progress total is zero', ['task_id' => $message->task->info->id]);
-                }
-                $url = config('app.url') . '/api/v2/task/' . $message->task->info->id;
-                $data = [
-                    'progress' => $progress,
-                ];
-                Log::debug($queue . ' task progress request', ['url' => $url, 'data' => $data]);
-                $response = Http::timeout(10)->withToken($modelToken)->patch($url, $data);
-                if ($response->failed()) {
-                    Log::error($queue . ' task progress error', ['data' => $response->json()]);
-                } else {
-                    $taskDiscussionContent[] = "- progress=" . $response->json()['data']['progress'];
-                    Log::info($queue . ' task progress successful progress=' . $response->json()['data']['progress']);
-                }
-
-                if (isset($taskDiscussionData['parent'])) {
-                    unset($taskDiscussionData['title']);
-                    $taskDiscussionData['content'] = implode('\n', $taskDiscussionContent);
-                    Log::debug($queue . ' task discussion child request', ['url' => $discussionUrl, 'data' => $data]);
-                    $response = Http::timeout(10)->withToken($modelToken)->post($discussionUrl, $taskDiscussionData);
-                    if ($response->failed()) {
-                        Log::error($queue . ' task discussion error', ['data' => $response->json()]);
-                    } else {
-                        Log::info($queue . ' task discussion child successful');
-                    }
-                } else {
-                    Log::error('no task discussion root');
-                }
-
-                //任务完成 修改任务状态为 done
-                if ($progress === 100) {
-                    $this->setTaskStatus($message->task->info->id, 'done', $modelToken);
-                }
-            }
-            Cache::forget($pointerKey);
-            $this->info('ai translate task complete');
-            return 0;
-        });
-        return 0;
-    }
-    private function setTaskStatus($taskId, $status, $token)
-    {
-        $url = config('app.url') . '/api/v2/task-status/' . $taskId;
-        $data = [
-            'status' => $status,
-        ];
-        Log::debug('ai_translate task status request', ['url' => $url, 'data' => $data]);
-        $response = Http::timeout(10)->withToken($token)->patch($url, $data);
-        //判断状态码
-        if ($response->failed()) {
-            Log::error('ai_translate task status error', ['data' => $response->json()]);
-        } else {
-            Log::info('ai_translate task status done');
-        }
-    }
-
-    private function saveModelLog($token, $data)
-    {
-        $url = config('app.url') . '/api/v2/model-log';
-
-        $response = Http::timeout(10)->withToken($token)->post($url, $data);
-        if ($response->failed()) {
-            Log::error('ai-translate model log create failed', ['data' => $response->json()]);
-            return false;
-        }
-        return true;
-    }
-}

+ 0 - 313
api-v12/app/Console/Commands/MqDiscussion.php

@@ -1,313 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Str;
-
-use App\Models\Sentence;
-use App\Models\WebHook;
-use App\Models\Discussion;
-use App\Models\Article;
-use App\Models\DhammaTerm;
-use App\Models\Wbw;
-use App\Models\WbwBlock;
-use App\Http\Api\Mq;
-use App\Tools\WebHook as WebHookSend;
-use App\Http\Api\MdRender;
-use App\Http\Api\UserApi;
-use App\Http\Controllers\NotificationController;
-
-
-class MqDiscussion extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan mq:discussion
-     * @var string
-     */
-    protected $signature = 'mq:discussion';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $exchange = 'router';
-        $queue = 'discussion';
-        $this->info(" [*] Waiting for {$queue}. To exit press CTRL+C");
-        Log::info("discussion worker start .");
-        Mq::worker($exchange, $queue, function ($message) {
-            Log::info('mq discussion receive {message}', ['message' => json_encode($message, JSON_UNESCAPED_UNICODE)]);
-            $result = 0;
-            $msgParam = array();
-            $msgParam['nickname'] = $message->editor->nickName;
-            $link = config('app.url') . "/pcd/discussion/topic/";
-            if ($message->parent) {
-                $msgParam['topic-title'] = Discussion::where('id', $message->parent)->value('title');
-                $id = $message->id;
-                $msgParam['link'] = $link . $message->parent . '#' . $id;
-                $msgParam['card_title'] = "回复讨论";
-                $type = 'reply';
-            } else {
-                $msgParam['title'] = $message->title;
-                $msgParam['link'] = $link . $message->id;
-                $msgParam['card_title'] = "创建讨论";
-                $type = 'create';
-            }
-            if ($message->content) {
-                $msgParam['content'] = $message->content;
-            }
-
-            switch ($message->res_type) {
-                case 'sentence':
-                    $sentence = Sentence::where('uid', $message->res_id)->first();
-                    if (!$sentence) {
-                        Log::error('invalid sentence id ' . $message->res_id);
-                        $result = 1;
-                        break;
-                    }
-
-                    //站内信
-                    try {
-                        $sendTo = array();
-                        //句子的channel拥有者
-                        //$sendTo[] = $prData->channel->studio_id;
-                        //句子的作者
-                        if (!in_array($sentence->editor_uid, $sendTo)) {
-                            $sendTo[] = $sentence->editor_uid;
-                        }
-                        //句子的采纳者
-                        if (!empty($sentence->acceptor_uid) && !in_array($sentence->acceptor_uid, $sendTo)) {
-                            $sendTo[] = $sentence->acceptor_uid;
-                        }
-                        $this->notification(
-                            $message->editor->id,
-                            $sendTo,
-                            'discussion',
-                            $message->id,
-                            $sentence->channel_uid
-                        );
-                    } catch (\Exception $e) {
-                        Log::error('send notification failed', ['exception' => $e]);
-                    }
-
-                    //webhook
-                    $contentHtml = MdRender::render(
-                        $sentence->content,
-                        [$sentence->channel_uid],
-                        null,
-                        'read',
-                        'translation',
-                        $sentence->content_type
-                    );
-                    $contentTxt = strip_tags($contentHtml);
-                    /**生成消息内容 */
-
-                    $msgParam['anchor-content'] = $contentTxt;
-                    $WebHookResId = $sentence->channel_uid;
-
-                    $this->WebHook($msgParam, $type, $WebHookResId);
-                    break;
-                case 'wbw':
-                    $wbw = Wbw::where('uid', $message->res_id)->first();
-                    if (!$wbw) {
-                        Log::error('invalid wbw id ' . $message->res_id);
-                        $result = 1;
-                        break;
-                    }
-                    $wbwBlock = WbwBlock::where('uid', $wbw->block_uid)->first();
-                    if (!$wbwBlock) {
-                        Log::error('invalid wbw-block id ' . $message->res_id);
-                        $result = 1;
-                        break;
-                    }
-
-                    //站内信
-                    try {
-                        $sendTo = array();
-                        //channel拥有者
-                        //$sendTo[] = $prData->channel->studio_id;
-                        //作者
-                        if (!in_array($wbw->creator_uid, $sendTo)) {
-                            $sendTo[] = $wbw->creator_uid;
-                        }
-                        //提问者
-                        if (!empty($message->parent)) {
-                            $topicEditor = Discussion::where('id', $message->parent)
-                                ->value('editor_uid');
-                            if (!empty($topicEditor) && !in_array($topicEditor, $sendTo)) {
-                                $sendTo[] = $topicEditor;
-                                Log::debug('发送给提问者', ['data' => $topicEditor]);
-                            }
-                        }
-
-                        $this->notification(
-                            $message->editor->id,
-                            $sendTo,
-                            'discussion',
-                            $message->id,
-                            $wbwBlock->channel_uid
-                        );
-                    } catch (\Exception $e) {
-                        Log::error('send notification failed', ['exception' => $e]);
-                    }
-
-                    $msgParam['anchor-content'] = $wbw->word;
-                    $WebHookResId = $wbwBlock->channel_uid;
-                    $this->WebHook($msgParam, $type, $WebHookResId);
-                    break;
-                case 'term':
-                    $term = DhammaTerm::where('guid', $message->res_id)->first();
-                    if (!$term) {
-                        Log::error('invalid term id ' . $message->res_id);
-                        $result = 1;
-                        break;
-                    }
-                    if (empty($term->channal) || !Str::isUuid($term->channal)) {
-                        break;
-                    }
-
-
-                    //站内信
-                    try {
-                        $sendTo = array();
-                        //拥有者
-                        $sendTo[] = $term->term;
-                        //作者
-                        $editor = UserApi::getById($term->editor_id);
-                        if ($editor['id'] !== 0 && !in_array($editor['id'], $sendTo)) {
-                            $sendTo[] = $editor['id'];
-                        }
-                        $this->notification(
-                            $message->editor->id,
-                            $sendTo,
-                            'discussion',
-                            $message->id,
-                            $term->channal
-                        );
-                    } catch (\Exception $e) {
-                        Log::error('send notification failed', ['exception' => $e]);
-                    }
-                    //webhook
-                    $msgParam['anchor-content'] = $term->meaning . '(' . $term->word . ')';
-                    $WebHookResId = $term->channal;
-                    $this->WebHook($msgParam, 'term', $WebHookResId);
-
-                    break;
-                default:
-                    # code...
-                    break;
-            }
-
-            return $result;
-        });
-
-        return 0;
-    }
-
-    private function WebHook($msgParam, $type, $resId)
-    {
-        $rootId = UserApi::getById(0)['id'];
-        $articleTitle = "webhook://discussion/{$type}/zh-hans";
-        $tpl = Article::where('owner', $rootId)
-            ->where('title', $articleTitle)
-            ->value('content');
-        if (empty($tpl)) {
-            Log::error('mq:discussion 模版不能为空', ['tpl_title' => $articleTitle]);
-            return 1;
-        }
-        $m = new \Mustache_Engine(array(
-            'entity_flags' => ENT_QUOTES,
-            'delimiters' => '{% %}',
-        ));
-        $msgContent = $m->render($tpl, $msgParam);
-
-        $webhooks = WebHook::where('res_id', $resId)
-            ->where('status', 'active')
-            ->get();
-        $result = 0;
-        foreach ($webhooks as $key => $hook) {
-            $event = json_decode($hook->event);
-
-            if (is_array($event)) {
-                if (!in_array('discussion', $event)) {
-                    continue;
-                }
-            } else {
-                continue;
-            }
-            $command = '';
-            $whSend = new WebHookSend;
-            $ok = 0;
-            switch ($hook->receiver) {
-                case 'dingtalk':
-                    $ok = $whSend->dingtalk($hook->url, $msgParam['card_title'], $msgContent);
-                    break;
-                case 'wechat':
-                    $ok = $whSend->wechat($hook->url, null, $msgContent);
-                    break;
-                default:
-                    $ok = 2;
-                    break;
-            }
-            $result += $ok;
-            $logMsg = "{$command}  ok={$ok}";
-            if ($ok === 0) {
-                $this->info($logMsg);
-            } else {
-                $this->error($logMsg);
-            }
-
-            if ($ok === 0) {
-                Log::debug('mq:discussion: send success {url}', ['url' => $hook->url]);
-                WebHook::where('id', $hook->id)->increment('success');
-            } else {
-                Log::error('mq:discussion: send fail {url}', ['url' => $hook->url]);
-                WebHook::where('id', $hook->id)->increment('fail');
-            }
-        }
-    }
-
-    private function notification($from, $to, $resType, $resId, $channel)
-    {
-        //发送站内信
-        try {
-
-            $sendCount = NotificationController::insert(
-                $from,
-                $to,
-                $resType,
-                $resId,
-                $channel
-            );
-            $this->info("send notification success to [" . $sendCount . '] users');
-        } catch (\Exception $e) {
-            Log::error('send notification failed', ['exception' => $e]);
-        }
-        return;
-    }
-}

+ 0 - 61
api-v12/app/Console/Commands/MqEmpty.php

@@ -1,61 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Log;
-use App\Http\Api\Mq;
-
-class MqEmpty extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'mq:empty';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $exchange = 'router';
-        $queue = 'ai_translate';
-        $this->info(" [*] Waiting for {$queue}. To exit press CTRL+C");
-        Log::debug("mq worker {$queue} start.");
-        Mq::worker(
-            $exchange,
-            $queue,
-            function ($message) {
-                $this->info('new message');
-                sleep(3);
-                return 0;
-            }
-        );
-
-        return 0;
-    }
-}

+ 0 - 71
api-v12/app/Console/Commands/MqExport.php

@@ -1,71 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\Mq;
-use Illuminate\Support\Facades\Log;
-
-class MqExport extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan mq:export
-     * @var string
-     */
-    protected $signature = 'mq:export';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '导出功能用的消息队列';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $exchange = 'router';
-        $queue = 'export';
-        $this->info(" [*] Waiting for {$queue}. To exit press CTRL+C");
-        Log::debug("mq:progress start.");
-        Mq::worker($exchange,$queue,function ($message){
-            $data = [
-                        'book'=>$message->book,
-                        'para'=>$message->para,
-                        'channel'=>$message->channel,
-                        '--format'=>$message->format,
-                        'filename'=>$message->filename,
-                    ];
-            if(isset($message->origin) && is_string($message->origin)){
-                $data['--origin'] = $message->origin;
-            }
-            if(isset($message->translation) && is_string($message->translation)){
-                $data['--translation'] = $message->translation;
-            }
-            $ok = $this->call('export:chapter',$data);
-            if($ok !== 0){
-                Log::error('mq:progress upgrade:progress fail',$data);
-            }else{
-                $this->info("Received book=".$message->book.' result='.$ok);
-                Log::debug("mq:export: done ",$data);
-                return $ok;
-            }
-        });
-        return 0;
-    }
-}

+ 0 - 75
api-v12/app/Console/Commands/MqExportArticle.php

@@ -1,75 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\Mq;
-use Illuminate\Support\Facades\Log;
-
-class MqExportArticle extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan mq:export.article
-     * @var string
-     */
-    protected $signature = 'mq:export.article';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '导出文章';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $exchange = 'router';
-        $queue = 'export_article';
-        $this->info(" [*] Waiting for {$queue}. To exit press CTRL+C");
-        Log::debug("mq:export_article start.");
-        Mq::worker($exchange,$queue,function ($message){
-            $data = [
-                        'id'=>$message->id,
-                        '--format'=>$message->format,
-                        'query_id'=>$message->queryId,
-                        '--origin'=>$message->origin,
-                        '--translation'=>$message->translation,
-                    ];
-            if(isset($message->token) && is_string($message->token)){
-                $data['--token'] = $message->token;
-            }
-            if(isset($message->anthology) && is_string($message->anthology)){
-                $data['--anthology'] = $message->anthology;
-            }
-            if(isset($message->channel) && is_string($message->channel)){
-                $data['--channel'] = $message->channel;
-            }
-            $ok = $this->call('export:article',$data);
-            if($ok !== 0){
-                Log::error('mq:export.article fail',$data);
-            }else{
-                $this->info("Received article id=".$message->id.' result='.$ok);
-                Log::debug("mq:export.article done ",$data);
-                return $ok;
-            }
-        });
-
-        return 0;
-    }
-}

+ 0 - 74
api-v12/app/Console/Commands/MqExportPaliChapter.php

@@ -1,74 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\Mq;
-use Illuminate\Support\Facades\Log;
-
-class MqExportPaliChapter extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan mq:export.pali.chapter
-     * @var string
-     */
-    protected $signature = 'mq:export.pali.chapter';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '导出巴利文章节';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $exchange = 'router';
-        $queue = 'export_pali_chapter';
-        $this->info(" [*] Waiting for {$queue}. To exit press CTRL+C");
-        Log::debug("mq:export_pali_chapter start.");
-        Mq::worker($exchange,$queue,function ($message){
-            $data = [
-                        'book'=>$message->book,
-                        'para'=>$message->para,
-                        'channel'=>$message->channel,
-                        '--format'=>$message->format,
-                        'query_id'=>$message->queryId,
-                    ];
-            if(isset($message->origin) && is_string($message->origin)){
-                $data['--origin'] = $message->origin;
-            }
-            if(isset($message->translation) && is_string($message->translation)){
-                $data['--translation'] = $message->translation;
-            }
-            if(isset($message->token) && is_string($message->token)){
-                $data['--token'] = $message->token;
-            }
-            $ok = $this->call('export:chapter',$data);
-            if($ok !== 0){
-                Log::error('mq:export.pali.chapter upgrade:progress fail',$data);
-            }else{
-                $this->info("Received book=".$message->book.' result='.$ok);
-                Log::debug("mq:export.pali.chapter done ",$data);
-                return $ok;
-            }
-        });
-        return 0;
-    }
-}

+ 0 - 53
api-v12/app/Console/Commands/MqIssues.php

@@ -1,53 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\Mq;
-
-class MqIssues extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan mq:issues
-     * @var string
-     */
-    protected $signature = 'mq:issues';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $exchange = 'router';
-        $queue = 'issues';
-        $this->info(" [*] Waiting for {$queue}. To exit press CTRL+C");
-        Mq::worker($exchange,$queue,function ($message){
-            print_r($message);
-            return 0;
-        });
-        return 0;
-    }
-}

+ 0 - 174
api-v12/app/Console/Commands/MqPr.php

@@ -1,174 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Http;
-use Illuminate\Support\Facades\Log;
-
-use App\Http\Api\Mq;
-use App\Models\Sentence;
-use App\Models\WebHook;
-use App\Models\PaliSentence;
-use App\Tools\WebHook as WebHookSend;
-use App\Http\Api\MdRender;
-use App\Http\Api\PaliTextApi;
-use App\Http\Controllers\NotificationController;
-
-class MqPr extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan mq:pr
-     * @var string
-     */
-    protected $signature = 'mq:pr';
-
-    protected $ver = '2024-1-2';
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'push pr message to mq';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $exchange = 'router';
-        $queue = 'suggestion';
-        $this->info(" [*] Waiting for {$queue}. Ver. " . $this->ver);
-        Log::debug("mq:pr start. ver=" . $this->ver);
-        Mq::worker($exchange, $queue, function ($message) {
-            /**生成消息内容 */
-
-            $msgTitle = '修改建议';
-            $prData = $message->data;
-            $sent_num = "{$prData->book}-{$prData->paragraph}-{$prData->word_start}-{$prData->word_end}";
-            $this->info('ver=' . $this->ver . ' request' . $sent_num);
-
-            $username = $prData->editor->nickName;
-            $palitext = PaliSentence::where('book', $prData->book)
-                ->where('paragraph', $prData->paragraph)
-                ->where('word_begin', $prData->word_start)
-                ->where('word_end', $prData->word_end)
-                ->value('text');
-            $orgText = Sentence::where('book_id', $prData->book)
-                ->where('paragraph', $prData->paragraph)
-                ->where('word_start', $prData->word_start)
-                ->where('word_end', $prData->word_end)
-                ->where('channel_uid', $prData->channel->id)
-                ->first();
-            $prtext = mb_substr($prData->content, 0, 140, "UTF-8");
-
-            $link = config('app.url') . "/pcd/article/para/{$prData->book}-{$prData->paragraph}";
-            $link .= "?book={$prData->book}&par={$prData->paragraph}&channel={$prData->channel->id}";
-
-            $msgContent = "{$username} 就文句`{$palitext}`提出了修改建议:\n";
-            $msgContent .= ">内容摘要:<font color=\"comment\">{$prtext}</font>,\n";
-            $msgContent .= ">句子编号:<font color=\"info\">{$sent_num}</font>\n";
-            $msgContent .= "欢迎大家[点击链接]({$link})查看并讨论。";
-
-
-            $result = 0;
-            //发送站内信
-            if ($message->webhook) {
-
-                try {
-                    $sendTo = array();
-                    if ($prData->editor->id !== $prData->channel->studio_id) {
-                        $sendTo[] = $prData->channel->studio_id;
-                    }
-                    if ($orgText) {
-                        //原文作者
-                        if (
-                            !in_array($orgText->editor_uid, $sendTo) &&
-                            $orgText->editor_uid !== $prData->editor->id
-                        ) {
-                            $sendTo[] = $orgText->editor_uid;
-                        }
-                        //原文采纳者
-                        if (
-                            !empty($orgText->acceptor_uid) &&
-                            !in_array($orgText->acceptor_uid, $sendTo) &&
-                            $orgText->acceptor_uid !== $prData->editor->id
-                        ) {
-                            $sendTo[] = $orgText->acceptor_uid;
-                        }
-                    }
-                    if (count($sendTo) > 0) {
-                        $sendCount = NotificationController::insert(
-                            from: $prData->editor->id,
-                            to: $sendTo,
-                            res_type: 'suggestion',
-                            res_id: $prData->uid,
-                            channel: $prData->channel->id
-                        );
-                    }
-
-                    $this->info("send notification success to [" . count($sendTo) . '] users');
-                } catch (\Exception $e) {
-                    $this->error('send notification failed');
-                    Log::error('send notification failed', ['exception' => $e]);
-                }
-            }
-
-            //发送webhook
-            if ($message->webhook) {
-                $webhooks = WebHook::where('res_id', $prData->channel->id)
-                    ->where('status', 'active')
-                    ->get();
-
-
-                foreach ($webhooks as $key => $hook) {
-                    $event = json_decode($hook->event);
-                    if (!in_array('pr', $event)) {
-                        continue;
-                    }
-                    $command = '';
-                    $whSend = new WebHookSend;
-                    switch ($hook->receiver) {
-                        case 'dingtalk':
-                            $ok = $whSend->dingtalk($hook->url, $msgTitle, $msgContent);
-                            break;
-                        case 'wechat':
-                            $ok = $whSend->wechat($hook->url, null, $msgContent);
-                            break;
-                        default:
-                            $ok = 2;
-                            break;
-                    }
-                    $this->info("{$command}  ok={$ok}");
-                    $result += $ok;
-                    if ($ok === 0) {
-                        Log::debug('mq:pr: send success {url}', ['url' => $hook->url]);
-                        WebHook::where('id', $hook->id)->increment('success');
-                    } else {
-                        Log::error('mq:pr: send fail {url}', ['url' => $hook->url]);
-                        WebHook::where('id', $hook->id)->increment('fail');
-                    }
-                }
-            }
-
-            return $result;
-        });
-        return 0;
-    }
-}

+ 0 - 70
api-v12/app/Console/Commands/MqProgress.php

@@ -1,70 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\Mq;
-use Illuminate\Support\Facades\Log;
-
-class MqProgress extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan mq:progress
-     * @var string
-     */
-    protected $signature = 'mq:progress';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $exchange = 'router';
-        $queue = 'progress';
-        $this->info(" [*] Waiting for {$queue}. To exit press CTRL+C");
-        Log::debug("mq:progress start.");
-        Mq::worker($exchange,$queue,function ($message){
-            $data = [
-                        '--book'=>$message->book,
-                        '--para'=>$message->para,
-                        '--channel'=>$message->channel,
-                    ];
-            $ok1 = $this->call('upgrade:progress',$data);
-            if($ok1 !== 0){
-                Log::error('mq:progress upgrade:progress fail',$data);
-            }
-            $ok2 = $this->call('upgrade:progress.chapter',$data);
-            if($ok2 !== 0){
-                Log::error('mq:progress upgrade:progress.chapter fail',$data);
-            }
-            $this->info("Received book=".$message->book.' progress='.$ok1.' chapter='.$ok2);
-            Log::debug("mq:progress: done book=".$message->book.' progress='.$ok1.' chapter='.$ok2);
-            return $ok1+$ok2;
-        });
-        return 0;
-
-    }
-}

+ 0 - 57
api-v12/app/Console/Commands/MqTask.php

@@ -1,57 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\Mq;
-use Illuminate\Support\Facades\Log;
-
-class MqTask extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'mq:task';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'run task';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $this->info('env='.env("RABBITMQ_HOST"));
-        $this->info('config='.config("queue.connections.rabbitmq.host"));
-        $exchange = 'router';
-        $queue = 'task';
-        $this->info(" [*] Waiting for {$queue}. To exit press CTRL+C");
-        Mq::worker($exchange,$queue,function ($message){
-            $message = json_decode(json_encode($message), true);
-            $this->info('name=',$message['name']);
-            return $this->call($message['name'],$message['param']);
-        });
-        return 0;
-    }
-}

+ 0 - 63
api-v12/app/Console/Commands/MqWbwAnalyses.php

@@ -1,63 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\Mq;
-use Illuminate\Support\Facades\Log;
-
-class MqWbwAnalyses extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'mq:wbw.analyses';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $exchange = 'router';
-        $queue = 'wbw-analyses';
-        $this->info(" [*] Waiting for {$queue}. To exit press CTRL+C");
-        Log::debug("mq:wbw.analyses start.");
-        Mq::worker($exchange,$queue,function ($message){
-            $data = ['id'=>implode(',',$message)];
-            $ok = $this->call('upgrade:wbw.analyses',$data);
-            if($ok === 0){
-                $this->info("Received count=".count($message).' ok='.$ok);
-                Log::debug('mq:wbw.analyses done count='.count($message));
-            }else{
-                Log::error('mq:wbw.analyses',$data);
-            }
-            return $ok;
-        });
-
-        return 0;
-    }
-}

+ 0 - 44
api-v12/app/Console/Commands/PatchWbwPageNumber.php

@@ -1,44 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-
-class PatchWbwPageNumber extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'command:name';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '修补vri原文件中的页码错误';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        /**
-         */
-        return 0;
-    }
-}

+ 0 - 33
api-v12/app/Console/Commands/PostInstall.php

@@ -1,33 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-
-class DeplyInit extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'app:post-install';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Execute the console command.
-     */
-    public function handle()
-    {
-        //
-        $this->info('deploy init start');
-        $this->call('create:opensearch.index');
-        $this->info('deploy init done');
-    }
-}

+ 0 - 92
api-v12/app/Console/Commands/ProcessDeadLetterQueue.php

@@ -1,92 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use PhpAmqpLib\Connection\AMQPStreamConnection;
-use PhpAmqpLib\Message\AMQPMessage;
-use Illuminate\Support\Facades\Log;
-
-class ProcessDeadLetterQueue extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * 查看死信队列消息
-     * php artisan rabbitmq:process-dlq orders_dlq
-     *
-     * 重新入队死信消息
-     * php artisan rabbitmq:process-dlq orders_dlq --requeue
-     *
-     * 删除死信消息
-     * php artisan rabbitmq:process-dlq orders_dlq --delete
-     * @var string
-     */
-    protected $signature = 'rabbitmq:process-dlq {dlq_name} {--requeue} {--delete}';
-    protected $description = '处理死信队列中的消息';
-
-    public function handle()
-    {
-        $dlqName = $this->argument('dlq_name');
-        $requeue = $this->option('requeue');
-        $delete = $this->option('delete');
-
-        $config = config('queue.connections.rabbitmq');
-        $connection = new AMQPStreamConnection(
-            $config['host'],
-            $config['port'],
-            $config['user'],
-            $config['password'],
-            $config['virtual_host']
-        );
-
-        $channel = $connection->channel();
-
-        $this->info("开始处理死信队列: {$dlqName}");
-
-        $messageCount = 0;
-
-        while (true) {
-            $msg = $channel->basic_get($dlqName, false);
-
-            if (!$msg) {
-                break; // 队列为空
-            }
-
-            $messageCount++;
-            $data = json_decode($msg->body, true);
-
-            $this->info("处理第 {$messageCount} 条死信消息");
-            $this->line("原始队列: " . ($data['queue'] ?? 'unknown'));
-            $this->line("失败原因: " . ($data['failure_reason'] ?? 'unknown'));
-            $this->line("失败时间: " . ($data['failed_at'] ?? 'unknown'));
-
-            if ($requeue) {
-                // 重新入队到原始队列
-                $originalQueue = $data['queue'] ?? null;
-                if ($originalQueue && isset($data['original_message'])) {
-                    $requeueMsg = new AMQPMessage(
-                        json_encode($data['original_message']),
-                        ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]
-                    );
-
-                    $channel->basic_publish($requeueMsg, '', $originalQueue);
-                    $this->info("消息已重新入队到: {$originalQueue}");
-                }
-            }
-
-            if ($delete || $requeue) {
-                $msg->ack();
-            } else {
-                // 只是查看,不删除
-                $msg->nack(false, true);
-            }
-        }
-
-        $this->info("死信队列处理完成,共处理 {$messageCount} 条消息");
-
-        $channel->close();
-        $connection->close();
-
-        return 0;
-    }
-}

+ 0 - 313
api-v12/app/Console/Commands/RabbitMQWorker.php

@@ -1,313 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use PhpAmqpLib\Message\AMQPMessage;
-use App\Jobs\ProcessAITranslateJob;
-use App\Jobs\BaseRabbitMQJob;
-use Illuminate\Support\Facades\Log;
-use PhpAmqpLib\Exception\AMQPTimeoutException;
-use PhpAmqpLib\Wire\AMQPTable;
-use App\Services\RabbitMQService;
-use App\Exceptions\SectionTimeoutException;
-use App\Exceptions\TaskFailException;
-
-class RabbitMQWorker extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php -d memory_limit=128M artisan rabbitmq:consume ai_translate
-     * @var string
-     */
-    protected $signature = 'rabbitmq:consume {queue} {--reset-loop-count}';
-    protected $description = '消费 RabbitMQ 队列消息';
-
-    private $connection;
-    private $channel;
-    private $processedCount = 0;
-    private $maxLoopCount = 0;
-    private $queueName;
-    private $queueConfig;
-    private $shouldStop = false;
-    private $timeout = 15;
-    private $job = null;
-
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $this->queueName = $this->argument('queue');
-        $this->queueConfig = config("mint.rabbitmq.queues.{$this->queueName}");
-
-        if (!$this->queueConfig) {
-            $this->error("队列 {$this->queueName} 的配置不存在");
-            return 1;
-        }
-
-        $this->maxLoopCount = $this->queueConfig['max_loop_count'];
-
-        $this->info("启动 RabbitMQ Worker");
-        $this->info("队列: {$this->queueName}");
-        $this->info("最大循环次数: {$this->maxLoopCount}");
-        $this->info("重试次数: {$this->queueConfig['retry_times']}");
-        $consume = app(RabbitMQService::class);
-        try {
-            $consume->setupQueue($this->queueName);
-            $this->channel = $consume->getChannel();
-            $this->startConsuming();
-        } catch (\Exception $e) {
-            $this->error("Worker 启动失败: " . $e->getMessage());
-            Log::error("RabbitMQ Worker 启动失败", [
-                'queue' => $this->queueName,
-                'error' => $e->getMessage()
-            ]);
-            return 1;
-        } finally {
-            $this->cleanup();
-        }
-
-        return 0;
-    }
-
-    private function startConsuming()
-    {
-        $callback = function (AMQPMessage $msg) {
-            $this->processMessage($msg);
-        };
-
-        $this->channel->basic_consume(
-            $this->queueName,
-            '',     // consumer_tag
-            false,  // no_local
-            false,  // no_ack
-            false,  // exclusive
-            false,  // nowait
-            $callback
-        );
-
-        $this->info("开始消费消息... 按 Ctrl+C 退出");
-
-        // 设置信号处理
-        if (extension_loaded('pcntl')) {
-            pcntl_signal(SIGTERM, [$this, 'handleSignal']);
-            pcntl_signal(SIGINT, [$this, 'handleSignal']);
-        }
-
-        while ($this->channel->is_consuming() && !$this->shouldStop) {
-            try {
-                $this->channel->wait(null, false, $this->timeout);
-            } catch (AMQPTimeoutException $e) {
-                //忽略
-            } catch (\Exception $e) {
-                $this->error($e->getMessage());
-                throw $e;
-            }
-
-
-            if (extension_loaded('pcntl')) {
-                pcntl_signal_dispatch();
-            }
-
-            // 检查是否达到最大循环次数
-            if ($this->processedCount >= $this->maxLoopCount) {
-                $this->info("达到最大循环次数 ({$this->maxLoopCount}),Worker 自动退出");
-                break;
-            }
-            if (\App\Tools\Tools::isStop()) {
-                //检测到停止标记
-                break;
-            }
-        }
-    }
-
-    private function processMessage(AMQPMessage $msg)
-    {
-        try {
-
-            Log::info('processMessage start', ['message_id' => $msg->get('message_id')]);
-
-            $data = json_decode($msg->getBody());
-            $this->info("processMessage start " . $msg->get('message_id') . '[' . count($data) . ']');
-
-            if (json_last_error() !== JSON_ERROR_NONE) {
-                throw new \Exception("JSON 解析失败: " . json_last_error_msg());
-            }
-
-            // 获取重试次数(从消息头中获取)
-            $retryCount = 0;
-            if ($msg->has('application_headers')) {
-                $headers = $msg->get('application_headers')->getNativeData();
-                $retryCount = $headers['retry_count'] ?? 0;
-            }
-
-            // 根据队列类型创建对应的 Job
-            $this->job = $this->createJob($msg->get('message_id'), $data, $retryCount);
-
-            try {
-                // 执行业务逻辑
-                $this->job->handle();
-                // 成功处理,确认消息
-                $msg->ack();
-
-                $this->processedCount++;
-
-                $this->info("消息处理成功 [{$this->processedCount}/{$this->maxLoopCount}]");
-            } catch (SectionTimeoutException $e) {
-                $msg->nack(true, false);
-                Log::warning('attempt to requeue the message message_id:' . $msg->get('message_id'));
-            } catch (TaskFailException $e) {
-                $msg->nack(false, false);
-            } catch (\Exception $e) {
-                //requeue
-                $this->handleJobException($msg, $data, $retryCount, $e);
-            }
-        } catch (\Exception $e) {
-            $this->error("消息处理异常: " . $e->getMessage());
-            Log::error("RabbitMQ 消息处理异常", [
-                'queue' => $this->queueName,
-                'error' => $e->getMessage(),
-                'message_body' => $msg->getBody()
-            ]);
-
-            // 拒绝消息并发送到死信队列
-            //$msg->nack(false, false);
-            $this->sendToDeadLetterQueue($data, $e);
-            $msg->ack(); // 确认原消息以避免重复
-            $this->error("已发送到死信队列");
-            $this->processedCount++;
-        }
-    }
-
-    private function createJob(string $messageId, array $data, int $retryCount): BaseRabbitMQJob
-    {
-        // 根据队列名称创建对应的 Job 实例
-        switch ($this->queueName) {
-            case 'ai_translate':
-                return new ProcessAITranslateJob(
-                    $this->queueName,
-                    $messageId,
-                    $data,
-                    $retryCount,
-                );
-                // 可以添加更多队列类型
-            default:
-                throw new \Exception("未知的队列类型: {$this->queueName}");
-        }
-    }
-
-    private function handleJobException(AMQPMessage $msg, array $data, int $retryCount, \Exception $e)
-    {
-        $maxRetries = $this->queueConfig['retry_times'];
-
-        if ($retryCount < $maxRetries - 1) {
-            // 还有重试机会,重新入队
-            $this->requeueMessage($msg, $data, $retryCount + 1);
-            $this->info("消息重新入队,重试次数: " . ($retryCount + 1) . "/{$maxRetries}");
-        } else {
-            // 超过重试次数,发送到死信队列
-            $this->sendToDeadLetterQueue($data, $e);
-            $msg->ack(); // 确认原消息以避免重复
-            $this->error("消息超过最大重试次数,已发送到死信队列 ");
-            Log::error("消息超过最大重试次数,已发送到死信队列 message_id=" . $msg->get('message_id'));
-        }
-
-        $this->processedCount++;
-    }
-
-    private function requeueMessage(AMQPMessage $msg, array $data, int $newRetryCount)
-    {
-        // 添加重试计数到消息头
-        // 使用 AMQPTable 包装头部数据
-        $headers = new AMQPTable([
-            'retry_count' => $newRetryCount,
-            'original_queue' => $this->queueName,
-            'retry_timestamp' => time()
-        ]);
-
-        $newMsg = new AMQPMessage(
-            json_encode($data, JSON_UNESCAPED_UNICODE),
-            [
-                'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
-                'timestamp' => time(),
-                'message_id' => $msg->get('message_id'),
-                'application_headers' => $headers,
-                "content_type" => 'application/json; charset=utf-8'
-            ]
-        );
-
-        // 发布到同一队列
-        $this->channel->basic_publish($newMsg, '', $this->queueName);
-
-        // 确认原消息
-        $msg->ack();
-    }
-
-    private function sendToDeadLetterQueue(array $data, \Exception $e)
-    {
-        $dlqName = $this->queueConfig['dead_letter_queue'];
-
-        $dlqData = [
-            'original_message' => $data,
-            'failure_reason' => $e->getMessage(),
-            'failed_at' => date('Y-m-d H:i:s'),
-            'queue' => $this->queueName,
-            'max_retries' => $this->queueConfig['retry_times']
-        ];
-
-        $dlqMsg = new AMQPMessage(
-            json_encode($dlqData),
-            ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]
-        );
-
-        $this->channel->basic_publish($dlqMsg, '', $dlqName);
-
-        Log::error("消息发送到死信队列", [
-            'original_queue' => $this->queueName,
-            'dead_letter_queue' => $dlqName,
-            'error' => $e->getMessage()
-        ]);
-    }
-
-    /**
-     * 处理系统信号
-     *
-     * @param int $signal 信号类型
-     * @param int|false $previousExitCode 上一个退出码
-     * @return int|false 返回退出码或 false
-     */
-    public function handleSignal(int $signal, int|false $previousExitCode = 0): int|false
-    {
-        $this->info("接收到退出信号,正在优雅关闭...");
-        $this->shouldStop = true;
-
-        if ($this->job) {
-            $this->job->stop();
-        }
-
-        if ($this->channel && $this->channel->is_consuming()) {
-            //$this->channel->basic_cancel_on_shutdown(true);
-            $this->channel->basic_cancel('');
-        }
-
-        // 返回 false 表示信号已处理,不需要进一步传播
-        return false;
-    }
-
-    private function cleanup()
-    {
-        try {
-            if ($this->channel) {
-                $this->channel->close();
-            }
-            if ($this->connection) {
-                $this->connection->close();
-            }
-
-            $this->info("连接已关闭,处理了 {$this->processedCount} 条消息");
-        } catch (\Exception $e) {
-            $this->error("清理资源时出错: " . $e->getMessage());
-        }
-    }
-}

+ 0 - 61
api-v12/app/Console/Commands/RemoveTermCache.php

@@ -1,61 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\DhammaTerm;
-use App\Models\Channel;
-use Illuminate\Support\Facades\Cache;
-
-class RemoveTermCache extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'remove:term.cache {word?}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $word = $this->argument('word');
-        $channels = Channel::select('uid')->get();
-        if(empty($word)){
-
-        }else{
-            foreach ($channels as $key => $channel) {
-                $key = "/term/{$channel}/{$word}";
-                if(Cache::has($key)){
-                    $this->info('has:'.$key);
-                    Cache::forget($key);
-                }
-            }
-        }
-        return 0;
-    }
-}

+ 0 - 80
api-v12/app/Console/Commands/StatisticsDict.php

@@ -1,80 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use Carbon\Carbon;
-use App\Models\UserOperationLog;
-
-class StatisticsDict extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'statistics:dict';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '统计 字典 每月查询';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $file = "public/statistics/lookup-monthly.csv";
-        Storage::disk('local')->put($file, "");
-        #按月获取数据
-        $firstDay = UserOperationLog::where('op_type','dict_lookup')
-                            ->orderBy('created_at')
-                            ->select('created_at')
-                            ->first();
-        $firstDay = strtotime($firstDay->created_at);
-        $firstMonth = Carbon::create(date("Y-m",$firstDay));
-        $now = Carbon::now();
-        $current = $firstMonth;
-        $sumCount = 0;
-        while ($current <= $now) {
-            # code...
-            $start = Carbon::create($current)->startOfMonth();
-            $end = Carbon::create($current)->endOfMonth();
-            $date = $current->format('Y-m');
-            $count = UserOperationLog::where('op_type','dict_lookup')
-                              ->whereDate('created_at','>=',$start)
-                              ->whereDate('created_at','<=',$end)
-                              ->count();
-            $sumCount += $count;
-            $editor = UserOperationLog::where('op_type','dict_lookup')
-                              ->whereDate('created_at','>=',$start)
-                              ->whereDate('created_at','<=',$end)
-                              ->groupBy('user_id')
-                              ->select('user_id')->get();
-            $info = $date.','.$count.','.$sumCount.','.count($editor);
-            $this->info($info);
-            Storage::disk('local')->append($file, $info);
-            $current->addMonth(1);
-        }
-        return 0;
-    }
-}

+ 0 - 77
api-v12/app/Console/Commands/StatisticsExp.php

@@ -1,77 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use Carbon\Carbon;
-use App\Models\UserOperationDaily;
-
-class StatisticsExp extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'statistics:exp';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '统计 经验值 每月查询';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $file = "public/statistics/exp-monthly.csv";
-        Storage::disk('local')->put($file, "");
-        #按月获取数据
-        $firstDay = UserOperationDaily::select('created_at')
-                            ->orderBy('created_at')
-                            ->first();
-        $firstDay = strtotime($firstDay->created_at);
-        $firstMonth = Carbon::create(date("Y-m",$firstDay));
-        $now = Carbon::now();
-        $current = $firstMonth;
-        $sumTime = 0;
-        while ($current <= $now) {
-            # code...
-            $start = Carbon::create($current)->startOfMonth();
-            $end = Carbon::create($current)->endOfMonth();
-            $date = $current->format('Y-m');
-            $time = UserOperationDaily::whereDate('created_at','>=',$start)
-                              ->whereDate('created_at','<=',$end)
-                              ->sum('duration')/1000;
-            $sumTime += $time;
-            $editor = UserOperationDaily::whereDate('created_at','>=',$start)
-                              ->whereDate('created_at','<=',$end)
-                              ->groupBy('user_id')
-                              ->select('user_id')->get();
-            $info = $date.','.(int)($time/3600).','.(int)($sumTime/3600).','.count($editor);
-            $this->info($info);
-            Storage::disk('local')->append($file, $info);
-            $current->addMonth(1);
-        }
-        return 0;
-    }
-}

+ 0 - 90
api-v12/app/Console/Commands/StatisticsNissaya.php

@@ -1,90 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\Channel;
-use App\Models\Sentence;
-use Illuminate\Support\Facades\Storage;
-use Carbon\Carbon;
-
-class StatisticsNissaya extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan statistics:nissaya
-     * @var string
-     */
-    protected $signature = 'statistics:nissaya';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '统计nissaya 每月录入进度';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $nissaya_channels = Channel::where('type','nissaya')
-                            ->where('lang','my')
-                            ->select('uid')->get();
-        $this->info('channel:'.count($nissaya_channels));
-        $file = "public/statistics/nissaya-monthly.csv";
-
-        Storage::disk('local')->put($file, "");
-        #按月获取数据
-        $firstDay = Sentence::whereIn('channel_uid',$nissaya_channels)
-                            ->orderBy('created_at')
-                            ->select('created_at')
-                            ->first();
-        $firstDay = strtotime($firstDay->created_at);
-        $firstMonth = Carbon::create(date("Y-m",$firstDay));
-        $now = Carbon::now();
-        $current = $firstMonth;
-        $sumStrlen = 0;
-        $sumCount = 0;
-        while ($current <= $now) {
-            # code...
-            $start = Carbon::create($current)->startOfMonth();
-            $end = Carbon::create($current)->endOfMonth();
-            $date = $current->format('Y-m');
-            $table = Sentence::whereIn('channel_uid',$nissaya_channels)
-                              ->whereDate('created_at','>=',$start)
-                              ->whereDate('created_at','<=',$end);
-            $strlen =  $table->sum('strlen');
-            $sumStrlen += $strlen;
-            $count = $table->count();
-            $sumCount += $count;
-            $editor = Sentence::whereIn('channel_uid',$nissaya_channels)
-                              ->whereDate('created_at','>=',$start)
-                              ->whereDate('created_at','<=',$end)
-                              ->groupBy('editor_uid')
-                              ->select('editor_uid')->get();
-            $info = "{$date},{$strlen},{$sumStrlen},{$count},{$sumCount},".count($editor);
-            $this->info($info);
-            Storage::disk('local')->append($file, $info);
-            $current->addMonth(1);
-        }
-        $this->info('path='.$file);
-        return 0;
-    }
-}

+ 0 - 355
api-v12/app/Console/Commands/StatisticsNissayaCover.php

@@ -1,355 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\Channel;
-use App\Models\Sentence;
-use App\Models\PaliSentence;
-use Illuminate\Support\Facades\Cache;
-
-class StatisticsNissayaCover extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan statistics:nissaya.cover
-     * @var string
-     */
-    protected $signature = 'statistics:nissaya.cover';
-    protected $types = [
-        'mula' => [
-            69,
-            70,
-            71,
-            72,
-            73,
-            74,
-            75,
-            76,
-            77,
-            78,
-            79,
-            80,
-            81,
-            82,
-            83,
-            84,
-            85,
-            86,
-            87,
-            88,
-            89,
-            90,
-            91,
-            92,
-            93,
-            94,
-            95,
-            143,
-            144,
-            145,
-            146,
-            147,
-            148,
-            149,
-            150,
-            151,
-            152,
-            153,
-            154,
-            155,
-            156,
-            157,
-            158,
-            159,
-            160,
-            161,
-            162,
-            163,
-            164,
-            165,
-            166,
-            167,
-            168,
-            169,
-            170,
-            171,
-            213,
-            214,
-            215,
-            216,
-            217,
-        ],
-        'atthakatha' => [
-            64,
-            65,
-            96,
-            97,
-            98,
-            99,
-            100,
-            101,
-            102,
-            103,
-            104,
-            105,
-            106,
-            107,
-            108,
-            109,
-            110,
-            111,
-            112,
-            113,
-            114,
-            115,
-            116,
-            117,
-            118,
-            119,
-            120,
-            121,
-            122,
-            123,
-            124,
-            125,
-            126,
-            127,
-            128,
-            129,
-            130,
-            131,
-            132,
-            133,
-            134,
-            135,
-            136,
-            137,
-            138,
-            139,
-            140,
-            141,
-            142,
-        ],
-        'tika' => [
-            66,
-            67,
-            68,
-            172,
-            173,
-            174,
-            175,
-            176,
-            177,
-            178,
-            179,
-            180,
-            181,
-            182,
-            183,
-            184,
-            185,
-            186,
-            187,
-            188,
-            189,
-            190,
-            191,
-            192,
-            193,
-            194,
-            195,
-            196,
-            197,
-            198,
-            199,
-            200,
-            201,
-            202,
-            203,
-            204,
-            205,
-            206,
-            207,
-            208,
-            209,
-            210,
-            211,
-            212,
-        ],
-        'vinaya' => [138, 139, 140, 141, 142, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217,],
-        'sutta' => [
-            82,
-            83,
-            84,
-            85,
-            86,
-            87,
-            88,
-            89,
-            90,
-            91,
-            92,
-            93,
-            94,
-            95,
-            99,
-            100,
-            101,
-            102,
-            103,
-            104,
-            105,
-            106,
-            107,
-            108,
-            109,
-            110,
-            111,
-            112,
-            113,
-            114,
-            115,
-            116,
-            117,
-            118,
-            119,
-            120,
-            121,
-            122,
-            123,
-            124,
-            125,
-            126,
-            127,
-            128,
-            129,
-            130,
-            131,
-            132,
-            133,
-            134,
-            135,
-            136,
-            137,
-            143,
-            144,
-            145,
-            146,
-            147,
-            148,
-            149,
-            150,
-            151,
-            152,
-            153,
-            154,
-            155,
-            156,
-            157,
-            158,
-            159,
-            160,
-            161,
-            162,
-            163,
-            164,
-            165,
-            166,
-            167,
-            168,
-            169,
-            170,
-            171,
-            181,
-            182,
-            183,
-            184,
-            185,
-            186,
-            187,
-            188,
-            189,
-            190,
-            191,
-            192,
-            193,
-            194,
-            195,
-            196,
-            197,
-            198,
-            199,
-        ],
-        'abhidhamma' => [69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 96, 97, 98, 172, 173, 174, 175, 176, 177, 178, 179, 180,],
-    ];
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '统计nissaya覆盖度';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $nissaya_channels = Channel::where('type', 'nissaya')
-            ->where('lang', 'my')
-            ->select('uid')->get();
-        $this->info('channel:' . count($nissaya_channels));
-        $output = [];
-        foreach ($this->types as $type => $books) {
-            # code...
-            $pali = PaliSentence::whereIn('book', $books)->sum('length');
-            $nissayaSentences = Sentence::whereIn('channel_uid', $nissaya_channels)
-                ->whereIn('book_id', $books)
-                ->groupBy(['book_id', 'paragraph', 'word_start', 'word_end'])
-                ->select(['book_id', 'paragraph', 'word_start', 'word_end'])
-                ->get();
-            $sentences = [];
-            $final = 0;
-            $this->info($type . count($nissayaSentences) . " sentences");
-            if (count($nissayaSentences) > 0) {
-                $count = 0;
-                foreach ($nissayaSentences as  $value) {
-                    $sentences[] = [
-                        $value->book_id,
-                        $value->paragraph,
-                        $value->word_start,
-                        $value->word_end,
-                    ];
-                    if ($count % 100 === 0) {
-                        $final += PaliSentence::whereIns(['book', 'paragraph', 'word_begin', 'word_end'], $sentences)
-                            ->sum('length');
-                        $sentences = [];
-                        $percent = intval($count * 100 / count($nissayaSentences));
-                        $this->info("[{$percent}] {$final}");
-                    }
-                    $count++;
-                }
-            }
-
-            $this->info($type . '=' . $pali . '=' . $final);
-            $output[] = ['type' => $type, 'total' => $pali, 'final' => $final];
-        }
-        Cache::put('/statistics/nissaya/cover', $output, 48 * 3600);
-        return 0;
-    }
-}

+ 0 - 77
api-v12/app/Console/Commands/StatisticsWbw.php

@@ -1,77 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\Wbw;
-use Illuminate\Support\Facades\Storage;
-use Carbon\Carbon;
-
-class StatisticsWbw extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'statistics:wbw';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '统计 wbw 每月建立数量';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $file = "public/statistics/wbw-monthly.csv";
-        Storage::disk('local')->put($file, "");
-        #按月获取数据
-        $firstDay = Wbw::select('created_at')
-                        ->orderBy('created_at')
-                        ->first();
-        $firstDay = strtotime($firstDay->created_at);
-        $firstMonth = Carbon::create(date("Y-m",$firstDay));
-        $now = Carbon::now();
-        $current = $firstMonth;
-        $sumCount = 0;
-        while ($current <= $now) {
-            # code...
-            $start = Carbon::create($current)->startOfMonth();
-            $end = Carbon::create($current)->endOfMonth();
-            $date = $current->format('Y-m');
-            $count = Wbw::whereDate('created_at','>=',$start)
-                              ->whereDate('created_at','<=',$end)
-                              ->count();
-            $sumCount += $count;
-            $editor = Wbw::whereDate('created_at','>=',$start)
-                              ->whereDate('created_at','<=',$end)
-                              ->groupBy('editor_id')
-                              ->select('editor_id')->get();
-            $info = $date.','.$count.','.$sumCount.','.count($editor);
-            $this->info($info);
-            Storage::disk('local')->append($file, $info);
-            $current->addMonth(1);
-        }
-        return 0;
-    }
-}

+ 0 - 60
api-v12/app/Console/Commands/TestAI.php

@@ -1,60 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Http;
-use Illuminate\Support\Facades\Log;
-
-class TestAI extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'test:ai';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $url = 'https://api.moonshot.cn/v1/chat/completions';
-        $param = [
-                "model" => "moonshot-v1-8k",
-                "messages" => [
-                    ["role" => "system","content" => "你是 Kimi,由 Moonshot AI 提供的人工智能助手,你更擅长中文和英文的对话。你会为用户提供安全,有帮助,准确的回答。同时,你会拒绝一切涉及恐怖主义,种族歧视,黄色暴力等问题的回答。Moonshot AI 为专有名词,不可翻译成其他语言。"],
-                    ["role" => "user","content" => "你好,我叫李雷,1+1等于多少?"],
-                ],
-                "temperature" => 0.3,
-        ];
-        $response = Http::withToken('sk-kwjHIMh3PoWwUwQyKdT3KHvNe8Es19SUiujGrxtH09uDQCui')
-                        ->post($url,$param);
-        if($response->failed()){
-            $this->error('http request error'.$response->json('message'));
-        }else{
-            $this->info(json_encode($response->json()));
-        }
-        return 0;
-    }
-}

+ 0 - 58
api-v12/app/Console/Commands/TestAIArticleTranslate.php

@@ -1,58 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Services\AIAssistant\ArticleTranslateService;
-
-class TestAIArticleTranslate extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan test:ai.article.translate
-     * @var string
-     */
-    protected $signature = 'test:ai.article.translate {--article=} {--anthology=} {--model=}  {--channel=}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Execute the console command.
-     */
-    public function handle()
-    {
-        if (
-            !$this->option('model') ||
-            !$this->option('channel')
-        ) {
-            $this->error('model,article,channel is requested');
-            return;
-        }
-        //
-        // ===== 创建 Service =====
-        $service = app(ArticleTranslateService::class);
-        // ===== 执行 =====
-        if ($this->option('article')) {
-            $this->info('article translate start');
-            $total = $service->setModel($this->option('model'))
-                ->setChannel($this->option('channel'))
-                ->translateArticle($this->option('article'))
-                ->save();
-            $this->info("{$total} sentences saved");
-        }
-        if ($this->option('anthology')) {
-            $this->info('anthology translate start');
-            $total = $service->setModel($this->option('model'))
-                ->setChannel($this->option('channel'))
-                ->translateAnthology($this->option('anthology'), function ($article, $sentences) {
-                    $this->info("translate article {$article} sentences {$sentences}");
-                });
-            $this->info("{$total} article saved");
-        }
-    }
-}

+ 0 - 40
api-v12/app/Console/Commands/TestAITerm.php

@@ -1,40 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Services\AIAssistant\AITermService;
-
-class TestAITerm extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'test:ai.term';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Execute the console command.
-     */
-    public function handle()
-    {
-        //
-        // ===== 创建 Service =====
-        $service = app(AITermService::class);
-
-        // ===== 执行 =====
-        $result = $service->setModel('dd81ce6c-e9ff-46b2-b1af-947728ba996e')
-            ->update('f3ba16e5-862d-49c4-b5b0-39ab8b8ca4f4');
-
-        // ===== 调试输出(建议保留)=====
-        dump($result);
-    }
-}

+ 0 - 55
api-v12/app/Console/Commands/TestAiTask.php

@@ -1,55 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\TaskAssignee;
-use App\Models\AiModel;
-
-class TestAiTask extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan test:ai.task c77af42f-ffb5-48ae-af71-4c32e1c30dab
-     * php artisan test:ai.task f42fa690-c590-400f-9de9-fbc81e838a5a
-     * @var string
-     */
-    protected $signature = 'test:ai.task {id} {--test}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'test ai task';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $taskId = $this->argument('id');
-        $taskAssignee = TaskAssignee::where('task_id', $taskId)
-            ->select('assignee_id')->get();
-        $aiAssistant = AiModel::whereIn('uid', $taskAssignee)->first();
-        if ($aiAssistant) {
-            $count = \App\Jobs\ProcessAITranslateJob::publish($taskId, $aiAssistant->uid);
-            $this->info('publish total:' . $count);
-        } else {
-            $this->error('no ai assistant');
-        }
-        return 0;
-    }
-}

+ 0 - 69
api-v12/app/Console/Commands/TestCaseMan.php

@@ -1,69 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Tools\CaseMan;
-use App\Models\UserDict;
-
-
-class TestCaseMan extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'test:case {word}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-		$caseMan = new CaseMan();
-        $case = $caseMan->Declension($this->argument('word'),'.n:base.','.nt.',0.5);
-        print_r($case);
-        return 0;
-
-		$parents = $caseMan->WordToBase($this->argument('word'),1);
-			# code...
-
-		foreach ($parents as $base => $rows) {
-			# code...
-			if(count($rows)==0){
-				$this->error("base={$base}-(".count($rows).")");
-			}else{
-				$this->warn("base={$base}-(".count($rows).")");
-			}
-
-			foreach ($rows as $value) {
-				# code...
-				$this->info($value['word'].'-'.$value['type'].'-'.$value['grammar'].'-'.$base);
-			}
-		}
-        return 0;
-    }
-}

+ 0 - 53
api-v12/app/Console/Commands/TestJsonToXml.php

@@ -1,53 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Tools\Tools;
-
-class TestJsonToXml extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'test:json.to.xml';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $array = [
-            'pali'=>['status'=>'7','value'=>'bārāṇasiyaṃ'],
-            'real'=>['status'=>'7','value'=>'bārāṇasiyaṃ'],
-            'id'=>'p171-2475-10'
-        ];
-        $xml = Tools::JsonToXml($array);
-        $this->info($xml);
-        return 0;
-    }
-}

+ 0 - 83
api-v12/app/Console/Commands/TestMarkdownToTpl.php

@@ -1,83 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Controllers\ArticleController;
-use Illuminate\Support\Facades\Log;
-
-class TestMarkdownToTpl extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'test:markdown.tpl {item?}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        Log::info('md render start item='.$this->argument('item'));
-        $data = array();
-        $data['basic'] = <<<md
-        # 去除烦恼的五种方法(一种分类)
-
-        1 为了自己的利益而从别人处听法;
-        2 为了自己的利益而开示自己听闻过的法;
-        3 念诵听闻过、学习过的法;
-        4 一次又一次地用心思维听闻过、学习过的法;
-        5 在心中忆念自己适合的禅修业处,如十遍、十不净等。
-
-        (无碍解道,义注,1,63)
-        md;
-
-        $data['tpl'] = <<<md
-        为了自己的利益而从别人处听法;
-
-        {{168-916-2-9}}
-        md;
-
-        $article = new ArticleController;
-
-        foreach ($data as $key => $value) {
-            $_item = $this->argument('item');
-            if(!empty($_item) && $key !==$_item){
-                continue;
-            }
-            $tpl = $article->toTpl($value,
-                        'eb9e3f7f-b942-4ca4-bd6f-b7876b59a523',
-                        [
-                            'user_uid'=>'ba5463f3-72d1-4410-858e-eadd10884713',
-                            'user_id'=>4,
-                        ]
-                    );
-            var_dump($tpl);
-        }
-        return 0;
-    }
-}

+ 0 - 200
api-v12/app/Console/Commands/TestMdRender.php

@@ -1,200 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\MdRender;
-use Illuminate\Support\Str;
-use Illuminate\Support\Facades\Log;
-use App\Tools\Markdown;
-
-class TestMdRender extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan test:md.render term --format=unity --driver=str
-     * @var string
-     */
-    protected $signature = 'test:md.render {item?} {--format=html} {--driver=morus}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-
-        $content = <<<md
-        # 测试
-        ## 测试
-
-        {{note|text=这是一个普通信息提示|type=info}}
-
-        下面是一个警告信息:
-        {{warning|message=请注意这个重要提示|title=重要}}
-
-        你也可以使用位置参数:
-        {{note|
-        成功完成操作|
-        success}}
-
-        支持嵌套模板:
-        {{info|
-        content=外层信息 {{note|内嵌提示|warning}} 继续外层|
-        title=嵌套示例}}
-
-        **粗体文本** 和 *斜体文本* 也被支持。
-        md;
-        $parser = new \App\Services\Template\TemplateService(false);
-        $render = $parser->parseAndRender($content, 'json');
-        var_dump($render);
-        return 0;
-
-        Log::info('md render start item=' . $this->argument('item'));
-        $data = array();
-        $data['bold'] = <<<md
-        **三十位** 经在[中间]六处为**[licchavi]**,在极果为**慧解脱**
-        md;
-
-        $data['sentence'] = <<<md
-        {{168-916-2-9}}
-        md;
-
-        $data['link'] = <<<md
-        aa `[link](wikipali.org/aa.php?view=b&c=d)` bb
-        md;
-
-        $data['term'] = <<<md
-        ## term
-        [[bhagavantu]]
-        md;
-        $data['noteMulti'] = <<<md
-        ## heading
-
-        [点击](http://127.0.0.1:3000/my/article/para/168-876?mode=edit&channel=00ae2c48-c204-4082-ae79-79ba2740d506&book=168&par=876)
-
-        ----
-
-        dfef
-
-        ```
-        bla **content**
-        {{99-556-8-12}}
-        bla **content**
-        ```
-        md;
-
-        $data['note'] = '`bla **bold** _em_ bla`';
-        $data['noteTpl'] = <<<md
-        {{note|trigger=kacayana|text=bla **bold** _em_ bla}}
-        md;
-
-        $data['noteTpl2'] = <<<md
-        {{note|trigger=kacayana|text={{99-556-8-12}}}}
-        md;
-
-        $data['trigger'] = <<<md
-        ## heading
-        ddd
-        - title
-          content-1
-        - title-2
-
-          content-2
-
-        aaa bbb
-        md;
-        $data['exercise'] = <<<md
-        {{168-916-10-37}}
-        {{exercise|1|((168-916-10-37))}}
-        {{exercise|
-        id=1|
-        content={{168-916-10-37}}
-        }}
-        {{exercise|
-        id=2|
-        content=# ddd}}
-        md;
-
-        $data['article'] = <<<md
-        {{article|
-        type=article|
-        id=27ade9ad-2d0c-4f66-b857-e9335252cc08|
-        title=第一章 戒律概说(Vinaya)|
-        style=modal}}
-        md;
-
-        $data['footnote'] = <<<md
-        # title
-        content `note content` `note2 content`
-        md;
-
-        $data['paragraph'] = <<<md
-        # title
-        content
-
-        {{168-916-10-37}}
-        {{168-916-10-37}}
-
-        the end
-        md;
-
-        $data['img'] = <<<md
-        # title
-        content
-
-        ![aaa](/images/aaa.jpg)
-
-        the end
-        md;
-
-        $data['empty'] = '';
-
-        Markdown::driver($this->option('driver'));
-
-        $format = $this->option('format');
-        if (empty($format)) {
-            $formats = ['react', 'unity', 'text', 'tex', 'html', 'simple'];
-        } else {
-            $formats = [$format];
-        }
-        foreach ($formats as $format) {
-            $this->info("format:{$format}");
-            foreach ($data as $key => $value) {
-                $_item = $this->argument('item');
-                if (!empty($_item) && $key !== $_item) {
-                    continue;
-                }
-                $mdRender = new MdRender([
-                    'format' => $format,
-                    'footnote' => true,
-                    'paragraph' => true,
-                ]);
-                $output = $mdRender->convert($value, ['00ae2c48-c204-4082-ae79-79ba2740d506']);
-                echo $output;
-            }
-        }
-        return 0;
-    }
-}

+ 0 - 68
api-v12/app/Console/Commands/TestMq.php

@@ -1,68 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Str;
-
-use App\Http\Api\Mq;
-use App\Models\Discussion;
-use App\Http\Resources\DiscussionResource;
-use App\Models\SentPr;
-use App\Http\Resources\SentPrResource;
-use App\Services\RabbitMQService;
-
-class TestMq extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan test:mq
-     * @var string
-     */
-    protected $signature = 'test:mq {--discussion=} {--pr=}';
-    protected $publish;
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (\App\Tools\Tools::isStop()) {
-            return 0;
-        }
-        $publish = app(RabbitMQService::class);
-        $this->publish = $publish;
-        $this->publish->publishMessage('ai_translate', ['text' => 'hello']);
-
-        Mq::publish('hello', ['hello world']);
-        $discussion = $this->option('discussion');
-        if ($discussion && Str::isUuid($discussion)) {
-            Mq::publish('discussion', new DiscussionResource(Discussion::find($discussion)));
-        }
-
-        $pr = $this->option('pr');
-        if ($pr && Str::isUuid($pr)) {
-            Mq::publish('suggestion', new SentPrResource(SentPr::where('uid', $pr)->first()));
-        }
-
-        return 0;
-    }
-}

+ 0 - 46
api-v12/app/Console/Commands/TestMqExit.php

@@ -1,46 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Http\Api\Mq;
-
-class TestMqExit extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan test:mq.exit
-     * @var string
-     */
-    protected $signature = 'test:mq.exit';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        for ($i = 0; $i < 10; $i++) {
-            Mq::publish('ai_translate', ['hello world']);
-        }
-        return 0;
-    }
-}

+ 0 - 131
api-v12/app/Console/Commands/TestMqWorker.php

@@ -1,131 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use PhpAmqpLib\Connection\AMQPStreamConnection;
-use PhpAmqpLib\Exchange\AMQPExchangeType;
-
-class TestMqWorker extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan test:mq.worker
-     * @var string
-     */
-    protected $signature = 'test:mq.worker';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $exchange = 'router';
-        $queue = 'hello';
-        $consumerTag = 'consumer';
-        $connection = new AMQPStreamConnection(config("queue.connections.rabbitmq.host"),
-                                            config("queue.connections.rabbitmq.port"),
-                                            config("queue.connections.rabbitmq.user"),
-                                            config("queue.connections.rabbitmq.password"),
-                                            config("queue.connections.rabbitmq.virtual_host"));
-        $channel = $connection->channel();
-
-        /*
-            The following code is the same both in the consumer and the producer.
-            In this way we are sure we always have a queue to consume from and an
-                exchange where to publish messages.
-        */
-
-        /*
-            name: $queue
-            passive: false
-            durable: true // the queue will survive server restarts
-            exclusive: false // the queue can be accessed in other channels
-            auto_delete: false //the queue won't be deleted once the channel is closed.
-        */
-        $channel->queue_declare($queue, false, true, false, false);
-
-        /*
-            name: $exchange
-            type: direct
-            passive: false
-            durable: true // the exchange will survive server restarts
-            auto_delete: false //the exchange won't be deleted once the channel is closed.
-        */
-
-        $channel->exchange_declare($exchange, AMQPExchangeType::DIRECT, false, true, false);
-
-        $channel->queue_bind($queue, $exchange);
-
-        /**
-         * @param \PhpAmqpLib\Message\AMQPMessage $message
-         */
-        $process_message = function ($message)
-        {
-            echo "\n--------\n";
-            echo $message->body;
-            echo "\n--------\n";
-
-            $message->ack();
-
-            // Send a message with the string "quit" to cancel the consumer.
-            if ($message->body === 'quit') {
-                $message->getChannel()->basic_cancel($message->getConsumerTag());
-            }
-        };
-
-        /*
-            queue: Queue from where to get the messages
-            consumer_tag: Consumer identifier
-            no_local: Don't receive messages published by this consumer.
-            no_ack: If set to true, automatic acknowledgement mode will be used by this consumer. See https://www.rabbitmq.com/confirms.html for details.
-            exclusive: Request exclusive consumer access, meaning only this consumer can access the queue
-            nowait:
-            callback: A PHP Callback
-        */
-
-        $channel->basic_consume($queue, $consumerTag, false, false, false, false, $process_message);
-
-        /**
-         * @param \PhpAmqpLib\Channel\AMQPChannel $channel
-         * @param \PhpAmqpLib\Connection\AbstractConnection $connection
-         */
-        $shutdown = function ($channel, $connection)
-        {
-            $channel->close();
-            $connection->close();
-        };
-
-        register_shutdown_function($shutdown, $channel, $connection);
-
-        // Loop as long as the channel has callbacks registered
-        while ($channel->is_consuming()) {
-            $channel->wait(null, true);
-            // do something else
-            usleep(300000);
-        }
-        return 0;
-    }
-}

+ 0 - 126
api-v12/app/Console/Commands/TestProjectCopyTask.php

@@ -1,126 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Facades\Http;
-use Illuminate\Support\Str;
-
-class TestProjectCopyTask extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan test:project.copy.task project-50 dd9bcba8-ad3f-4082-9b52-4f5f8acdbd5f visuddhinanda
-     * @var string
-     */
-    protected $signature = 'test:project.copy.task {project} {task} {studio} {--token=}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '建立project 并复制task';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $appUrl = config('app.url');
-        $projectTitle = $this->argument('project');
-        $taskId = $this->argument('task');
-        $studioName = $this->argument('studio');
-        $token = $this->option('token');
-
-        // 如果 role 选项未提供(为空),提示用户输入
-        if (empty($token)) {
-            $token = $this->ask('Please enter the user token:');
-        }
-
-        $taskCount = $this->ask('Please enter the task count:');
-        $url = $appUrl . '/api/v2/project-tree';
-        $this->info('create project ' . $url);
-        $projects = array();
-        $rootId = Str::uuid();
-        $projects[] = [
-            'id' => $rootId,
-            'title' => $projectTitle,
-            'type' => "instance",
-            'parent_id' => '',
-            'weight' => 0,
-            'res_id' => $rootId,
-        ];
-        for ($i = 0; $i < $taskCount; $i++) {
-            $uid = Str::uuid();
-            $projects[] = [
-                'id' => $uid,
-                'title' => "{$projectTitle}_{$i}",
-                'type' => "instance",
-                'parent_id' => $rootId,
-                'weight' => 0,
-                'res_id' => $uid,
-            ];
-        }
-        $response = Http::withToken($token)
-            ->post($url, [
-                'studio_name' => $studioName,
-                'data' => $projects,
-            ]);
-        if ($response->failed()) {
-            $this->error('project create fail' . $response->json('message'));
-            Log::error('project create fail', ['data' => $response->body()]);
-            return 1;
-        }
-
-        $projectsData = $response->json()['data']['rows'];
-        $this->info('project :' . count($projectsData));
-        //获取task
-        $response = Http::withToken($token)
-            ->get($appUrl . '/api/v2/task/' . $taskId);
-        if ($response->failed()) {
-            $this->error('task read fail' . $response->json('message'));
-            Log::error('task read fail', ['data' => $response->body()]);
-            return 1;
-        }
-
-        //建立task
-        $task = $response->json()['data'];
-        $taskTitle = $task['title'];
-        $this->info('task title:' . $task['title']);
-        $tasks = array();
-        foreach ($projectsData as $key => $project) {
-            if ($project['isLeaf']) {
-                $task['title'] = "{$taskTitle}_{$key}";
-                $tasks[] = [
-                    'project_id' => $project['id'],
-                    'tasks' => [$task]
-                ];
-            }
-        }
-
-        $response = Http::withToken($token)
-            ->post($appUrl . '/api/v2/task-group', [
-                'data' => $tasks,
-            ]);
-        if ($response->failed()) {
-            $this->error('task create fail' . $response->json('message'));
-            Log::error('task create fail', ['data' => $response->body()]);
-            return 1;
-        }
-        return 0;
-    }
-}

+ 0 - 117
api-v12/app/Console/Commands/TestRedis.php

@@ -1,117 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Redis;
-use Illuminate\Support\Facades\Cache;
-
-class TestRedis extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'test:redis';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'testing redis';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $value = 'this is a test';
-        $this->info("test redis start");
-
-
-        $key = "test-redis";
-        Redis::set($key, $value);
-        if (Redis::exists($key)) {
-            $this->info("has key " . $key);
-        } else {
-            $this->error("no key " . $key);
-        }
-        $expire = Redis::expire($key, 10);
-        $this->info("key expire " . $expire);
-        $this->info('del key ' . Redis::del($key));
-        Redis::set($key, $value);
-        $getValue = Redis::get($key);
-        if ($getValue === $value) {
-            $this->info("redis set ok ");
-        } else {
-            $this->error("redis set fail ");
-        }
-
-
-        Redis::hSet("test-redis-hash", 'hash', $value);
-        if (Redis::hGet("test-redis-hash", 'hash') == $value) {
-            $this->info("redis hash set ok ");
-        } else {
-            $this->error("redis hash set fail ");
-        }
-
-
-        $this->info("test cache start");
-        $this->info("testing cache put");
-        $key = 'cache-key';
-
-
-
-        Cache::put($key, $value, 1000);
-        if (Cache::has($key)) {
-            $this->info("cache::put() exist key={$key}");
-            if (Cache::get($key) == $value) {
-                $this->info("cache::get() ok value={$value}");
-            } else {
-                $this->error("cache::get() fail ");
-            }
-        } else {
-            $this->error('no key cache-key');
-        }
-
-
-        $key = 'cache-key-2';
-        $this->info("testing cache() function");
-        $this->info("cache() key={$key} value={$value}");
-        cache(["cache-key-2" => $value]);
-        if (Cache::has($key)) {
-            if (Cache::get($key) == $value) {
-                $this->info("cache() get ok value={$value}");
-            } else {
-                $this->error("cache::get() fail ");
-            }
-        } else {
-            $this->error('no key cache-key-2');
-        }
-
-        $key = 'cache-key-3';
-        $this->info("testing cache remember()");
-        $value = Cache::remember($key, 600, function () {
-            return 'cache-value-3';
-        });
-        if (Cache::has($key)) {
-            $this->info("{$key} exist value=" . Cache::get($key));
-        } else {
-            $this->error("cache::remember() fail.");
-        }
-    }
-}

+ 0 - 48
api-v12/app/Console/Commands/TestSchedule.php

@@ -1,48 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Log;
-
-class TestSchedule extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'test:schedule';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        Log::info('schedule test start');
-        $this->info('schedule test start');
-        return 0;
-    }
-}

+ 0 - 77
api-v12/app/Console/Commands/TestSearchPali.php

@@ -1,77 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Tools\PaliSearch;
-
-class TestSearchPali extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan test:search.pali
-     * @var string
-     */
-    protected $signature = 'test:search.pali {word?}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $word = $this->argument('word');
-        if(empty($word)){
-            $word = 'citta';
-        }
-        $words = str_replace('_',' ',$word);
-        $words = explode(',',$words);
-        $this->info("searching word={$word} limit=10,offset=0");
-        $result = PaliSearch::search($words,[],'case',0,10);
-        if($result){
-            $this->info("word={$word} total=".$result['total']);
-        }else{
-            $this->error("word={$word} search fail");
-        }
-
-        $rpc_result = PaliSearch::book_list($words,
-                                            [],
-                                            'case');
-        $this->info('book list count='.count($rpc_result['rows']));
-
-        $this->info("searching word={$word} limit=10,offset=10");
-        $result = PaliSearch::search($words,[],'case',10,10);
-        if($result){
-            $this->info("word={$word} total=".$result['total']);
-        }else{
-            $this->error("word={$word} search fail");
-        }
-        $this->info("searching word={$word} book=267");
-        $result = PaliSearch::search($words,[267],'case',0,3);
-        if($result){
-            $this->info("word={$word} book=267 total=".$result['total']);
-        }else{
-            $this->error("word={$word} book=267 search fail");
-        }
-
-        return 0;
-    }
-}

+ 0 - 102
api-v12/app/Console/Commands/TestTex.php

@@ -1,102 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Storage;
-use App\Tools\Export;
-
-class TestTex extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'test:tex';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $tex = array();
-        $content = <<<'EOF'
-% 导言区
-\documentclass[a4paper, 12pt, fontset=ubuntu]{article} % book, report, letter
-\usepackage{ctex} % Use chinese package
-
-\title{\heiti 一级标题}
-\author{\kaishu 半闲}
-\date{\today}
-
-% 正文区
-
-\begin{document}
-    \maketitle % 头部信息在正文显示
-    \newpage
-    \tableofcontents % 显示索引列
-
-    \include{section-1.tex}
-    \include{section-2.tex}
-
-\end{document}
-
-EOF;
-$tex[] = ['name'=>'main.tex','content'=>$content];
-$content = <<<'EOF'
-\section{三十位经}
-
-住在王舍城的竹林园。
-那时,三十位波婆城的比丘全是住林野者、全是常乞食者、全是穿粪扫衣者、全是但三衣者、全是尚有结缚者,他们去见世尊。
-\subsubsection{子章节1.1 标题}
-子章节1-1 正文
-\subsection{子章节1.2 标题}
-子章节1-2 正文
-EOF;
-$tex[] = ['name'=>'section-1.tex','content'=>$content];
-
-$content = <<<'EOF'
-\section{章节2 标题}
-章节2 正文
-\subsection{子章节2.1 标题}
-子章节2-1 正文
-\subsection{子章节2.2 标题}
-子章节2-2 正文
-EOF;
-
-$tex[] = ['name'=>'section-2.tex','content'=>$content];
-
-        $data = Export::ToPdf($tex);
-        if($data['ok']){
-            $filename = "export/test.pdf";
-            $this->info($data['content-type']);
-            Storage::disk('local')->put($filename, $data['data']);
-        }else{
-            $this->error($data['code'].'-'.$data['message']);
-        }
-        return 0;
-    }
-}

+ 0 - 76
api-v12/app/Console/Commands/TestWorkerStartProject.php

@@ -1,76 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Log;
-use Illuminate\Support\Facades\Http;
-
-class TestWorkerStartProject extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan test:worker.start.project 0c3d2f69-1098-428b-95db-f1183667c799
-     * @var string
-     */
-    protected $signature = 'test:worker.start.project {project} {--token=}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $appUrl = config('app.url');
-        $projectId = $this->argument('project');
-        $token = $this->option('token');
-        // 如果 role 选项未提供(为空),提示用户输入
-        if (empty($token)) {
-            $token = $this->ask('Please enter the user token:');
-        }
-
-        $status = $this->choice(
-            'Which framework do you prefer?',
-            ['published', 'restarted', 'stop'],
-            0 // 默认选择 Laravel(索引 0)
-        );
-
-        $response = Http::withToken($token)
-            ->get($appUrl . "/api/v2/task?view=project&project_id={$projectId}&status=all&order=order&dir=asc");
-        if ($response->failed()) {
-            $this->error('task read fail' . $response->json('message'));
-            Log::error('task read fail', ['data' => $response->body()]);
-            return 1;
-        }
-        $tasks = $response->json()['data']['rows'];
-        foreach ($tasks as $key => $task) {
-            $this->info("[{$key}]task " . $task['title'] . ' status ' . $task['status']);
-            $response = Http::withToken($token)
-                ->patch($appUrl . "/api/v2/task-status/" . $task['id'], ['status' => $status]);
-            if ($response->failed()) {
-                $this->error('task status fail' . $response->json('message'));
-                Log::error('task status fail', ['data' => $response->body()]);
-            }
-            $this->info("[{$key}]task status changed {$status}");
-        }
-        return 0;
-    }
-}

+ 0 - 71
api-v12/app/Console/Commands/UpdateOpenSearchIndex.php

@@ -1,71 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Services\OpenSearchService;
-use Illuminate\Console\Command;
-
-class UpdateOpenSearchIndex extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan create:opensearch.index
-     * @var string
-     */
-    protected $signature = 'update:opensearch.index';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $openSearch = app(OpenSearchService::class);
-
-        // Test OpenSearch connection
-        $open = $openSearch->testConnection();
-        if ($open[0]) {
-            $this->info($open[1]);
-        } else {
-            $this->error($open[1]);
-            return 1; // Exit with error code
-        }
-
-        // Attempt to create or update index
-        $this->warn('Index already exists, attempting to update...');
-        try {
-            $update = $openSearch->updateIndex();
-            if (!empty($update['settings']) && $update['settings']['acknowledged']) {
-                $this->info('Index settings updated successfully');
-            }
-            if (!empty($update['mappings']) && $update['mappings']['acknowledged']) {
-                $this->info('Index mappings updated successfully');
-            }
-            if (empty($update['settings']) && empty($update['mappings'])) {
-                $this->warn('No settings or mappings provided for update');
-            }
-        } catch (\Exception $updateException) {
-            $this->error('Failed to update index: ' . $updateException->getMessage());
-            return 1;
-        }
-        return 0;
-    }
-}

+ 0 - 62
api-v12/app/Console/Commands/UpdateRelationTo.php

@@ -1,62 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\Relation;
-
-class UpdateRelationTo extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'update:relation.to';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $count=0;
-        $all=0;
-        foreach (Relation::select(['id','to'])->cursor() as $relation) {
-            $all++;
-            if(!empty($relation->to)){
-                $old = json_decode($relation->to,true);
-                if(count(array_filter(array_keys($old),'is_string'))===0){
-                    //索引数组,需要转换
-                    $new = ['case'=>$old];
-                    Relation::where('id',$relation->id)->update(['to'=>json_encode($new)]);
-                    $count++;
-                }
-            }
-        }
-        $this->info("{$count} of {$all}");
-
-        return 0;
-    }
-}

+ 0 - 89
api-v12/app/Console/Commands/UpdateSentenceUnique.php

@@ -1,89 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\Sentence;
-use App\Models\SentHistory;
-use App\Models\Discussion;
-
-use Illuminate\Support\Facades\DB;
-
-class UpdateSentenceUnique extends Command
-{
-    /**
-     * 将channel+book+paragraph+start+end重复的数据筛查,合并
-     * 与此句相关的资源也要合并,包括,pr,history,discussion
-     * 多的句子软删除
-     * php artisan update:sentence.unique
-     * @var string
-     */
-    protected $signature = 'update:sentence.unique';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '将sentence中的重复数据合并';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $queryCount = "SELECT count(*) from (SELECT * from (SELECT book_id ,paragraph ,word_start ,word_end ,channel_uid , count(*) as co from sentences s where ver = 2  group by book_id ,paragraph ,word_start ,word_end ,channel_uid) T where co>1) TT ";
-        $total = DB::select($queryCount);
-        $querySame = "SELECT * from (SELECT book_id ,paragraph ,word_start ,word_end ,channel_uid , count(*) as co from sentences s where ver = 2  group by book_id ,paragraph ,word_start ,word_end ,channel_uid) T where co>1";
-        $query = DB::select($querySame);
-
-        $count = 0;
-        foreach ($query as $key => $value) {
-            $count++;
-            $same = Sentence::where('book_id',$value->book_id)
-                            ->where('paragraph',$value->paragraph)
-                            ->where('word_start',$value->word_start)
-                            ->where('word_end',$value->word_end)
-                            ->where('channel_uid',$value->channel_uid)
-                            ->orderBy('updated_at','desc')
-                            ->get();
-            $per = (int)($count*100 / $total[0]->count);
-            $this->info("[{$per}]-{$count} ".$same[0]->updated_at.' '.$same[1]->updated_at.' '.count($same));
-
-            for ($i=1; $i < count($same); $i++) {
-                //将旧数据的历史记录 重新定位到新数据
-                $history = SentHistory::where('sent_uid',$same[$i]->uid)
-                                      ->update(['sent_uid'=>$same[0]->uid]);
-                //将旧数据的discussion 重新定位到新数据
-                $discussion = Discussion::where('res_id',$same[$i]->uid)
-                                        ->update(['res_id'=>$same[0]->uid]);
-                $this->info("{$history}-$discussion");
-                //将旧数据的 pr 重新定位到新数据
-                //删除旧数据
-                $same[$i]->delete();
-                if($same[$i]->trashed()){
-                    $this->info('软删除成功!');
-                }else{
-                    $this->error('软删除失败!');
-                }
-            }
-
-            if($count >= 1){
-                break;
-            }
-        }
-        return 0;
-    }
-}

+ 0 - 58
api-v12/app/Console/Commands/UpdateSentenceVer.php

@@ -1,58 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use App\Models\Sentence;
-use Illuminate\Support\Str;
-
-class UpdateSentenceVer extends Command
-{
-    /**
-     * 将无channel_uid的旧版句子数据的ver修改为1.
-     * php artisan update:sentence.ver
-     * @var string
-     */
-    protected $signature = 'update:sentence.ver';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '将无channel_uid的旧版句子数据的ver修改为1';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        $count = 0;
-        $total = Sentence::whereNull('channel_uid')->orWhere('channel_uid','')->count();
-        foreach (Sentence::whereNull('channel_uid')->orWhere('channel_uid','')->cursor() as $key => $value) {
-            # code...
-            $value->ver = 1;
-            $value->channel_uid = Str::uuid();
-            $value->save();
-            $count++;
-            if($count % 1000 === 0){
-                $per = (int)($count*100 / $total);
-                $this->info("[{$per}%]-{$count}");
-            }
-        }
-        $this->info("all done [{$count}]");
-        return 0;
-    }
-}

+ 0 - 30
api-v12/app/Console/Commands/Upgrade.php

@@ -1,30 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-
-class Upgrade extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'app:upgrade';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    /**
-     * Execute the console command.
-     */
-    public function handle()
-    {
-        //
-    }
-}

+ 0 - 81
api-v12/app/Console/Commands/UpgradeAITerm.php

@@ -1,81 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-
-use App\Services\AIModelService;
-use App\Services\TermService;
-use App\Services\AIAssistant\AITermService;
-
-use App\Http\Resources\AiModelResource;
-use App\Http\Controllers\AuthController;
-
-
-class UpgradeAITerm extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan upgrade:ai.term  --id=e07bf5b8-bd81-4f0a-9d2c-8e0128b954d7
-     * php artisan upgrade:ai.term
-     * @var string
-     */
-    protected $signature = 'upgrade:ai.term {--id=} {--resume} {--model=} ';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-
-    protected AiModelResource $model;
-    protected $modelToken;
-    protected $workChannel;
-    protected $accessToken;
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct(
-        protected AIModelService $modelService,
-        protected TermService $termService,
-        protected AITermService $aiTermService
-    ) {
-
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if (!$this->option('model')) {
-            $modelId = $this->ask('请输入 llm model id');
-        } else {
-            $modelId = $this->option('model');
-        }
-        $this->aiTermService->setModel($modelId);
-        $this->model = $this->modelService->getModelById($modelId);
-        $this->info("model:{$this->model['model']}");
-        $this->modelToken = AuthController::getUserToken($modelId);
-
-        if ($this->option('id')) {
-            $terms = [['guid' => $this->option('id'), 'word' => 'word']];
-        } else {
-            $terms = $this->termService->getCommunityGlossary('zh-Hans')['items']->toArray();
-        }
-
-        foreach ($terms as $key => $term) {
-            $this->info("[{$term['word']}] running");
-            $result = $this->aiTermService->update($term['guid']);
-            $this->info("[{$term['word']}]content " . substr($result, 0, 30));
-        }
-
-        return 0;
-    }
-}

+ 0 - 342
api-v12/app/Console/Commands/UpgradeAITranslation.php

@@ -1,342 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Log;
-
-use App\Services\OpenAIService;
-use App\Services\AIModelService;
-use App\Services\SentenceService;
-use App\Services\SearchPaliDataService;
-use App\Services\AIAssistant\NissayaTranslateService;
-
-use App\Http\Resources\AiModelResource;
-use App\Http\Controllers\AuthController;
-
-use App\Models\PaliText;
-use App\Models\PaliSentence;
-use App\Models\Sentence;
-
-use App\Helpers\LlmResponseParser;
-
-use App\Http\Api\ChannelApi;
-use App\Tools\Tools;
-
-class UpgradeAITranslation extends Command
-{
-    /**
-     * The name and signature of the console command.
-     * php artisan upgrade:ai.translation translation --book=141 --para=535
-     * php artisan upgrade:ai.translation nissaya --book=207 --para=1247
-     * @var string
-     */
-    protected $signature = 'upgrade:ai.translation {type} {--book=} {--para=} {--resume} {--model=} ';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'Command description';
-    protected $sentenceService;
-    protected $modelService;
-    protected $openAIService;
-    protected $nissayaTranslateService;
-    protected AiModelResource $model;
-    protected $modelToken;
-    protected $workChannel;
-    protected $accessToken;
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct(
-        AIModelService $model,
-        SentenceService $sent,
-        OpenAIService $openAI,
-        NissayaTranslateService $nissayaTranslate
-    ) {
-        $this->modelService = $model;
-        $this->sentenceService = $sent;
-        $this->openAIService = $openAI;
-        $this->nissayaTranslateService = $nissayaTranslate;
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if ($this->option('model')) {
-            $this->model = $this->modelService->getModelById($this->option('model'));
-            $this->info("model:{$this->model['model']}");
-            $this->modelToken = AuthController::getUserToken($this->model['uid']);
-        }
-        $this->workChannel = ChannelApi::getById($this->ask('请输入结果channel'));
-
-        $books = [];
-        if ($this->option('book')) {
-            $books = [$this->option('book')];
-        } else {
-            $books = range(1, 217);
-        }
-        foreach ($books as $key => $book) {
-            $maxParagraph = PaliText::where('book', $book)->max('paragraph');
-            $paragraphs = range(1, $maxParagraph);
-            if ($this->option('para')) {
-                $paragraphs = [$this->option('para')];
-            }
-            foreach ($paragraphs as $key => $paragraph) {
-                $this->info($this->argument('type') . " {$book}-{$paragraph}");
-                $data = [];
-                switch ($this->argument('type')) {
-                    case 'translation':
-                        $data = $this->aiPaliTranslate($book, $paragraph);
-                        break;
-                    case 'nissaya':
-                        $data = $this->aiNissayaTranslate($book, $paragraph);
-                        break;
-                    case 'wbw':
-                        $data = $this->aiWBW($book, $paragraph);
-                        break;
-                    default:
-                        # code...
-                        break;
-                }
-                $this->save($data);
-            }
-        }
-        return 0;
-    }
-
-    private function getPaliContent($book, $para)
-    {
-        $sentenceService = app(SearchPaliDataService::class);
-        $sentences = PaliSentence::where('book', $book)
-            ->where('paragraph', $para)
-            ->orderBy('word_begin')
-            ->get();
-        if (!$sentences) {
-            return null;
-        }
-        $json = [];
-        foreach ($sentences as $key => $sentence) {
-            $content = $sentenceService->getSentenceText($book, $para, $sentence->word_begin, $sentence->word_end);
-            $id = "{$book}-{$para}-{$sentence->word_begin}-{$sentence->word_end}";
-            $json[] = ['id' => $id, 'content' => $content['markdown']];
-        }
-        return $json;
-    }
-
-    private function aiPaliTranslate($book, $para)
-    {
-        $prompt = <<<md
-        你是一个巴利语翻译助手。
-        pali 是巴利原文的一个段落,json格式, 每条记录是一个句子。包括id 和 content 两个字段
-        请翻译这个段落为简体中文。
-
-        翻译要求
-        1. 语言风格为现代汉语书面语,不要使用古汉语或者半文半白。
-        2. 译文严谨,完全贴合巴利原文,不要加入自己的理解
-        3. 巴利原文中的黑体字在译文中也使用黑体。其他标点符号跟随巴利原文,但应该替换为相应的汉字全角符号
-
-        输出格式jsonl
-        输出id 和 content 两个字段,
-        id 使用巴利原文句子的id ,
-        content 为中文译文
-
-        直接输出jsonl数据,无需解释
-
-
-    **输出范例**
-    {"id":"1-2-3-4","content":"译文"}
-    {"id":"2-3-4-5","content":"译文"}
-    md;
-
-        $pali = $this->getPaliContent($book, $para);
-        $originalText = "```json\n" . json_encode($pali, JSON_UNESCAPED_UNICODE) . "\n```";
-        Log::debug($originalText);
-        if (!$this->model) {
-            Log::error('model is invalid');
-            return [];
-        }
-        $startAt = time();
-        $response = $this->openAIService->setApiUrl($this->model['url'])
-            ->setModel($this->model['model'])
-            ->setApiKey($this->model['key'])
-            ->setSystemPrompt($prompt)
-            ->setTemperature(0.0)
-            ->setStream(false)
-            ->send("# pali\n\n{$originalText}\n\n");
-        $complete = time() - $startAt;
-        $translationText = $response['choices'][0]['message']['content'] ?? '[]';
-        Log::debug("complete in {$complete}s", $translationText);
-        $json = [];
-        if (is_string($translationText)) {
-            $json = LlmResponseParser::jsonl($translationText);
-        }
-        return $json;
-    }
-    private function aiWBW($book, $para)
-    {
-        $sysPrompt = <<<md
-        你是一个佛教翻译专家,精通巴利文和缅文,精通巴利文逐词解析
-        ## 翻译要求:
-        - 请将用户提供的巴利句子单词表中的每个巴利文单词翻译为中文
-        - 这些单词是一个完整的句子,请根据单词的上下文翻译
-        - original 里面的数据是巴利文单词
-        - 输入格式为 json 数组
-        - 输出jsonl格式
-
-        在原来的数据中添加下列输出字段
-        1. meaning:单词的中文意思,如果有两个可能的意思,两个意思之间用/符号分隔
-        5. confidence:你认为你给出的这个单词的信息的信心指数(准确程度) 数值1-100 如果觉得非常有把握100, 如果觉得把握不大,适当降低信心指数
-        6. note:如果你认为信心指数很低,这个是疑难单词,请在note字段写明原因,如果不是疑难单词,请不要填写note
-
-
-        **范例**:
-
-        {"id":1,"original":"bhikkhusanghassa","meaning":"比库僧团[的]","confidence":100}
-
-        直接输出jsonl, 无需其他内容
-        md;
-        $channelId = ChannelApi::getSysChannel('_System_Wbw_VRI_');
-        $sentences = Sentence::where('channel_uid', $channelId)
-            ->where('book_id', $book)
-            ->where('paragraph', $para)
-            ->get();
-        $result = [];
-        foreach ($sentences as $key => $sentence) {
-            $wbw = json_decode($sentence->content);
-            $tpl = [];
-            foreach ($wbw as $key => $word) {
-                if (
-                    !empty($word->real->value) &&
-                    $word->type->value !== '.ctl.'
-                ) {
-                    $tpl[] = [
-                        'id' => $word->sn[0],
-                        'original' => $word->real->value,
-                    ];
-                }
-            }
-
-            $tplText = json_encode($tpl, JSON_UNESCAPED_UNICODE);
-            Log::debug($tplText);
-            $startAt = time();
-            $response = $this->openAIService->setApiUrl($this->model['url'])
-                ->setModel($this->model['model'])
-                ->setApiKey($this->model['key'])
-                ->setSystemPrompt($sysPrompt)
-                ->setTemperature(0.7)
-                ->setStream(false)
-                ->send("```json\n{$tplText}\n```");
-            $complete = time() - $startAt;
-            $content = $response['choices'][0]['message']['content'] ?? '[]';
-            Log::debug("ai response in {$complete}s content=" . $content);
-
-            $json = LlmResponseParser::jsonl($content);
-
-            $id = "{$sentence->book_id}-{$sentence->paragraph}-{$sentence->word_start}-{$sentence->word_end}";
-            $result[] = [
-                'id' => $id,
-                'content' => json_encode($json, JSON_UNESCAPED_UNICODE),
-            ];
-        }
-        return $result;
-    }
-    private function aiNissayaTranslate($book, $para)
-    {
-        $sysPrompt = <<<md
-        你是一个佛教翻译专家,精通巴利文和缅文
-        ## 翻译要求:
-        - 请将nissaya单词表中的巴利文和缅文分别翻译为中文
-        - 输入格式为 巴利文:缅文
-        - 一行是一条记录,翻译的时候,请不要拆分一行中的巴利文单词或缅文单词,一行中出现多个单词的,一起翻译
-        - 输出csv格式内容,分隔符为"$",
-        - 字段如下:巴利文\$巴利文的中文译文\$缅文\$缅文的中文译文 #两个译文的语义相似度(%)
-
-        **范例**:
-
-        pana\$然而\$ဝါဒန္တရကား\$教义之说 #60%
-
-        直接输出csv, 无需其他内容
-        用```包裹的行为注释内容,也需要翻译和解释。放在最后面。如果没有```,无需处理
-        md;
-
-        $sentences = Sentence::nissaya()
-            ->language('my') // 过滤缅文
-            ->where('book_id', $book)
-            ->where('paragraph', $para)
-            ->orderBy('strlen')
-            ->get();
-        $result = [];
-        foreach ($sentences as $key => $sentence) {
-            $id = "{$sentence->book_id}-{$sentence->paragraph}-{$sentence->word_start}-{$sentence->word_end}";
-            /*
-            $nissaya = [];
-            $rows = explode("\n", $sentence->content);
-            foreach ($rows as $key => $row) {
-                if (strpos('=', $row) >= 0) {
-                    $factors = explode("=", $row);
-                    $nissaya[] = Tools::MyToRm($factors[0]) . ':' . end($factors);
-                } else {
-                    $nissaya[] = $row;
-                }
-            }
-            $nissayaText = json_encode(implode("\n", $nissaya), JSON_UNESCAPED_UNICODE);
-            Log::debug($nissayaText);
-            $startAt = time();
-            $response = $this->openAIService->setApiUrl($this->model['url'])
-                ->setModel($this->model['model'])
-                ->setApiKey($this->model['key'])
-                ->setSystemPrompt($sysPrompt)
-                ->setTemperature(0.7)
-                ->setStream(false)
-                ->send("# nissaya\n\n{$nissayaText}\n\n");
-            $complete = time() - $startAt;
-            $content = $response['choices'][0]['message']['content'] ?? '';
-            Log::debug("ai response in {$complete}s content=" . $content);
-            */
-            $aiNissaya = $this->nissayaTranslateService
-                ->setModel($this->model)
-                ->translate($sentence->content, false);
-            Log::debug("ai response ", ['content' => $aiNissaya['data']]);
-            $result[] = [
-                'id' => $id,
-                'content' => json_encode($aiNissaya['data'] ?? [], JSON_UNESCAPED_UNICODE),
-                'content_type' => 'json'
-            ];
-        }
-        return $result;
-    }
-
-    private function save($data)
-    {
-        //写入句子库
-        $sentData = [];
-        $sentData = array_map(function ($n) {
-            $sId = explode('-', $n['id']);
-            return [
-                'book_id' => $sId[0],
-                'paragraph' => $sId[1],
-                'word_start' => $sId[2],
-                'word_end' => $sId[3],
-                'channel_uid' => $this->workChannel['id'],
-                'content' => $n['content'],
-                'content_type' => $n['content_type'] ?? 'markdown',
-                'lang' => $this->workChannel['lang'],
-                'status' => $this->workChannel['status'],
-                'editor_uid' => $this->model['uid'],
-            ];
-        }, $data);
-        foreach ($sentData as $key => $value) {
-            $this->sentenceService->save($value);
-        }
-    }
-}

+ 0 - 60
api-v12/app/Console/Commands/UpgradeAt20230227.php

@@ -1,60 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use Illuminate\Console\Command;
-
-class UpgradeAt20230227 extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'upgrade:at20230227';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = 'update to 2.0';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-        $this->call('init:system.channel');
-        $this->call('init:system.dict');
-        $this->call('upgrade:dict');
-        $this->call('upgrade:dict.vocabulary');
-        $this->call('upgrade:dict.default.meaning');
-
-        //语料库
-        $this->call('init:cs6sentence');
-        $this->call('upgrade:palitext');
-        $this->call('upgrade:wbw.template');
-
-        $this->call('upgrade:related.paragraph');
-        $this->call('upgrade:fts',['--content'=>true]);
-        $this->call('upgrade:pcd.book.id');
-
-        return 0;
-    }
-}

+ 0 - 173
api-v12/app/Console/Commands/UpgradeChapterDynamic.php

@@ -1,173 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-use Illuminate\Support\Facades\Storage;
-use Illuminate\Console\Command;
-use Illuminate\Support\Carbon;
-use App\Models\SentHistory;
-use App\Models\Sentence;
-use App\Models\ProgressChapter;
-use App\Models\PaliText;
-
-class UpgradeChapterDynamic extends Command
-{
-    /**
-     * The name and signature of the console command.
-     *
-     * @var string
-     */
-    protected $signature = 'upgrade:chapter.dynamic {--test}';
-
-    /**
-     * The console command description.
-     *
-     * @var string
-     */
-    protected $description = '更新章节活跃程度svg';
-
-    /**
-     * Create a new command instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    /**
-     * Execute the console command.
-     *
-     * @return int
-     */
-    public function handle()
-    {
-        if(\App\Tools\Tools::isStop()){
-            return 0;
-        }
-		$this->info('upgrade:chapterdynamic start.');
-
-        $startAt = time();
-        $img_width = 600;
-        $img_height = 120;
-        $days = 300; //统计多少天
-        $min = 30;
-        $linewidth = 2;
-
-
-//更新总动态
-		$this->info("更新总动态");
-        $chapters = ProgressChapter::select('book','para')
-                                    ->groupBy('book','para')
-                                    ->orderBy('book')
-                                    ->get();
-        $bar = $this->output->createProgressBar(count($chapters));
-        foreach ($chapters as $key => $chapter) {
-            # code...
-            $max=0;
-            #章节长度
-            $paraEnd = PaliText::where('book',$chapter->book)
-                            ->where('paragraph',$chapter->para)
-                            ->value('chapter_len')+$chapter->para-1;
-
-            $svg = "<svg xmlns='http://www.w3.org/2000/svg'  fill='currentColor' viewBox='0 0 $img_width $img_height'>";
-            $svg .= "<polyline points='";
-            for ($i=$days; $i >0 ; $i--) {
-                # code...
-
-                #这一天有多少次更新
-                $count = SentHistory::whereDate('sent_histories.created_at', '=', Carbon::today()->subDays($i)->toDateString())
-                           ->leftJoin('sentences', 'sent_histories.sent_uid', '=', 'sentences.uid')
-                             ->where('book_id',$chapter->book)
-                             ->whereBetween('paragraph',[$chapter->para,$paraEnd])
-                             ->count();
-                $x=($days-$i)*($img_width/$days);
-                $y=(300-$count)*($img_height/300)-$linewidth;
-                $svg .= "{$x},{$y} ";
-            }
-            $svg .= "'  style='fill:none;stroke:green;stroke-width:{$linewidth}' /></svg>";
-            $filename = "{$chapter->book}/{$chapter->para}/globle.svg";
-            Storage::disk('local')->put("public/images/chapter_dynamic/{$filename}", $svg);
-            $bar->advance();
-
-            if($this->option('test')){
-                break; //调试代码
-            }
-
-        }
-        $bar->finish();
-
-		$time = time()- $startAt;
-        $this->info("用时 {$time}");
-
-        $startAt = time();
-
-        $this->info('更新缺的章节空白图');
-        // 更新缺的章节空白图
-        $chapters = PaliText::select('book','paragraph')
-                            ->where('level', '<', 8)
-                            ->get();
-        $bar = $this->output->createProgressBar(count($chapters));
-        $svg = "<svg xmlns='http://www.w3.org/2000/svg'  fill='currentColor' viewBox='0 0 $img_width $img_height'></svg>";
-        foreach ($chapters as $key => $chapter) {
-            $filename = "{$chapter->book}/{$chapter->paragraph}/globle.svg";
-            if(!Storage::disk('local')->exists("public/images/chapter_dynamic/{$filename}")){
-                Storage::disk('local')->put("public/images/chapter_dynamic/{$filename}", $svg);
-            }
-            $bar->advance();
-
-            if($this->option('test')){
-                break; //调试代码
-            }
-        }
-        $bar->finish();
-		$time = time()- $startAt;
-        $this->info("用时 {$time}");
-
-		$startAt = time();
-        //更新chennel动态
-        $this->info('更新chennel动态');
-        $bar = $this->output->createProgressBar(ProgressChapter::count());
-
-        foreach (ProgressChapter::select('book','para','channel_id')->cursor() as $chapter) {
-            # code...
-            $max=0;
-            #章节长度
-            $paraEnd = PaliText::where('book',$chapter->book)
-                            ->where('paragraph',$chapter->para)
-                            ->value('chapter_len')+$chapter->para-1;
-
-            $svg = "<svg xmlns='http://www.w3.org/2000/svg'  fill='currentColor' viewBox='0 0 $img_width $img_height'>";
-            $svg .= "<polyline points='";
-            for ($i=$days; $i >0 ; $i--) {
-                # code...
-
-                #这一天有多少次更新
-                $count = SentHistory::whereDate('sent_histories.created_at', '=', Carbon::today()->subDays($i)->toDateString())
-                           ->leftJoin('sentences', 'sent_histories.sent_uid', '=', 'sentences.uid')
-                             ->where('book_id',$chapter->book)
-                             ->whereBetween('paragraph',[$chapter->para,$paraEnd])
-                             ->where('sentences.channel_uid',$chapter->channel_id)
-                             ->count();
-                $x=($days-$i)*($img_width/$days);
-                $y=(300-$count)*($img_height/300)-$linewidth;
-                $svg .= "{$x},{$y} ";
-            }
-            $svg .= "'  style='fill:none;stroke:green;stroke-width:{$linewidth}' /></svg>";
-            $filename = "{$chapter->book}/{$chapter->para}/ch_{$chapter->channel_id}.svg";
-            Storage::disk('local')->put("public/images/chapter_dynamic/{$filename}", $svg);
-            $bar->advance();
-
-            if($this->option('test')){
-                break; //调试代码
-            }
-        }
-        $bar->finish();
-		$time = time()- $startAt;
-        $this->info("用时 {$time}");
-
-        $this->info("upgrade:chapterdynamic done");
-
-        return 0;
-    }
-}

Some files were not shown because too many files changed in this diff