Browse Source

Merge pull request #2352 from visuddhinanda/development

Development
visuddhinanda 4 months ago
parent
commit
9670e89db0
100 changed files with 13669 additions and 3826 deletions
  1. 6 1
      api-v8/.env.example
  2. 45 0
      api-v8/app/Console/Commands/ClearEmbeddingsCache.php
  3. 89 0
      api-v8/app/Console/Commands/CreateOpenSearchIndex.php
  4. 68 0
      api-v8/app/Console/Commands/ExportIKPaliTeam.php
  5. 97 0
      api-v8/app/Console/Commands/ExportPaliSynonyms.php
  6. 284 0
      api-v8/app/Console/Commands/IndexPaliText.php
  7. 50 45
      api-v8/app/Console/Commands/InitSystemChannel.php
  8. 131 0
      api-v8/app/Console/Commands/UpgradeSystemSummary.php
  9. 115 0
      api-v8/app/Http/Controllers/ChatController.php
  10. 106 0
      api-v8/app/Http/Controllers/ChatMessageController.php
  11. 2 1
      api-v8/app/Http/Controllers/CollectionController.php
  12. 11 4
      api-v8/app/Http/Controllers/DictController.php
  13. 68 64
      api-v8/app/Http/Controllers/NissayaCardController.php
  14. 62 168
      api-v8/app/Http/Controllers/NissayaEndingController.php
  15. 50 14
      api-v8/app/Http/Controllers/PaliTextController.php
  16. 154 0
      api-v8/app/Http/Controllers/SearchPlusController.php
  17. 194 0
      api-v8/app/Http/Controllers/SearchSuggestController.php
  18. 7 0
      api-v8/app/Http/Controllers/SiteInfoController.php
  19. 96 0
      api-v8/app/Http/Controllers/SysModelController.php
  20. 2 1
      api-v8/app/Http/Controllers/TaskStatusController.php
  21. 237 221
      api-v8/app/Http/Controllers/WbwLookupController.php
  22. 30 0
      api-v8/app/Http/Requests/ChatMessageRequest.php
  23. 30 0
      api-v8/app/Http/Requests/ChatRequest.php
  24. 51 0
      api-v8/app/Http/Requests/StoreChatMessageRequest.php
  25. 30 0
      api-v8/app/Http/Requests/StoreChatRequest.php
  26. 32 0
      api-v8/app/Http/Requests/UpdateChatMessageRequest.php
  27. 30 0
      api-v8/app/Http/Requests/UpdateChatRequest.php
  28. 32 0
      api-v8/app/Http/Resources/ChatMessageResource.php
  29. 28 0
      api-v8/app/Http/Resources/ChatResource.php
  30. 19 0
      api-v8/app/Http/Resources/PaliTextResource.php
  31. 5 3
      api-v8/app/Jobs/ProcessAITranslateJob.php
  32. 106 0
      api-v8/app/Models/Chat.php
  33. 186 0
      api-v8/app/Models/ChatMessage.php
  34. 36 0
      api-v8/app/Services/AIModelService.php
  35. 116 0
      api-v8/app/Services/EmbeddingService.php
  36. 795 0
      api-v8/app/Services/OpenSearchService.php
  37. 2 2
      api-v8/app/Services/RabbitMQService.php
  38. 97 0
      api-v8/app/Services/ResourceService.php
  39. 219 0
      api-v8/app/Services/SearchPaliDataService.php
  40. 214 0
      api-v8/app/Services/SummaryService.php
  41. 3220 3218
      api-v8/app/Tools/CaseEnding.php
  42. 25 9
      api-v8/app/Tools/CaseMan.php
  43. 5 1
      api-v8/composer.json
  44. 13 0
      api-v8/config/mint.php
  45. 24 0
      api-v8/database/factories/ChatFactory.php
  46. 123 0
      api-v8/database/factories/ChatMessageFactory.php
  47. 39 0
      api-v8/database/migrations/2025_09_07_154047_create_chats_table.php
  48. 54 0
      api-v8/database/migrations/2025_09_07_154243_create_chat_messages_table.php
  49. 16 1
      api-v8/routes/api.php
  50. 89 0
      api-v8/tests/Feature/ChatControllerTest.php
  51. 56 0
      api-v8/tests/Feature/ChatMessageControllerTest.php
  52. 1 1
      api-v8/tests/Feature/MockOpenAIApiTest.php
  53. 14 0
      dashboard-v4/dashboard/src/Router.tsx
  54. 4 0
      dashboard-v4/dashboard/src/components/admin/LeftSider.tsx
  55. 13 1
      dashboard-v4/dashboard/src/components/api/Corpus.ts
  56. 5 0
      dashboard-v4/dashboard/src/components/api/ai.ts
  57. 423 0
      dashboard-v4/dashboard/src/components/article/TreeText.tsx
  58. 30 1
      dashboard-v4/dashboard/src/components/channel/ChannelMy.tsx
  59. 2 2
      dashboard-v4/dashboard/src/components/channel/CopyToModal.tsx
  60. 149 38
      dashboard-v4/dashboard/src/components/chat/AiChat.tsx
  61. 133 0
      dashboard-v4/dashboard/src/components/chat/AssistantMessage.tsx
  62. 56 0
      dashboard-v4/dashboard/src/components/chat/ChatContainer.tsx
  63. 404 0
      dashboard-v4/dashboard/src/components/chat/ChatInput.tsx
  64. 4 2
      dashboard-v4/dashboard/src/components/chat/PromptButtonGroup.tsx
  65. 60 0
      dashboard-v4/dashboard/src/components/chat/SearchResults.tsx
  66. 73 0
      dashboard-v4/dashboard/src/components/chat/SessionGroup.tsx
  67. 25 0
      dashboard-v4/dashboard/src/components/chat/StreamingMessage.tsx
  68. 53 0
      dashboard-v4/dashboard/src/components/chat/ToolMessage.tsx
  69. 105 0
      dashboard-v4/dashboard/src/components/chat/UserMessage.tsx
  70. 54 0
      dashboard-v4/dashboard/src/components/chat/VersionSwitcher.tsx
  71. 202 0
      dashboard-v4/dashboard/src/components/chat/style.css
  72. 339 0
      dashboard-v4/dashboard/src/components/corpus/NissayaAligner.tsx
  73. 60 0
      dashboard-v4/dashboard/src/components/corpus/NissayaAlignerModal.tsx
  74. 7 4
      dashboard-v4/dashboard/src/components/general/NissayaCard.tsx
  75. 30 0
      dashboard-v4/dashboard/src/components/general/PaliEnding.ts
  76. 332 0
      dashboard-v4/dashboard/src/components/template/AIWbw.ts
  77. 107 4
      dashboard-v4/dashboard/src/components/template/WbwSent.tsx
  78. 45 0
      dashboard-v4/dashboard/src/hooks/useActivePath.ts
  79. 631 0
      dashboard-v4/dashboard/src/hooks/useChatData.ts
  80. 109 0
      dashboard-v4/dashboard/src/hooks/useSessionGroups.ts
  81. 13 15
      dashboard-v4/dashboard/src/load.ts
  82. 15 0
      dashboard-v4/dashboard/src/pages/admin/ai/index.tsx
  83. 124 0
      dashboard-v4/dashboard/src/pages/admin/ai/list.tsx
  84. 16 0
      dashboard-v4/dashboard/src/pages/library/chat/ai.tsx
  85. 19 0
      dashboard-v4/dashboard/src/pages/library/chat/index.tsx
  86. 19 0
      dashboard-v4/dashboard/src/pages/library/chat/new.tsx
  87. 23 5
      dashboard-v4/dashboard/src/pages/nut/index.tsx
  88. 4 0
      dashboard-v4/dashboard/src/reducers/layout.ts
  89. 289 0
      dashboard-v4/dashboard/src/services/agentApi.ts
  90. 38 0
      dashboard-v4/dashboard/src/services/chatApi.ts
  91. 74 0
      dashboard-v4/dashboard/src/services/messageApi.ts
  92. 269 0
      dashboard-v4/dashboard/src/services/mockChatApi.ts
  93. 24 0
      dashboard-v4/dashboard/src/services/mockMessageApi.ts
  94. 105 0
      dashboard-v4/dashboard/src/services/modelAdapters/base.ts
  95. 25 0
      dashboard-v4/dashboard/src/services/modelAdapters/index.ts
  96. 419 0
      dashboard-v4/dashboard/src/services/modelAdapters/mockOpenAI.ts
  97. 108 0
      dashboard-v4/dashboard/src/services/modelAdapters/openai.ts
  98. 330 0
      dashboard-v4/dashboard/src/types/chat.ts
  99. 284 0
      dashboard-v4/dashboard/src/types/search.ts
  100. 405 0
      dashboard-v4/documents/development/chat/README.md

+ 6 - 1
api-v8/.env.example

@@ -72,4 +72,9 @@ MQ_PASSWORD="guest"
 
 MQ_LOOP_LIMIT_AI_TRANSLATE=100
 
-
+OPENSEARCH_SCHEME=https
+OPENSEARCH_HOST=127.0.0.1
+OPENSEARCH_PORT=9200
+OPENSEARCH_USERNAME=your_username
+OPENSEARCH_PASSWORD=your_password
+OPENSEARCH_SSL_VERIFICATION=false

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

@@ -0,0 +1,45 @@
+<?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;
+    }
+}

+ 89 - 0
api-v8/app/Console/Commands/CreateOpenSearchIndex.php

@@ -0,0 +1,89 @@
+<?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...');
+                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;
+                }
+            } else {
+                $this->error('Failed to create index: ' . $e->getMessage());
+                return 1;
+            }
+        }
+        return 0;
+    }
+}

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

@@ -0,0 +1,68 @@
+<?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;
+    }
+}

+ 97 - 0
api-v8/app/Console/Commands/ExportPaliSynonyms.php

@@ -0,0 +1,97 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use App\Http\Api\DictApi;
+use App\Models\UserDict;
+use App\Models\DhammaTerm;
+use Illuminate\Support\Facades\Redis;
+use Illuminate\Support\Facades\Log;
+
+class ExportPaliSynonyms extends Command
+{
+    /**
+     * The name and signature of the console command.
+     * php artisan export:pali.synonyms
+     * @var string
+     */
+    protected $signature = 'export:pali.synonyms';
+
+    /**
+     * 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()
+    {
+        //irregular
+        $dictId = ['4d3a0d92-0adc-4052-80f5-512a2603d0e8'];
+        //regular
+        $dictId[] = DictApi::getSysDict('system_regular');
+        $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_synonyms.txt";
+        $fp = fopen($path . $filename, 'w') or die("Unable to open file!");
+        foreach ($dictId as $key => $dict) {
+            $parents = UserDict::where('dict_id', $dict)
+                ->select('parent')
+                ->groupBy('parent')->cursor();
+
+            foreach ($parents as $key => $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;
+    }
+}

+ 284 - 0
api-v8/app/Console/Commands/IndexPaliText.php

@@ -0,0 +1,284 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use App\Services\SearchPaliDataService;
+use App\Services\OpenSearchService;
+use App\Services\SummaryService;
+use Illuminate\Support\Facades\Log;
+use App\Models\PaliText;
+
+class IndexPaliText extends Command
+{
+    /**
+     * The name and signature of the console command.
+     * php artisan opensearch:index-pali 93 --para=6
+     * @var string
+     */
+    protected $signature = 'opensearch:index-pali {book : The book ID to index data for}
+    {--test}
+    {--para= : index paragraph No. omit to all}
+    {--summary=on}
+    {--resume}
+    {--granularity= : 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)';
+
+    protected $searchPaliDataService;
+    protected $openSearchService;
+    protected $summaryService;
+    private $isTest = false;
+    private $summary = false;
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct(
+        SearchPaliDataService $searchPaliDataService,
+        OpenSearchService $openSearchService,
+        SummaryService $summaryService
+    ) {
+        parent::__construct();
+        $this->searchPaliDataService = $searchPaliDataService;
+        $this->openSearchService = $openSearchService;
+        $this->summaryService = $summaryService;
+    }
+
+    /**
+     * 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) {
+                $this->indexPaliParagraphs($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;
+        }
+    }
+
+    /**
+     *
+     */
+    protected function indexPaliParagraph($paraInfo, $paraContent, $related_id)
+    {
+        $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' => "pali_para_{$paraId}",
+            'resource_id' => $resource_id, // Use uid from getPaliData for resource_id
+            'resource_type' => 'original_text',
+            'title' => [
+                'pali' => $title,
+            ],
+            'summary' => [
+                'text' => $this->summary  ? $this->summaryService->summarize($paraContent['markdown']) : ''
+            ],
+            'content' => [
+                'pali' => $paraContent['markdown'],
+                'suggest' => $paraContent['words'],
+            ],
+            'bold_single' => implode(' ', $paraContent['bold1']),
+            'bold_multi' => implode(' ', array_merge($paraContent['bold2'], $paraContent['bold3'])),
+            'related_id' => $related_id,
+            'category' => 'pali', // Assuming Pali paragraphs are sutta; adjust as needed
+            'language' => 'pali',
+            'updated_at' => now()->toIso8601String(),
+            'granularity' => 'paragraph',
+            'path' => $this->getPathTitle($path),
+        ];
+        if ($paraInfo['level'] < 8) {
+            $document['title']['suggest'] = $paraContent['words'];
+        }
+        if ($this->isTest) {
+            $this->info($document['title']['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;
+    }
+
+    private function getPathTitle(array $input)
+    {
+        $output = [];
+        foreach ($input as $key => $node) {
+            $output[] = $node->title;
+        }
+        return implode('/', $output);
+    }
+    /**
+     * Index Pali paragraphs for a given book.
+     *
+     * @param int $book
+     * @return int
+     */
+    protected function indexPaliParagraphs($book, $paragraph)
+    {
+        $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();
+        }
+
+        $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->indexPaliParagraph($para->toArray(), $paraContent, $commentaryId);
+            $this->info("{$para['book']}-[{$para['paragraph']}]-[{$commentaryId}]");
+            usleep(10000);
+        }
+
+        $this->info("Successfully indexed $total paragraphs for book: $book");
+        Log::info("Indexed $total paragraphs for book: $book");
+
+        return 0;
+    }
+
+    /**
+     * Index Pali suttas for a given book (placeholder for future implementation).
+     *
+     * @param int $book
+     * @return int
+     */
+    protected function indexPaliSutta($book)
+    {
+        $this->warn("Sutta indexing is not yet implemented for book: $book");
+        Log::warning("Sutta indexing not implemented for book: $book");
+        return 1;
+    }
+
+    /**
+     * 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;
+    }
+}

+ 50 - 45
api-v8/app/Console/Commands/InitSystemChannel.php

@@ -21,71 +21,76 @@ class InitSystemChannel extends Command
      */
     protected $description = 'create system channel. like pali text , wbw template ect.';
 
-    protected $channels =[
+    protected $channels = [
         [
-            "name"=>'_System_Pali_VRI_',
-            'type'=>'original',
-            'lang'=>'pali',
+            "name" => '_System_Pali_VRI_',
+            'type' => 'original',
+            'lang' => 'pali',
         ],
         [
-            "name"=>'_System_Wbw_VRI_',
-            'type'=>'original',
-            'lang'=>'pali',
+            "name" => '_System_Wbw_VRI_',
+            'type' => 'original',
+            'lang' => 'pali',
         ],
         [
-            "name"=>'_System_Grammar_Term_zh-hans_',
-            'type'=>'translation',
-            'lang'=>'zh-Hans',
+            "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_zh-hant_',
+            'type' => 'translation',
+            'lang' => 'zh-Hant',
         ],
         [
-            "name"=>'_System_Grammar_Term_en_',
-            'type'=>'translation',
-            'lang'=>'en',
+            "name" => '_System_Grammar_Term_en_',
+            'type' => 'translation',
+            'lang' => 'en',
         ],
         [
-            "name"=>'_System_Grammar_Term_my_',
-            'type'=>'translation',
-            'lang'=>'my',
+            "name" => '_System_Grammar_Term_my_',
+            'type' => 'translation',
+            'lang' => 'my',
         ],
         [
-            "name"=>'_community_term_zh-hans_',
-            'type'=>'translation',
-            'lang'=>'zh-Hans',
+            "name" => '_community_term_zh-hans_',
+            'type' => 'translation',
+            'lang' => 'zh-Hans',
         ],
         [
-            "name"=>'_community_term_zh-hant_',
-            'type'=>'translation',
-            'lang'=>'zh-Hant',
+            "name" => '_community_term_zh-hant_',
+            'type' => 'translation',
+            'lang' => 'zh-Hant',
         ],
         [
-            "name"=>'_community_term_en_',
-            'type'=>'translation',
-            'lang'=>'en',
+            "name" => '_community_term_en_',
+            'type' => 'translation',
+            'lang' => 'en',
         ],
         [
-            "name"=>'_community_translation_zh-hans_',
-            'type'=>'translation',
-            'lang'=>'zh-Hans',
+            "name" => '_community_translation_zh-hans_',
+            'type' => 'translation',
+            'lang' => 'zh-Hans',
         ],
         [
-            "name"=>'_community_translation_zh-hant_',
-            'type'=>'translation',
-            'lang'=>'zh-Hant',
+            "name" => '_community_translation_zh-hant_',
+            'type' => 'translation',
+            'lang' => 'zh-Hant',
         ],
         [
-            "name"=>'_community_translation_en_',
-            'type'=>'translation',
-            'lang'=>'en',
+            "name" => '_community_translation_en_',
+            'type' => 'translation',
+            'lang' => 'en',
         ],
         [
-            "name"=>'_System_Quote_',
-            'type'=>'original',
-            'lang'=>'en',
+            "name" => '_System_Quote_',
+            'type' => 'original',
+            'lang' => 'en',
+        ],
+        [
+            "name" => '_community_summary_zh-hans_',
+            'type' => 'translation',
+            'lang' => 'zh-Hans',
         ],
     ];
 
@@ -106,7 +111,7 @@ class InitSystemChannel extends Command
      */
     public function handle()
     {
-        if(\App\Tools\Tools::isStop()){
+        if (\App\Tools\Tools::isStop()) {
             return 0;
         }
         $this->info("start");
@@ -116,18 +121,18 @@ class InitSystemChannel extends Command
                 'name' => $value['name'],
                 'owner_uid' => config("mint.admin.root_uuid"),
             ]);
-            if(empty($channel->id)){
+            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->create_time = time() * 1000;
+            $channel->modify_time = time() * 1000;
             $channel->is_system = true;
             $channel->save();
-            $this->info("created". $value['name']);
+            $this->info("created" . $value['name']);
         }
         return 0;
     }

+ 131 - 0
api-v8/app/Console/Commands/UpgradeSystemSummary.php

@@ -0,0 +1,131 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use App\Services\SummaryService;
+use App\Models\PaliText;
+use Illuminate\Support\Facades\Log;
+
+
+class UpgradeSystemSummary extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'upgrade:sys.summary {book : The book ID to index data for} {--para= : index paragraph No. omit to all} {--test}';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Command description';
+
+    protected $summaryService;
+    private $isTest = false;
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct(SummaryService $summaryService)
+    {
+        parent::__construct();
+        $this->summaryService = $summaryService;
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        $book = $this->argument('book');
+        $paragraph = $this->option('para');
+
+        if ($this->option('test')) {
+            $this->isTest = true;
+            $this->info('test mode');
+        }
+
+        if ((int)$book === 0) {
+            $maxBookId = PaliText::max('book');
+            $booksId = range(1, $maxBookId);
+        } else {
+            $booksId = [$book];
+        }
+        foreach ($booksId as $key => $bookId) {
+            $this->summarize($bookId, $paragraph);
+        }
+
+        return 0;
+    }
+
+    /**
+     * Index Pali paragraphs for a given book.
+     *
+     * @param int $book
+     * @return int
+     */
+    protected function summarize($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();
+        }
+
+
+        $commentaryId = '';
+        $chapterContent = array();
+        $chapterStart = 0;
+        $chapterEnd = 0;
+        foreach ($paragraphs as $key => $para) {
+            $total++;
+            $content = $para->text;
+            if ($para->level < 8) {
+                $start = $para->paragraph;
+                $end = $start + $para->chapter_len - 1;
+                $subChapter = PaliText::whereBetween('paragraph', [$start, $end])
+                    ->where('level', '<', 8)
+                    ->count();
+                if ($subChapter === 0) {
+                    $chapterStart = $start;
+                    $chapterEnd = $end;
+                    $chapterContent = [];
+                } else {
+                    $chapterStart = 0;
+                    $chapterEnd = 0;
+                }
+            } else {
+                $summary = $this->summaryService->summarize($para->text);
+                $this->info("{$para['book']}-[{$para['paragraph']}]-{$summary}");
+                if ($chapterStart !== 0) {
+                    $chapterContent[] = $summary;
+                }
+                if ($para->paragraph === $chapterEnd) {
+                    $chapterSummary = $this->summaryService->summarize(implode(' ', $chapterContent));
+                    $this->info("{$para['book']}-[{$chapterStart}]-{$chapterSummary}");
+                    $chapterStart = 0;
+                    $chapterEnd = 0;
+                    $chapterContent = [];
+                }
+            }
+        }
+
+        $this->info("Successfully indexed $total paragraphs for book: $book");
+        Log::info("Indexed $total paragraphs for book: $book");
+
+        return 0;
+    }
+}

+ 115 - 0
api-v8/app/Http/Controllers/ChatController.php

@@ -0,0 +1,115 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+use App\Http\Requests\StoreChatRequest;
+use App\Http\Requests\UpdateChatRequest;
+use App\Models\Chat;
+use App\Http\Resources\ChatResource;
+
+class ChatController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index(Request $request)
+    {
+        $query = Chat::query();
+
+        if ($request->has('user_id')) {
+            $query->where('user_id', $request->user_id);
+        }
+
+        $total = $query->count();
+
+        $chats = $query->orderBy('updated_at', 'desc')
+            ->paginate($request->get('limit', 20));
+
+        return $this->ok([
+            'rows' => ChatResource::collection($chats),
+            'total' => $total
+        ]);
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \App\Http\Requests\StoreChatRequest  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(StoreChatRequest $request)
+    {
+        $chat = Chat::create($request->validated());
+
+        return $this->ok(new ChatResource($chat));
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  \App\Models\Chat  $chat
+     * @return \Illuminate\Http\Response
+     */
+    public function show(Chat $chat)
+    {
+        return $this->ok(new ChatResource($chat));
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \App\Http\Requests\UpdateChatRequest  $request
+     * @param  \App\Models\Chat  $chat
+     * @return \Illuminate\Http\Response
+     */
+    public function update(UpdateChatRequest $request, Chat $chat)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  \App\Models\Chat  $chat
+     * @return \Illuminate\Http\Response
+     */
+    /**
+     * 单个软删除
+     */
+    public function destroy(Chat $chat)
+    {
+        $chat->delete(); // 软删除
+        return $this->ok('Chat deleted successfully.');
+    }
+
+    /**
+     * 批量软删除
+     */
+    public function batchDelete(Request $request)
+    {
+        $chatIds = $request->input('uids', []); // 前端传入数组
+        $count = Chat::batchSoftDelete($chatIds);
+
+        return $this->ok([
+            'message' => "Chats soft deleted successfully.",
+            'deleted_count' => $count
+        ]);
+    }
+
+    /**
+     * 批量恢复
+     */
+    public function batchRestore(Request $request)
+    {
+        $chatIds = $request->input('uids', []); // 前端传入数组
+        $count = Chat::batchRestore($chatIds);
+
+        return $this->ok([
+            'message' => "Chats restored successfully.",
+            'restored_count' => $count
+        ]);
+    }
+}

+ 106 - 0
api-v8/app/Http/Controllers/ChatMessageController.php

@@ -0,0 +1,106 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Http\Requests\StoreChatMessageRequest;
+use App\Http\Requests\UpdateChatMessageRequest;
+use App\Models\ChatMessage;
+use App\Http\Resources\ChatMessageResource;
+use App\Models\Chat;
+use Illuminate\Http\Request;
+use Illuminate\Support\Str;
+
+class ChatMessageController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index(Request $request)
+    {
+        //
+        $query = ChatMessage::where('chat_id', $request->get('chat'));
+
+        $total = $query->count();
+
+        $messages = $query->orderBy('id')->paginate($request->get('limit', 500));
+
+        return $this->ok([
+            'data' => ChatMessageResource::collection($messages),
+            'total' => $total
+        ]);
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \App\Http\Requests\StoreChatMessageRequest  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(StoreChatMessageRequest $request)
+    {
+
+        $messagesData = $request->validated()['messages'];
+        $chatId = $request->validated()['chat_id'];
+
+        $created = [];
+        foreach ($messagesData as $key => $data) {
+            $data['chat_id'] = $chatId;
+            $data['uid'] = (string) Str::uuid();
+
+            // 如果是新消息且没有指定session_id,创建新的session
+            if (empty($data['session_id']) && empty($data['parent_id'])) {
+                $data['session_id'] = (string) Str::uuid();
+            }
+            // 如果有parent_id但没有session_id,继承父消息的session_id
+            elseif (empty($data['session_id']) && !empty($data['parent_id'])) {
+                $parent = ChatMessage::where('uid', $data['parent_id'])->first();
+                if ($parent) {
+                    $data['session_id'] = $parent->session_id;
+                }
+            }
+
+            $created[] = ChatMessage::create($data);
+        }
+
+        return $this->ok([
+            'data' => ChatMessageResource::collection($created),
+            'total' => count($created),
+        ]);
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  \App\Models\ChatMessage  $chatMessage
+     * @return \Illuminate\Http\Response
+     */
+    public function show(ChatMessage $chatMessage)
+    {
+        return $this->ok(new ChatMessageResource($chatMessage));
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \App\Http\Requests\UpdateChatMessageRequest  $request
+     * @param  \App\Models\ChatMessage  $chatMessage
+     * @return \Illuminate\Http\Response
+     */
+    public function update(UpdateChatMessageRequest $request, ChatMessage $chatMessage)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  \App\Models\ChatMessage  $chatMessage
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy(ChatMessage $chatMessage)
+    {
+        //
+    }
+}

+ 2 - 1
api-v8/app/Http/Controllers/CollectionController.php

@@ -201,7 +201,8 @@ class CollectionController extends Controller
     {
         $result  = Collection::where('uid', $id)->first();
         if (!$result) {
-            return $this->warning("没有查询到数据 id={$id}");
+            Log::warning("没有查询到数据 id={$id}");
+            return $this->error("没有查询到数据 id={$id}");
         }
         if ($result->status < 30) {
             //私有文章,判断权限

+ 11 - 4
api-v8/app/Http/Controllers/DictController.php

@@ -55,7 +55,8 @@ class DictController extends Controller
             $inMyHanGroup = true;
         }
         $resultCount = 0;
-        for ($i = 0; $i < 2; $i++) {
+        $MAX_LOOP = 2;
+        for ($i = 0; $i < $MAX_LOOP; $i++) {
             # code...
             $word_base = [];
             $wordDataOutput = [];
@@ -105,7 +106,7 @@ class DictController extends Controller
                 }
                 $dictList = [
                     'href' => '#' . $anchor,
-                    'title' => "{$word}",
+                    'title' => $word,
                     'children' => [],
                 ];
                 foreach ($result as $key => $value) {
@@ -160,8 +161,11 @@ class DictController extends Controller
                     }
                 }
 
-                $wordDataOutput[] = $wordData;
-                $dictListOutput[] = $dictList;
+                if ($i < $MAX_LOOP - 1 || count($wordData['dict']) > 0) {
+                    $wordDataOutput[] = $wordData;
+                    $dictListOutput[] = $dictList;
+                }
+
 
                 //TODO 加变格查询
                 $case = new CaseMan();
@@ -174,6 +178,9 @@ class DictController extends Controller
                 }
             }
 
+            usort($wordDataOutput, function ($a, $b) {
+                return count($b['dict']) - count($a['dict']);
+            });
             $wordDataPass[] = ['pass' => $i + 1, 'words' => $wordDataOutput];
 
             if (count($word_base) === 0) {

+ 68 - 64
api-v8/app/Http/Controllers/NissayaCardController.php

@@ -13,6 +13,7 @@ use App\Models\Relation;
 
 class NissayaCardController extends Controller
 {
+
     /**
      * Display a listing of the resource.
      *
@@ -40,49 +41,50 @@ class NissayaCardController extends Controller
      * @param  string  $nissayaEnding
      * @return \Illuminate\Http\Response
      */
-    public function show(Request $request,string $nissayaEnding)
+    public function show(Request $request, string $nissayaEnding)
     {
         //
         $cardData = [];
         App::setLocale($request->get('lang'));
         $localTerm = ChannelApi::getSysChannel(
-                                "_System_Grammar_Term_".strtolower($request->get('lang'))."_",
-                                "_System_Grammar_Term_en_"
-                            );
-        if(!$localTerm){
+            "_System_Grammar_Term_" . strtolower($request->get('lang')) . "_",
+            "_System_Grammar_Term_en_"
+        );
+        if (!$localTerm) {
             return $this->error('no term channel');
         }
-        $termTable = DhammaTerm::where('channal',$localTerm);
+        $termTable = DhammaTerm::where('channal', $localTerm);
 
         $cardData['ending']['word'] = $nissayaEnding;
-        $endingTerm = $termTable->where('word',$nissayaEnding)->first();
-        if($endingTerm){
+        $endingTerm = $termTable->where('word', $nissayaEnding)->first();
+        if ($endingTerm) {
             $cardData['ending']['id'] = $endingTerm->guid;
             $cardData['ending']['tag'] = $endingTerm->tag;
             $cardData['ending']['meaning'] = $endingTerm->meaning;
             $cardData['ending']['note'] = $endingTerm->note;
-            if(!empty($endingTerm->note)){
+            if (!empty($endingTerm->note)) {
                 $mdRender = new MdRender(
                     [
-                        'mode'=>'read',
-                        'format'=>'react',
-                        'lang'=>$endingTerm->lang,
-                    ]);
-                    $cardData['ending']['html']  = $mdRender->convert($endingTerm->note,[],null);
+                        'mode' => 'read',
+                        'format' => 'react',
+                        'lang' => $endingTerm->lang,
+                    ]
+                );
+                $cardData['ending']['html']  = $mdRender->convert($endingTerm->note, [], null);
             }
         }
 
-        $myEnding = NissayaEnding::where('ending',$nissayaEnding)
-                                 ->select('relation')->get();
-        if(count($myEnding) === 0){
-            if(!isset($cardData['ending']['note'])){
+        $myEnding = NissayaEnding::where('ending', $nissayaEnding)
+            ->select('relation')->get();
+        if (count($myEnding) === 0) {
+            if (!isset($cardData['ending']['note'])) {
                 $cardData['ending']['note'] = "no record\n";
             }
         }
 
-        $relations = Relation::whereIn('name',$myEnding)->get();
+        $relations = Relation::whereIn('name', $myEnding)->get();
 
-        if(count($relations) > 0){
+        if (count($relations) > 0) {
             $cardData['title_case'] = "本词";
             $cardData['title_relation'] = "关系";
             $cardData['title_local_relation'] = "关系";
@@ -92,68 +94,69 @@ class NissayaCardController extends Controller
 
             foreach ($relations as $key => $relation) {
                 $newLine = array();
-                $relationInTerm = DhammaTerm::where('channal',$localTerm)
-                                            ->where('word',$relation['name'])
-                                            ->first();
-                if(empty($relation->from)){
-                    $cardData['row'][] = ["relation"=>$relation->name];
+                $relationInTerm = DhammaTerm::where('channal', $localTerm)
+                    ->where('word', $relation['name'])
+                    ->first();
+                if (empty($relation->from)) {
+                    $cardData['row'][] = ["relation" => $relation->name];
                     continue;
                 }
                 $from = json_decode($relation->from);
-                if(isset($from->case)){
+                if (isset($from->case)) {
                     $cases = $from->case;
-                    $localCase  =[];
+                    $localCase  = [];
                     foreach ($cases as $case) {
-                        $localCase[] = ['label'=>__("grammar.".$case),
-                                        'case'=>$case,
-                                        'link'=>config('mint.server.dashboard_base_path').'/term/list/'.$case
-                                        ];
+                        $localCase[] = [
+                            'label' => $termTable->where('word', $case)->value('meaning'),
+                            'case' => $case,
+                            'link' => config('mint.server.dashboard_base_path') . '/term/list/' . $case
+                        ];
                     }
                     # 格位
                     $newLine['from']['case'] = $localCase;
                 }
-                if(isset($from->spell)){
+                if (isset($from->spell)) {
                     $newLine['from']['spell'] = $from->spell;
                 }
                 //连接到
                 $linkTos = json_decode($relation->to);
-                if(isset($linkTos->case) && is_array($linkTos->case) && count($linkTos->case)>0){
-                    $localTo  =[];
+                if (isset($linkTos->case) && is_array($linkTos->case) && count($linkTos->case) > 0) {
+                    $localTo  = [];
                     foreach ($linkTos->case as $to) {
                         $localTo[] = [
-                            'label'=>__("grammar.".$to),
-                            'case'=>$to,
-                            'link'=>config('mint.server.dashboard_base_path').'/term/list/'.$to
-                            ];
+                            'label' => $termTable->where('word', $to)->value('meaning'),
+                            'case' => $to,
+                            'link' => config('mint.server.dashboard_base_path') . '/term/list/' . $to
+                        ];
                     }
 
                     # 格位
                     $newLine['to']['case'] = $localTo;
                 }
-                if(isset($linkTos->spell)){
+                if (isset($linkTos->spell)) {
                     $newLine['to']['spell'] = $linkTos->spell;
                 }
                 //含义 用分类字段的term 数据
-                if(isset($relation['category']) && !empty($relation['category'])){
+                if (isset($relation['category']) && !empty($relation['category'])) {
                     $newLine['category']['name'] = $relation['category'];
-                    $localCategory = DhammaTerm::where('channal',$localTerm)
-                                                ->where('word',$relation['category'])
-                                                ->first();
+                    $localCategory = DhammaTerm::where('channal', $localTerm)
+                        ->where('word', $relation['category'])
+                        ->first();
 
-                    if($localCategory){
+                    if ($localCategory) {
                         $mdRender = new MdRender(
                             [
-                                'mode'=>'read',
-                                'format'=>'text',
-                                'lang'=>$endingTerm->lang,
-                            ]);
-                        $newLine['category']['note'] = $mdRender->convert($localCategory->note,[],null);
-                        $newLine['category']['meaning'] =$localCategory->meaning;
-                    }else{
+                                'mode' => 'read',
+                                'format' => 'text',
+                                'lang' => $endingTerm->lang,
+                            ]
+                        );
+                        $newLine['category']['note'] = $mdRender->convert($localCategory->note, [], null);
+                        $newLine['category']['meaning'] = $localCategory->meaning;
+                    } else {
                         $newLine['category']['note'] = $relation['category'];
                         $newLine['category']['meaning'] = $relation['category'];
                     }
-
                 }
 
                 /**
@@ -162,38 +165,39 @@ class NissayaCardController extends Controller
                  * from 为空 只匹配 relation
                  */
                 $arrLocalEnding = array();
-                $localEndings = NissayaEnding::where('relation',$relation['name'])
-                                                  ->where('lang',$request->get('lang'))
-                                                  ->get();
+                $localEndings = NissayaEnding::where('relation', $relation['name'])
+                    ->where('lang', $request->get('lang'))
+                    ->get();
                 foreach ($localEndings as $localEnding) {
-                    if(empty($localEnding->from) || $localEnding->from===$relation->from){
-                        $arrLocalEnding[]=$localEnding->ending;
+                    if (empty($localEnding->from) || $localEnding->from === $relation->from) {
+                        $arrLocalEnding[] = $localEnding->ending;
                     }
                 }
-                $newLine['local_ending'] = implode(';',$arrLocalEnding);
+                $newLine['local_ending'] = implode(';', $arrLocalEnding);
 
                 //本地语言 关系名称
-                if($relationInTerm){
+                if ($relationInTerm) {
                     $newLine['local_relation'] =  $relationInTerm->meaning;
                 }
                 //关系名称
                 $newLine['relation'] =  $relation['name'];
-                $newLine['relation_link'] =  config('mint.server.dashboard_base_path').'/term/list/'.$relation['name'];
+                $newLine['relation_link'] =  config('mint.server.dashboard_base_path') . '/term/list/' . $relation['name'];
                 $cardData['row'][] = $newLine;
             }
         }
 
-        if($request->get('content_type','markdown') === 'markdown'){
-            $m = new \Mustache_Engine(array('entity_flags'=>ENT_QUOTES));
+        if ($request->get('content_type', 'markdown') === 'markdown') {
+            $m = new \Mustache_Engine(array('entity_flags' => ENT_QUOTES));
             $tpl = file_get_contents(resource_path("mustache/nissaya_ending_card.tpl"));
-            $result = $m->render($tpl,$cardData);
-        }else{
+            $result = $m->render($tpl, $cardData);
+        } else {
             $result = $cardData;
         }
 
         return $this->ok($result);
     }
 
+
     /**
      * Update the specified resource in storage.
      *

+ 62 - 168
api-v8/app/Http/Controllers/NissayaEndingController.php

@@ -24,47 +24,59 @@ class NissayaEndingController extends Controller
     public function index(Request $request)
     {
         //
-        $table = NissayaEnding::select(['id','ending','lang','relation',
-                                        'case','from','count','editor_id',
-                                        'created_at','updated_at']);
+        $table = NissayaEnding::select([
+            'id',
+            'ending',
+            'lang',
+            'relation',
+            'case',
+            'from',
+            'count',
+            'editor_id',
+            'created_at',
+            'updated_at'
+        ]);
 
-        if(($request->has('case'))){
-            $table->whereIn('case', explode(",",$request->get('case')) );
+        if (($request->has('case'))) {
+            $table->whereIn('case', explode(",", $request->get('case')));
         }
 
-        if(($request->has('lang'))){
-            $table->whereIn('lang', explode(",",$request->get('lang')) );
+        if (($request->has('lang'))) {
+            $table->whereIn('lang', explode(",", $request->get('lang')));
         }
 
-        if(($request->has('relation'))){
+        if (($request->has('relation'))) {
             $table->where('relation', $request->get('relation'));
         }
-        if(($request->has('case'))){
+        if (($request->has('case'))) {
             $table->where('case', $request->get('case'));
         }
 
-        if(($request->has('search'))){
-            $table->where('ending', 'like', "%".$request->get('search')."%");
+        if (($request->has('search'))) {
+            $table->where('ending', 'like', "%" . $request->get('search') . "%");
         }
 
         $count = $table->count();
 
-        $table->orderBy($request->get('order','updated_at'),
-                        $request->get('dir','desc'));
+        $table->orderBy(
+            $request->get('order', 'updated_at'),
+            $request->get('dir', 'desc')
+        );
 
-        $table->skip($request->get("offset",0))
-              ->take($request->get('limit',1000));
+        $table->skip($request->get("offset", 0))
+            ->take($request->get('limit', 1000));
         $result = $table->get();
 
-        return $this->ok(["rows"=>NissayaEndingResource::collection($result),"count"=>$count]);
+        return $this->ok(["rows" => NissayaEndingResource::collection($result), "count" => $count]);
     }
 
-    public function vocabulary(Request $request){
+    public function vocabulary(Request $request)
+    {
         $result = NissayaEnding::select(['ending'])
-                              ->where('lang', $request->get('lang') )
-                              ->groupBy('ending')
-                              ->get();
-        return $this->ok(["rows"=>$result,"count"=>count($result)]);
+            ->where('lang', $request->get('lang'))
+            ->groupBy('ending')
+            ->get();
+        return $this->ok(["rows" => $result, "count" => count($result)]);
     }
     /**
      * Store a newly created resource in storage.
@@ -76,7 +88,7 @@ class NissayaEndingController extends Controller
     {
         //
         $user = AuthApi::current($request);
-        if(!$user){
+        if (!$user) {
             return $this->error(__('auth.failed'));
         }
         //TODO 判断权限
@@ -86,13 +98,13 @@ class NissayaEndingController extends Controller
         ]);
         $new = new NissayaEnding;
         $new->ending = $validated['ending'];
-        $new->strlen = mb_strlen($validated['ending'],"UTF-8") ;
+        $new->strlen = mb_strlen($validated['ending'], "UTF-8");
         $new->lang = $validated['lang'];
         $new->relation = $request->get('relation');
         $new->case = $request->get('case');
-        if($request->has('from')){
-            $new->from = json_encode($request->get('from'),JSON_UNESCAPED_UNICODE);
-        }else{
+        if ($request->has('from')) {
+            $new->from = json_encode($request->get('from'), JSON_UNESCAPED_UNICODE);
+        } else {
             $new->from = null;
         }
         $new->editor_id = $user['user_uid'];
@@ -110,125 +122,6 @@ class NissayaEndingController extends Controller
     {
         //
         return $this->ok(new NissayaEndingResource($nissayaEnding));
-
-    }
-
-    public function nissaya_card(Request $request)
-    {
-        //
-        $cardData = [];
-        App::setLocale($request->get('lang'));
-        $localTerm = ChannelApi::getSysChannel(
-                                "_System_Grammar_Term_".strtolower($request->get('lang'))."_",
-                                "_System_Grammar_Term_en_"
-                            );
-        if(!$localTerm){
-            return $this->error('no term channel');
-        }
-        $termTable = DhammaTerm::where('channal',$localTerm);
-        $cardData['ending'] = $request->get('ending');
-        $endingTerm = $termTable->where('word',$request->get('ending'))->first();
-        if($endingTerm){
-            $cardData['ending_tag'] = $endingTerm->tag;
-            $cardData['ending_meaning'] = $endingTerm->meaning;
-            $cardData['ending_note'] = $endingTerm->note;
-        }
-
-        $myEnding = NissayaEnding::where('ending',$request->get('ending'))
-                                 ->groupBy('relation')
-                                 ->select('relation')->get();
-        if(count($myEnding) === 0){
-            if(!isset($cardData['ending_note'])){
-                $cardData['ending_note'] = "no record\n";
-            }
-        }
-
-        $relations = Relation::whereIn('name',$myEnding)->get();
-        if(count($relations) > 0){
-            $cardData['title_case'] = "本词";
-            $cardData['title_relation'] = "关系";
-            $cardData['title_local_relation'] = "关系";
-            $cardData['title_local_link_to'] = "目标词特征";
-            $cardData['title_content'] = "含义";
-            $cardData['title_local_ending'] = "翻译建议";
-
-            foreach ($relations as $key => $relation) {
-                $relationInTerm = DhammaTerm::where('channal',$localTerm)
-                                            ->where('word',$relation['name'])
-                                            ->first();
-                if(empty($relation->from)){
-                    $cardData['row'][] = ["relation"=>$relation->name];
-                    continue;
-                }
-                $from = json_decode($relation->from);
-                if(isset($from->case)){
-                    $cases = $from->case;
-                    $localCase  =[];
-                    foreach ($cases as $case) {
-                        $localCase[] = ['label'=>__("grammar.".$case),
-                                        'link'=>config('mint.server.dashboard_base_path').'/term/list/'.$case
-                                        ];
-                    }
-                    # 格位
-                    $newLine['case'] = $localCase;
-                }
-                if(isset($from->spell)){
-                    $newLine['spell'] = $from->spell;
-                }
-                //连接到
-                $linkTos = json_decode($relation->to);
-                if(count($linkTos)>0){
-                    $localTo  =[];
-                    foreach ($linkTos as $to) {
-                        $localTo[] = ['label'=>__("grammar.".$to),
-                                        'link'=>config('mint.server.dashboard_base_path').'/term/list/'.$case
-                                        ];
-                    }
-                    # 格位
-                    $newLine['to'] = $localTo;
-                }
-                //含义 用分类字段的term 数据
-                if(isset($relation['category']) && !empty($relation['category'])){
-                    $localCategory = DhammaTerm::where('channal',$localTerm)
-                                                ->where('word',$relation['category'])
-                                                ->first();
-                    if($localCategory){
-                        $newLine['category_note'] = $localCategory->note;
-                    }
-                }
-
-                /**
-                 * 翻译建议
-                 * relation 和 from 都匹配成功
-                 * from 为空 只匹配 relation
-                 */
-                $arrLocalEnding = array();
-                $localEndings = NissayaEnding::where('relation',$relation['name'])
-                                                  ->where('lang',$request->get('lang'))
-                                                  ->get();
-                foreach ($localEndings as $localEnding) {
-                    if(empty($localEnding->from) || $localEnding->from===$relation->from){
-                        $arrLocalEnding[]=$localEnding->ending;
-                    }
-                }
-                $newLine['local_ending'] = implode(';',$arrLocalEnding);
-
-                //本地语言 关系名称
-                if($relationInTerm){
-                    $newLine['local_relation'] =  $relationInTerm->meaning;
-                }
-                //关系名称
-                $newLine['relation'] =  $relation['name'];
-                $newLine['relation_link'] =  config('mint.server.dashboard_base_path').'/term/list/'.$relation['name'];
-                $cardData['row'][] = $newLine;
-            }
-        }
-
-
-        $m = new \Mustache_Engine(array('entity_flags'=>ENT_QUOTES));
-        $tpl = file_get_contents(resource_path("mustache/nissaya_ending_card.tpl"));
-        $md = $m->render($tpl,$cardData);
-        return $this->ok($md);
     }
 
     /**
@@ -242,7 +135,7 @@ class NissayaEndingController extends Controller
     {
         //
         $user = AuthApi::current($request);
-        if(!$user){
+        if (!$user) {
             return $this->error(__('auth.failed'));
         }
         //查询是否重复
@@ -262,18 +155,17 @@ class NissayaEndingController extends Controller
         }
 */
         $nissayaEnding->ending = $request->get('ending');
-        $nissayaEnding->strlen = mb_strlen($request->get('ending'),"UTF-8") ;
+        $nissayaEnding->strlen = mb_strlen($request->get('ending'), "UTF-8");
         $nissayaEnding->lang = $request->get('lang');
         $nissayaEnding->relation = $request->get('relation');
-        if($request->has('from') && !empty($request->get('from'))){
-            $nissayaEnding->from = json_encode($request->get('from'),JSON_UNESCAPED_UNICODE);
-        }else{
+        if ($request->has('from') && !empty($request->get('from'))) {
+            $nissayaEnding->from = json_encode($request->get('from'), JSON_UNESCAPED_UNICODE);
+        } else {
             $nissayaEnding->from = null;
         }
         $nissayaEnding->editor_id = $user['user_uid'];
         $nissayaEnding->save();
         return $this->ok(new NissayaEndingResource($nissayaEnding));
-
     }
 
     /**
@@ -283,11 +175,11 @@ class NissayaEndingController extends Controller
      * @param  \App\Models\NissayaEnding  $nissayaEnding
      * @return \Illuminate\Http\Response
      */
-    public function destroy(Request $request,NissayaEnding $nissayaEnding)
+    public function destroy(Request $request, NissayaEnding $nissayaEnding)
     {
         //
         $user = AuthApi::current($request);
-        if(!$user){
+        if (!$user) {
             return $this->error(__('auth.failed'));
         }
         //TODO 判断当前用户是否有权限
@@ -297,7 +189,8 @@ class NissayaEndingController extends Controller
         return $this->ok($delete);
     }
 
-    public function export(){
+    public function export()
+    {
         $spreadsheet = new Spreadsheet();
         $activeWorksheet = $spreadsheet->getActiveSheet();
         $activeWorksheet->setCellValue('A1', 'id');
@@ -322,9 +215,10 @@ class NissayaEndingController extends Controller
         $writer->save("php://output");
     }
 
-    public function import(Request $request){
+    public function import(Request $request)
+    {
         $user = AuthApi::current($request);
-        if(!$user){
+        if (!$user) {
             return $this->error(__('auth.failed'));
         }
 
@@ -343,44 +237,44 @@ class NissayaEndingController extends Controller
             $lang = $activeWorksheet->getCell("C{$currLine}")->getValue();
             $relation = $activeWorksheet->getCell("D{$currLine}")->getValue();
             $case = $activeWorksheet->getCell("E{$currLine}")->getValue();
-            if(!empty($ending)){
+            if (!empty($ending)) {
                 //查询是否有冲突数据
                 //查询此id是否有旧数据
-                if(!empty($id)){
+                if (!empty($id)) {
                     $oldRow = NissayaEnding::find($id);
                 }
                 //查询是否跟已有数据重复
-                $row = NissayaEnding::where(['ending'=>$ending,'relation'=>$relation,'case'=>$case])->first();
-                if(!$row){
+                $row = NissayaEnding::where(['ending' => $ending, 'relation' => $relation, 'case' => $case])->first();
+                if (!$row) {
                     //不重复
-                    if(isset($oldRow) && $oldRow){
+                    if (isset($oldRow) && $oldRow) {
                         //有旧的记录-修改旧数据
                         $row = $oldRow;
-                    }else{
+                    } else {
                         //没找到旧的记录-新建
                         $row = new NissayaEnding();
                     }
-                }else{
+                } else {
                     //重复-如果与旧的id不同旧报错
-                    if(isset($oldRow) && $oldRow && $row->id !== $id){
-                        $error .= "重复的数据:{$id} - {$word}\n";
+                    if (isset($oldRow) && $oldRow && $row->id !== $id) {
+                        $error .= "重复的数据:{$id} - {$ending}\n";
                         $currLine++;
                         $countFail++;
                         continue;
                     }
                 }
                 $row->ending = $ending;
-                $row->strlen = mb_strlen($ending,"UTF-8") ;
+                $row->strlen = mb_strlen($ending, "UTF-8");
                 $row->lang = $lang;
                 $row->relation = $relation;
                 $row->case = $case;
                 $row->editor_id = $user['user_uid'];
                 $row->save();
-            }else{
+            } else {
                 break;
             }
             $currLine++;
         } while (true);
-        return $this->ok(["success"=>$currLine-2-$countFail,'fail'=>($countFail)],$error);
+        return $this->ok(["success" => $currLine - 2 - $countFail, 'fail' => ($countFail)], $error);
     }
 }

+ 50 - 14
api-v8/app/Http/Controllers/PaliTextController.php

@@ -9,6 +9,7 @@ use App\Models\Tag;
 use App\Models\TagMap;
 use Illuminate\Http\Request;
 use App\Tools\RedisClusters;
+use App\Http\Resources\PaliTextResource;
 
 class PaliTextController extends Controller
 {
@@ -130,6 +131,42 @@ class PaliTextController extends Controller
                 $all_count = $table->count();
                 $chapters = $table->orderBy('paragraph')->get();
                 break;
+            case 'children':
+                if ($request->has('id')) {
+                    $root = PaliText::where('uid', $request->get('id'))
+                        ->first();
+                } else {
+                    $root = PaliText::where('book', $request->get('book'))
+                        ->where('paragraph', $request->get('para'))
+                        ->first();
+                }
+
+                if ($root->level >= 8) {
+                    $chapters = [];
+                    break;
+                }
+                $start = $root->paragraph + 1;
+                $end = $root->paragraph + $root->chapter_len - 1;
+                $nextLevelChapter = PaliText::where('book', $root->book)
+                    ->whereBetween('paragraph', [$start, $end])
+                    ->whereBetween('level', [$root->level + 1, 7])
+                    ->orderBy('level', 'asc')
+                    ->first();
+                if ($nextLevelChapter) {
+                    //存在子目录
+                    $chapters = PaliText::where('book', $root->book)
+                        ->whereBetween('paragraph', [$start, $end])
+                        ->where('level', $nextLevelChapter->level)
+                        ->orderBy('paragraph', 'asc')
+                        ->get();
+                } else {
+                    $chapters = PaliText::where('book', $root->book)
+                        ->whereBetween('paragraph', [$start, $end])
+                        ->orderBy('paragraph', 'asc')
+                        ->get();
+                }
+                $all_count = count($chapters);
+                break;
             case 'paragraph':
                 $result = PaliText::where('book', $request->get('book'))
                     ->where('paragraph', $request->get('para'))
@@ -210,20 +247,17 @@ class PaliTextController extends Controller
 
                 break;
         }
-        if ($chapters) {
-            if ($request->get('view') !== 'book-toc') {
-                foreach ($chapters as $key => $value) {
-                    if (is_object($value)) {
-                        //TODO $value->book 可能不存在
-                        $progress_key = "/chapter_dynamic/{$value->book}/{$value->paragraph}/global";
-                        $chapters[$key]->progress_line = RedisClusters::get($progress_key);
-                    }
+
+        if ($request->get('view') !== 'book-toc') {
+            foreach ($chapters as $key => $value) {
+                if (is_object($value)) {
+                    //TODO $value->book 可能不存在
+                    $progress_key = "/chapter_dynamic/{$value->book}/{$value->paragraph}/global";
+                    $chapters[$key]->progress_line = RedisClusters::get($progress_key);
                 }
             }
-            return $this->ok(["rows" => $chapters, "count" => $all_count]);
-        } else {
-            return $this->error("no data");
         }
+        return $this->ok(["rows" => $chapters, "count" => $all_count]);
     }
 
     /**
@@ -240,13 +274,15 @@ class PaliTextController extends Controller
     /**
      * Display the specified resource.
      *
-     * @param  \Illuminate\Http\Request  $request
+     * @param  string  $id
      * @return \Illuminate\Http\Response
      */
-    public function show(Request $request)
+    public function show(string $id)
     {
         //
-
+        $para = explode('-', $id);
+        $paragraph = PaliText::where('book', $para[0])->where('paragraph', $para[1])->first();
+        return $this->ok(new PaliTextResource($paragraph));
     }
 
     /**

+ 154 - 0
api-v8/app/Http/Controllers/SearchPlusController.php

@@ -0,0 +1,154 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Services\OpenSearchService;
+use Illuminate\Http\Request;
+
+class SearchPlusController extends Controller
+{
+    protected $searchService;
+
+    /**
+     * 构造函数,注入 OpenSearchService
+     *
+     * @param  \App\Services\OpenSearchService  $searchService
+     */
+    public function __construct(OpenSearchService $searchService)
+    {
+        $this->searchService = $searchService;
+    }
+
+    /**
+     * Display a listing of the resource.
+     *
+     * 处理搜索请求,支持 fuzzy / exact / semantic / hybrid 四种模式。
+     * 接收查询参数并调用 OpenSearchService 执行搜索。
+     *
+     * 支持 GET 和 POST 请求
+     *
+     * @param  \Illuminate\Http\Request  $request
+     *   - q (string): 搜索关键词
+     *   - resource_type (string): 资源类型 (article|term|dictionary|translation|origin_text|nissaya)
+     *   - granularity (string): 文档颗粒度 (book|chapter|sutta|section|paragraph|sentence)
+     *   - language (string): 语言,如 pali, zh-Hans, zh-Hant, en-US, my
+     *   - category (string): 文档分类 (pali|commentary|subcommentary)
+     *   - tags (array): 标签过滤
+     *   - page_refs (array): 页码标记 ["V3.81","M3.58"]
+     *   - related_id (array): 关联 ID,如 ["chapter_93-5","m.n. 38"]
+     *   - author (string): 作者或译者 (metadata.author)
+     *   - channel (string): 来源渠道 (metadata.channel)
+     *   - page (int): 页码,默认 1
+     *   - page_size (int): 每页数量,默认 20,最大 100
+     *   - search_mode (string): fuzzy|exact|semantic|hybrid,默认 fuzzy
+     *
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function index(Request $request)
+    {
+        // 获取所有输入参数(自动兼容 GET 和 POST)
+        $input = $request->all();
+
+        // 基础参数 - 使用 $input 或直接用 $request->input() (已兼容 GET/POST)
+        $query        = $request->input('q', '');
+        $page         = max(1, (int) $request->input('page', 1));
+        $pageSize     = min(100, (int) $request->input('page_size', 20));
+        $searchMode   = $request->input('search_mode', 'fuzzy');
+        $resourceType = $request->input('resource_type'); // 资源类型
+        $resourceId = $request->input('resource_id'); // 资源类型
+        $granularity  = $request->input('granularity');   // 文档颗粒度
+        $language     = $request->input('language');      // 语言
+        $category     = $request->input('category');      // 分类
+        $tags         = $request->input('tags', []);      // 标签
+        $pageRefs     = $request->input('page_refs', []); // 页码标记
+        $relatedId    = $request->input('related_id'); // 关联 ID
+        $author       = $request->input('author');        // 作者/译者 (metadata.author)
+        $channel      = $request->input('channel');       // 来源渠道 (metadata.channel)
+
+        // 确保数组类型参数正确解析(POST 时可能是 JSON 字符串)
+        $tags = is_array($tags) ? $tags : (is_string($tags) ? json_decode($tags, true) ?? [] : []);
+        $pageRefs = is_array($pageRefs) ? $pageRefs : (is_string($pageRefs) ? json_decode($pageRefs, true) ?? [] : []);
+
+        // 组装搜索参数
+        $params = [
+            'query'        => $query,
+            'page'         => $page,
+            'pageSize'     => $pageSize,
+            'searchMode'   => $searchMode,
+            'resourceType' => $resourceType,
+            'resourceId'   => $resourceId,
+            'granularity'  => $granularity,
+            'language'     => $language,
+            'category'     => $category,
+            'tags'         => $tags,
+            'pageRefs'     => $pageRefs,
+            'relatedId'    => $relatedId,
+            'author'       => $author,
+            'channel'      => $channel,
+        ];
+
+        try {
+            // 调用 OpenSearchService 执行搜索
+            $result = $this->searchService->search($params);
+
+            return response()->json([
+                'success' => true,
+                'data'    => $result,
+                'query_info' => [
+                    'original_query' => $query,
+                    'search_mode'    => $searchMode,
+                    'request_method' => $request->method(), // 可选:返回请求方法
+                ],
+            ]);
+        } catch (\Exception $e) {
+            return response()->json([
+                'success' => false,
+                'error'   => $e->getMessage(),
+            ], 500);
+        }
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * POST 方式调用搜索接口(与 index 方法功能相同)
+     *
+     * @route POST /api/search
+     * @param JSON: 搜索参数(与 index 方法参数相同)
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function store(Request $request)
+    {
+        // 直接调用 index 方法,复用搜索逻辑
+        return $this->index($request);
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  int  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function show($id)
+    {
+        //
+    }
+
+    /**
+     * 更新资源
+     * @route PUT /api/search/{uid}
+     * @param JSON: OpenSearch 格式数据
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, $uid) {}
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * 删除资源
+     * @route DELETE /api/search/{uid}
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy($uid) {}
+}

+ 194 - 0
api-v8/app/Http/Controllers/SearchSuggestController.php

@@ -0,0 +1,194 @@
+<?php
+// api-v8/app/Http/Controllers/SearchSuggestController.php
+namespace App\Http\Controllers;
+
+use App\Http\Controllers\Controller;
+use Illuminate\Http\Request;
+use App\Services\OpenSearchService;
+
+/**
+ * 搜索自动建议控制器
+ *
+ * 返回示例:
+ *
+ * 请求:GET /api/v2/suggest?q=dhamma&fields=title,content&limit=10
+ *
+ * 返回:
+ * {
+ *   "success": true,
+ *   "data": {
+ *     "query": "dhamma",
+ *     "suggestions": [
+ *       {
+ *         "text": "dhammapada",
+ *         "source": "title",
+ *         "score": 5.2,
+ *         "resource_type": "sutta",
+ *         "language": "pali",
+ *         "doc_id": "doc_123"
+ *       },
+ *       {
+ *         "text": "dhammapadā",
+ *         "source": "content",
+ *         "score": 4.8,
+ *         "resource_type": "commentary",
+ *         "language": "pali",
+ *         "doc_id": "doc_456"
+ *       }
+ *     ],
+ *     "total": 2
+ *   }
+ * }
+ */
+class SearchSuggestController extends Controller
+{
+    protected $searchService;
+
+    /**
+     * 构造函数,注入 OpenSearchService
+     *
+     * @param  \App\Services\OpenSearchService  $searchService
+     */
+    public function __construct(OpenSearchService $searchService)
+    {
+        $this->searchService = $searchService;
+    }
+
+    /**
+     * # 1. 查询所有字段(默认)
+GET /api/v2/suggest?q=dhamma&limit=10
+
+# 2. 只查询标题
+GET /api/v2/suggest?q=dhamma&fields=title&limit=10
+
+# 3. 查询标题和内容
+GET /api/v2/suggest?q=dhamma&fields=title,content&limit=10
+
+# 4. 查询页面引用,带语言过滤
+GET /api/v2/suggest?q=M.1&fields=page_refs&language=pali&limit=5
+
+# 5. 数组形式传递多个字段
+GET /api/v2/suggest?q=dhamma&fields[]=title&fields[]=content&limit=10
+     */
+    /**
+     * 自动建议接口
+     *
+     * 基于 OpenSearch completion suggester,支持从不同字段获取建议。
+     *
+     * @param  \Illuminate\Http\Request  $request
+     *   - q (string): 输入的部分文本(必填)
+     *   - fields (string|array): 要查询的字段,可选值:
+     *       - 不传:查询所有字段 (title, content, page_refs)
+     *       - 单个字段:'title' | 'content' | 'page_refs'
+     *       - 多个字段:'title,content' 或 ['title', 'content']
+     *   - language (string): 语言过滤,可选(如:pali, zh, en)
+     *   - limit (int): 每个字段返回的建议数量,默认 10,最大 50
+     *
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function index(Request $request)
+    {
+        // 验证必填参数
+        $query = $request->input('q', '');
+        if (empty($query)) {
+            return response()->json([
+                'success' => false,
+                'error'   => '缺少参数 q(查询文本)'
+            ], 400);
+        }
+
+        // 解析 fields 参数
+        $fields = $this->parseFields($request->input('fields'));
+
+        // 获取其他参数
+        $language = $request->input('language', null);
+        $limit = min(50, max(1, (int) $request->input('limit', 10)));
+
+        try {
+            // 调用搜索服务
+            $rawSuggestions = $this->searchService->suggest(
+                $query,
+                $fields,
+                $language,
+                $limit
+            );
+
+            // 格式化返回结果
+            $suggestions = $this->formatSuggestions($rawSuggestions);
+
+            return response()->json([
+                'success' => true,
+                'data'    => [
+                    'query'       => $query,
+                    'suggestions' => $suggestions,
+                    'total'       => count($suggestions)
+                ]
+            ]);
+        } catch (\InvalidArgumentException $e) {
+            return response()->json([
+                'success' => false,
+                'error'   => '无效的字段参数:' . $e->getMessage(),
+                'hint'    => '有效的字段值:title, content, page_refs'
+            ], 400);
+        } catch (\Exception $e) {
+            return response()->json([
+                'success' => false,
+                'error'   => '搜索建议失败:' . $e->getMessage(),
+            ], 500);
+        }
+    }
+
+    /**
+     * 解析 fields 参数
+     *
+     * @param  mixed  $fields
+     * @return string|array|null
+     */
+    protected function parseFields($fields)
+    {
+        if ($fields === null) {
+            return null;  // 查询所有字段
+        }
+
+        if (is_string($fields)) {
+            // 如果是逗号分隔的字符串,转换为数组
+            if (strpos($fields, ',') !== false) {
+                $fieldsArray = array_map('trim', explode(',', $fields));
+                return $fieldsArray;
+            }
+            // 单个字段
+            return $fields;
+        }
+
+        if (is_array($fields)) {
+            return $fields;
+        }
+
+        return null;
+    }
+
+    /**
+     * 格式化建议结果
+     *
+     * @param  array  $rawSuggestions
+     * @return array
+     */
+    protected function formatSuggestions(array $rawSuggestions): array
+    {
+        return collect($rawSuggestions)->map(function ($item) {
+            $docSource = $item['doc_source'] ?? [];
+
+            return [
+                'text'          => $item['text'] ?? '',
+                'source'        => $item['source'] ?? null,
+                'score'         => round($item['score'] ?? 0, 2),
+                'resource_type' => $docSource['resource_type'] ?? null,
+                'language'      => $docSource['language'] ?? null,
+                'doc_id'        => $item['doc_id'] ?? null,
+                // 可选:添加更多元数据
+                'category'      => $docSource['category'] ?? null,
+                'granularity'   => $docSource['granularity'] ?? null,
+            ];
+        })->all();
+    }
+}

+ 7 - 0
api-v8/app/Http/Controllers/SiteInfoController.php

@@ -4,6 +4,9 @@ namespace App\Http\Controllers;
 
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\App;
+use App\Tools\RedisClusters;
+use App\Services\AIModelService;
+
 
 class SiteInfoController extends Controller
 {
@@ -41,6 +44,7 @@ class SiteInfoController extends Controller
         } else {
             App::setLocale($language);
         }
+        $model = app(AIModelService::class);
         $response = [
             'logo' => __("site.logo"),
             'title' => __('site.title'),
@@ -52,6 +56,9 @@ class SiteInfoController extends Controller
                 'name' => __('site.author.name'),
                 'email' => __('site.author.email'),
             ],
+            'settings' => [
+                'models' => $model->getSysModels(),
+            ]
         ];
         return response()->json(
             $response,

+ 96 - 0
api-v8/app/Http/Controllers/SysModelController.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\AiModel;
+use Illuminate\Http\Request;
+use App\Http\Api\AuthApi;
+use Illuminate\Support\Facades\Log;
+use App\Tools\RedisClusters;
+use App\Http\Resources\AiModelResource;
+
+class SysModelController extends Controller
+{
+    protected $key = "/ai/model/system/";
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index(Request $request)
+    {
+        //
+        $user = AuthApi::current($request);
+        if (!$user) {
+            Log::error('notification auth failed {request}', ['request' => $request]);
+            return $this->error(__('auth.failed'), 401, 401);
+        }
+        $modelsId = RedisClusters::get($this->key . $request->get('view', 'wbw'));
+        if (!is_array($modelsId)) {
+            $modelsId = [];
+        }
+        $result = AiModel::whereIn('uid', $modelsId)
+            ->get();
+        return $this->ok(
+            [
+                "rows" => AiModelResource::collection(resource: $result),
+                "count" => count($result),
+            ]
+        );
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(Request $request)
+    {
+        //
+        $user = AuthApi::current($request);
+        if (!$user) {
+            Log::error('notification auth failed {request}', ['request' => $request]);
+            return $this->error(__('auth.failed'), 401, 401);
+        }
+        RedisClusters::put(
+            $this->key . $request->get('view', 'wbw'),
+            $request->get('models')
+        );
+        return $this->ok('ok');
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  \App\Models\AiModel  $aiModel
+     * @return \Illuminate\Http\Response
+     */
+    public function show(string $view)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \App\Models\AiModel  $aiModel
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, AiModel $aiModel)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  \App\Models\AiModel  $aiModel
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy(AiModel $aiModel)
+    {
+        //
+    }
+}

+ 2 - 1
api-v8/app/Http/Controllers/TaskStatusController.php

@@ -195,7 +195,7 @@ class TaskStatusController extends Controller
             if ($aiAssistant) {
                 $aiTask = Task::find($taskId);
                 try {
-                    \App\Jobs\ProcessAITranslateJob::publish($taskId, $aiAssistant->uid);
+                    $msgId = \App\Jobs\ProcessAITranslateJob::publish($taskId, $aiAssistant->uid);
                     $aiTask->executor_id = $aiAssistant->uid;
                     $aiTask->status = 'queue';
                     $this->pushChange('queue', $taskId);
@@ -252,6 +252,7 @@ class TaskStatusController extends Controller
                         'res_id' => $taskId,
                         'res_type' => 'task',
                         'title' => "{$editor['nickName']} 将任务状态变为 {$key}",
+                        'content' => isset($msgId) ? "message id:{$msgId}" : null,
                         'editor_uid' => $user['user_uid'],
                     ]);
                 }

+ 237 - 221
api-v8/app/Http/Controllers/WbwLookupController.php

@@ -18,18 +18,18 @@ use App\Http\Api\AuthApi;
 
 class WbwLookupController extends Controller
 {
-	private $dictList = [
-		'85dcc61c-c9e1-4ae0-9b44-cd6d9d9f0d01',//社区汇总
-		'4d3a0d92-0adc-4052-80f5-512a2603d0e8',// system irregular
-		'8359757e-9575-455b-a772-cc6f036caea0',// system sandhi
-		'61f23efb-b526-4a8e-999e-076965034e60',// pali myanmar grammar
-		'eae9fd6f-7bac-4940-b80d-ad6cd6f433bf',// Concise P-E Dict
-		'2f93d0fe-3d68-46ee-a80b-11fa445a29c6',// unity
-		'beb45062-7c20-4047-bcd4-1f636ba443d1',// U Hau Sein
-		'8833de18-0978-434c-b281-a2e7387f69be',// 巴汉增订
-		'3acf0c0f-59a7-4d25-a3d9-bf394a266ebd',// 汉译パーリ语辞典-黃秉榮
-        '9ce6a53b-e28f-4fb7-b69d-b35fd5d76a24',//缅英字典
-	];
+    private $dictList = [
+        '85dcc61c-c9e1-4ae0-9b44-cd6d9d9f0d01', //社区汇总
+        '4d3a0d92-0adc-4052-80f5-512a2603d0e8', // system irregular
+        '8359757e-9575-455b-a772-cc6f036caea0', // system sandhi
+        '61f23efb-b526-4a8e-999e-076965034e60', // pali myanmar grammar
+        'eae9fd6f-7bac-4940-b80d-ad6cd6f433bf', // Concise P-E Dict
+        '2f93d0fe-3d68-46ee-a80b-11fa445a29c6', // unity
+        'beb45062-7c20-4047-bcd4-1f636ba443d1', // U Hau Sein
+        '8833de18-0978-434c-b281-a2e7387f69be', // 巴汉增订
+        '3acf0c0f-59a7-4d25-a3d9-bf394a266ebd', // 汉译パーリ语辞典-黃秉榮
+        '9ce6a53b-e28f-4fb7-b69d-b35fd5d76a24', //缅英字典
+    ];
     /**
      * Create a new command instance.
      *
@@ -54,82 +54,85 @@ class WbwLookupController extends Controller
     {
 
         //
-		$startAt = microtime(true)*1000;
+        $startAt = microtime(true) * 1000;
 
         $this->initSysDict();
 
-		$words = \explode(',',$request->get("word"));
-        $bases = \explode(',',$request->get("base"));
+        $words = \explode(',', $request->get("word"));
+        $bases = \explode(',', $request->get("base"));
         # 查询深度
-		$deep = $request->get("deep",2);
-        $result = $this->lookup($words,$bases,$deep);
-        $endAt = microtime(true)*1000;
+        $deep = $request->get("deep", 2);
+        $result = $this->lookup($words, $bases, $deep);
+        $endAt = microtime(true) * 1000;
 
 
-		return $this->ok(["rows"=>$result,
-                          "count"=>count($result),
-                          "time"=>(int)($endAt-$startAt)]);
+        return $this->ok([
+            "rows" => $result,
+            "count" => count($result),
+            "time" => (int)($endAt - $startAt)
+        ]);
     }
 
     //查用户字典获取全部结果
-    public function lookup($words,$bases,$deep){
-		$wordPool = array();
-		$output  = array();
+    public function lookup($words, $bases, $deep)
+    {
+        $wordPool = array();
+        $output  = array();
         foreach ($words as $word) {
-			$wordPool[$word] = ['base' => false,'done' => false,'apply' => false];
-		}
-		foreach ($bases as $base) {
-			$wordPool[$base] = ['base' => true,'done' => false,'apply' => false];
-		}
+            $wordPool[$word] = ['base' => false, 'done' => false, 'apply' => false];
+        }
+        foreach ($bases as $base) {
+            $wordPool[$base] = ['base' => true, 'done' => false, 'apply' => false];
+        }
         /**
          * 先查询字典名称
          */
-        $dict_info = DictInfo::whereIn('id',$this->dictList)->select('id','shortname')->get();
+        $dict_info = DictInfo::whereIn('id', $this->dictList)->select('id', 'shortname')->get();
         $dict_name = [];
         foreach ($dict_info as $key => $value) {
             # code...
             $dict_name[$value->id] = $value->shortname;
         }
         $caseman = new CaseMan();
-		for ($i=0; $i < $deep; $i++) {
+        for ($i = 0; $i < $deep; $i++) {
             $newBase = array();
 
             $newWords = [];
             foreach ($wordPool as $word => $info) {
                 # code...
-                if($info['done'] === false){
+                if ($info['done'] === false) {
                     $newWords[] = $word;
                     $wordPool[$word]['done'] = true;
                 }
             }
-            $data = UserDict::whereIn('word',$newWords)
-                            ->whereIn('dict_id',$this->dictList)
-                            ->leftJoin('dict_infos', 'user_dicts.dict_id', '=', 'dict_infos.id')
-                            ->orderBy('confidence','desc')
-                            ->get();
+            $data = UserDict::whereIn('word', $newWords)
+                ->whereIn('dict_id', $this->dictList)
+                ->leftJoin('dict_infos', 'user_dicts.dict_id', '=', 'dict_infos.id')
+                ->orderBy('confidence', 'desc')
+                ->get();
             foreach ($data as $row) {
                 # code...
-                array_push($output,$row);
-                if(!empty($row->parent) && !isset($wordPool[$row->parent]) ){
+                array_push($output, $row);
+                if (!empty($row->parent) && !isset($wordPool[$row->parent])) {
                     //将parent 插入待查询列表
-                    $wordPool[$row->parent] = ['base' => true,'done' => false,'apply' => false];
+                    $wordPool[$row->parent] = ['base' => true, 'done' => false, 'apply' => false];
                 }
             }
 
-			//处理查询结果中的拆分信息
-			$newWordPart = array();
-			foreach ($wordPool as $word => $info) {
-				if(!empty($info['factors'])){
-					$factors = \explode('+',$info['factors']);
-					foreach ($factors as $factor) {
-						# 将没有的拆分放入单词查询列表
-						if(!isset($wordPool[$factor])){
-							$wordPool[$factor] = ['base' => true,'done' => false,'apply' => false];
-						}
-					}
-				}
-			}
-		}
+            //处理查询结果中的拆分信息
+            $newWordPart = array();
+            foreach ($wordPool as $word => $info) {
+                if (!empty($info['factors'])) {
+                    $factors = \explode('+', $info['factors']);
+                    foreach ($factors as $factor) {
+                        # 将没有的拆分放入单词查询列表
+                        if (!isset($wordPool[$factor])) {
+                            $wordPool[$factor] = ['base' => true, 'done' => false, 'apply' => false];
+                        }
+                    }
+                }
+            }
+        }
 
         return $output;
     }
@@ -137,16 +140,17 @@ class WbwLookupController extends Controller
     /**
      *
      */
-    private function langCheck($query,$lang){
-        if($query===[]){
+    private function langCheck($query, $lang)
+    {
+        if ($query === []) {
             return true;
-        }else{
-            if(in_array(strtolower($lang),$query)){
+        } else {
+            if (in_array(strtolower($lang), $query)) {
                 return true;
-            }else{
-                $langFamily = explode('-',$lang)[0];
+            } else {
+                $langFamily = explode('-', $lang)[0];
                 foreach ($query as $value) {
-                    if(strpos($value,$langFamily) !== false){
+                    if (strpos($value, $langFamily) !== false) {
                         return true;
                     }
                 }
@@ -154,31 +158,31 @@ class WbwLookupController extends Controller
         }
         return false;
     }
-    private function wbwPreference($word,$field,$userId){
+    private function wbwPreference($word, $field, $userId)
+    {
         $prefix = 'wbw-preference';
         $fieldMap = [
-                    'type'=>1,
-                    'grammar'=>2,
-                    'meaning'=>3,
-                    'factors'=>4,
-                    'factorMeaning'=>5,
-                    'parent'=>6,
-                    'part'=>7,
-                    'case'=>8,
-                ];
+            'type' => 1,
+            'grammar' => 2,
+            'meaning' => 3,
+            'factors' => 4,
+            'factorMeaning' => 5,
+            'parent' => 6,
+            'part' => 7,
+            'case' => 8,
+        ];
         $fieldId = $fieldMap[$field];
         $myPreference = RedisClusters::get("{$prefix}/{$word}/{$fieldId}/{$userId}");
-        if(!empty($myPreference)){
-            Log::debug($word.'命中我的wbw-'.$field,['data'=>$myPreference]);
-            return ['value'=>$myPreference,'status'=>5];
-        }else{
+        if (!empty($myPreference)) {
+            Log::debug($word . '命中我的wbw-' . $field, ['data' => $myPreference]);
+            return ['value' => $myPreference, 'status' => 5];
+        } else {
             $myPreference = RedisClusters::get("{$prefix}/{$word}/3/0");
-            if(!empty($myPreference)){
-                Log::debug($word.'命中社区wbw-'.$field,['data'=>$myPreference]);
-                return ['value'=>$myPreference,'status'=>5];
+            if (!empty($myPreference)) {
+                Log::debug($word . '命中社区wbw-' . $field, ['data' => $myPreference]);
+                return ['value' => $myPreference, 'status' => 5];
             }
         }
-        //Log::debug($word.'未命中'.$field);
         return false;
     }
     /**
@@ -191,12 +195,12 @@ class WbwLookupController extends Controller
     {
         //
         $user = AuthApi::current($request);
-        if(!$user ){
+        if (!$user) {
             //未登录用户
-            return $this->error(__('auth.failed'),401,401);
+            return $this->error(__('auth.failed'), 401, 401);
         }
 
-        $startAt = microtime(true)*1000;
+        $startAt = microtime(true) * 1000;
 
         // system regular
         $this->initSysDict();
@@ -204,50 +208,54 @@ class WbwLookupController extends Controller
         $channel = Channel::find($request->get('channel_id'));
         $orgData = $request->get('data');
         $lang = [];
-        foreach ($request->get('lang',[]) as $value) {
+        foreach ($request->get('lang', []) as $value) {
             $lang[] = strtolower($value);
         }
         //句子中的单词
         $words = [];
         foreach ($orgData as  $word) {
             # code...
-            if( isset($word['type']) && $word['type']['value'] === '.ctl.'){
+            if (isset($word['type']) && $word['type']['value'] === '.ctl.') {
                 continue;
             }
-            if(!empty($word['real']['value'])){
+            if (!empty($word['real']['value'])) {
                 $words[] = $word['real']['value'];
             }
         }
 
-        $result = $this->lookup($words,[],2);
+        $result = $this->lookup($words, [], 2);
         $indexed = $this->toIndexed($result);
 
         foreach ($orgData as  $key => $word) {
-            if( isset($word['type']) && $word['type']['value'] === '.ctl.'){
+            if (isset($word['type']) && $word['type']['value'] === '.ctl.') {
                 continue;
             }
-            if(empty($word['real']['value'])){
+            if (empty($word['real']['value'])) {
                 continue;
             }
             $data = $word;
 
-            $preference = $this->wbwPreference($word['real']['value'],'meaning',$user['user_id']);
-            if($preference!==false){
+            $preference = $this->wbwPreference($word['real']['value'], 'meaning', $user['user_id']);
+            if ($preference !== false) {
                 $data['meaning'] = $preference;
             }
-            $preference = $this->wbwPreference($word['real']['value'],'factors',$user['user_id']);
-            if($preference!==false){
+            $preference = $this->wbwPreference($word['real']['value'], 'factors', $user['user_id']);
+            if ($preference !== false) {
                 $data['factors'] = $preference;
             }
-            $preference = $this->wbwPreference($word['real']['value'],'factorMeaning',$user['user_id']);
-            if($preference!==false){
+            $preference = $this->wbwPreference($word['real']['value'], 'factorMeaning', $user['user_id']);
+            if ($preference !== false) {
                 $data['factorMeaning'] = $preference;
             }
-            $preference = $this->wbwPreference($word['real']['value'],'case',$user['user_id']);
-            if($preference!==false){
+            $preference = $this->wbwPreference($word['real']['value'], 'case', $user['user_id']);
+            if ($preference !== false) {
                 $data['case'] = $preference;
             }
-            if(isset($indexed[$word['real']['value']])){
+            $preference = $this->wbwPreference($word['real']['value'], 'parent', $user['user_id']);
+            if ($preference !== false) {
+                $data['parent'] = $preference;
+            }
+            if (isset($indexed[$word['real']['value']])) {
                 //parent
                 $case = [];
                 $parent = [];
@@ -258,130 +266,133 @@ class WbwLookupController extends Controller
                 $case2 = [];
                 foreach ($indexed[$word['real']['value']] as $value) {
                     //非base优先
-                    if(strstr($value->type,'base') === FALSE){
+                    if (strstr($value->type, 'base') === FALSE) {
                         $increment = 10;
-                    }else{
+                    } else {
                         $increment = 1;
                     }
                     //将全部结果加上得分放入数组
-                    if($value->type !== '.cp.'){
-                        $parent = $this->insertValue([$value->parent],$parent,$increment);
+                    if ($value->type !== '.cp.') {
+                        $parent = $this->insertValue([$value->parent], $parent, $increment);
                     }
-                    if(isset($data['case']) && $data['case']['status']<5){
-                        if(!empty($value->type) && $value->type !== ".cp."){
-                            $case = $this->insertValue([$value->type."#".$value->grammar],$case,$increment);
+                    if (isset($data['case']) && $data['case']['status'] < 5) {
+                        if (!empty($value->type) && $value->type !== ".cp.") {
+                            $case = $this->insertValue([$value->type . "#" . $value->grammar], $case, $increment);
                         }
                     }
-                    if($data['factors']['status'] < 50){
-                        $factors = $this->insertValue([$value->factors],$factors,$increment);
+                    if ($data['factors']['status'] < 50) {
+                        $factors = $this->insertValue([$value->factors], $factors, $increment);
                     }
-                    if(isset($data['factorMeaning']) && $data['factorMeaning']['status'] < 50){
-                        $factorMeaning = $this->insertValue([$value->factormean],$factorMeaning,$increment,false);
+                    if (isset($data['factorMeaning']) && $data['factorMeaning']['status'] < 50) {
+                        $factorMeaning = $this->insertValue([$value->factormean], $factorMeaning, $increment, false);
                     }
 
-                    if($data['meaning']['status'] < 50){
-                        if($this->langCheck($lang,$value->language)){
-                            $meaning = $this->insertValue(explode('$',$value->mean),$meaning,$increment,false);
+                    if ($data['meaning']['status'] < 50) {
+                        if ($this->langCheck($lang, $value->language)) {
+                            $meaning = $this->insertValue(explode('$', $value->mean), $meaning, $increment, false);
                         }
                     }
                 }
-                if(count($case)>0){
+                if (count($case) > 0) {
                     arsort($case);
                     $first = array_keys($case)[0];
-                    $data['case'] = ['value'=>$first==="_null"?"":$first,'status'=>3];
+                    $data['case'] = ['value' => $first === "_null" ? "" : $first, 'status' => 3];
                 }
-                if(count($parent)>0){
+                if (count($parent) > 0) {
                     arsort($parent);
                     $first = array_keys($parent)[0];
-                    $data['parent'] = ['value'=>$first==="_null"?"":$first,'status'=>3];
+                    $data['parent'] = ['value' => $first === "_null" ? "" : $first, 'status' => 3];
+                } else {
+                    $data['parent'] = ['value' =>  "", 'status' => 3];
                 }
-                if(count($factors)>0 && empty($data['factors']['value'])){
+                if (count($factors) > 0 && empty($data['factors']['value'])) {
                     arsort($factors);
                     $first = array_keys($factors)[0];
-                    $data['factors'] = ['value'=>$first==="_null"?"":$first,'status'=>3];
+                    $data['factors'] = ['value' => $first === "_null" ? "" : $first, 'status' => 3];
                 }
 
-                if(count($factorMeaning)>0){
+                if (count($factorMeaning) > 0) {
                     arsort($factorMeaning);
                     $first = array_keys($factorMeaning)[0];
-                    $data['factorMeaning'] = ['value'=>$first==="_null"?"":$first,'status'=>5];
+                    $data['factorMeaning'] = ['value' => $first === "_null" ? "" : $first, 'status' => 5];
                 }
-                if(isset($data['factorMeaning']) && $data['factorMeaning']['status']<5){
+                if (isset($data['factorMeaning']) && $data['factorMeaning']['status'] < 5) {
                     $wbwFactorMeaning = [];
-                    if(!empty($data['factors']['value'])){
-                        foreach (explode("+",$data['factors']['value']) as  $factor) {
-                            $preference = $this->wbwPreference($factor,'meaning',$user['user_id']);
-                            if($preference!==false){
+                    if (!empty($data['factors']['value'])) {
+                        foreach (explode("+", $data['factors']['value']) as  $factor) {
+                            $preference = $this->wbwPreference($factor, 'meaning', $user['user_id']);
+                            if ($preference !== false) {
                                 $wbwFactorMeaning[] = $preference['value'];
-                            }else{
+                            } else {
                                 $wbwFactorMeaning[] = $factor;
                             }
                         }
                     }
-                    $data['factorMeaning'] = ['value'=>implode('+',$wbwFactorMeaning),'status'=>3];
+                    $data['factorMeaning'] = ['value' => implode('+', $wbwFactorMeaning), 'status' => 3];
                 }
 
-                if(empty($data['meaning']['value']) && !empty($data['parent']['value'])){
-                    if(isset($indexed[$data['parent']['value']])){
+                if (empty($data['meaning']['value']) && !empty($data['parent']['value'])) {
+                    if (isset($indexed[$data['parent']['value']])) {
                         foreach ($indexed[$data['parent']['value']] as $value) {
                             //根据base 查找词意
                             //非base优先
                             $increment = 10;
-                            if($this->langCheck($lang,$value->language)){
-                                $meaning = $this->insertValue(explode('$',$value->mean),$meaning,$increment,false);
+                            if ($this->langCheck($lang, $value->language)) {
+                                $meaning = $this->insertValue(explode('$', $value->mean), $meaning, $increment, false);
                             }
                             //查找词源
-                            if(!empty($value->parent) && $value->parent !== $value->word && strstr($value->type,"base") !== FALSE ){
-                                $parent2 = $this->insertValue([$value->grammar."$".$value->parent],$parent2,1,false);
+                            if (!empty($value->parent) && $value->parent !== $value->word && strstr($value->type, "base") !== FALSE) {
+                                $parent2 = $this->insertValue([$value->grammar . "$" . $value->parent], $parent2, 1, false);
                             }
                         }
                     }
                 }
-                if(count($meaning)>0){
+                if (count($meaning) > 0) {
                     arsort($meaning);
                     $first = array_keys($meaning)[0];
-                    $data['meaning'] = ['value'=>$first==="_null"?"":$first,'status'=>3];
+                    $data['meaning'] = ['value' => $first === "_null" ? "" : $first, 'status' => 3];
                 }
-                if(count($parent2)>0){
+                if (count($parent2) > 0) {
                     arsort($parent2);
-                    $first = explode("$",array_keys($parent2)[0]);
-                    $data['parent2'] = ['value'=>$first[1],'status'=>3];
-                    $data['grammar2'] = ['value'=>$first[0],'status'=>3];
+                    $first = explode("$", array_keys($parent2)[0]);
+                    $data['parent2'] = ['value' => $first[1], 'status' => 3];
+                    $data['grammar2'] = ['value' => $first[0], 'status' => 3];
                 }
             }
 
-            if(!isset($data['factorMeaning']['value']) ||
-                $this->fmEmpty($data['factorMeaning']['value'])){
+            if (
+                !isset($data['factorMeaning']['value']) ||
+                $this->fmEmpty($data['factorMeaning']['value'])
+            ) {
                 $factorMeaning = [];
                 //生成自动的拆分意思
                 $autoMeaning = '';
-                $currFactors = explode('+',$data['factors']['value']) ;
+                $currFactors = explode('+', $data['factors']['value']);
                 $autoFM = [];
                 foreach ($currFactors as $factor) {
-                    $subFactors = explode('-',$factor) ;
+                    $subFactors = explode('-', $factor);
                     $autoSubFM = [];
                     foreach ($subFactors as $subFactor) {
-                        $preference = $this->wbwPreference($subFactor,'factorMeaning',$user['user_id']);
-                        if($preference !== false){
+                        $preference = $this->wbwPreference($subFactor, 'factorMeaning', $user['user_id']);
+                        if ($preference !== false) {
                             $autoSubFM[] = $preference['value'];
-                        }else{
-                            $preference = $this->wbwPreference($subFactor,'meaning',$user['user_id']);
-                            if($preference !== false){
+                        } else {
+                            $preference = $this->wbwPreference($subFactor, 'meaning', $user['user_id']);
+                            if ($preference !== false) {
                                 $autoSubFM[] = $preference['value'];
-                            }else{
+                            } else {
                                 $autoSubFM[] = '';
                             }
-
                         }
                     }
-                    $autoFM[] = implode('-',$autoSubFM);
-                    $autoMeaning .= implode('',$autoSubFM);
+                    $autoFM[] = implode('-', $autoSubFM);
+                    $autoMeaning .= implode('', $autoSubFM);
                 }
-                $autoMeaning .= implode('',$autoFM);
-                if(count($autoFM) > 0){
-                    $data['factorMeaning'] = ['value'=>implode('+',$autoFM),'status'=>3];
-                    if(empty($data['meaning']['value']) && !empty($autoMeaning)){
-                        $data['meaning'] = ['value'=>$autoMeaning,'status'=>3];
+                $autoMeaning .= implode('', $autoFM);
+                if (count($autoFM) > 0) {
+                    $data['factorMeaning'] = ['value' => implode('+', $autoFM), 'status' => 3];
+                    if (empty($data['meaning']['value']) && !empty($autoMeaning)) {
+                        $data['meaning'] = ['value' => $autoMeaning, 'status' => 3];
                     }
                 }
             }
@@ -392,10 +403,11 @@ class WbwLookupController extends Controller
         return $this->ok($orgData);
     }
 
-    private function fmEmpty($value){
-        if(str_replace(['+','-',' '],'',$value) === ''){
+    private function fmEmpty($value)
+    {
+        if (str_replace(['+', '-', ' '], '', $value) === '') {
             return true;
-        }else{
+        } else {
             return false;
         }
     }
@@ -405,54 +417,54 @@ class WbwLookupController extends Controller
      * @param  string  $sentId
      * @return \Illuminate\Http\Response
      */
-    public function show(Request $request,string $sentId)
+    public function show(Request $request, string $sentId)
     {
-        $startAt = microtime(true)*1000;
+        $startAt = microtime(true) * 1000;
 
         $channel = Channel::find($request->get('channel_id'));
 
         //查询句子中的单词
-        $sent = \explode('-',$sentId);
-        $wbw = WbwTemplate::where('book',$sent[0])
-                ->where('paragraph',$sent[1])
-                ->whereBetween('wid',[$sent[2],$sent[3]])
-                ->orderBy('wid')
-                ->get();
+        $sent = \explode('-', $sentId);
+        $wbw = WbwTemplate::where('book', $sent[0])
+            ->where('paragraph', $sent[1])
+            ->whereBetween('wid', [$sent[2], $sent[3]])
+            ->orderBy('wid')
+            ->get();
         $words = [];
         foreach ($wbw as  $row) {
-            if($row->type !== '.ctl.' && !empty($row->real)){
+            if ($row->type !== '.ctl.' && !empty($row->real)) {
                 $words[] = $row->real;
             }
         }
-        $result = $this->lookup($words,[],2);
+        $result = $this->lookup($words, [], 2);
         $indexed = $this->toIndexed($result);
 
         //生成自动填充结果
         $wbwContent = [];
         foreach ($wbw as  $row) {
-            $type = $row->type=='?'? '':$row->type;
-            $grammar = $row->gramma=='?'? '':$row->gramma;
-            $part = $row->part=='?'? '':$row->part;
-            if(!empty($type) || !empty($grammar)){
+            $type = $row->type == '?' ? '' : $row->type;
+            $grammar = $row->gramma == '?' ? '' : $row->gramma;
+            $part = $row->part == '?' ? '' : $row->part;
+            if (!empty($type) || !empty($grammar)) {
                 $case = "{$type}#$grammar";
-            }else{
+            } else {
                 $case = "";
             }
             $data = [
-                    'sn'=>[$row->wid],
-                    'word'=>['value'=>$row->word,'status'=>3],
-                    'real'=> ['value'=>$row->real,'status'=>3],
-                    'meaning'=> ['value'=>[],'status'=>3],
-                    'type'=> ['value'=>$type,'status'=>3],
-                    'grammar'=> ['value'=>$grammar,'status'=>3],
-                    'case'=> ['value'=>$case,'status'=>3],
-                    'style'=> ['value'=>$row->style,'status'=>3],
-                    'factors'=> ['value'=>$part,'status'=>3],
-                    'factorMeaning'=> ['value'=>'','status'=>3],
-                    'confidence'=> 0.5
-                ];
-            if($row->type !== '.ctl.' && !empty($row->real)){
-                if(isset($indexed[$row->real])){
+                'sn' => [$row->wid],
+                'word' => ['value' => $row->word, 'status' => 3],
+                'real' => ['value' => $row->real, 'status' => 3],
+                'meaning' => ['value' => [], 'status' => 3],
+                'type' => ['value' => $type, 'status' => 3],
+                'grammar' => ['value' => $grammar, 'status' => 3],
+                'case' => ['value' => $case, 'status' => 3],
+                'style' => ['value' => $row->style, 'status' => 3],
+                'factors' => ['value' => $part, 'status' => 3],
+                'factorMeaning' => ['value' => '', 'status' => 3],
+                'confidence' => 0.5
+            ];
+            if ($row->type !== '.ctl.' && !empty($row->real)) {
+                if (isset($indexed[$row->real])) {
                     //parent
                     $case = [];
                     $parent = [];
@@ -463,67 +475,70 @@ class WbwLookupController extends Controller
                     $case2 = [];
                     foreach ($indexed[$row->real] as $value) {
                         //非base优先
-                        if(strstr($value->type,'base') === FALSE){
+                        if (strstr($value->type, 'base') === FALSE) {
                             $increment = 10;
-                        }else{
+                        } else {
                             $increment = 1;
                         }
                         //将全部结果加上得分放入数组
-                        $parent = $this->insertValue([$value->parent],$parent,$increment);
-                        $case = $this->insertValue([$value->type."#".$value->grammar],$case,$increment);
-                        $factors = $this->insertValue([$value->factors],$factors,$increment);
-                        $factorMeaning = $this->insertValue([$value->factormean],$factorMeaning,$increment);
-                        $meaning = $this->insertValue(explode('$',$value->mean),$meaning,$increment,false);
+                        $parent = $this->insertValue([$value->parent], $parent, $increment);
+                        $case = $this->insertValue([$value->type . "#" . $value->grammar], $case, $increment);
+                        $factors = $this->insertValue([$value->factors], $factors, $increment);
+                        $factorMeaning = $this->insertValue([$value->factormean], $factorMeaning, $increment);
+                        $meaning = $this->insertValue(explode('$', $value->mean), $meaning, $increment, false);
                     }
-                    if(count($case)>0){
+                    if (count($case) > 0) {
                         arsort($case);
                         $first = array_keys($case)[0];
-                        $data['case'] = ['value'=>$first==="_null"?"":$first,'status'=>3];
+                        $data['case'] = ['value' => $first === "_null" ? "" : $first, 'status' => 3];
                     }
-                    if(count($parent)>0){
+                    if (count($parent) > 0) {
                         arsort($parent);
                         $first = array_keys($parent)[0];
-                        $data['parent'] = ['value'=>$first==="_null"?"":$first,'status'=>3];
+                        $data['parent'] = ['value' => $first === "_null" ? "" : $first, 'status' => 3];
                     }
-                    if(count($factors)>0){
+                    if (count($factors) > 0) {
                         arsort($factors);
                         $first = array_keys($factors)[0];
-                        $data['factors'] = ['value'=>$first==="_null"?"":$first,'status'=>3];
+                        $data['factors'] = ['value' => $first === "_null" ? "" : $first, 'status' => 3];
                     }
-                    if(count($factorMeaning)>0){
+                    if (count($factorMeaning) > 0) {
                         arsort($factorMeaning);
                         $first = array_keys($factorMeaning)[0];
-                        $data['factorMeaning'] = ['value'=>$first==="_null"?"":$first,'status'=>3];
+                        $data['factorMeaning'] = ['value' => $first === "_null" ? "" : $first, 'status' => 3];
                     }
 
                     //根据base 查找词意
-                    if(!empty($data['parent'])){
-                        if(isset($indexed[$data['parent']['value']])){
+                    if (!empty($data['parent'])) {
+                        if (isset($indexed[$data['parent']['value']])) {
                             foreach ($indexed[$data['parent']['value']] as $value) {
                                 //非base优先
                                 $increment = 10;
-                                $meaning = $this->insertValue(explode('$',$value->mean),$meaning,$increment,false);
+                                $meaning = $this->insertValue(explode('$', $value->mean), $meaning, $increment, false);
                             }
-                        }else{
+                        } else {
                             //Log::error("no set parent".$data['parent']['value']);
                         }
                     }
-                    if(count($meaning)>0){
+                    if (count($meaning) > 0) {
                         arsort($meaning);
                         $first = array_keys($meaning)[0];
-                        $data['meaning'] = ['value'=>$first==="_null"?"":$first,'status'=>3];
+                        $data['meaning'] = ['value' => $first === "_null" ? "" : $first, 'status' => 3];
                     }
                 }
             }
             $wbwContent[]  = $data;
         }
-        $endAt = microtime(true)*1000;
-        return $this->ok(["rows"=>$wbwContent,
-                        "count"=>count($wbwContent),
-                        "time"=>(int)($endAt-$startAt)]);
+        $endAt = microtime(true) * 1000;
+        return $this->ok([
+            "rows" => $wbwContent,
+            "count" => count($wbwContent),
+            "time" => (int)($endAt - $startAt)
+        ]);
     }
 
-    private function toIndexed($words){
+    private function toIndexed($words)
+    {
         //转成索引数组
         $indexed = [];
         foreach ($words as $key => $value) {
@@ -536,21 +551,22 @@ class WbwLookupController extends Controller
     /**
      * $empty:是否允许空值
      */
-    private function insertValue($value,$container,$increment,$empty=true){
+    private function insertValue($value, $container, $increment, $empty = true)
+    {
         foreach ($value as $one) {
-            if($empty === false){
-                if($this->fmEmpty($one)){
+            if ($empty === false) {
+                if ($this->fmEmpty($one)) {
                     break;
                 }
             }
-            $one=trim($one);
+            $one = trim($one);
             $key = $one;
-            if(empty($key)){
+            if (empty($key)) {
                 $key = '_null';
             }
-            if(isset($container[$key])){
+            if (isset($container[$key])) {
                 $container[$key] += $increment;
-            }else{
+            } else {
                 $container[$key] = $increment;
             }
         }

+ 30 - 0
api-v8/app/Http/Requests/ChatMessageRequest.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class ChatMessageRequest extends FormRequest
+{
+    /**
+     * Determine if the user is authorized to make this request.
+     *
+     * @return bool
+     */
+    public function authorize()
+    {
+        return false;
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            //
+        ];
+    }
+}

+ 30 - 0
api-v8/app/Http/Requests/ChatRequest.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class ChatRequest extends FormRequest
+{
+    /**
+     * Determine if the user is authorized to make this request.
+     *
+     * @return bool
+     */
+    public function authorize()
+    {
+        return false;
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            //
+        ];
+    }
+}

+ 51 - 0
api-v8/app/Http/Requests/StoreChatMessageRequest.php

@@ -0,0 +1,51 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Validation\Rule;
+
+class StoreChatMessageRequest extends FormRequest
+{
+    /**
+     * Determine if the user is authorized to make this request.
+     *
+     * @return bool
+     */
+    public function authorize()
+    {
+        return true;
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'chat_id' => 'required|string|size:36',
+            'messages' => 'required|array|min:1',
+            'messages.*.parent_id' => 'nullable|string|exists:chat_messages,uid',
+            'messages.*.session_id' => 'nullable|string|size:36',
+            'messages.*.role' => ['required', Rule::in(['user', 'assistant', 'tool'])],
+            'messages.*.content' => 'nullable|string',
+            'messages.*.model_name' => 'nullable|string|max:100',
+            'messages.*.tool_calls' => 'nullable|array',
+            'messages.*.tool_calls.*.id' => 'required_with:tool_calls|string',
+            'messages.*.tool_calls.*.function' => 'required_with:tool_calls|string',
+            'messages.*.tool_calls.*.arguments' => 'required_with:tool_calls',
+            'messages.*.tool_call_id' => 'nullable|string|max:100'
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'messages.required' => '批量更新的消息列表不能为空',
+            'messages.*.parent_id.required' => '消息ID不能为空',
+            'messages.*.parent_id.exists' => '消息不存在'
+        ];
+    }
+}

+ 30 - 0
api-v8/app/Http/Requests/StoreChatRequest.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class StoreChatRequest extends FormRequest
+{
+    public function authorize()
+    {
+        return true;
+    }
+
+    public function rules()
+    {
+        return [
+            'title' => 'required|string|max:255',
+            'user_id' => 'required|string|exists:user_infos,userid'
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'title.required' => '聊天标题不能为空',
+            'title.max' => '聊天标题不能超过255个字符',
+            'user_id.exists' => '用户不存在'
+        ];
+    }
+}

+ 32 - 0
api-v8/app/Http/Requests/UpdateChatMessageRequest.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class UpdateChatMessageRequest extends FormRequest
+{
+    /**
+     * Determine if the user is authorized to make this request.
+     *
+     * @return bool
+     */
+    public function authorize()
+    {
+        return true;
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'content' => 'sometimes|string',
+            'is_active' => 'sometimes|boolean',
+            'model_name' => 'sometimes|string|max:100'
+        ];
+    }
+}

+ 30 - 0
api-v8/app/Http/Requests/UpdateChatRequest.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class UpdateChatRequest extends FormRequest
+{
+    /**
+     * Determine if the user is authorized to make this request.
+     *
+     * @return bool
+     */
+    public function authorize()
+    {
+        return true;
+    }
+
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'title' => 'sometimes|string|max:255'
+        ];
+    }
+}

+ 32 - 0
api-v8/app/Http/Resources/ChatMessageResource.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class ChatMessageResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        return [
+            'id' => $this->uid,
+            'chat_id' => $this->chat_id,
+            'parent_id' => $this->parent_id,
+            'session_id' => $this->session_id,
+            'role' => $this->role,
+            'content' => $this->content,
+            'model_name' => $this->model_name,
+            'tool_calls' => $this->tool_calls,
+            'tool_call_id' => $this->tool_call_id,
+            'is_active' => $this->is_active,
+            'created_at' => $this->created_at,
+            'updated_at' => $this->updated_at,
+        ];
+    }
+}

+ 28 - 0
api-v8/app/Http/Resources/ChatResource.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class ChatResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        return [
+            'id' => $this->uid,
+            'title' => $this->title,
+            'user_id' => $this->user_id,
+            'created_at' => $this->created_at,
+            'updated_at' => $this->updated_at,
+            'messages_count' => $this->when($this->relationLoaded('messages'), function () {
+                return $this->messages->count();
+            }),
+        ];
+    }
+}

+ 19 - 0
api-v8/app/Http/Resources/PaliTextResource.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class PaliTextResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        return parent::toArray($request);
+    }
+}

+ 5 - 3
api-v8/app/Jobs/ProcessAITranslateJob.php

@@ -6,6 +6,7 @@ use App\Services\AiTranslateService;
 use App\Services\RabbitMQService;
 use Illuminate\Support\Facades\Log;
 use App\Exceptions\TaskFailException;
+use App\Tools\RedisClusters;
 
 class ProcessAITranslateJob extends BaseRabbitMQJob
 {
@@ -43,12 +44,13 @@ class ProcessAITranslateJob extends BaseRabbitMQJob
         $this->aiService->stop();
     }
 
-    public static function publish(string $taskId, $aiAssistantId)
+    public static function publish(string $taskId, $aiAssistantId): string
     {
         $data = AiTranslateService::makeByTask($taskId, $aiAssistantId);
         $mq = app(RabbitMQService::class);
         $queue = 'ai_translate_v2';
-        $mq->publishMessage($queue, $data);
-        return count($data['payload']);
+        $msgId = $mq->publishMessage($queue, []);
+        RedisClusters::put("/mq/message/{$msgId}/data", $data);
+        return $msgId;
     }
 }

+ 106 - 0
api-v8/app/Models/Chat.php

@@ -0,0 +1,106 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Str;
+
+class Chat extends Model
+{
+    use HasFactory;
+
+    protected $fillable = [
+        'uid',
+        'title',
+        'user_id'
+    ];
+
+    protected $casts = [
+        'id' => 'string',
+        'uid' => 'string',
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+        'deleted_at' => 'datetime',
+    ];
+    protected $primaryKey = 'uid';
+    protected static function boot()
+    {
+        parent::boot();
+
+        static::creating(function ($model) {
+            if (empty($model->uid)) {
+                $model->uid = (string) Str::uuid();
+            }
+        });
+
+        // 级联软删除:删除Chat时同时软删除所有相关消息
+        static::deleting(function ($chat) {
+            if ($chat->isForceDeleting()) {
+                // 强制删除时,物理删除所有消息
+                $chat->messages()->forceDelete();
+            } else {
+                // 软删除时,级联软删除所有消息
+                $chat->messages()->delete();
+            }
+        });
+
+        // 恢复Chat时同时恢复所有相关消息
+        static::restoring(function ($chat) {
+            $chat->messages()->withTrashed()->restore();
+        });
+    }
+    // 使用 uid 作为路由键
+    public function messages()
+    {
+        return $this->hasMany(ChatMessage::class);
+    }
+
+    public function getRouteKeyName()
+    {
+        return 'uid';
+    }
+
+    /**
+     * 获取根消息(没有parent_id的消息)
+     */
+    public function rootMessages()
+    {
+        return $this->hasMany(ChatMessage::class, 'chat_id', 'uid')
+            ->whereNull('parent_id')
+            ->where('is_active', true);
+    }
+
+    /**
+     * 获取token使用统计
+     */
+    public function getTokenStats()
+    {
+        return $this->messages()
+            ->where('role', 'assistant')
+            ->whereNotNull('metadata')
+            ->selectRaw('
+                       SUM(JSON_EXTRACT(metadata, "$.token_usage.total_tokens")) as total_tokens,
+                       SUM(JSON_EXTRACT(metadata, "$.token_usage.prompt_tokens")) as prompt_tokens,
+                       SUM(JSON_EXTRACT(metadata, "$.token_usage.completion_tokens")) as completion_tokens,
+                       AVG(JSON_EXTRACT(metadata, "$.performance.response_time_ms")) as avg_response_time
+                   ')
+            ->first();
+    }
+
+    /**
+     * 批量软删除多个聊天
+     */
+    public static function batchSoftDelete(array $chatIds): int
+    {
+        return static::whereIn('uid', $chatIds)->delete();
+    }
+
+    /**
+     * 批量恢复多个聊天
+     */
+    public static function batchRestore(array $chatIds): int
+    {
+        return static::withTrashed()->whereIn('uid', $chatIds)->restore();
+    }
+}

+ 186 - 0
api-v8/app/Models/ChatMessage.php

@@ -0,0 +1,186 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Str;
+
+class ChatMessage extends Model
+{
+    use HasFactory;
+
+    protected $fillable = [
+        'uid',
+        'chat_id',
+        'parent_id',
+        'session_id',
+        'role',
+        'content',
+        'model_name',
+        'tool_calls',
+        'tool_call_id',
+        'is_active'
+    ];
+    protected $dates = [
+        'deleted_at'
+    ];
+    protected $casts = [
+        'id' => 'string',
+        'tool_calls' => 'array',
+        'is_active' => 'boolean',
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+        'deleted_at' => 'datetime',
+    ];
+
+    protected static function boot()
+    {
+        parent::boot();
+
+        static::creating(function ($model) {
+            if (empty($model->uid)) {
+                $model->uid = (string) Str::uuid();
+            }
+            if (empty($model->session_id)) {
+                $model->session_id = (string) Str::uuid();
+            }
+        });
+    }
+    /**
+     * 关联聊天
+     */
+    public function chat()
+    {
+        return $this->belongsTo(Chat::class);
+    }
+    /**
+     * 关联父消息
+     */
+    public function parent()
+    {
+        return $this->belongsTo(ChatMessage::class, 'parent_id', 'uid');
+    }
+    /**
+     * 关联子消息
+     */
+    public function children()
+    {
+        return $this->hasMany(ChatMessage::class, 'parent_id', 'uid');
+    }
+    /**
+     * 关联激活状态的子消息
+     */
+    public function activeChildren()
+    {
+        return $this->hasMany(ChatMessage::class, 'parent_id', 'uid')
+            ->where('is_active', true);
+    }
+    /**
+     * Scope: 只查询激活状态的消息
+     */
+    public function scopeActive($query)
+    {
+        return $query->where('is_active', true);
+    }
+
+    /**
+     * Scope: 根据角色查询
+     */
+    public function scopeByRole($query, string $role)
+    {
+        return $query->where('role', $role);
+    }
+
+    /**
+     * Scope: 根据会话ID查询
+     */
+    public function scopeBySession($query, string $sessionId)
+    {
+        return $query->where('session_id', $sessionId);
+    }
+
+    /**
+     * Scope: 根据聊天ID查询
+     */
+    public function scopeByChat($query, string $chatId)
+    {
+        return $query->where('chat_id', $chatId);
+    }
+
+    /**
+     * 获取消息路径(从根到当前消息)
+     */
+    public function getPath(): array
+    {
+        $path = [];
+        $current = $this;
+
+        while ($current) {
+            array_unshift($path, $current);
+            $current = $current->parent;
+        }
+
+        return $path;
+    }
+
+    /**
+     * 获取消息树的所有叶子节点
+     */
+    public function getLeaves(): \Illuminate\Database\Eloquent\Collection
+    {
+        return ChatMessage::where('chat_id', $this->chat_id)
+            ->whereNotNull('parent_id')
+            ->whereDoesntHave('children')
+            ->get();
+    }
+
+    /**
+     * 获取Token使用情况
+     */
+    public function getTokenUsage(): ?array
+    {
+        return $this->metadata['token_usage'] ?? null;
+    }
+
+    /**
+     * 获取生成参数
+     */
+    public function getGenerationParams(): ?array
+    {
+        return $this->metadata['generation_params'] ?? null;
+    }
+
+    /**
+     * 设置Token使用情况
+     */
+    public function setTokenUsage(array $tokenUsage): void
+    {
+        $metadata = $this->metadata ?? [];
+        $metadata['token_usage'] = $tokenUsage;
+        $this->update(['metadata' => $metadata]);
+    }
+
+    /**
+     * 设置生成参数
+     */
+    public function setGenerationParams(array $params): void
+    {
+        $metadata = $this->metadata ?? [];
+        $metadata['generation_params'] = $params;
+        $this->update(['metadata' => $metadata]);
+    }
+
+    public function siblings()
+    {
+        return $this->where('parent_id', $this->parent_id)
+            ->where('role', $this->role)
+            ->where('id', '!=', $this->id);
+    }
+
+
+    public function getRouteKeyName()
+    {
+        return 'uid';
+    }
+}

+ 36 - 0
api-v8/app/Services/AIModelService.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\AiModel;
+use App\Http\Resources\AiModelResource;
+use App\Tools\RedisClusters;
+
+class AIModelService
+{
+
+    public function getModelsById($id)
+    {
+        $table = AiModel::whereIn('uid', $id);
+        $result = $table->get();
+        return AiModelResource::collection(resource: $result);
+    }
+
+    public function getSysModels($type = null)
+    {
+        if (empty($type)) {
+            $types = ['wbw', 'chat', 'summarize'];
+        } else {
+            $types = [$type];
+        }
+
+        $sysModels = [];
+        foreach ($types as $key => $type) {
+            $sysModels[$type] =  $this->getModelsById(RedisClusters::get('/ai/model/system/' . $type) ?? []);
+        }
+        if (!empty($type)) {
+            return $sysModels[$type];
+        }
+        return $sysModels;
+    }
+}

+ 116 - 0
api-v8/app/Services/EmbeddingService.php

@@ -0,0 +1,116 @@
+<?php
+
+namespace App\Services;
+
+use Illuminate\Support\Facades\Http;
+use App\Services\AIModelService;
+
+class EmbeddingService
+{
+    protected string $modelId;
+    protected string $apiUrl = '';
+    protected int $maxRetries = 3;
+
+    /**
+     * 创建服务实例,初始化 OpenAI API Key
+     *
+     * @return void
+     */
+    public function __construct(AIModelService $aiModels)
+    {
+        $models = $aiModels->getSysModels('embedding');
+        $this->modelId = $models[0]['uid'];
+        $this->apiUrl = config('mint.ai.proxy') . '/api/openai';
+    }
+
+    public function generate($text)
+    {
+        return $this->callOpenAI($text);
+    }
+
+    /**
+     * 调用 OpenAI GPT 模型生成embedding
+     *
+     * {
+  "object": "list",
+  "data": [
+    {
+      "object": "embedding",
+      "index": 0,
+      "embedding": [
+        -0.012345,
+        0.021876,
+        0.004231,
+        -0.037654,
+        0.016482,
+        -0.001273,
+        0.029871,
+        -0.015630
+        // ... 共1536个浮点数
+      ]
+    }
+  ],
+  "model": "text-embedding-3-small",
+  "usage": {
+    "prompt_tokens": 16,
+    "total_tokens": 16
+  }
+}
+
+     *
+     * 带有重试机制和指数退避。
+     * 在 429 或 500+ 错误时重试,最大重试次数为 maxRetries。
+     * 其他错误直接返回空字符串。
+     *
+     * @param  string  $text       输入文本
+     * @param  int     $maxTokens  每次请求允许的最大 tokens 数
+     * @return string              模型返回的摘要文本
+     */
+    protected function callOpenAI(string $text): string
+    {
+        $attempt = 0;
+        $delay = 1;
+
+        $payload = [
+            'model' => $this->modelId,
+            'input' => $text,
+        ];
+        while ($attempt < $this->maxRetries) {
+            try {
+                $response = Http::timeout(100)
+                    ->withHeaders([
+                        'Authorization' => 'Bearer ',
+                        'Content-Type' => 'application/json',
+                    ])->post($this->apiUrl, [
+                        'model_id' => $this->modelId,
+                        'payload' => $payload
+                    ]);
+
+                if ($response->successful()) {
+                    $data = $response->json();
+                    if (isset($data['data']['embedding'])) {
+                        return $data['data']['embedding'];
+                    } else {
+                        return false;
+                    }
+                }
+
+                if (in_array($response->status(), [429, 500, 502, 503, 504])) {
+                    throw new \Exception("Temporary server error: " . $response->status());
+                }
+
+                return false;
+            } catch (\Exception $e) {
+                $attempt++;
+                if ($attempt >= $this->maxRetries) {
+                    return false;
+                }
+
+                sleep($delay);
+                $delay *= 10;
+            }
+        }
+
+        return false;
+    }
+}

+ 795 - 0
api-v8/app/Services/OpenSearchService.php

@@ -0,0 +1,795 @@
+<?php
+// api-v8/app/Services/OpenSearchService.php
+namespace App\Services;
+
+use OpenSearch\GuzzleClientFactory;
+use Illuminate\Support\Facades\Log;
+use GuzzleHttp\Client;
+use Illuminate\Support\Facades\Cache;
+
+use Exception;
+
+class OpenSearchService
+{
+    protected $client;
+    protected $http;
+    protected $openaiApiKey;
+
+    /** 默认查询排除字段 **/
+    private $sourceExcludes = [
+        'title.suggest',
+        'content.suggest',
+    ];
+
+    /** 默认权重配置 **/
+    private $weights = [
+        'fuzzy' => [
+            'bold_single' => 50,
+            'bold_multi' => 10,
+            'title.pali.text'   => 3,
+            'title.zh'          => 3,
+            'summary.text'      => 2,
+            'content.pali.text' => 1,
+            'content.zh'        => 1,
+        ],
+        'hybrid' => [
+            'fuzzy_ratio'    => 0.7,
+            'semantic_ratio' => 0.3,
+            'bold_single' => 50,
+            'bold_multi' => 10,
+            'title.pali.text'   => 3,
+            'title.zh'          => 3,
+            'summary.text'      => 2,
+            'content.pali.text' => 1,
+            'content.zh'        => 1,
+        ],
+    ];
+
+
+
+    private $indexDefinition = [
+        'settings' => [
+            'index' => [
+                'knn' => true,
+            ],
+            'analysis' => [
+                'analyzer' => [
+                    /** */
+                    'pali_query_analyzer' => [
+                        'tokenizer' => 'standard',
+                        'filter' => ['lowercase', 'pali_synonyms'],
+                    ],
+                    'pali_index_analyzer' => [
+                        'type'        => 'custom',
+                        'tokenizer' => 'standard',
+                        'char_filter' => ['markdown_strip'],
+                        'filter' => ['lowercase'],
+                    ],
+                    'markdown_clean' => [
+                        'type'        => 'custom',
+                        'tokenizer'   => 'standard',
+                        'char_filter' => ['markdown_strip'],
+                        'filter'      => ['lowercase'],
+                    ],
+                    // Suggest 专用(忽略大小写 + 变音)
+                    'pali_suggest_analyzer' => [
+                        'tokenizer' => 'standard',
+                        'filter' => ['lowercase', 'asciifolding']
+                    ],
+                    // 中文简繁统一 (繁 -> 简)
+                    'zh_index_analyzer' => [
+                        'tokenizer' => 'ik_max_word',
+                        'char_filter' => ['tsconvert'],
+                    ],
+                    'zh_query_analyzer' => [
+                        'tokenizer' => 'ik_smart',
+                        'char_filter' => ['tsconvert'],
+                    ]
+                ],
+                'filter' => [
+                    'pali_synonyms' => [
+                        'type' => 'synonym_graph',
+                        'synonyms_path' => 'analysis/pali_synonyms.txt',
+                    ],
+                ],
+                'char_filter' => [
+                    'markdown_strip' => [
+                        'type'        => 'pattern_replace',
+                        'pattern'     => '\\*\\*|\\*|_|`|~',
+                        'replacement' => '',
+                    ],
+                    "tsconvert" => [
+                        "type" => "stconvert",
+                        "convert_type" => "t2s"
+                    ]
+                ],
+            ],
+        ],
+        'mappings' => [
+            'properties' => [
+                'id' => ['type' => 'keyword'],
+                'resource_id' => ['type' => 'keyword'],
+                'resource_type' => ['type' => 'keyword'],
+                'title' => [
+                    'properties' => [
+                        'pali' => [
+                            'type' => 'text',
+                            'fields' => [
+                                /**模糊查询 */
+                                'text' => [
+                                    'type' => 'text',
+                                    'analyzer' => 'pali_index_analyzer',
+                                    'search_analyzer' => 'pali_query_analyzer',
+                                ],
+                                /**准确查询 */
+                                'exact' => [
+                                    'type' => 'text',
+                                    'analyzer' => 'markdown_clean',
+                                ],
+                            ],
+                        ],
+                        'zh' => [
+                            'type' => 'text',
+                            'analyzer' => 'zh_index_analyzer',
+                            'search_analyzer' => 'zh_query_analyzer',
+                        ],
+
+                        'vector' => [
+                            'type' => 'knn_vector',
+                            'dimension' => 1536,
+                            'method' => [
+                                'name'       => 'hnsw',
+                                'space_type' => 'cosinesimil',
+                                'engine'     => 'nmslib',
+                            ],
+                        ],
+                        // 自动建议字段
+                        'suggest' => [
+                            'type' => 'completion',
+                            'analyzer' => 'pali_suggest_analyzer'
+                        ],
+                    ],
+                ],
+                /** 简体中文 llm生成 */
+                'summary' => [
+                    'properties' => [
+                        'text' => [
+                            'type' => 'text',
+                            'analyzer' => 'zh_index_analyzer',
+                            'search_analyzer' => 'zh_query_analyzer',
+                        ],
+                        'vector' => [
+                            'type' => 'knn_vector',
+                            'dimension' => 1536,
+                            'method' => [
+                                'name'       => 'hnsw',
+                                'space_type' => 'cosinesimil',
+                                'engine'     => 'nmslib',
+                            ],
+                        ],
+                    ]
+                ],
+                'content' => [
+                    'properties' => [
+                        'pali' => [
+                            'type' => 'text',
+                            'fields' => [
+                                /**模糊查询 */
+                                'text' => [
+                                    'type' => 'text',
+                                    'analyzer' => 'pali_index_analyzer',
+                                    'search_analyzer' => 'pali_query_analyzer',
+                                ],
+                                /**准确查询 */
+                                'exact' => [
+                                    'type' => 'text',
+                                    'analyzer' => 'markdown_clean',
+                                ],
+
+                            ],
+                        ],
+                        'zh' => [
+                            'type' => 'text',
+                            'analyzer' => 'zh_index_analyzer',
+                            'search_analyzer' => 'zh_query_analyzer',
+                        ],
+                        'tokens' => [
+                            'type' => 'nested',
+                            'properties' => [
+                                'surface' => ['type' => 'keyword'],
+                                'lemma' => ['type' => 'keyword'],
+                                'compound_parts' => ['type' => 'keyword'],
+                                'case' => ['type' => 'keyword'],
+                            ],
+                        ],
+                        'vector' => [
+                            'type' => 'knn_vector',
+                            'dimension' => 1536,
+                            'method' => [
+                                'name'       => 'hnsw',
+                                'space_type' => 'cosinesimil',
+                                'engine'     => 'nmslib',
+                            ],
+                        ],
+                        'suggest' => [
+                            'type' => 'completion',
+                            'analyzer' => 'pali_suggest_analyzer'
+                        ]
+                    ],
+                ],
+                'related_id' => ['type' => 'keyword'],
+                'bold_single' => [
+                    'type' => 'text',
+                    'analyzer' => 'standard',
+                    'search_analyzer' => 'pali_query_analyzer',
+                ],
+                'bold_multi' => [
+                    'type' => 'text',
+                    'analyzer' => 'standard',
+                    'search_analyzer' => 'pali_query_analyzer',
+                ],
+                'path' => ['type' => 'text', 'analyzer' => 'standard'],
+                'page_refs' => [
+                    'type' => 'keyword',
+                ],
+                'tags' => ['type' => 'keyword'],
+                'category' => ['type' => 'keyword'],
+                'author' => ['type' => 'text'],
+                'language' => ['type' => 'keyword'],
+                'updated_at' => ['type' => 'date'],
+                'granularity' => ['type' => 'keyword'],
+                'metadata' => [
+                    'properties' => [
+                        'APA' => ['type' => 'text', 'index' => false],
+                        'MLA' => ['type' => 'text', 'index' => false],
+                        'widget' => ['type' => 'text', 'index' => false],
+                        'author' => ['type' => 'text'],   //
+                        'channel' => ['type' => 'text'], //
+                    ],
+                ],
+            ],
+        ],
+    ];
+
+    public function __construct()
+    {
+        $config = config('mint.opensearch.config');
+        $hostUrl = "{$config['scheme']}://{$config['host']}:{$config['port']}";
+
+        $this->client = (new GuzzleClientFactory())->create([
+            'base_uri' => $hostUrl,
+            'auth' => [$config['username'], $config['password']],
+            'verify' => $config['ssl_verification'],
+        ]);
+
+        $this->openaiApiKey = env('OPENAI_API_KEY');
+        $this->http = new Client([
+            'base_uri' => 'https://api.openai.com/v1/',
+            'timeout' => 15,
+        ]);
+    }
+
+    public function setWeights(string $mode, array $weights)
+    {
+        if (isset($this->weights[$mode])) {
+            $this->weights[$mode] = array_merge($this->weights[$mode], $weights);
+        }
+    }
+
+    public function testConnection()
+    {
+        try {
+            $info = $this->client->info();
+            $message = 'OpenSearch 连接成功: ' . json_encode($info['version']['number']);
+            Log::info($message);
+            return [true, $message];
+        } catch (\Exception $e) {
+            $message = 'OpenSearch 连接失败: ' . $e->getMessage();
+            Log::error($message);
+            return [false, $message];
+        }
+    }
+
+    /** 索引管理方法保持不变... **/
+
+    public function createIndex()
+    {
+        $index = config('mint.opensearch.index');
+        $exists = $this->client->indices()->exists(['index' => $index]);
+        if ($exists) {
+            throw new \Exception("Index [$index] already exists.");
+        }
+        return $this->client->indices()->create([
+            'index' => $index,
+            'body' => $this->indexDefinition
+        ]);
+    }
+
+    public function updateIndex()
+    {
+        $index = config('mint.opensearch.index');
+        $settings = $this->indexDefinition['settings'] ?? [];
+        $mappings = $this->indexDefinition['mappings'] ?? [];
+
+        $response = [];
+        if (!empty($settings)) {
+            $this->client->indices()->close(['index' => $index]);
+            $response['settings'] = $this->client->indices()->putSettings([
+                'index' => $index,
+                'body' => ['settings' => $settings]
+            ]);
+            $this->client->indices()->open(['index' => $index]);
+        }
+        if (!empty($mappings)) {
+            $response['mappings'] = $this->client->indices()->putMapping([
+                'index' => $index,
+                'body' => $mappings
+            ]);
+        }
+        return $response;
+    }
+
+    public function deleteIndex()
+    {
+        $index = config('mint.opensearch.index');
+        return $this->client->indices()->delete(['index' => $index]);
+    }
+
+    public function create(string $id, array $body)
+    {
+        return $this->client->index([
+            'index' => config('mint.opensearch.index'),
+            'id' => $id,
+            'body' => $body
+        ]);
+    }
+
+    public function delete($id)
+    {
+        return $this->client->delete(['index' => config('mint.opensearch.index'), 'id' => $id]);
+    }
+
+    /**
+     * 执行高级搜索(支持 fuzzy / exact / semantic / hybrid 四种模式)
+     *
+     * @param  array  $params  搜索参数数组
+     *   - query: 搜索关键词
+     *   - searchMode: 搜索模式 (fuzzy|exact|semantic|hybrid)
+     *   - page: 页码,默认 1
+     *   - pageSize: 每页条数,默认 20
+     *   - resourceType / language / category / tags / relatedId / pageRefs / author / channel 等过滤条件
+     * @return array OpenSearch 返回的搜索结果
+     *
+     * @throws \Exception
+     */
+    public function search(array $params)
+    {
+        // 分页参数
+        $page = $params['page'] ?? 1;
+        $pageSize = $params['pageSize'] ?? 20;
+        $from = ($page - 1) * $pageSize;
+
+        // 搜索模式,默认 fuzzy
+        $mode = $params['searchMode'] ?? 'fuzzy';
+
+        // ---------- 过滤条件 ----------
+        $filters = [];
+        if (!empty($params['resourceType'])) {
+            $filters[] = ['term' => ['resource_type' => $params['resourceType']]];
+        }
+        if (!empty($params['resourceId'])) {
+            $filters[] = ['term' => ['resource_id' => $params['resourceId']]];
+        }
+        if (!empty($params['granularity'])) {
+            $filters[] = ['term' => ['granularity' => $params['granularity']]];
+        }
+        if (!empty($params['language'])) {
+            $filters[] = ['term' => ['language' => $params['language']]];
+        }
+        if (!empty($params['category'])) {
+            $filters[] = ['term' => ['category' => $params['category']]];
+        }
+        if (!empty($params['tags'])) {
+            $filters[] = ['terms' => ['tags' => $params['tags']]];
+        }
+        if (!empty($params['pageRefs'])) {
+            $filters[] = ['terms' => ['page_refs' => $params['pageRefs']]];
+        }
+        if (!empty($params['relatedId'])) {
+            $filters[] = ['term' => ['related_id' => $params['relatedId']]];
+        }
+        if (!empty($params['author'])) {
+            $filters[] = ['match' => ['metadata.author' => $params['author']]];
+        }
+        if (!empty($params['channel'])) {
+            $filters[] = ['term' => ['metadata.channel' => $params['channel']]];
+        }
+
+        // ---------- 查询部分 ----------
+        switch ($mode) {
+            case 'exact':
+                $query = $this->buildExactQuery($params['query']);
+                break;
+
+            case 'semantic':
+                $query = $this->buildSemanticQuery($params['query']);
+                break;
+
+            case 'hybrid':
+                $query = $this->buildHybridQuery($params['query']);
+                break;
+
+            case 'fuzzy':
+            default:
+                $query = $this->buildFuzzyQuery($params['query']);
+        }
+
+        // ---------- 最终 DSL ----------
+        $dsl = [
+            'from' => $from,
+            'size' => $pageSize,
+            '_source' => [
+                'excludes' => $this->sourceExcludes
+            ],
+            'query' => !empty($filters)
+                ? ['bool' => ['must' => [$query], 'filter' => $filters]]
+                : $query,
+            'aggs' => [
+                'resource_type' => ['terms' => ['field' => 'resource_type']],
+                'language' => ['terms' => ['field' => 'language']],
+                'category' => ['terms' => ['field' => 'category']],
+                'granularity' => ['terms' => ['field' => 'granularity']],
+            ],
+            'highlight' => [
+                'fields' => [
+                    'title.pali.text' => new \stdClass(),
+                    'title.zh' => new \stdClass(),
+                    'summary.text' => new \stdClass(),
+                    'content.pali.text' => new \stdClass(),
+                    'content.zh' => new \stdClass(),
+                ],
+                "fragmenter" => "sentence",
+                "fragment_size" => 200,
+                "number_of_fragments" => 1,
+                'pre_tags' => ['_'],
+                'post_tags' => ['_'],
+            ],
+        ];
+
+        Log::debug('search', ['dsl' => json_encode($dsl, JSON_UNESCAPED_UNICODE)]);
+        // ---------- 执行查询 ----------
+        $response = $this->client->search([
+            'index' => config('mint.opensearch.index'),
+            'body'  => $dsl
+        ]);
+
+        return $response;
+    }
+
+    /**
+     * 构建 exact 查询
+     * 精确匹配 title.pali.exact, content.pali.exact, summary
+     */
+    protected function buildExactQuery(string $query): array
+    {
+        return [
+            'multi_match' => [
+                'query'  => $query,
+                'fields' => [
+                    'title.pali.exact',
+                    'content.pali.exact',
+                    'summary.text'
+                ],
+                'type'   => 'best_fields',
+            ]
+        ];
+    }
+
+    /**
+     * 构建 semantic 查询
+     * 使用 OpenAI embedding,同时查询三个向量字段
+     */
+    protected function buildSemanticQuery(string $query): array
+    {
+        $vector = $this->embedText($query);
+
+        // OpenSearch 支持多个 knn 查询,使用 bool should
+        return [
+            'bool' => [
+                'should' => [
+                    [
+                        'knn' => [
+                            'content.vector' => [
+                                'vector' => $vector,
+                                'k' => 20,
+                            ]
+                        ]
+                    ],
+                    [
+                        'knn' => [
+                            'summary.vector' => [
+                                'vector' => $vector,
+                                'k' => 10,
+                            ]
+                        ]
+                    ],
+                    [
+                        'knn' => [
+                            'title.vector' => [
+                                'vector' => $vector,
+                                'k' => 5,
+                            ]
+                        ]
+                    ]
+                ],
+                'minimum_should_match' => 1
+            ]
+        ];
+    }
+
+    /**
+     * 构建 fuzzy 查询
+     */
+    protected function buildFuzzyQuery(string $query)
+    {
+        $fields = [];
+        foreach ($this->weights['fuzzy'] as $field => $weight) {
+            $fields[] = $field . "^" . $weight;
+        }
+
+        return [
+            'multi_match' => [
+                'query'  => $query,
+                'fields' => $fields,
+                'type'   => 'best_fields'
+            ]
+        ];
+    }
+
+    /**
+     * 构建 hybrid 查询 (fuzzy + semantic)
+     */
+    protected function buildHybridQuery(string $query)
+    {
+        $fuzzyFields = [];
+        foreach ($this->weights['hybrid'] as $field => $weight) {
+            if (in_array($field, ['fuzzy_ratio', 'semantic_ratio'])) {
+                continue;
+            }
+            $fuzzyFields[] = $field . "^" . $weight;
+        }
+
+        $fuzzyPart = [
+            'multi_match' => [
+                'query'  => $query,
+                'fields' => $fuzzyFields,
+                'type'   => 'best_fields'
+            ]
+        ];
+
+        $vector = $this->embedText($query);
+
+        $fuzzyRatio = $this->weights['hybrid']['fuzzy_ratio'];
+        $semanticRatio = $this->weights['hybrid']['semantic_ratio'];
+
+        // 使用 bool should 组合 fuzzy 和 semantic 查询
+        return [
+            'bool' => [
+                'should' => [
+                    // Fuzzy 部分,带权重
+                    [
+                        'constant_score' => [
+                            'filter' => $fuzzyPart,
+                            'boost' => $fuzzyRatio
+                        ]
+                    ],
+                    // Semantic 部分 - content
+                    [
+                        'knn' => [
+                            'content.vector' => [
+                                'vector' => $vector,
+                                'k' => 20,
+                                'boost' => $semanticRatio * 1.0  // 主要权重
+                            ]
+                        ]
+                    ],
+                    // Semantic 部分 - summary
+                    [
+                        'knn' => [
+                            'summary.vector' => [
+                                'vector' => $vector,
+                                'k' => 10,
+                                'boost' => $semanticRatio * 0.8
+                            ]
+                        ]
+                    ],
+                    // Semantic 部分 - title
+                    [
+                        'knn' => [
+                            'title.vector' => [
+                                'vector' => $vector,
+                                'k' => 5,
+                                'boost' => $semanticRatio * 1.2  // title 稍微高一点
+                            ]
+                        ]
+                    ]
+                ]
+            ]
+        ];
+    }
+
+    /**
+     * 调用 OpenAI Embedding API
+     * 使用 Redis 缓存,避免重复调用
+     *
+     * @param  string  $text 输入文本
+     * @return array 向量 embedding
+     * @throws \Exception
+     */
+    protected function embedText(string $text): array
+    {
+        if (!$this->openaiApiKey) {
+            throw new Exception("请在 .env 设置 OPENAI_API_KEY");
+        }
+
+        // 缓存 key,可以用 md5 保证唯一
+        $cacheKey = "embedding:" . md5($text);
+
+        // 先查缓存
+        return Cache::remember($cacheKey, now()->addDays(7), function () use ($text) {
+            $response = $this->http->post('embeddings', [
+                'headers' => [
+                    'Authorization' => 'Bearer ' . $this->openaiApiKey,
+                    'Content-Type'  => 'application/json',
+                ],
+                'json' => [
+                    'model' => 'text-embedding-3-small',
+                    'input' => $text,
+                ],
+            ]);
+
+            $json = json_decode((string)$response->getBody(), true);
+
+            if (empty($json['data'][0]['embedding'])) {
+                throw new Exception("OpenAI embedding 返回异常: " . json_encode($json));
+            }
+
+            return $json['data'][0]['embedding'];
+        });
+    }
+
+    /**
+     * 清理指定文本的 embedding 缓存
+     * $service = app(App\Services\OpenSearchService::class);
+
+        // 清理某个文本的缓存
+        $service->clearEmbeddingCache("sabbe dhammā anattā");
+
+        // 清理所有 embedding 缓存
+        $count = $service->clearAllEmbeddingCache();
+        echo "已清理缓存 {$count} 条";
+     *
+     * @param  string  $text
+     * @return bool
+     */
+    public function clearEmbeddingCache(string $text): bool
+    {
+        $cacheKey = "embedding:" . md5($text);
+        return Cache::forget($cacheKey);
+    }
+
+    /**
+     * 清理所有 embedding 缓存
+     * 注意:这会删除 Redis 里所有 "embedding:*" 的缓存
+     *
+     * @return int 删除的条数
+     */
+    public function clearAllEmbeddingCache(): int
+    {
+        $redis = Cache::getRedis();
+        $pattern = "embedding:*";
+        $keys = $redis->keys($pattern);
+        if (!empty($keys)) {
+            $redis->del($keys);
+        }
+        return count($keys);
+    }
+
+
+    /**
+     * 自动建议
+     *
+     * @param string $query 查询文本
+     * @param array|string|null $fields 要查询的字段,可选值:
+     *   - null: 查询所有字段 ['title', 'content', 'page_refs']
+     *   - 'title': 只查询 title.suggest
+     *   - 'content': 只查询 content.pali.suggest
+     *   - 'page_refs': 只查询 page_refs.suggest
+     *   - ['title', 'content']: 查询多个字段
+     * @param string|null $language 语言过滤(可选)
+     * @param int $limit 每个字段返回的建议数量
+     * @return array
+     */
+    public function suggest(
+        string $query,
+        $fields = null,
+        ?string $language = null,
+        int $limit = 10
+    ): array {
+        // 字段映射配置
+        $fieldMap = [
+            'title' => 'title.suggest',
+            'content' => 'content.suggest',
+        ];
+
+        // 处理字段参数
+        if ($fields === null) {
+            // 默认查询所有字段
+            $searchFields = array_keys($fieldMap);
+        } elseif (is_string($fields)) {
+            // 单个字段
+            $searchFields = [$fields];
+        } else {
+            // 数组形式
+            $searchFields = $fields;
+        }
+
+        // 验证字段有效性
+        $searchFields = array_filter($searchFields, function ($field) use ($fieldMap) {
+            return isset($fieldMap[$field]);
+        });
+
+        if (empty($searchFields)) {
+            throw new \InvalidArgumentException('Invalid fields specified for suggestion');
+        }
+
+        // 构建 suggest 查询
+        $suggests = [];
+        foreach ($searchFields as $field) {
+            $suggests[$field . '_suggest'] = [
+                'prefix' => $query,
+                'completion' => [
+                    'field' => $fieldMap[$field],
+                    'size'  => $limit,
+                    'skip_duplicates' => true,
+                ]
+            ];
+        }
+
+        $dsl = ['suggest' => $suggests];
+
+        // 添加语言过滤
+        if ($language) {
+            $dsl['query'] = ['term' => ['language' => $language]];
+        }
+
+        $response = $this->client->search([
+            'index' => config('mint.opensearch.index'),
+            'body' => $dsl
+        ]);
+
+        // 处理返回结果,包含来源信息
+        $results = [];
+        foreach ($searchFields as $field) {
+            $options = $response['suggest'][$field . '_suggest'][0]['options'] ?? [];
+
+            foreach ($options as $opt) {
+                $results[] = [
+                    'text'      => $opt['text'] ?? '',
+                    'source'    => $field,  // 添加来源字段
+                    'score'     => $opt['_score'] ?? 0,
+                    // 可选:添加文档信息
+                    'doc_id'    => $opt['_id'] ?? null,
+                    'doc_source' => $opt['_source'] ?? null,
+                ];
+            }
+        }
+
+        // 按分数排序
+        usort($results, function ($a, $b) {
+            return $b['score'] <=> $a['score'];
+        });
+
+        return $results;
+    }
+}

+ 2 - 2
api-v8/app/Services/RabbitMQService.php

@@ -143,7 +143,7 @@ class RabbitMQService
             */
     }
 
-    public function publishMessage(string $queueName, array $data): bool
+    public function publishMessage(string $queueName, array $data): string
     {
         try {
             $this->setupQueue($queueName);
@@ -161,7 +161,7 @@ class RabbitMQService
             $this->channel->basic_publish($message, '', $queueName);
 
             Log::info("Message published to queue: {$queueName} msg id={$msgId}");
-            return true;
+            return $msgId;
         } catch (\Exception $e) {
             Log::error("Failed to publish message to queue: {$queueName}", [
                 'error' => $e->getMessage(),

+ 97 - 0
api-v8/app/Services/ResourceService.php

@@ -0,0 +1,97 @@
+<?php
+
+namespace App\Services;
+
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+class ResourceService
+{
+    protected $openSearch;
+    protected $embeddingService;
+    protected $markdownConverter;
+
+    public function __construct(OpenSearchService $openSearch, EmbeddingService $embeddingService)
+    {
+        $this->openSearch = $openSearch;
+        $this->embeddingService = $embeddingService;
+        $this->markdownConverter = new GithubFlavoredMarkdownConverter();
+    }
+
+    public function store(array $data)
+    {
+        $doc = $this->buildDocument($data);
+        return $this->openSearch->create('wikipali_resources', $doc['id'], $doc);
+    }
+
+    public function update($uid, array $data)
+    {
+        $doc = $this->buildDocument(array_merge(['uid' => $uid], $data));
+        return $this->openSearch->create('wikipali_resources', $doc['id'], $doc); // 使用 create 覆盖更新
+    }
+
+    public function delete($uid)
+    {
+        $this->openSearch->delete('wikipali_resources', $uid);
+    }
+
+    public function generateEmbedding($text)
+    {
+        return $this->embeddingService->generate($text);
+    }
+
+    private function buildDocument(array $data)
+    {
+        $contentText = is_array($data['content']) ? $data['content'][0]['text'] ?? '' : $data['content'];
+        $normalizedText = $this->normalizeMarkdown($contentText);
+
+        $doc = [
+            'id' => $data['uid'],
+            'uid' => $data['uid'],
+            'type' => $data['type'],
+            'title' => $data['title'],
+            'content' => [
+                [
+                    'id' => $data['uid'],
+                    'text' => $contentText,
+                    'text_normalized' => $normalizedText
+                ]
+            ],
+            'confidence' => $data['confidence'] ?? 1.0,
+            'content_embedding' => $this->embeddingService->generate($normalizedText),
+            'suggest_content' => $this->extractSuggestions($contentText, $data['title']),
+            'metadata' => $data['metadata'] ?? []
+        ];
+
+        if (in_array($data['type'], ['sutta', 'paragraph'])) {
+            $doc['book_id'] = $data['book_id'] ?? null;
+            $doc['paragraph'] = $data['paragraph'] ?? null;
+            $doc['scripture_id'] = $data['book_id'] && $data['paragraph'] ? "{$data['book_id']}-{$data['paragraph']}" : null;
+            $doc['path_full'] = $data['path_full'] ?? '';
+            $doc['path_embedding'] = $this->embeddingService->generate($doc['path_full']);
+            $doc['book_name'] = $data['book_name'] ?? '';
+            $doc['vagga'] = $data['vagga'] ?? '';
+            $doc['chapter'] = $data['chapter'] ?? '';
+            $doc['sutta_name'] = $data['sutta_name'] ?? $data['title'];
+        }
+
+        return $doc;
+    }
+
+    private function normalizeMarkdown($markdown)
+    {
+        // 转换为纯文本,去除 Markdown 标记
+        $html = $this->markdownConverter->convert($markdown)->getContent();
+        $text = strip_tags($html);
+        // 简单巴利文规范化(可进一步用 ICU folding)
+        $text = str_replace(['ā', 'ī', 'ū'], ['a', 'i', 'u'], strtolower($text));
+        return $text;
+    }
+
+    private function extractSuggestions($markdown, $title)
+    {
+        $text = $this->normalizeMarkdown($markdown);
+        // 提取标题和关键词(简单示例,可用 NLP 优化)
+        $keywords = array_unique(array_filter(explode(' ', $text), fn($word) => strlen($word) > 2));
+        return array_merge([$title], array_slice($keywords, 0, 5));
+    }
+}

+ 219 - 0
api-v8/app/Services/SearchPaliDataService.php

@@ -0,0 +1,219 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\BookTitle;
+use App\Models\WbwTemplate;
+use App\Models\PaliText;
+use App\Models\PaliSentence;
+
+class SearchPaliDataService
+{
+    /**
+     * Retrieve paginated Pali data for search.
+     *
+     * @param int $book
+     * @param int $start
+     * @param int $pageSize
+     * @return array
+     */
+    public function getPaliData($book, $start = 1, $pageSize = null)
+    {
+        $maxParagraph = WbwTemplate::where('book', $book)->max('paragraph');
+        $output = [];
+        $pageSize = $pageSize === null ? $maxParagraph : $pageSize;
+        // Calculate end paragraph for pagination
+        $endOfPara = min($start + $pageSize, $maxParagraph + 1);
+
+        for ($iPara = $start; $iPara < $endOfPara; $iPara++) {
+            $content = $this->getParaContent($book, $iPara);
+
+
+
+
+            // Retrieve book ID
+            $pcd_book = BookTitle::where('book', $book)
+                ->where('paragraph', '<=', $iPara)
+                ->orderBy('paragraph', 'desc')
+                ->first();
+
+            $pcd_book_id = $pcd_book ? $pcd_book->sn : BookTitle::where('book', $book)
+                ->orderBy('paragraph')
+                ->value('sn');
+
+            $output[] = [
+                'uid' => PaliText::where('book', $book)->where('paragraph', $iPara)->value('uid'),
+                'book' => $book,
+                'paragraph' => $iPara,
+                'bold1' => implode(' ', $content['bold1']),
+                'bold2' => implode(' ', $content['bold2']),
+                'bold3' => implode(' ', $content['bold3']),
+                'content' => $content['markdown'],
+                'markdown' => $content['markdown'],
+                'text' => $content['text'],
+                'pcd_book_id' => $pcd_book_id
+            ];
+        }
+
+        return ['rows' => $output, 'count' => $maxParagraph];
+    }
+
+    /**
+     * Generate content string for a given book and paragraph.
+     *
+     * @param int $book
+     * @param int $para
+     * @return string
+     */
+    private function getContent($book, $para)
+    {
+        $words = WbwTemplate::where('book', $book)
+            ->where('paragraph', $para)
+            ->where('type', '<>', '.ctl.')
+            ->orderBy('wid')
+            ->get();
+
+        $content = '';
+        foreach ($words as $word) {
+            if ($word->style === 'bld') {
+                if (strpos($word->word, '{') === false) {
+                    $content .= "**{$word->word}** ";
+                } else {
+                    $content .= str_replace(['{', '}'], ['**', '** '], $word->word);
+                }
+            } elseif ($word->style === 'note') {
+                $content .= " _{$word->word}_ ";
+            } else {
+                $content .= $word->word . ' ';
+            }
+        }
+
+        return trim($content);
+    }
+
+    /**
+     * Generate paragraph sentence list for a given book and paragraph.
+     *
+     * @param int $book
+     * @param int $para
+     * @return array $sentences
+     */
+    public function getParaContent($book, $para)
+    {
+        $sentences = PaliSentence::where('book', $book)
+            ->where('paragraph', $para)
+            ->orderBy('word_begin')
+            ->get();
+        if (!$sentences) {
+            return null;
+        }
+        $markdown = [];
+        $text = [];
+        $wordList = [];
+        foreach ($sentences as $key => $sentence) {
+            $content = $this->getSentenceText($book, $para, $sentence->word_begin, $sentence->word_end);
+            $id = "{$book}-{$para}-{$sentence->word_begin}-{$sentence->word_end}";
+            $markdown[] = $content['markdown'];
+            $text[] = $content['text'];
+            $wordList = array_merge($wordList, $content['words']);
+        }
+
+        // Retrieve bold words
+        $words = WbwTemplate::where('book', $book)
+            ->where('paragraph', $para)
+            ->orderBy('wid')
+            ->get();
+
+        $bold1 = [];
+        $bold2 = [];
+        $bold3 = [];
+        $currBold = [];
+
+        foreach ($words as $word) {
+            if ($word->type === '.ctl.') {
+                //检测义注段落号
+                if (preg_match('/^para\d+_[a-zA-Z].*$/', $word->real)) {
+                    $commentary = $word->real;
+                }
+            } else {
+                if ($word->style === 'bld') {
+                    $currBold[] = $word->real;
+                } else {
+                    $countBold = count($currBold);
+                    if ($countBold === 1) {
+                        $bold1[] = $currBold[0];
+                    } elseif ($countBold === 2) {
+                        $bold2 = array_merge($bold2, $currBold);
+                    } elseif ($countBold > 0) {
+                        $bold3 = array_merge($bold3, $currBold);
+                    }
+                    $currBold = [];
+                }
+            }
+        }
+
+        $data = [
+            'markdown' => implode("\n", $markdown),
+            'text' => implode(" ", $text),
+            'words' => $wordList,
+            'bold1' => $bold1,
+            'bold2' => $bold2,
+            'bold3' => $bold3,
+        ];
+        if (isset($commentary)) {
+            $data['commentary'] = $commentary;
+        }
+        return $data;
+    }
+
+    /**
+     * Generate paragraph sentence list for a given book and paragraph.
+     *
+     * @param int $book
+     * @param int $para
+     * @return array $sentence
+     */
+    private function getSentenceText($book, $para, $start, $end)
+    {
+        $words = WbwTemplate::where('book', $book)
+            ->where('paragraph', $para)
+            ->where('type', '<>', '.ctl.')
+            ->whereBetween('wid', [$start, $end])
+            ->orderBy('wid')
+            ->get();
+
+        $arrText = [];
+        $markdown = '';
+        $wordList = [];
+        foreach ($words as $word) {
+            $arrText[] = str_replace(['{', '}'], ['', ''], $word->word);
+            $wordList[] = $word->real;
+            if ($word->style === 'bld') {
+                if (strpos($word->word, '{') === false) {
+                    $markdown .= "**{$word->word}** ";
+                } else {
+                    $markdown .= str_replace(['{', '}'], ['**', '**'], $word->word) . ' ';
+                }
+            } elseif ($word->style === 'note') {
+                $markdown .= " ~~{$word->word}~~ ";
+            } else {
+                $markdown .= $word->word . ' ';
+            }
+        }
+        $markdown = str_replace([' ti', ' ,', ' .', ' ?'], ['ti', ',', '.', '?'], $markdown);
+        $markdown = str_replace(['~~  ~~', '** **'], [' ', ' '], $markdown);
+        $text = implode(' ', $arrText);
+        $text = str_replace([' ti', ' ,', ' .', ' ?'], ['ti', ',', '.', '?'], $text);
+        return [
+            'markdown' => $this->abbrReplace(trim($markdown)),
+            'text' => $this->abbrReplace($text),
+            'words' => $wordList,
+        ];
+    }
+    private function abbrReplace($input)
+    {
+        $abbr = ['sī .', 'syā .', 'kaṃ .', 'pī .'];
+        $abbrTo = ['sī.', 'syā.', 'kaṃ.', 'pī.'];
+        return str_replace($abbr, $abbrTo, $input);
+    }
+}

+ 214 - 0
api-v8/app/Services/SummaryService.php

@@ -0,0 +1,214 @@
+<?php
+
+namespace App\Services;
+
+use Illuminate\Support\Facades\Http;
+use App\Services\AIModelService;
+use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\Log;
+
+class SummaryService
+{
+    protected string $modelId;
+    protected string $apiUrl = '';
+    protected string $apiModel = 'deepseek-v3';
+    protected int $maxRetries = 3;
+    protected int $chunkSize = 20000; // 每段字符数,可根据模型上下文调整
+    private string $system_prompt = '你是一个摘要写作助手.请根据用户的输入文本生成中文的摘要,直接输出摘要,无需解释说明。';
+
+    /**
+     * 创建服务实例,初始化 OpenAI API Key
+     *
+     * @return void
+     */
+    public function __construct(AIModelService $aiModels)
+    {
+        $models = $aiModels->getSysModels('summarize');
+        $this->modelId = $models[0]['uid'];
+        $this->apiUrl = config('mint.ai.proxy') . '/api/openai';
+    }
+
+    /**
+     * 生成输入文本的摘要,并支持缓存与强制刷新。
+     *
+     * 此方法会根据文本长度自动拆分为多个片段,
+     * 对每个片段调用模型生成部分摘要,
+     * 并最终将所有部分摘要再次合并生成整体摘要。
+     *
+     * 同时支持缓存机制:
+     * - 缓存键使用文本内容的 md5 计算。
+     * - 默认缓存有效期为 1 天。
+     * - 可通过 forceRefresh 参数强制重新生成摘要。
+     *
+     * @param  string  $text          输入的 Markdown 文本
+     * @param  int     $maxTokens     每次请求允许的最大 tokens 数
+     * @param  bool    $forceRefresh  是否忽略缓存并强制刷新摘要
+     * @return string                 最终生成的摘要文本
+     */
+    public function summarize(string $text, int $maxTokens = 500, bool $forceRefresh = false): string
+    {
+        // 1️⃣ 计算缓存 key
+        $cacheKey = 'summary_' . md5($text);
+
+        // 2️⃣ 检查缓存命中
+        if (!$forceRefresh && Cache::has($cacheKey)) {
+            Log::debug("SummaryService cache hit", ['key' => $cacheKey]);
+            return Cache::get($cacheKey);
+        }
+
+        Log::debug("SummaryService generating new summary", [
+            'key' => $cacheKey,
+            'forceRefresh' => $forceRefresh
+        ]);
+
+        // 3️⃣ 执行摘要逻辑
+        $chunks = $this->splitText($text, $this->chunkSize);
+        $partialSummaries = [];
+
+        foreach ($chunks as $chunk) {
+            $summary = $this->callOpenAI($chunk, $maxTokens);
+            if ($summary !== '') {
+                $partialSummaries[] = $summary;
+            }
+        }
+
+        if (count($partialSummaries) === 0) {
+            Log::warning("SummaryService no partial summaries", ['key' => $cacheKey]);
+            return '';
+        }
+
+        $finalSummary = '';
+        if (count($partialSummaries) === 1) {
+            $finalSummary = $partialSummaries[0];
+        } else {
+            $combinedText = implode("\n\n", $partialSummaries);
+            $finalSummary = $this->callOpenAI($combinedText, $maxTokens);
+        }
+
+        // 4️⃣ 写入缓存(默认缓存 1 周)
+        Cache::put($cacheKey, $finalSummary, now()->addWeek());
+
+        Log::debug("SummaryService cached new summary", [
+            'key' => $cacheKey,
+            'summary' => mb_substr($finalSummary, 0, 10, 'UTF-8')
+        ]);
+
+        return $finalSummary;
+    }
+
+    /**
+     * 按段落拆分文本
+     *
+     * 将 Markdown 文本按空行识别为段落,
+     * 避免在段落中间截断。
+     * 如果段落超过设定 chunkSize,则按字符截断。
+     *
+     * @param  string  $text       输入的 Markdown 文本
+     * @param  int     $chunkSize  每个块的最大字符数
+     * @return array               分割后的文本块数组
+     */
+    protected function splitText(string $text, int $chunkSize): array
+    {
+        $paragraphs = preg_split("/\r?\n\r?\n/", $text); // 按空行拆段落
+        $chunks = [];
+        $currentChunk = '';
+
+        foreach ($paragraphs as $para) {
+            $para = trim($para);
+            if ($para === '') {
+                continue;
+            }
+
+            // 如果单段落超长,按 chunkSize 截断
+            if (mb_strlen($para) > $chunkSize) {
+                $subStart = 0;
+                while ($subStart < mb_strlen($para)) {
+                    $subChunk = mb_substr($para, $subStart, $chunkSize);
+                    $chunks[] = $subChunk;
+                    $subStart += $chunkSize;
+                }
+                continue;
+            }
+
+            // 如果加上当前段落超过 chunkSize,则先保存当前 chunk
+            if (mb_strlen($currentChunk) + mb_strlen($para) + 2 > $chunkSize) { // +2 保留空行
+                $chunks[] = $currentChunk;
+                $currentChunk = $para;
+            } else {
+                // 否则累加到当前 chunk
+                $currentChunk .= ($currentChunk === '' ? '' : "\n\n") . $para;
+            }
+        }
+
+        if ($currentChunk !== '') {
+            $chunks[] = $currentChunk;
+        }
+
+        return $chunks;
+    }
+
+    /**
+     * 调用 OpenAI GPT 模型生成摘要
+     *
+     * 带有重试机制和指数退避。
+     * 在 429 或 500+ 错误时重试,最大重试次数为 maxRetries。
+     * 其他错误直接返回空字符串。
+     *
+     * @param  string  $text       输入文本
+     * @param  int     $maxTokens  每次请求允许的最大 tokens 数
+     * @return string              模型返回的摘要文本
+     */
+    protected function callOpenAI(string $text, int $maxTokens = 200): string
+    {
+        $attempt = 0;
+        $delay = 1;
+
+        $payload = [
+            'model' => $this->modelId,
+            'messages' => [
+                [
+                    'role' => 'system',
+                    'content' => $this->system_prompt
+                ],
+                [
+                    'role' => 'user',
+                    'content' => $text
+                ],
+            ],
+            'max_tokens' => $maxTokens,
+        ];
+        while ($attempt < $this->maxRetries) {
+            try {
+                $response = Http::timeout(100)
+                    ->withHeaders([
+                        'Authorization' => 'Bearer ',
+                        'Content-Type' => 'application/json',
+                    ])->post($this->apiUrl, [
+                        'model_id' => $this->modelId,
+                        'payload' => $payload
+                    ]);
+
+                if ($response->successful()) {
+                    $data = $response->json();
+                    return $data['choices'][0]['message']['content'] ?? '';
+                }
+
+                if (in_array($response->status(), [429, 500, 502, 503, 504])) {
+                    throw new \Exception("Temporary server error: " . $response->status());
+                }
+
+                return '';
+            } catch (\Exception $e) {
+                $attempt++;
+                if ($attempt >= $this->maxRetries) {
+                    return '';
+                }
+
+                sleep($delay);
+                $delay *= 10;
+            }
+        }
+
+        return '';
+    }
+}

+ 3220 - 3218
api-v8/app/Tools/CaseEnding.php

@@ -1,3226 +1,3228 @@
 <?php
+
 namespace App\Tools;
 
 
-class CaseEnding{
-	public $ending = [
-		["ti","tuṃ",".v:ind.",".inf.",0.99],
-		["ati","ituṃ",".v:ind.",".inf.",0.99],
-		["ati","itvā",".v:ind.",".abs.",0.99],
-		["ati","atvā",".v:ind.",".abs.",0.99],
-		["ti","tvā",".v:ind.",".abs.",0.99],
-		["ant","antā",".ti.",".m.$.pl.$.nom.",0.99],
-		["ant","antā",".ti.",".m.$.pl.$.voc.",0.3],
-		["ant","antā",".ti.",".m.$.sg.$.abl.",0.99],
-		["ant","anta",".ti.",".m.$.sg.$.voc.",0.3],
-		["ant","antā",".ti.",".m.$.sg.$.voc.",0.3],
-		["ant","anta",".ti.",".nt.$.pl.$.acc.",0.99],
-		["ant","antā",".ti.",".nt.$.pl.$.acc.",0.99],
-		["ant","anta",".ti.",".nt.$.pl.$.nom.",0.99],
-		["ant","antā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["ant","anta",".ti.",".nt.$.pl.$.voc.",0.3],
-		["ant","antā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["ant","antā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["ant","anta",".ti.",".nt.$.sg.$.voc.",0.3],
-		["ant","antā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["ant","antaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["ant","antaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["ant","antaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["ant","antaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["ant","antaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["ant","antaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["ant","antamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["ant","antamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["ant","antamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["ant","antamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["ant","antamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["ant","antamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["ant","antamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["ant","antamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["ant","antānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["ant","antānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["ant","antānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["ant","antānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["ant","antānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["ant","antānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["ant","antani",".ti.",".nt.$.pl.$.acc.",0.99],
-		["ant","antāni",".ti.",".nt.$.pl.$.acc.",0.99],
-		["ant","antani",".ti.",".nt.$.pl.$.nom.",0.99],
-		["ant","antāni",".ti.",".nt.$.pl.$.nom.",0.99],
-		["ant","antani",".ti.",".nt.$.pl.$.voc.",0.3],
-		["ant","antāni",".ti.",".nt.$.pl.$.voc.",0.3],
-		["ant","antasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["ant","antasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["ant","antasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["ant","antasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["ant","antasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["ant","antasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["ant","antasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["ant","antasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["ant","antassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["ant","antassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["ant","antassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["ant","antassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["ant","antassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["ant","antassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["ant","antassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["ant","antassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["ant","ante",".ti.",".m.$.pl.$.acc.",0.99],
-		["ant","ante",".ti.",".m.$.sg.$.loc.",0.99],
-		["ant","ante",".ti.",".nt.$.pl.$.acc.",0.99],
-		["ant","ante",".ti.",".nt.$.sg.$.loc.",0.99],
-		["ant","antebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["ant","antebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["ant","antebhi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["ant","antebhi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["ant","antehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["ant","antehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["ant","antehi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["ant","antehi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["ant","antesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["ant","antesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["ant","antesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["ant","antī",".ti.",".f.$.pl.$.acc.",0.99],
-		["ant","antī",".ti.",".f.$.pl.$.nom.",0.99],
-		["ant","antī",".ti.",".f.$.pl.$.voc.",0.3],
-		["ant","antī",".ti.",".f.$.sg.$.nom.",0.99],
-		["ant","antī",".ti.",".f.$.sg.$.voc.",0.3],
-		["ant","antībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["ant","antībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["ant","antīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["ant","antīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["ant","antiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["ant","antīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["ant","antīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["ant","antīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["ant","antiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["ant","antiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["ant","antiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["ant","antiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["ant","antiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["ant","antiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["ant","antiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["ant","antiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["ant","antiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["ant","anto",".ti.",".m.$.pl.$.nom.",0.99],
-		["ant","anto",".ti.",".m.$.pl.$.voc.",0.3],
-		["ant","anto",".ti.",".m.$.sg.$.nom.",0.99],
-		["ant","anto",".ti.",".nt.$.pl.$.nom.",0.99],
-		["ant","anto",".ti.",".nt.$.pl.$.voc.",0.3],
-		["ant","anto",".ti.",".nt.$.sg.$.nom.",0.99],
-		["ant","atā",".ti.",".m.$.sg.$.abl.",0.99],
-		["ant","atā",".ti.",".m.$.sg.$.inst.",0.99],
-		["ant","atā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["ant","atā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["ant","atā",".ti.",".m.$.sg.$.abl.",0.99],
-		["ant","atā",".ti.",".m.$.sg.$.inst.",0.99],
-		["ant","atā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["ant","atā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["ant","ataṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["ant","ataṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["ant","ataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["ant","ataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["ant","ataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["ant","ataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["ant","atena",".ti.",".m.$.sg.$.inst.",0.99],
-		["ant","atena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["ant","atena",".ti.",".m.$.sg.$.inst.",0.99],
-		["ant","atena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["ant","atī",".ti.",".f.$.pl.$.acc.",0.99],
-		["ant","atī",".ti.",".f.$.pl.$.nom.",0.99],
-		["ant","atī",".ti.",".f.$.pl.$.voc.",0.3],
-		["ant","atī",".ti.",".f.$.sg.$.nom.",0.99],
-		["ant","atī",".ti.",".f.$.sg.$.voc.",0.3],
-		["ant","ati",".ti.",".m.$.sg.$.loc.",0.99],
-		["ant","ati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["ant","ati",".ti.",".m.$.sg.$.loc.",0.99],
-		["ant","ati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["ant","atībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["ant","atībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["ant","atīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["ant","atīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["ant","atiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["ant","atīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["ant","atīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["ant","atīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["ant","atiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["ant","atiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["ant","atiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["ant","atiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["ant","atiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["ant","atiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["ant","atiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["ant","atiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["ant","atiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["ant","ato",".ti.",".m.$.sg.$.dat.",0.99],
-		["ant","ato",".ti.",".m.$.sg.$.gen.",0.99],
-		["ant","ato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["ant","ato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["ant","ato",".ti.",".m.$.sg.$.dat.",0.99],
-		["ant","ato",".ti.",".m.$.sg.$.gen.",0.99],
-		["ant","ato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["ant","ato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["anta","antā",".ti.",".m.$.pl.$.nom.",0.99],
-		["anta","antā",".ti.",".m.$.pl.$.voc.",0.3],
-		["anta","antā",".ti.",".m.$.sg.$.abl.",0.99],
-		["anta","anta",".ti.",".m.$.sg.$.voc.",0.3],
-		["anta","antā",".ti.",".m.$.sg.$.voc.",0.3],
-		["anta","anta",".ti.",".nt.$.pl.$.acc.",0.99],
-		["anta","antā",".ti.",".nt.$.pl.$.acc.",0.99],
-		["anta","anta",".ti.",".nt.$.pl.$.nom.",0.99],
-		["anta","antā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["anta","anta",".ti.",".nt.$.pl.$.voc.",0.3],
-		["anta","antā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["anta","antā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["anta","anta",".ti.",".nt.$.sg.$.voc.",0.3],
-		["anta","antā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["anta","antaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["anta","antaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["anta","antaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["anta","antaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["anta","antaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["anta","antaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["anta","antamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["anta","antamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["anta","antamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["anta","antamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["anta","antamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["anta","antamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["anta","antamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["anta","antamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["anta","antānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["anta","antānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["anta","antānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["anta","antānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["anta","antānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["anta","antānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["anta","antani",".ti.",".nt.$.pl.$.acc.",0.99],
-		["anta","antāni",".ti.",".nt.$.pl.$.acc.",0.99],
-		["anta","antani",".ti.",".nt.$.pl.$.nom.",0.99],
-		["anta","antāni",".ti.",".nt.$.pl.$.nom.",0.99],
-		["anta","antani",".ti.",".nt.$.pl.$.voc.",0.3],
-		["anta","antāni",".ti.",".nt.$.pl.$.voc.",0.3],
-		["anta","antasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["anta","antasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["anta","antasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["anta","antasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["anta","antasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["anta","antasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["anta","antasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["anta","antasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["anta","antassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["anta","antassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["anta","antassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["anta","antassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["anta","antassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["anta","antassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["anta","antassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["anta","antassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["anta","ante",".ti.",".m.$.pl.$.acc.",0.99],
-		["anta","ante",".ti.",".m.$.sg.$.loc.",0.99],
-		["anta","ante",".ti.",".nt.$.pl.$.acc.",0.99],
-		["anta","ante",".ti.",".nt.$.sg.$.loc.",0.99],
-		["anta","antebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["anta","antebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["anta","antebhi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["anta","antebhi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["anta","antehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["anta","antehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["anta","antehi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["anta","antehi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["anta","antesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["anta","antesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["anta","antesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["anta","antī",".ti.",".f.$.pl.$.acc.",0.99],
-		["anta","antī",".ti.",".f.$.pl.$.nom.",0.99],
-		["anta","antī",".ti.",".f.$.pl.$.voc.",0.3],
-		["anta","antī",".ti.",".f.$.sg.$.nom.",0.99],
-		["anta","antī",".ti.",".f.$.sg.$.voc.",0.3],
-		["anta","antībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["anta","antībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["anta","antīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["anta","antīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["anta","antiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["anta","antīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["anta","antīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["anta","antīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["anta","antiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["anta","antiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["anta","antiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["anta","antiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["anta","antiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["anta","antiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["anta","antiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["anta","antiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["anta","antiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["anta","anto",".ti.",".m.$.pl.$.nom.",0.99],
-		["anta","anto",".ti.",".m.$.pl.$.voc.",0.3],
-		["anta","anto",".ti.",".m.$.sg.$.nom.",0.99],
-		["anta","anto",".ti.",".nt.$.pl.$.nom.",0.99],
-		["anta","anto",".ti.",".nt.$.pl.$.voc.",0.3],
-		["anta","anto",".ti.",".nt.$.sg.$.nom.",0.99],
-		["anta","atā",".ti.",".m.$.sg.$.abl.",0.99],
-		["anta","atā",".ti.",".m.$.sg.$.inst.",0.99],
-		["anta","atā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["anta","atā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["anta","atā",".ti.",".m.$.sg.$.abl.",0.99],
-		["anta","atā",".ti.",".m.$.sg.$.inst.",0.99],
-		["anta","atā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["anta","atā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["anta","ataṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["anta","ataṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["anta","ataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["anta","ataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["anta","ataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["anta","ataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["anta","atena",".ti.",".m.$.sg.$.inst.",0.99],
-		["anta","atena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["anta","atena",".ti.",".m.$.sg.$.inst.",0.99],
-		["anta","atena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["anta","atī",".ti.",".f.$.pl.$.acc.",0.99],
-		["anta","atī",".ti.",".f.$.pl.$.nom.",0.99],
-		["anta","atī",".ti.",".f.$.pl.$.voc.",0.3],
-		["anta","atī",".ti.",".f.$.sg.$.nom.",0.99],
-		["anta","atī",".ti.",".f.$.sg.$.voc.",0.3],
-		["anta","ati",".ti.",".m.$.sg.$.loc.",0.99],
-		["anta","ati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["anta","ati",".ti.",".m.$.sg.$.loc.",0.99],
-		["anta","ati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["anta","atībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["anta","atībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["anta","atīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["anta","atīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["anta","atiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["anta","atīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["anta","atīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["anta","atīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["anta","atiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["anta","atiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["anta","atiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["anta","atiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["anta","atiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["anta","atiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["anta","atiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["anta","atiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["anta","atiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["anta","ato",".ti.",".m.$.sg.$.dat.",0.99],
-		["anta","ato",".ti.",".m.$.sg.$.gen.",0.99],
-		["anta","ato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["anta","ato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["anta","ato",".ti.",".m.$.sg.$.dat.",0.99],
-		["anta","ato",".ti.",".m.$.sg.$.gen.",0.99],
-		["anta","ato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["anta","ato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mant","mā",".ti.",".m.$.pl.$.nom.",0.99],
-		["mant","mā",".ti.",".m.$.pl.$.voc.",0.3],
-		["mant","mā",".ti.",".m.$.sg.$.nom.",0.99],
-		["mant","ma",".ti.",".m.$.sg.$.voc.",0.3],
-		["mant","mā",".ti.",".m.$.sg.$.voc.",0.3],
-		["mant","mā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mant","mā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mant","ma",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mant","mā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mant","mā",".ti.",".m.$.sg.$.voc.",0.3],
-		["mant","mā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mant","maṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["mant","maṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["mant","maṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mant","maṃ",".ti.",".m.$.sg.$.nom.",0.99],
-		["mant","maṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["mant","maṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mant","maṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["mant","maṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mant","mānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["mant","mānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["mant","mantā",".ti.",".m.$.pl.$.nom.",0.99],
-		["mant","mantā",".ti.",".m.$.pl.$.voc.",0.3],
-		["mant","mantā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mant","manta",".ti.",".m.$.sg.$.voc.",0.3],
-		["mant","mantā",".ti.",".m.$.sg.$.voc.",0.3],
-		["mant","manta",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mant","mantā",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mant","manta",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mant","mantā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mant","manta",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mant","mantā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mant","mantā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mant","manta",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mant","mantā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mant","mantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["mant","mantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["mant","mantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mant","mantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mant","mantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["mant","mantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["mant","mantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mant","mantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mant","mantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mant","mantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mant","mantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["mant","mantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mant","mantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["mant","mantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mant","mantānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["mant","mantānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["mant","mantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mant","mantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mant","mantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mant","mantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mant","mantani",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mant","mantāni",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mant","mantani",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mant","mantāni",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mant","mantani",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mant","mantāni",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mant","mantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mant","mantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mant","mantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mant","mantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mant","mantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["mant","mantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mant","mantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["mant","mantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mant","mantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["mant","mantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["mant","mantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mant","mantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mant","mantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["mant","mantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["mant","mantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mant","mantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mant","mante",".ti.",".m.$.pl.$.acc.",0.99],
-		["mant","mante",".ti.",".m.$.sg.$.loc.",0.99],
-		["mant","mante",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mant","mante",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mant","mantebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mant","mantebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mant","mantebhi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["mant","mantebhi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["mant","mantehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mant","mantehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mant","mantehi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["mant","mantehi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["mant","mantesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["mant","mantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["mant","mantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["mant","mantī",".ti.",".f.$.pl.$.acc.",0.99],
-		["mant","mantī",".ti.",".f.$.pl.$.nom.",0.99],
-		["mant","mantī",".ti.",".f.$.pl.$.voc.",0.3],
-		["mant","mantī",".ti.",".f.$.sg.$.nom.",0.99],
-		["mant","mantī",".ti.",".f.$.sg.$.voc.",0.3],
-		["mant","mantībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mant","mantībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mant","mantīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mant","mantīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mant","mantiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["mant","mantīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["mant","mantīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["mant","mantīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["mant","mantiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["mant","mantiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["mant","mantiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["mant","mantiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["mant","mantiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["mant","mantiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["mant","mantiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["mant","mantiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["mant","mantiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["mant","manto",".ti.",".m.$.pl.$.nom.",0.99],
-		["mant","manto",".ti.",".m.$.pl.$.voc.",0.3],
-		["mant","manto",".ti.",".m.$.sg.$.nom.",0.99],
-		["mant","manto",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mant","manto",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mant","manto",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mant","matā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mant","matā",".ti.",".m.$.sg.$.inst.",0.99],
-		["mant","matā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mant","matā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mant","matā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mant","matā",".ti.",".m.$.sg.$.inst.",0.99],
-		["mant","matā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mant","matā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mant","mataṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["mant","mataṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["mant","mataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mant","mataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mant","mataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mant","mataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mant","matena",".ti.",".m.$.sg.$.inst.",0.99],
-		["mant","matena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mant","matena",".ti.",".m.$.sg.$.inst.",0.99],
-		["mant","matena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mant","matī",".ti.",".f.$.pl.$.acc.",0.99],
-		["mant","matī",".ti.",".f.$.pl.$.nom.",0.99],
-		["mant","matī",".ti.",".f.$.pl.$.voc.",0.3],
-		["mant","matī",".ti.",".f.$.sg.$.nom.",0.99],
-		["mant","matī",".ti.",".f.$.sg.$.voc.",0.3],
-		["mant","mati",".ti.",".m.$.sg.$.loc.",0.99],
-		["mant","mati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mant","mati",".ti.",".m.$.sg.$.loc.",0.99],
-		["mant","mati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mant","matībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mant","matībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mant","matīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mant","matīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mant","matiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["mant","matīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["mant","matīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["mant","matīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["mant","matiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["mant","matiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["mant","matiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["mant","matiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["mant","matiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["mant","matiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["mant","matiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["mant","matiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["mant","matiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["mant","mato",".ti.",".m.$.sg.$.dat.",0.99],
-		["mant","mato",".ti.",".m.$.sg.$.gen.",0.99],
-		["mant","mato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mant","mato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mant","mato",".ti.",".m.$.sg.$.dat.",0.99],
-		["mant","mato",".ti.",".m.$.sg.$.gen.",0.99],
-		["mant","mato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mant","mato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mant","me",".ti.",".m.$.pl.$.acc.",0.99],
-		["mant","mebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mant","mebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mant","mehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mant","mehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mant","mesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["vant","vā",".ti.",".m.$.pl.$.nom.",0.99],
-		["vant","vā",".ti.",".m.$.pl.$.voc.",0.3],
-		["vant","vā",".ti.",".m.$.sg.$.nom.",0.99],
-		["vant","va",".ti.",".m.$.sg.$.voc.",0.3],
-		["vant","vā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vant","vā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vant","vā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vant","va",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vant","vā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vant","vā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vant","vā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vant","vaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vant","vaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vant","vaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vant","vaṃ",".ti.",".m.$.sg.$.nom.",0.99],
-		["vant","vaṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["vant","vaṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vant","vaṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["vant","vaṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vant","vānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vant","vānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vant","vantā",".ti.",".m.$.pl.$.nom.",0.99],
-		["vant","vantā",".ti.",".m.$.pl.$.voc.",0.3],
-		["vant","vantā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vant","vanta",".ti.",".m.$.sg.$.voc.",0.3],
-		["vant","vantā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vant","vanta",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vant","vantā",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vant","vanta",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vant","vantā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vant","vanta",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vant","vantā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vant","vantā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vant","vanta",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vant","vantā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vant","vantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vant","vantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vant","vantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vant","vantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vant","vantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vant","vantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vant","vantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vant","vantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vant","vantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vant","vantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vant","vantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["vant","vantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vant","vantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["vant","vantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vant","vantānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vant","vantānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vant","vantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vant","vantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vant","vantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vant","vantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vant","vantani",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vant","vantāni",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vant","vantani",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vant","vantāni",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vant","vantani",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vant","vantāni",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vant","vantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vant","vantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vant","vantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vant","vantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vant","vantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["vant","vantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vant","vantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["vant","vantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vant","vantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["vant","vantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["vant","vantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vant","vantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vant","vantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["vant","vantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["vant","vantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vant","vantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vant","vante",".ti.",".m.$.pl.$.acc.",0.99],
-		["vant","vante",".ti.",".m.$.sg.$.loc.",0.99],
-		["vant","vante",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vant","vante",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vant","vantebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vant","vantebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vant","vantebhi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["vant","vantebhi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["vant","vantehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vant","vantehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vant","vantehi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["vant","vantehi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["vant","vantesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["vant","vantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["vant","vantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["vant","vantī",".ti.",".f.$.pl.$.acc.",0.99],
-		["vant","vantī",".ti.",".f.$.pl.$.nom.",0.99],
-		["vant","vantī",".ti.",".f.$.pl.$.voc.",0.3],
-		["vant","vantī",".ti.",".f.$.sg.$.nom.",0.99],
-		["vant","vantī",".ti.",".f.$.sg.$.voc.",0.3],
-		["vant","vantībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vant","vantībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vant","vantīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vant","vantīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vant","vantiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["vant","vantīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["vant","vantīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["vant","vantīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["vant","vantiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["vant","vantiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["vant","vantiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["vant","vantiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["vant","vantiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["vant","vantiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["vant","vantiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["vant","vantiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["vant","vantiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["vant","vanto",".ti.",".m.$.pl.$.nom.",0.99],
-		["vant","vanto",".ti.",".m.$.pl.$.voc.",0.3],
-		["vant","vanto",".ti.",".m.$.sg.$.nom.",0.99],
-		["vant","vanto",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vant","vanto",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vant","vanto",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vant","vatā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vant","vatā",".ti.",".m.$.sg.$.inst.",0.99],
-		["vant","vatā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vant","vatā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vant","vatā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vant","vatā",".ti.",".m.$.sg.$.inst.",0.99],
-		["vant","vatā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vant","vatā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vant","vataṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vant","vataṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vant","vataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vant","vataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vant","vataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vant","vataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vant","vatena",".ti.",".m.$.sg.$.inst.",0.99],
-		["vant","vatena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vant","vatena",".ti.",".m.$.sg.$.inst.",0.99],
-		["vant","vatena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vant","vatī",".ti.",".f.$.pl.$.acc.",0.99],
-		["vant","vatī",".ti.",".f.$.pl.$.nom.",0.99],
-		["vant","vatī",".ti.",".f.$.pl.$.voc.",0.3],
-		["vant","vatī",".ti.",".f.$.sg.$.nom.",0.99],
-		["vant","vatī",".ti.",".f.$.sg.$.voc.",0.3],
-		["vant","vati",".ti.",".m.$.sg.$.loc.",0.99],
-		["vant","vati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vant","vati",".ti.",".m.$.sg.$.loc.",0.99],
-		["vant","vati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vant","vatībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vant","vatībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vant","vatīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vant","vatīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vant","vatiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["vant","vatīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["vant","vatīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["vant","vatīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["vant","vatiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["vant","vatiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["vant","vatiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["vant","vatiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["vant","vatiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["vant","vatiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["vant","vatiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["vant","vatiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["vant","vatiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["vant","vato",".ti.",".m.$.sg.$.dat.",0.99],
-		["vant","vato",".ti.",".m.$.sg.$.gen.",0.99],
-		["vant","vato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vant","vato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vant","vato",".ti.",".m.$.sg.$.dat.",0.99],
-		["vant","vato",".ti.",".m.$.sg.$.gen.",0.99],
-		["vant","vato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vant","vato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vant","ve",".ti.",".m.$.pl.$.acc.",0.99],
-		["vant","vebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vant","vebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vant","vehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vant","vehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vant","vesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["mantu","mā",".ti.",".m.$.pl.$.nom.",0.99],
-		["mantu","mā",".ti.",".m.$.pl.$.voc.",0.3],
-		["mantu","mā",".ti.",".m.$.sg.$.nom.",0.99],
-		["mantu","ma",".ti.",".m.$.sg.$.voc.",0.3],
-		["mantu","mā",".ti.",".m.$.sg.$.voc.",0.3],
-		["mantu","mā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mantu","mā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mantu","ma",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mantu","mā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mantu","mā",".ti.",".m.$.sg.$.voc.",0.3],
-		["mantu","mā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mantu","maṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["mantu","maṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["mantu","maṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mantu","maṃ",".ti.",".m.$.sg.$.nom.",0.99],
-		["mantu","maṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["mantu","maṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mantu","maṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["mantu","maṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mantu","mānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["mantu","mānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["mantu","mantā",".ti.",".m.$.pl.$.nom.",0.99],
-		["mantu","mantā",".ti.",".m.$.pl.$.voc.",0.3],
-		["mantu","mantā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mantu","manta",".ti.",".m.$.sg.$.voc.",0.3],
-		["mantu","mantā",".ti.",".m.$.sg.$.voc.",0.3],
-		["mantu","manta",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mantu","mantā",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mantu","manta",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mantu","mantā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mantu","manta",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mantu","mantā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mantu","mantā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mantu","manta",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mantu","mantā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mantu","mantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["mantu","mantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["mantu","mantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mantu","mantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mantu","mantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["mantu","mantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["mantu","mantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mantu","mantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mantu","mantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mantu","mantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mantu","mantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["mantu","mantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mantu","mantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["mantu","mantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mantu","mantānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["mantu","mantānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["mantu","mantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mantu","mantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mantu","mantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mantu","mantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mantu","mantani",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mantu","mantāni",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mantu","mantani",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mantu","mantāni",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mantu","mantani",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mantu","mantāni",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mantu","mantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mantu","mantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mantu","mantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mantu","mantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mantu","mantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["mantu","mantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mantu","mantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["mantu","mantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mantu","mantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["mantu","mantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["mantu","mantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mantu","mantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mantu","mantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["mantu","mantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["mantu","mantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mantu","mantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mantu","mante",".ti.",".m.$.pl.$.acc.",0.99],
-		["mantu","mante",".ti.",".m.$.sg.$.loc.",0.99],
-		["mantu","mante",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mantu","mante",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mantu","mantebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mantu","mantebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mantu","mantebhi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["mantu","mantebhi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["mantu","mantehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mantu","mantehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mantu","mantehi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["mantu","mantehi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["mantu","mantesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["mantu","mantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["mantu","mantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["mantu","mantī",".ti.",".f.$.pl.$.acc.",0.99],
-		["mantu","mantī",".ti.",".f.$.pl.$.nom.",0.99],
-		["mantu","mantī",".ti.",".f.$.pl.$.voc.",0.3],
-		["mantu","mantī",".ti.",".f.$.sg.$.nom.",0.99],
-		["mantu","mantī",".ti.",".f.$.sg.$.voc.",0.3],
-		["mantu","mantībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mantu","mantībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mantu","mantīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mantu","mantīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mantu","mantiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["mantu","mantīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["mantu","mantīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["mantu","mantīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["mantu","mantiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["mantu","mantiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["mantu","mantiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["mantu","mantiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["mantu","mantiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["mantu","mantiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["mantu","mantiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["mantu","mantiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["mantu","mantiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["mantu","manto",".ti.",".m.$.pl.$.nom.",0.99],
-		["mantu","manto",".ti.",".m.$.pl.$.voc.",0.3],
-		["mantu","manto",".ti.",".m.$.sg.$.nom.",0.99],
-		["mantu","manto",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mantu","manto",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mantu","manto",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mantu","matā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mantu","matā",".ti.",".m.$.sg.$.inst.",0.99],
-		["mantu","matā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mantu","matā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mantu","matā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mantu","matā",".ti.",".m.$.sg.$.inst.",0.99],
-		["mantu","matā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mantu","matā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mantu","mataṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["mantu","mataṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["mantu","mataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mantu","mataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mantu","mataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mantu","mataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mantu","matena",".ti.",".m.$.sg.$.inst.",0.99],
-		["mantu","matena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mantu","matena",".ti.",".m.$.sg.$.inst.",0.99],
-		["mantu","matena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mantu","matī",".ti.",".f.$.pl.$.acc.",0.99],
-		["mantu","matī",".ti.",".f.$.pl.$.nom.",0.99],
-		["mantu","matī",".ti.",".f.$.pl.$.voc.",0.3],
-		["mantu","matī",".ti.",".f.$.sg.$.nom.",0.99],
-		["mantu","matī",".ti.",".f.$.sg.$.voc.",0.3],
-		["mantu","mati",".ti.",".m.$.sg.$.loc.",0.99],
-		["mantu","mati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mantu","mati",".ti.",".m.$.sg.$.loc.",0.99],
-		["mantu","mati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mantu","matībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mantu","matībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mantu","matīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mantu","matīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mantu","matiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["mantu","matīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["mantu","matīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["mantu","matīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["mantu","matiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["mantu","matiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["mantu","matiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["mantu","matiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["mantu","matiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["mantu","matiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["mantu","matiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["mantu","matiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["mantu","matiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["mantu","mato",".ti.",".m.$.sg.$.dat.",0.99],
-		["mantu","mato",".ti.",".m.$.sg.$.gen.",0.99],
-		["mantu","mato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mantu","mato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mantu","mato",".ti.",".m.$.sg.$.dat.",0.99],
-		["mantu","mato",".ti.",".m.$.sg.$.gen.",0.99],
-		["mantu","mato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mantu","mato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mantu","me",".ti.",".m.$.pl.$.acc.",0.99],
-		["mantu","mebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mantu","mebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mantu","mehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mantu","mehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mantu","mesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["vantu","vā",".ti.",".m.$.pl.$.nom.",0.99],
-		["vantu","vā",".ti.",".m.$.pl.$.voc.",0.3],
-		["vantu","vā",".ti.",".m.$.sg.$.nom.",0.99],
-		["vantu","va",".ti.",".m.$.sg.$.voc.",0.3],
-		["vantu","vā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vantu","vā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vantu","vā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vantu","va",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vantu","vā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vantu","vā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vantu","vā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vantu","vaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vantu","vaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vantu","vaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vantu","vaṃ",".ti.",".m.$.sg.$.nom.",0.99],
-		["vantu","vaṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["vantu","vaṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vantu","vaṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["vantu","vaṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vantu","vānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vantu","vānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vantu","vantā",".ti.",".m.$.pl.$.nom.",0.99],
-		["vantu","vantā",".ti.",".m.$.pl.$.voc.",0.3],
-		["vantu","vantā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vantu","vanta",".ti.",".m.$.sg.$.voc.",0.3],
-		["vantu","vantā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vantu","vanta",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vantu","vantā",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vantu","vanta",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vantu","vantā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vantu","vanta",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vantu","vantā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vantu","vantā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vantu","vanta",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vantu","vantā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vantu","vantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vantu","vantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vantu","vantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vantu","vantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vantu","vantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vantu","vantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vantu","vantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vantu","vantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vantu","vantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vantu","vantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vantu","vantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["vantu","vantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vantu","vantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["vantu","vantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vantu","vantānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vantu","vantānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vantu","vantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vantu","vantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vantu","vantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vantu","vantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vantu","vantani",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vantu","vantāni",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vantu","vantani",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vantu","vantāni",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vantu","vantani",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vantu","vantāni",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vantu","vantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vantu","vantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vantu","vantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vantu","vantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vantu","vantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["vantu","vantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vantu","vantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["vantu","vantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vantu","vantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["vantu","vantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["vantu","vantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vantu","vantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vantu","vantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["vantu","vantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["vantu","vantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vantu","vantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vantu","vante",".ti.",".m.$.pl.$.acc.",0.99],
-		["vantu","vante",".ti.",".m.$.sg.$.loc.",0.99],
-		["vantu","vante",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vantu","vante",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vantu","vantebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vantu","vantebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vantu","vantebhi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["vantu","vantebhi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["vantu","vantehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vantu","vantehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vantu","vantehi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["vantu","vantehi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["vantu","vantesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["vantu","vantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["vantu","vantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["vantu","vantī",".ti.",".f.$.pl.$.acc.",0.99],
-		["vantu","vantī",".ti.",".f.$.pl.$.nom.",0.99],
-		["vantu","vantī",".ti.",".f.$.pl.$.voc.",0.3],
-		["vantu","vantī",".ti.",".f.$.sg.$.nom.",0.99],
-		["vantu","vantī",".ti.",".f.$.sg.$.voc.",0.3],
-		["vantu","vantībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vantu","vantībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vantu","vantīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vantu","vantīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vantu","vantiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["vantu","vantīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["vantu","vantīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["vantu","vantīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["vantu","vantiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["vantu","vantiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["vantu","vantiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["vantu","vantiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["vantu","vantiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["vantu","vantiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["vantu","vantiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["vantu","vantiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["vantu","vantiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["vantu","vanto",".ti.",".m.$.pl.$.nom.",0.99],
-		["vantu","vanto",".ti.",".m.$.pl.$.voc.",0.3],
-		["vantu","vanto",".ti.",".m.$.sg.$.nom.",0.99],
-		["vantu","vanto",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vantu","vanto",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vantu","vanto",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vantu","vatā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vantu","vatā",".ti.",".m.$.sg.$.inst.",0.99],
-		["vantu","vatā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vantu","vatā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vantu","vatā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vantu","vatā",".ti.",".m.$.sg.$.inst.",0.99],
-		["vantu","vatā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vantu","vatā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vantu","vataṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vantu","vataṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vantu","vataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vantu","vataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vantu","vataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vantu","vataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vantu","vatena",".ti.",".m.$.sg.$.inst.",0.99],
-		["vantu","vatena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vantu","vatena",".ti.",".m.$.sg.$.inst.",0.99],
-		["vantu","vatena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vantu","vatī",".ti.",".f.$.pl.$.acc.",0.99],
-		["vantu","vatī",".ti.",".f.$.pl.$.nom.",0.99],
-		["vantu","vatī",".ti.",".f.$.pl.$.voc.",0.3],
-		["vantu","vatī",".ti.",".f.$.sg.$.nom.",0.99],
-		["vantu","vatī",".ti.",".f.$.sg.$.voc.",0.3],
-		["vantu","vati",".ti.",".m.$.sg.$.loc.",0.99],
-		["vantu","vati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vantu","vati",".ti.",".m.$.sg.$.loc.",0.99],
-		["vantu","vati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vantu","vatībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vantu","vatībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vantu","vatīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vantu","vatīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vantu","vatiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["vantu","vatīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["vantu","vatīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["vantu","vatīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["vantu","vatiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["vantu","vatiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["vantu","vatiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["vantu","vatiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["vantu","vatiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["vantu","vatiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["vantu","vatiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["vantu","vatiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["vantu","vatiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["vantu","vato",".ti.",".m.$.sg.$.dat.",0.99],
-		["vantu","vato",".ti.",".m.$.sg.$.gen.",0.99],
-		["vantu","vato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vantu","vato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vantu","vato",".ti.",".m.$.sg.$.dat.",0.99],
-		["vantu","vato",".ti.",".m.$.sg.$.gen.",0.99],
-		["vantu","vato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vantu","vato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vantu","ve",".ti.",".m.$.pl.$.acc.",0.99],
-		["vantu","vebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vantu","vebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vantu","vehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vantu","vehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vantu","vesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["mat","mā",".ti.",".m.$.pl.$.nom.",0.99],
-		["mat","mā",".ti.",".m.$.pl.$.voc.",0.3],
-		["mat","mā",".ti.",".m.$.sg.$.nom.",0.99],
-		["mat","ma",".ti.",".m.$.sg.$.voc.",0.3],
-		["mat","mā",".ti.",".m.$.sg.$.voc.",0.3],
-		["mat","mā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mat","mā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mat","ma",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mat","mā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mat","mā",".ti.",".m.$.sg.$.voc.",0.3],
-		["mat","mā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mat","maṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["mat","maṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["mat","maṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mat","maṃ",".ti.",".m.$.sg.$.nom.",0.99],
-		["mat","maṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["mat","maṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mat","maṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["mat","maṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mat","mānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["mat","mānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["mat","mantā",".ti.",".m.$.pl.$.nom.",0.99],
-		["mat","mantā",".ti.",".m.$.pl.$.voc.",0.3],
-		["mat","mantā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mat","manta",".ti.",".m.$.sg.$.voc.",0.3],
-		["mat","mantā",".ti.",".m.$.sg.$.voc.",0.3],
-		["mat","manta",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mat","mantā",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mat","manta",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mat","mantā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mat","manta",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mat","mantā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mat","mantā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mat","manta",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mat","mantā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["mat","mantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["mat","mantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["mat","mantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mat","mantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mat","mantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["mat","mantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["mat","mantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mat","mantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mat","mantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mat","mantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mat","mantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["mat","mantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mat","mantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["mat","mantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mat","mantānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["mat","mantānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["mat","mantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mat","mantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mat","mantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mat","mantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mat","mantani",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mat","mantāni",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mat","mantani",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mat","mantāni",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mat","mantani",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mat","mantāni",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mat","mantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mat","mantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mat","mantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mat","mantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mat","mantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["mat","mantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mat","mantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["mat","mantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mat","mantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["mat","mantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["mat","mantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mat","mantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mat","mantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["mat","mantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["mat","mantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mat","mantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mat","mante",".ti.",".m.$.pl.$.acc.",0.99],
-		["mat","mante",".ti.",".m.$.sg.$.loc.",0.99],
-		["mat","mante",".ti.",".nt.$.pl.$.acc.",0.99],
-		["mat","mante",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mat","mantebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mat","mantebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mat","mantebhi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["mat","mantebhi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["mat","mantehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mat","mantehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mat","mantehi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["mat","mantehi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["mat","mantesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["mat","mantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["mat","mantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["mat","mantī",".ti.",".f.$.pl.$.acc.",0.99],
-		["mat","mantī",".ti.",".f.$.pl.$.nom.",0.99],
-		["mat","mantī",".ti.",".f.$.pl.$.voc.",0.3],
-		["mat","mantī",".ti.",".f.$.sg.$.nom.",0.99],
-		["mat","mantī",".ti.",".f.$.sg.$.voc.",0.3],
-		["mat","mantībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mat","mantībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mat","mantīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mat","mantīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mat","mantiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["mat","mantīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["mat","mantīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["mat","mantīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["mat","mantiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["mat","mantiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["mat","mantiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["mat","mantiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["mat","mantiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["mat","mantiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["mat","mantiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["mat","mantiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["mat","mantiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["mat","manto",".ti.",".m.$.pl.$.nom.",0.99],
-		["mat","manto",".ti.",".m.$.pl.$.voc.",0.3],
-		["mat","manto",".ti.",".m.$.sg.$.nom.",0.99],
-		["mat","manto",".ti.",".nt.$.pl.$.nom.",0.99],
-		["mat","manto",".ti.",".nt.$.pl.$.voc.",0.3],
-		["mat","manto",".ti.",".nt.$.sg.$.nom.",0.99],
-		["mat","matā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mat","matā",".ti.",".m.$.sg.$.inst.",0.99],
-		["mat","matā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mat","matā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mat","matā",".ti.",".m.$.sg.$.abl.",0.99],
-		["mat","matā",".ti.",".m.$.sg.$.inst.",0.99],
-		["mat","matā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["mat","matā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mat","mataṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["mat","mataṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["mat","mataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mat","mataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mat","mataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["mat","mataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["mat","matena",".ti.",".m.$.sg.$.inst.",0.99],
-		["mat","matena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mat","matena",".ti.",".m.$.sg.$.inst.",0.99],
-		["mat","matena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["mat","matī",".ti.",".f.$.pl.$.acc.",0.99],
-		["mat","matī",".ti.",".f.$.pl.$.nom.",0.99],
-		["mat","matī",".ti.",".f.$.pl.$.voc.",0.3],
-		["mat","matī",".ti.",".f.$.sg.$.nom.",0.99],
-		["mat","matī",".ti.",".f.$.sg.$.voc.",0.3],
-		["mat","mati",".ti.",".m.$.sg.$.loc.",0.99],
-		["mat","mati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mat","mati",".ti.",".m.$.sg.$.loc.",0.99],
-		["mat","mati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["mat","matībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mat","matībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mat","matīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["mat","matīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["mat","matiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["mat","matīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["mat","matīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["mat","matīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["mat","matiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["mat","matiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["mat","matiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["mat","matiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["mat","matiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["mat","matiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["mat","matiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["mat","matiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["mat","matiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["mat","mato",".ti.",".m.$.sg.$.dat.",0.99],
-		["mat","mato",".ti.",".m.$.sg.$.gen.",0.99],
-		["mat","mato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mat","mato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mat","mato",".ti.",".m.$.sg.$.dat.",0.99],
-		["mat","mato",".ti.",".m.$.sg.$.gen.",0.99],
-		["mat","mato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["mat","mato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["mat","me",".ti.",".m.$.pl.$.acc.",0.99],
-		["mat","mebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mat","mebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mat","mehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["mat","mehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["mat","mesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["vat","vā",".ti.",".m.$.pl.$.nom.",0.99],
-		["vat","vā",".ti.",".m.$.pl.$.voc.",0.3],
-		["vat","vā",".ti.",".m.$.sg.$.nom.",0.99],
-		["vat","va",".ti.",".m.$.sg.$.voc.",0.3],
-		["vat","vā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vat","vā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vat","vā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vat","va",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vat","vā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vat","vā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vat","vā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vat","vaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vat","vaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vat","vaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vat","vaṃ",".ti.",".m.$.sg.$.nom.",0.99],
-		["vat","vaṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["vat","vaṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vat","vaṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["vat","vaṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vat","vānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vat","vānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vat","vantā",".ti.",".m.$.pl.$.nom.",0.99],
-		["vat","vantā",".ti.",".m.$.pl.$.voc.",0.3],
-		["vat","vantā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vat","vanta",".ti.",".m.$.sg.$.voc.",0.3],
-		["vat","vantā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vat","vanta",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vat","vantā",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vat","vanta",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vat","vantā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vat","vanta",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vat","vantā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vat","vantā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vat","vanta",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vat","vantā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vat","vantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vat","vantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vat","vantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vat","vantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vat","vantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vat","vantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vat","vantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vat","vantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vat","vantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vat","vantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vat","vantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["vat","vantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vat","vantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["vat","vantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vat","vantānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vat","vantānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vat","vantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vat","vantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vat","vantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vat","vantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vat","vantani",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vat","vantāni",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vat","vantani",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vat","vantāni",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vat","vantani",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vat","vantāni",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vat","vantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vat","vantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vat","vantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vat","vantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vat","vantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["vat","vantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vat","vantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["vat","vantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vat","vantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["vat","vantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["vat","vantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vat","vantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vat","vantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["vat","vantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["vat","vantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vat","vantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vat","vante",".ti.",".m.$.pl.$.acc.",0.99],
-		["vat","vante",".ti.",".m.$.sg.$.loc.",0.99],
-		["vat","vante",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vat","vante",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vat","vantebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vat","vantebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vat","vantebhi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["vat","vantebhi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["vat","vantehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vat","vantehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vat","vantehi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["vat","vantehi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["vat","vantesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["vat","vantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["vat","vantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["vat","vantī",".ti.",".f.$.pl.$.acc.",0.99],
-		["vat","vantī",".ti.",".f.$.pl.$.nom.",0.99],
-		["vat","vantī",".ti.",".f.$.pl.$.voc.",0.3],
-		["vat","vantī",".ti.",".f.$.sg.$.nom.",0.99],
-		["vat","vantī",".ti.",".f.$.sg.$.voc.",0.3],
-		["vat","vantībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vat","vantībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vat","vantīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vat","vantīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vat","vantiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["vat","vantīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["vat","vantīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["vat","vantīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["vat","vantiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["vat","vantiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["vat","vantiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["vat","vantiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["vat","vantiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["vat","vantiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["vat","vantiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["vat","vantiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["vat","vantiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["vat","vanto",".ti.",".m.$.pl.$.nom.",0.99],
-		["vat","vanto",".ti.",".m.$.pl.$.voc.",0.3],
-		["vat","vanto",".ti.",".m.$.sg.$.nom.",0.99],
-		["vat","vanto",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vat","vanto",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vat","vanto",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vat","vatā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vat","vatā",".ti.",".m.$.sg.$.inst.",0.99],
-		["vat","vatā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vat","vatā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vat","vatā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vat","vatā",".ti.",".m.$.sg.$.inst.",0.99],
-		["vat","vatā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vat","vatā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vat","vataṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vat","vataṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vat","vataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vat","vataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vat","vataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vat","vataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vat","vatena",".ti.",".m.$.sg.$.inst.",0.99],
-		["vat","vatena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vat","vatena",".ti.",".m.$.sg.$.inst.",0.99],
-		["vat","vatena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vat","vatī",".ti.",".f.$.pl.$.acc.",0.99],
-		["vat","vatī",".ti.",".f.$.pl.$.nom.",0.99],
-		["vat","vatī",".ti.",".f.$.pl.$.voc.",0.3],
-		["vat","vatī",".ti.",".f.$.sg.$.nom.",0.99],
-		["vat","vatī",".ti.",".f.$.sg.$.voc.",0.3],
-		["vat","vati",".ti.",".m.$.sg.$.loc.",0.99],
-		["vat","vati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vat","vati",".ti.",".m.$.sg.$.loc.",0.99],
-		["vat","vati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vat","vatībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vat","vatībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vat","vatīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vat","vatīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vat","vatiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["vat","vatīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["vat","vatīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["vat","vatīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["vat","vatiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["vat","vatiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["vat","vatiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["vat","vatiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["vat","vatiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["vat","vatiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["vat","vatiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["vat","vatiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["vat","vatiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["vat","vato",".ti.",".m.$.sg.$.dat.",0.99],
-		["vat","vato",".ti.",".m.$.sg.$.gen.",0.99],
-		["vat","vato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vat","vato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vat","vato",".ti.",".m.$.sg.$.dat.",0.99],
-		["vat","vato",".ti.",".m.$.sg.$.gen.",0.99],
-		["vat","vato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vat","vato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vat","ve",".ti.",".m.$.pl.$.acc.",0.99],
-		["vat","vebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vat","vebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vat","vehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vat","vehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vat","vesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["manta","mā",".ti.",".m.$.pl.$.nom.",0.99],
-		["manta","mā",".ti.",".m.$.pl.$.voc.",0.3],
-		["manta","mā",".ti.",".m.$.sg.$.nom.",0.99],
-		["manta","ma",".ti.",".m.$.sg.$.voc.",0.3],
-		["manta","mā",".ti.",".m.$.sg.$.voc.",0.3],
-		["manta","mā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["manta","mā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["manta","ma",".ti.",".nt.$.sg.$.voc.",0.3],
-		["manta","mā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["manta","mā",".ti.",".m.$.sg.$.voc.",0.3],
-		["manta","mā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["manta","maṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["manta","maṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["manta","maṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["manta","maṃ",".ti.",".m.$.sg.$.nom.",0.99],
-		["manta","maṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["manta","maṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["manta","maṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["manta","maṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["manta","mānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["manta","mānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["manta","mantā",".ti.",".m.$.pl.$.nom.",0.99],
-		["manta","mantā",".ti.",".m.$.pl.$.voc.",0.3],
-		["manta","mantā",".ti.",".m.$.sg.$.abl.",0.99],
-		["manta","manta",".ti.",".m.$.sg.$.voc.",0.3],
-		["manta","mantā",".ti.",".m.$.sg.$.voc.",0.3],
-		["manta","manta",".ti.",".nt.$.pl.$.acc.",0.99],
-		["manta","mantā",".ti.",".nt.$.pl.$.acc.",0.99],
-		["manta","manta",".ti.",".nt.$.pl.$.nom.",0.99],
-		["manta","mantā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["manta","manta",".ti.",".nt.$.pl.$.voc.",0.3],
-		["manta","mantā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["manta","mantā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["manta","manta",".ti.",".nt.$.sg.$.voc.",0.3],
-		["manta","mantā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["manta","mantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["manta","mantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["manta","mantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["manta","mantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["manta","mantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["manta","mantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["manta","mantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["manta","mantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["manta","mantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["manta","mantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["manta","mantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["manta","mantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["manta","mantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["manta","mantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["manta","mantānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["manta","mantānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["manta","mantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["manta","mantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["manta","mantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["manta","mantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["manta","mantani",".ti.",".nt.$.pl.$.acc.",0.99],
-		["manta","mantāni",".ti.",".nt.$.pl.$.acc.",0.99],
-		["manta","mantani",".ti.",".nt.$.pl.$.nom.",0.99],
-		["manta","mantāni",".ti.",".nt.$.pl.$.nom.",0.99],
-		["manta","mantani",".ti.",".nt.$.pl.$.voc.",0.3],
-		["manta","mantāni",".ti.",".nt.$.pl.$.voc.",0.3],
-		["manta","mantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["manta","mantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["manta","mantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["manta","mantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["manta","mantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["manta","mantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["manta","mantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["manta","mantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["manta","mantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["manta","mantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["manta","mantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["manta","mantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["manta","mantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["manta","mantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["manta","mantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["manta","mantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["manta","mante",".ti.",".m.$.pl.$.acc.",0.99],
-		["manta","mante",".ti.",".m.$.sg.$.loc.",0.99],
-		["manta","mante",".ti.",".nt.$.pl.$.acc.",0.99],
-		["manta","mante",".ti.",".nt.$.sg.$.loc.",0.99],
-		["manta","mantebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["manta","mantebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["manta","mantebhi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["manta","mantebhi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["manta","mantehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["manta","mantehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["manta","mantehi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["manta","mantehi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["manta","mantesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["manta","mantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["manta","mantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["manta","mantī",".ti.",".f.$.pl.$.acc.",0.99],
-		["manta","mantī",".ti.",".f.$.pl.$.nom.",0.99],
-		["manta","mantī",".ti.",".f.$.pl.$.voc.",0.3],
-		["manta","mantī",".ti.",".f.$.sg.$.nom.",0.99],
-		["manta","mantī",".ti.",".f.$.sg.$.voc.",0.3],
-		["manta","mantībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["manta","mantībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["manta","mantīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["manta","mantīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["manta","mantiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["manta","mantīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["manta","mantīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["manta","mantīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["manta","mantiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["manta","mantiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["manta","mantiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["manta","mantiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["manta","mantiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["manta","mantiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["manta","mantiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["manta","mantiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["manta","mantiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["manta","manto",".ti.",".m.$.pl.$.nom.",0.99],
-		["manta","manto",".ti.",".m.$.pl.$.voc.",0.3],
-		["manta","manto",".ti.",".m.$.sg.$.nom.",0.99],
-		["manta","manto",".ti.",".nt.$.pl.$.nom.",0.99],
-		["manta","manto",".ti.",".nt.$.pl.$.voc.",0.3],
-		["manta","manto",".ti.",".nt.$.sg.$.nom.",0.99],
-		["manta","matā",".ti.",".m.$.sg.$.abl.",0.99],
-		["manta","matā",".ti.",".m.$.sg.$.inst.",0.99],
-		["manta","matā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["manta","matā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["manta","matā",".ti.",".m.$.sg.$.abl.",0.99],
-		["manta","matā",".ti.",".m.$.sg.$.inst.",0.99],
-		["manta","matā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["manta","matā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["manta","mataṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["manta","mataṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["manta","mataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["manta","mataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["manta","mataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["manta","mataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["manta","matena",".ti.",".m.$.sg.$.inst.",0.99],
-		["manta","matena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["manta","matena",".ti.",".m.$.sg.$.inst.",0.99],
-		["manta","matena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["manta","matī",".ti.",".f.$.pl.$.acc.",0.99],
-		["manta","matī",".ti.",".f.$.pl.$.nom.",0.99],
-		["manta","matī",".ti.",".f.$.pl.$.voc.",0.3],
-		["manta","matī",".ti.",".f.$.sg.$.nom.",0.99],
-		["manta","matī",".ti.",".f.$.sg.$.voc.",0.3],
-		["manta","mati",".ti.",".m.$.sg.$.loc.",0.99],
-		["manta","mati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["manta","mati",".ti.",".m.$.sg.$.loc.",0.99],
-		["manta","mati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["manta","matībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["manta","matībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["manta","matīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["manta","matīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["manta","matiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["manta","matīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["manta","matīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["manta","matīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["manta","matiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["manta","matiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["manta","matiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["manta","matiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["manta","matiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["manta","matiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["manta","matiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["manta","matiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["manta","matiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["manta","mato",".ti.",".m.$.sg.$.dat.",0.99],
-		["manta","mato",".ti.",".m.$.sg.$.gen.",0.99],
-		["manta","mato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["manta","mato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["manta","mato",".ti.",".m.$.sg.$.dat.",0.99],
-		["manta","mato",".ti.",".m.$.sg.$.gen.",0.99],
-		["manta","mato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["manta","mato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["manta","me",".ti.",".m.$.pl.$.acc.",0.99],
-		["manta","mebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["manta","mebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["manta","mehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["manta","mehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["manta","mesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["vanta","vā",".ti.",".m.$.pl.$.nom.",0.99],
-		["vanta","vā",".ti.",".m.$.pl.$.voc.",0.3],
-		["vanta","vā",".ti.",".m.$.sg.$.nom.",0.99],
-		["vanta","va",".ti.",".m.$.sg.$.voc.",0.3],
-		["vanta","vā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vanta","vā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vanta","vā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vanta","va",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vanta","vā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vanta","vā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vanta","vā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vanta","vaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vanta","vaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vanta","vaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vanta","vaṃ",".ti.",".m.$.sg.$.nom.",0.99],
-		["vanta","vaṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["vanta","vaṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vanta","vaṃ",".ti.",".m.$.sg.$.voc.",0.3],
-		["vanta","vaṃ",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vanta","vānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vanta","vānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vanta","vantā",".ti.",".m.$.pl.$.nom.",0.99],
-		["vanta","vantā",".ti.",".m.$.pl.$.voc.",0.3],
-		["vanta","vantā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vanta","vanta",".ti.",".m.$.sg.$.voc.",0.3],
-		["vanta","vantā",".ti.",".m.$.sg.$.voc.",0.3],
-		["vanta","vanta",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vanta","vantā",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vanta","vanta",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vanta","vantā",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vanta","vanta",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vanta","vantā",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vanta","vantā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vanta","vanta",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vanta","vantā",".ti.",".nt.$.sg.$.voc.",0.3],
-		["vanta","vantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vanta","vantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vanta","vantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vanta","vantaṃ",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vanta","vantaṃ",".ti.",".m.$.sg.$.acc.",0.99],
-		["vanta","vantaṃ",".ti.",".nt.$.sg.$.acc.",0.99],
-		["vanta","vantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vanta","vantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vanta","vantamhā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vanta","vantamhā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vanta","vantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["vanta","vantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vanta","vantamhi",".ti.",".m.$.sg.$.loc.",0.99],
-		["vanta","vantamhi",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vanta","vantānaṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vanta","vantānaṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vanta","vantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vanta","vantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vanta","vantānaṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vanta","vantānaṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vanta","vantani",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vanta","vantāni",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vanta","vantani",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vanta","vantāni",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vanta","vantani",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vanta","vantāni",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vanta","vantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vanta","vantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vanta","vantasmā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vanta","vantasmā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vanta","vantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["vanta","vantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vanta","vantasmiṃ",".ti.",".m.$.sg.$.loc.",0.99],
-		["vanta","vantasmiṃ",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vanta","vantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["vanta","vantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["vanta","vantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vanta","vantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vanta","vantassa",".ti.",".m.$.sg.$.dat.",0.99],
-		["vanta","vantassa",".ti.",".m.$.sg.$.gen.",0.99],
-		["vanta","vantassa",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vanta","vantassa",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vanta","vante",".ti.",".m.$.pl.$.acc.",0.99],
-		["vanta","vante",".ti.",".m.$.sg.$.loc.",0.99],
-		["vanta","vante",".ti.",".nt.$.pl.$.acc.",0.99],
-		["vanta","vante",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vanta","vantebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vanta","vantebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vanta","vantebhi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["vanta","vantebhi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["vanta","vantehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vanta","vantehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vanta","vantehi",".ti.",".nt.$.pl.$.abl.",0.99],
-		["vanta","vantehi",".ti.",".nt.$.pl.$.inst.",0.99],
-		["vanta","vantesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["vanta","vantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["vanta","vantesu",".ti.",".nt.$.pl.$.loc.",0.99],
-		["vanta","vantī",".ti.",".f.$.pl.$.acc.",0.99],
-		["vanta","vantī",".ti.",".f.$.pl.$.nom.",0.99],
-		["vanta","vantī",".ti.",".f.$.pl.$.voc.",0.3],
-		["vanta","vantī",".ti.",".f.$.sg.$.nom.",0.99],
-		["vanta","vantī",".ti.",".f.$.sg.$.voc.",0.3],
-		["vanta","vantībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vanta","vantībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vanta","vantīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vanta","vantīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vanta","vantiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["vanta","vantīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["vanta","vantīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["vanta","vantīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["vanta","vantiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["vanta","vantiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["vanta","vantiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["vanta","vantiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["vanta","vantiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["vanta","vantiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["vanta","vantiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["vanta","vantiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["vanta","vantiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["vanta","vanto",".ti.",".m.$.pl.$.nom.",0.99],
-		["vanta","vanto",".ti.",".m.$.pl.$.voc.",0.3],
-		["vanta","vanto",".ti.",".m.$.sg.$.nom.",0.99],
-		["vanta","vanto",".ti.",".nt.$.pl.$.nom.",0.99],
-		["vanta","vanto",".ti.",".nt.$.pl.$.voc.",0.3],
-		["vanta","vanto",".ti.",".nt.$.sg.$.nom.",0.99],
-		["vanta","vatā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vanta","vatā",".ti.",".m.$.sg.$.inst.",0.99],
-		["vanta","vatā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vanta","vatā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vanta","vatā",".ti.",".m.$.sg.$.abl.",0.99],
-		["vanta","vatā",".ti.",".m.$.sg.$.inst.",0.99],
-		["vanta","vatā",".ti.",".nt.$.sg.$.abl.",0.99],
-		["vanta","vatā",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vanta","vataṃ",".ti.",".m.$.pl.$.dat.",0.99],
-		["vanta","vataṃ",".ti.",".m.$.pl.$.gen.",0.99],
-		["vanta","vataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vanta","vataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vanta","vataṃ",".ti.",".nt.$.pl.$.dat.",0.99],
-		["vanta","vataṃ",".ti.",".nt.$.pl.$.gen.",0.99],
-		["vanta","vatena",".ti.",".m.$.sg.$.inst.",0.99],
-		["vanta","vatena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vanta","vatena",".ti.",".m.$.sg.$.inst.",0.99],
-		["vanta","vatena",".ti.",".nt.$.sg.$.inst.",0.99],
-		["vanta","vatī",".ti.",".f.$.pl.$.acc.",0.99],
-		["vanta","vatī",".ti.",".f.$.pl.$.nom.",0.99],
-		["vanta","vatī",".ti.",".f.$.pl.$.voc.",0.3],
-		["vanta","vatī",".ti.",".f.$.sg.$.nom.",0.99],
-		["vanta","vatī",".ti.",".f.$.sg.$.voc.",0.3],
-		["vanta","vati",".ti.",".m.$.sg.$.loc.",0.99],
-		["vanta","vati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vanta","vati",".ti.",".m.$.sg.$.loc.",0.99],
-		["vanta","vati",".ti.",".nt.$.sg.$.loc.",0.99],
-		["vanta","vatībhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vanta","vatībhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vanta","vatīhi",".ti.",".f.$.pl.$.abl.",0.99],
-		["vanta","vatīhi",".ti.",".f.$.pl.$.inst.",0.99],
-		["vanta","vatiṃ",".ti.",".f.$.sg.$.acc.",0.99],
-		["vanta","vatīnaṃ",".ti.",".f.$.pl.$.dat.",0.99],
-		["vanta","vatīnaṃ",".ti.",".f.$.pl.$.gen.",0.99],
-		["vanta","vatīsu",".ti.",".f.$.pl.$.loc.",0.99],
-		["vanta","vatiyā",".ti.",".f.$.sg.$.abl.",0.99],
-		["vanta","vatiyā",".ti.",".f.$.sg.$.dat.",0.99],
-		["vanta","vatiyā",".ti.",".f.$.sg.$.gen.",0.99],
-		["vanta","vatiyā",".ti.",".f.$.sg.$.inst.",0.99],
-		["vanta","vatiyā",".ti.",".f.$.sg.$.loc.",0.99],
-		["vanta","vatiyaṃ",".ti.",".f.$.sg.$.loc.",0.99],
-		["vanta","vatiyo",".ti.",".f.$.pl.$.acc.",0.99],
-		["vanta","vatiyo",".ti.",".f.$.pl.$.nom.",0.99],
-		["vanta","vatiyo",".ti.",".f.$.pl.$.voc.",0.3],
-		["vanta","vato",".ti.",".m.$.sg.$.dat.",0.99],
-		["vanta","vato",".ti.",".m.$.sg.$.gen.",0.99],
-		["vanta","vato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vanta","vato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vanta","vato",".ti.",".m.$.sg.$.dat.",0.99],
-		["vanta","vato",".ti.",".m.$.sg.$.gen.",0.99],
-		["vanta","vato",".ti.",".nt.$.sg.$.dat.",0.99],
-		["vanta","vato",".ti.",".nt.$.sg.$.gen.",0.99],
-		["vanta","ve",".ti.",".m.$.pl.$.acc.",0.99],
-		["vanta","vebhi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vanta","vebhi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vanta","vehi",".ti.",".m.$.pl.$.abl.",0.99],
-		["vanta","vehi",".ti.",".m.$.pl.$.inst.",0.99],
-		["vanta","vesu",".ti.",".m.$.pl.$.loc.",0.99],
-		["a","o",".n.",".m.$.sg.$.nom.",0.99],
-		["a","a",".n.",".m.$.sg.$.voc.",0.3],
-		["a","ā",".n.",".m.$.sg.$.voc.",0.3],
-		["a","aṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["a","assa",".n.",".m.$.sg.$.gen.",0.99],
-		["a","assa",".n.",".m.$.sg.$.dat.",0.99],
-		["a","āya",".n.",".m.$.sg.$.dat.",0.99],
-		["a","ena",".n.",".m.$.sg.$.inst.",0.99],
-		["a","ā",".n.",".m.$.sg.$.abl.",0.99],
-		["a","asmā",".n.",".m.$.sg.$.abl.",0.99],
-		["a","amhā",".n.",".m.$.sg.$.abl.",0.99],
-		["a","ato",".n.",".m.$.sg.$.abl.",0.99],
-		["a","e",".n.",".m.$.sg.$.loc.",0.99],
-		["a","asmiṃ",".n.",".m.$.sg.$.loc.",0.99],
-		["a","amhi",".n.",".m.$.sg.$.loc.",0.99],
-		["a","ā",".n.",".m.$.pl.$.nom.",0.99],
-		["a","āse",".n.",".m.$.pl.$.nom.",0.99],
-		["a","ā",".n.",".m.$.pl.$.voc.",0.3],
-		["a","e",".n.",".m.$.pl.$.acc.",0.99],
-		["a","ānaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["a","ānaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["a","ehi",".n.",".m.$.pl.$.inst.",0.99],
-		["a","ebhi",".n.",".m.$.pl.$.inst.",0.99],
-		["a","ehi",".n.",".m.$.pl.$.abl.",0.99],
-		["a","ebhi",".n.",".m.$.pl.$.abl.",0.99],
-		["a","esu",".n.",".m.$.pl.$.loc.",0.99],
-		["a","aṃ",".n.",".nt.$.sg.$.nom.",0.99],
-		["a","a",".n.",".nt.$.sg.$.voc.",0.3],
-		["a","aṃ",".n.",".nt.$.sg.$.acc.",0.99],
-		["a","assa",".n.",".nt.$.sg.$.gen.",0.99],
-		["a","assa",".n.",".nt.$.sg.$.dat.",0.99],
-		["a","āya",".n.",".nt.$.sg.$.dat.",0.99],
-		["a","ena",".n.",".nt.$.sg.$.inst.",0.99],
-		["a","ā",".n.",".nt.$.sg.$.abl.",0.99],
-		["a","asmā",".n.",".nt.$.sg.$.abl.",0.99],
-		["a","amhā",".n.",".nt.$.sg.$.abl.",0.99],
-		["a","ato",".n.",".nt.$.sg.$.abl.",0.99],
-		["a","e",".n.",".nt.$.sg.$.loc.",0.99],
-		["a","asmiṃ",".n.",".nt.$.sg.$.loc.",0.99],
-		["a","amhi",".n.",".nt.$.sg.$.loc.",0.99],
-		["a","āni",".n.",".nt.$.pl.$.nom.",0.99],
-		["a","ā",".n.",".nt.$.pl.$.nom.",0.99],
-		["a","āni",".n.",".nt.$.pl.$.voc.",0.3],
-		["a","ā",".n.",".nt.$.pl.$.voc.",0.3],
-		["a","āni",".n.",".nt.$.pl.$.acc.",0.99],
-		["a","e",".n.",".nt.$.pl.$.acc.",0.99],
-		["a","ānaṃ",".n.",".nt.$.pl.$.gen.",0.99],
-		["a","ānaṃ",".n.",".nt.$.pl.$.dat.",0.99],
-		["a","ehi",".n.",".nt.$.pl.$.inst.",0.99],
-		["a","ebhi",".n.",".nt.$.pl.$.inst.",0.99],
-		["a","ehi",".n.",".nt.$.pl.$.abl.",0.99],
-		["a","ebhi",".n.",".nt.$.pl.$.abl.",0.99],
-		["a","esu",".n.",".nt.$.pl.$.loc.",0.99],
-		["a","esaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["a","esaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["a","esaṃ",".n.",".nt.$.pl.$.dat.",0.99],
-		["a","esaṃ",".n.",".nt.$.pl.$.gen.",0.99],
-		["ā","ā",".n.",".f.$.sg.$.nom.",0.99],
-		["ā","ā",".n.",".f.$.sg.$.voc.",0.3],
-		["ā","e",".n.",".f.$.sg.$.voc.",0.3],
-		["ā","aṃ",".n.",".f.$.sg.$.acc.",0.99],
-		["ā","āya",".n.",".f.$.sg.$.gen.",0.99],
-		["ā","āya",".n.",".f.$.sg.$.dat.",0.99],
-		["ā","āya",".n.",".f.$.sg.$.inst.",0.99],
-		["ā","āya",".n.",".f.$.sg.$.abl.",0.99],
-		["ā","ato",".n.",".f.$.sg.$.abl.",0.99],
-		["ā","āya",".n.",".f.$.sg.$.loc.",0.99],
-		["ā","āyaṃ",".n.",".f.$.sg.$.loc.",0.99],
-		["ā","ā",".n.",".f.$.pl.$.nom.",0.99],
-		["ā","āyo",".n.",".f.$.pl.$.nom.",0.99],
-		["ā","ā",".n.",".f.$.pl.$.voc.",0.3],
-		["ā","āyo",".n.",".f.$.pl.$.voc.",0.3],
-		["ā","ā",".n.",".f.$.pl.$.acc.",0.99],
-		["ā","āyo",".n.",".f.$.pl.$.acc.",0.99],
-		["ā","ānaṃ",".n.",".f.$.pl.$.gen.",0.99],
-		["ā","ānaṃ",".n.",".f.$.pl.$.dat.",0.99],
-		["ā","āhi",".n.",".f.$.pl.$.inst.",0.99],
-		["ā","ābhi",".n.",".f.$.pl.$.inst.",0.99],
-		["ā","āhi",".n.",".f.$.pl.$.abl.",0.99],
-		["ā","ābhi",".n.",".f.$.pl.$.abl.",0.99],
-		["ā","āsu",".n.",".f.$.pl.$.loc.",0.99],
-		["i","i",".n.",".m.$.sg.$.nom.",0.99],
-		["i","i",".n.",".m.$.sg.$.voc.",0.3],
-		["i","iṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["i","issa",".n.",".m.$.sg.$.gen.",0.99],
-		["i","ino",".n.",".m.$.sg.$.gen.",0.99],
-		["i","issa",".n.",".m.$.sg.$.dat.",0.99],
-		["i","ino",".n.",".m.$.sg.$.dat.",0.99],
-		["i","inā",".n.",".m.$.sg.$.inst.",0.99],
-		["i","inā",".n.",".m.$.sg.$.abl.",0.99],
-		["i","ismā",".n.",".m.$.sg.$.abl.",0.99],
-		["i","imhā",".n.",".m.$.sg.$.abl.",0.99],
-		["i","ismiṃ",".n.",".m.$.sg.$.loc.",0.99],
-		["i","imhi",".n.",".m.$.sg.$.loc.",0.99],
-		["i","ī",".n.",".m.$.pl.$.nom.",0.99],
-		["i","ayo",".n.",".m.$.pl.$.nom.",0.99],
-		["i","ī",".n.",".m.$.pl.$.voc.",0.3],
-		["i","ayo",".n.",".m.$.pl.$.voc.",0.3],
-		["i","ī",".n.",".m.$.pl.$.acc.",0.99],
-		["i","ayo",".n.",".m.$.pl.$.acc.",0.99],
-		["i","īnaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["i","īnaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["i","īhi",".n.",".m.$.pl.$.inst.",0.99],
-		["i","ībhi",".n.",".m.$.pl.$.inst.",0.99],
-		["i","īhi",".n.",".m.$.pl.$.abl.",0.99],
-		["i","ībhi",".n.",".m.$.pl.$.abl.",0.99],
-		["i","īsu",".n.",".m.$.pl.$.loc.",0.99],
-		["i","i",".n.",".nt.$.sg.$.nom.",0.99],
-		["i","i",".n.",".nt.$.sg.$.voc.",0.3],
-		["i","iṃ",".n.",".nt.$.sg.$.acc.",0.99],
-		["i","assa",".n.",".nt.$.sg.$.gen.",0.99],
-		["i","ino",".n.",".nt.$.sg.$.gen.",0.99],
-		["i","assa",".n.",".nt.$.sg.$.dat.",0.99],
-		["i","ino",".n.",".nt.$.sg.$.dat.",0.99],
-		["i","inā",".n.",".nt.$.sg.$.inst.",0.99],
-		["i","inā",".n.",".nt.$.sg.$.abl.",0.99],
-		["i","ismā",".n.",".nt.$.sg.$.abl.",0.99],
-		["i","imhā",".n.",".nt.$.sg.$.abl.",0.99],
-		["i","ismiṃ",".n.",".nt.$.sg.$.loc.",0.99],
-		["i","imhi",".n.",".nt.$.sg.$.loc.",0.99],
-		["i","īni",".n.",".nt.$.pl.$.nom.",0.99],
-		["i","ī",".n.",".nt.$.pl.$.nom.",0.99],
-		["i","īni",".n.",".nt.$.pl.$.voc.",0.3],
-		["i","ī",".n.",".nt.$.pl.$.voc.",0.3],
-		["i","īni",".n.",".nt.$.pl.$.acc.",0.99],
-		["i","ī",".n.",".nt.$.pl.$.acc.",0.99],
-		["i","īnaṃ",".n.",".nt.$.pl.$.gen.",0.99],
-		["i","īnaṃ",".n.",".nt.$.pl.$.dat.",0.99],
-		["i","īhi",".n.",".nt.$.pl.$.inst.",0.99],
-		["i","ībhi",".n.",".nt.$.pl.$.inst.",0.99],
-		["i","īhi",".n.",".nt.$.pl.$.abl.",0.99],
-		["i","ībhi",".n.",".nt.$.pl.$.abl.",0.99],
-		["i","īsu",".n.",".nt.$.pl.$.loc.",0.99],
-		["i","i",".n.",".f.$.sg.$.nom.",0.99],
-		["i","i",".n.",".f.$.sg.$.voc.",0.3],
-		["i","iṃ",".n.",".f.$.sg.$.acc.",0.99],
-		["i","iyā",".n.",".f.$.sg.$.gen.",0.99],
-		["i","yā",".n.",".f.$.sg.$.gen.",0.99],
-		["i","iyā",".n.",".f.$.sg.$.dat.",0.99],
-		["i","yā",".n.",".f.$.sg.$.dat.",0.99],
-		["i","iyā",".n.",".f.$.sg.$.inst.",0.99],
-		["i","yā",".n.",".f.$.sg.$.inst.",0.99],
-		["i","iyā",".n.",".f.$.sg.$.abl.",0.99],
-		["i","yā",".n.",".f.$.sg.$.abl.",0.99],
-		["i","iyā",".n.",".f.$.sg.$.loc.",0.99],
-		["i","yā",".n.",".f.$.sg.$.loc.",0.99],
-		["i","iyaṃ",".n.",".f.$.sg.$.loc.",0.99],
-		["i","yaṃ",".n.",".f.$.sg.$.loc.",0.99],
-		["i","ī",".n.",".f.$.pl.$.nom.",0.99],
-		["i","iyo",".n.",".f.$.pl.$.nom.",0.99],
-		["i","yo",".n.",".f.$.pl.$.nom.",0.99],
-		["i","ī",".n.",".f.$.pl.$.voc.",0.3],
-		["i","iyo",".n.",".f.$.pl.$.voc.",0.3],
-		["i","yo",".n.",".f.$.pl.$.voc.",0.3],
-		["i","ī",".n.",".f.$.pl.$.acc.",0.99],
-		["i","iyo",".n.",".f.$.pl.$.acc.",0.99],
-		["i","yo",".n.",".f.$.pl.$.acc.",0.99],
-		["i","īnaṃ",".n.",".f.$.pl.$.gen.",0.99],
-		["i","īnaṃ",".n.",".f.$.pl.$.dat.",0.99],
-		["i","īhi",".n.",".f.$.pl.$.inst.",0.99],
-		["i","ībhi",".n.",".f.$.pl.$.inst.",0.99],
-		["i","īhi",".n.",".f.$.pl.$.abl.",0.99],
-		["i","ībhi",".n.",".f.$.pl.$.abl.",0.99],
-		["i","īsu",".n.",".f.$.pl.$.loc.",0.99],
-		["ī","ī",".n.",".m.$.sg.$.nom.",0.99],
-		["in","ī",".n.",".m.$.sg.$.nom.",0.99],
-		["ī","ī",".n.",".m.$.sg.$.voc.",0.3],
-		["ī","inī",".n.",".m.$.sg.$.voc.",0.3],
-		["in","ī",".n.",".m.$.sg.$.voc.",0.3],
-		["in","inī",".n.",".m.$.sg.$.voc.",0.3],
-		["ī","iṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["ī","inaṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["in","iṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["in","inaṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["ī","issa",".n.",".m.$.sg.$.gen.",0.99],
-		["ī","ino",".n.",".m.$.sg.$.gen.",0.99],
-		["in","issa",".n.",".m.$.sg.$.gen.",0.99],
-		["in","ino",".n.",".m.$.sg.$.gen.",0.99],
-		["ī","issa",".n.",".m.$.sg.$.dat.",0.99],
-		["ī","ino",".n.",".m.$.sg.$.dat.",0.99],
-		["in","issa",".n.",".m.$.sg.$.dat.",0.99],
-		["in","ino",".n.",".m.$.sg.$.dat.",0.99],
-		["ī","inā",".n.",".m.$.sg.$.inst.",0.99],
-		["in","inā",".n.",".m.$.sg.$.inst.",0.99],
-		["ī","inā",".n.",".m.$.sg.$.abl.",0.99],
-		["ī","ismā",".n.",".m.$.sg.$.abl.",0.99],
-		["ī","imhā",".n.",".m.$.sg.$.abl.",0.99],
-		["in","inā",".n.",".m.$.sg.$.abl.",0.99],
-		["in","ismā",".n.",".m.$.sg.$.abl.",0.99],
-		["in","imhā",".n.",".m.$.sg.$.abl.",0.99],
-		["ī","ismiṃ",".n.",".m.$.sg.$.loc.",0.99],
-		["ī","imhi",".n.",".m.$.sg.$.loc.",0.99],
-		["in","ismiṃ",".n.",".m.$.sg.$.loc.",0.99],
-		["in","imhi",".n.",".m.$.sg.$.loc.",0.99],
-		["ī","ī",".n.",".m.$.pl.$.nom.",0.99],
-		["ī","ino",".n.",".m.$.pl.$.nom.",0.99],
-		["in","ī",".n.",".m.$.pl.$.nom.",0.99],
-		["in","ino",".n.",".m.$.pl.$.nom.",0.99],
-		["ī","ī",".n.",".m.$.pl.$.voc.",0.3],
-		["ī","ino",".n.",".m.$.pl.$.voc.",0.3],
-		["in","ī",".n.",".m.$.pl.$.voc.",0.3],
-		["in","ino",".n.",".m.$.pl.$.voc.",0.3],
-		["ī","ī",".n.",".m.$.pl.$.acc.",0.99],
-		["ī","ino",".n.",".m.$.pl.$.acc.",0.99],
-		["in","ī",".n.",".m.$.pl.$.acc.",0.99],
-		["in","ino",".n.",".m.$.pl.$.acc.",0.99],
-		["ī","inaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["in","inaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["ī","inaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["in","inaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["ī","īhi",".n.",".m.$.pl.$.inst.",0.99],
-		["ī","ībhi",".n.",".m.$.pl.$.inst.",0.99],
-		["in","īhi",".n.",".m.$.pl.$.inst.",0.99],
-		["in","ībhi",".n.",".m.$.pl.$.inst.",0.99],
-		["ī","īhi",".n.",".m.$.pl.$.abl.",0.99],
-		["ī","ībhi",".n.",".m.$.pl.$.abl.",0.99],
-		["in","īhi",".n.",".m.$.pl.$.abl.",0.99],
-		["in","ībhi",".n.",".m.$.pl.$.abl.",0.99],
-		["ī","īsu",".n.",".m.$.pl.$.loc.",0.99],
-		["in","īsu",".n.",".m.$.pl.$.loc.",0.99],
-		["ī","ī",".n.",".f.$.sg.$.nom.",0.99],
-		["ī","ī",".n.",".f.$.sg.$.voc.",0.3],
-		["ī","iṃ",".n.",".f.$.sg.$.acc.",0.99],
-		["ī","iyā",".n.",".f.$.sg.$.gen.",0.99],
-		["ī","ayā",".n.",".f.$.sg.$.gen.",0.99],
-		["ī","yā",".n.",".f.$.sg.$.gen.",0.99],
-		["ī","iyā",".n.",".f.$.sg.$.dat.",0.99],
-		["ī","ayā",".n.",".f.$.sg.$.dat.",0.99],
-		["ī","yā",".n.",".f.$.sg.$.dat.",0.99],
-		["ī","iyā",".n.",".f.$.sg.$.inst.",0.99],
-		["ī","ayā",".n.",".f.$.sg.$.inst.",0.99],
-		["ī","yā",".n.",".f.$.sg.$.inst.",0.99],
-		["ī","iyā",".n.",".f.$.sg.$.abl.",0.99],
-		["ī","ayā",".n.",".f.$.sg.$.abl.",0.99],
-		["ī","yā",".n.",".f.$.sg.$.abl.",0.99],
-		["ī","iyā",".n.",".f.$.sg.$.loc.",0.99],
-		["ī","ayā",".n.",".f.$.sg.$.loc.",0.99],
-		["ī","yā",".n.",".f.$.sg.$.loc.",0.99],
-		["ī","iyaṃ",".n.",".f.$.sg.$.loc.",0.99],
-		["ī","ayaṃ",".n.",".f.$.sg.$.loc.",0.99],
-		["ī","yaṃ",".n.",".f.$.sg.$.loc.",0.99],
-		["ī","ī",".n.",".f.$.pl.$.nom.",0.99],
-		["ī","iyo",".n.",".f.$.pl.$.nom.",0.99],
-		["ī","yo",".n.",".f.$.pl.$.nom.",0.99],
-		["ī","ī",".n.",".f.$.pl.$.voc.",0.3],
-		["ī","iyo",".n.",".f.$.pl.$.voc.",0.3],
-		["ī","yo",".n.",".f.$.pl.$.voc.",0.3],
-		["ī","ī",".n.",".f.$.pl.$.acc.",0.99],
-		["ī","iyo",".n.",".f.$.pl.$.acc.",0.99],
-		["ī","yo",".n.",".f.$.pl.$.acc.",0.99],
-		["ī","īnaṃ",".n.",".f.$.pl.$.gen.",0.99],
-		["ī","īnaṃ",".n.",".f.$.pl.$.dat.",0.99],
-		["ī","īhi",".n.",".f.$.pl.$.inst.",0.99],
-		["ī","ībhi",".n.",".f.$.pl.$.inst.",0.99],
-		["ī","īhi",".n.",".f.$.pl.$.abl.",0.99],
-		["ī","ībhi",".n.",".f.$.pl.$.abl.",0.99],
-		["ī","īsu",".n.",".f.$.pl.$.loc.",0.99],
-		["u","u",".n.",".m.$.sg.$.nom.",0.99],
-		["u","u",".n.",".m.$.sg.$.voc.",0.3],
-		["u","uṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["u","ussa",".n.",".m.$.sg.$.gen.",0.99],
-		["u","uno",".n.",".m.$.sg.$.gen.",0.99],
-		["u","ussa",".n.",".m.$.sg.$.dat.",0.99],
-		["u","uno",".n.",".m.$.sg.$.dat.",0.99],
-		["u","unā",".n.",".m.$.sg.$.inst.",0.99],
-		["u","unā",".n.",".m.$.sg.$.abl.",0.99],
-		["u","usmā",".n.",".m.$.sg.$.abl.",0.99],
-		["u","umhā",".n.",".m.$.sg.$.abl.",0.99],
-		["u","usmiṃ",".n.",".m.$.sg.$.loc.",0.99],
-		["u","umhi",".n.",".m.$.sg.$.loc.",0.99],
-		["u","ū",".n.",".m.$.pl.$.nom.",0.99],
-		["u","avo",".n.",".m.$.pl.$.nom.",0.99],
-		["u","ū",".n.",".m.$.pl.$.voc.",0.3],
-		["u","avo",".n.",".m.$.pl.$.voc.",0.3],
-		["u","ave",".n.",".m.$.pl.$.voc.",0.3],
-		["u","ū",".n.",".m.$.pl.$.acc.",0.99],
-		["u","avo",".n.",".m.$.pl.$.acc.",0.99],
-		["u","ūnaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["u","ūnaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["u","ūhi",".n.",".m.$.pl.$.inst.",0.99],
-		["u","ūbhi",".n.",".m.$.pl.$.inst.",0.99],
-		["u","ūhi",".n.",".m.$.pl.$.abl.",0.99],
-		["u","ūbhi",".n.",".m.$.pl.$.abl.",0.99],
-		["u","ūsu",".n.",".m.$.pl.$.loc.",0.99],
-		["u","u",".n.",".nt.$.sg.$.nom.",0.99],
-		["u","u",".n.",".nt.$.sg.$.voc.",0.3],
-		["u","uṃ",".n.",".nt.$.sg.$.acc.",0.99],
-		["u","ussa",".n.",".nt.$.sg.$.gen.",0.99],
-		["u","uno",".n.",".nt.$.sg.$.gen.",0.99],
-		["u","ussa",".n.",".nt.$.sg.$.dat.",0.99],
-		["u","uno",".n.",".nt.$.sg.$.dat.",0.99],
-		["u","unā",".n.",".nt.$.sg.$.inst.",0.99],
-		["u","unā",".n.",".nt.$.sg.$.abl.",0.99],
-		["u","usmā",".n.",".nt.$.sg.$.abl.",0.99],
-		["u","umhā",".n.",".nt.$.sg.$.abl.",0.99],
-		["u","usmiṃ",".n.",".nt.$.sg.$.loc.",0.99],
-		["u","umhi",".n.",".nt.$.sg.$.loc.",0.99],
-		["u","ū",".n.",".nt.$.pl.$.nom.",0.99],
-		["u","ūni",".n.",".nt.$.pl.$.nom.",0.99],
-		["u","ū",".n.",".nt.$.pl.$.voc.",0.3],
-		["u","ūni",".n.",".nt.$.pl.$.voc.",0.3],
-		["u","ū",".n.",".nt.$.pl.$.acc.",0.99],
-		["u","ūni",".n.",".nt.$.pl.$.acc.",0.99],
-		["u","ūnaṃ",".n.",".nt.$.pl.$.gen.",0.99],
-		["u","ūnaṃ",".n.",".nt.$.pl.$.dat.",0.99],
-		["u","ūhi",".n.",".nt.$.pl.$.inst.",0.99],
-		["u","ūbhi",".n.",".nt.$.pl.$.inst.",0.99],
-		["u","ūhi",".n.",".nt.$.pl.$.abl.",0.99],
-		["u","ūbhi",".n.",".nt.$.pl.$.abl.",0.99],
-		["u","ūsu",".n.",".nt.$.pl.$.loc.",0.99],
-		["u","u",".n.",".f.$.sg.$.nom.",0.99],
-		["u","u",".n.",".f.$.sg.$.voc.",0.3],
-		["u","uṃ",".n.",".f.$.sg.$.acc.",0.99],
-		["u","uyā",".n.",".f.$.sg.$.gen.",0.99],
-		["u","uyā",".n.",".f.$.sg.$.dat.",0.99],
-		["u","uyā",".n.",".f.$.sg.$.inst.",0.99],
-		["u","uyā",".n.",".f.$.sg.$.abl.",0.99],
-		["u","uto",".n.",".f.$.sg.$.abl.",0.99],
-		["u","uyā",".n.",".f.$.sg.$.loc.",0.99],
-		["u","uyaṃ",".n.",".f.$.sg.$.loc.",0.99],
-		["u","ū",".n.",".f.$.pl.$.nom.",0.99],
-		["u","uyo",".n.",".f.$.pl.$.nom.",0.99],
-		["u","ūvo",".n.",".f.$.pl.$.nom.",0.99],
-		["u","ū",".n.",".f.$.pl.$.voc.",0.3],
-		["u","uyo",".n.",".f.$.pl.$.voc.",0.3],
-		["u","ū",".n.",".f.$.pl.$.acc.",0.99],
-		["u","uyo",".n.",".f.$.pl.$.acc.",0.99],
-		["u","ūnaṃ",".n.",".f.$.pl.$.gen.",0.99],
-		["u","ūnaṃ",".n.",".f.$.pl.$.dat.",0.99],
-		["u","ūhi",".n.",".f.$.pl.$.inst.",0.99],
-		["u","ūbhi",".n.",".f.$.pl.$.inst.",0.99],
-		["u","ūhi",".n.",".f.$.pl.$.abl.",0.99],
-		["u","ūbhi",".n.",".f.$.pl.$.abl.",0.99],
-		["u","ūsu",".n.",".f.$.pl.$.loc.",0.99],
-		["ū","ū",".n.",".m.$.sg.$.nom.",0.99],
-		["ū","ū",".n.",".m.$.sg.$.voc.",0.3],
-		["ū","uṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["ū","ussa",".n.",".m.$.sg.$.gen.",0.99],
-		["ū","uno",".n.",".m.$.sg.$.gen.",0.99],
-		["ū","ussa",".n.",".m.$.sg.$.dat.",0.99],
-		["ū","uno",".n.",".m.$.sg.$.dat.",0.99],
-		["ū","unā",".n.",".m.$.sg.$.inst.",0.99],
-		["ū","unā",".n.",".m.$.sg.$.abl.",0.99],
-		["ū","usmā",".n.",".m.$.sg.$.abl.",0.99],
-		["ū","umhā",".n.",".m.$.sg.$.abl.",0.99],
-		["ū","usmiṃ",".n.",".m.$.sg.$.loc.",0.99],
-		["ū","umhi",".n.",".m.$.sg.$.loc.",0.99],
-		["ū","ū",".n.",".m.$.pl.$.nom.",0.99],
-		["ū","avo",".n.",".m.$.pl.$.nom.",0.99],
-		["ū","ū",".n.",".m.$.pl.$.voc.",0.3],
-		["ū","avo",".n.",".m.$.pl.$.voc.",0.3],
-		["ū","ave",".n.",".m.$.pl.$.voc.",0.3],
-		["ū","ū",".n.",".m.$.pl.$.acc.",0.99],
-		["ū","avo",".n.",".m.$.pl.$.acc.",0.99],
-		["ū","ūnaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["ū","ūnaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["ū","ūhi",".n.",".m.$.pl.$.inst.",0.99],
-		["ū","ūbhi",".n.",".m.$.pl.$.inst.",0.99],
-		["ū","ūhi",".n.",".m.$.pl.$.abl.",0.99],
-		["ū","ūbhi",".n.",".m.$.pl.$.abl.",0.99],
-		["ū","ūsu",".n.",".m.$.pl.$.loc.",0.99],
-		["ū","ū",".n.",".f.$.sg.$.nom.",0.99],
-		["ū","ū",".n.",".f.$.sg.$.voc.",0.3],
-		["ū","uṃ",".n.",".f.$.sg.$.acc.",0.99],
-		["ū","uyā",".n.",".f.$.sg.$.gen.",0.99],
-		["ū","uyā",".n.",".f.$.sg.$.dat.",0.99],
-		["ū","uyā",".n.",".f.$.sg.$.inst.",0.99],
-		["ū","uyā",".n.",".f.$.sg.$.abl.",0.99],
-		["ū","uto",".n.",".f.$.sg.$.abl.",0.99],
-		["ū","uyā",".n.",".f.$.sg.$.loc.",0.99],
-		["ū","uyaṃ",".n.",".f.$.sg.$.loc.",0.99],
-		["ū","ū",".n.",".f.$.pl.$.nom.",0.99],
-		["ū","uyo",".n.",".f.$.pl.$.nom.",0.99],
-		["ū","ū",".n.",".f.$.pl.$.voc.",0.3],
-		["ū","uyo",".n.",".f.$.pl.$.voc.",0.3],
-		["ū","ū",".n.",".f.$.pl.$.acc.",0.99],
-		["ū","uyo",".n.",".f.$.pl.$.acc.",0.99],
-		["ū","ūnaṃ",".n.",".f.$.pl.$.gen.",0.99],
-		["ū","ūnaṃ",".n.",".f.$.pl.$.dat.",0.99],
-		["ū","ūhi",".n.",".f.$.pl.$.inst.",0.99],
-		["ū","ūbhi",".n.",".f.$.pl.$.inst.",0.99],
-		["ū","ūhi",".n.",".f.$.pl.$.abl.",0.99],
-		["ū","ūbhi",".n.",".f.$.pl.$.abl.",0.99],
-		["ū","ūsu",".n.",".f.$.pl.$.loc.",0.99],
-		["as","o",".n.",".m.$.sg.$.nom.",0.99],
-		["as","aṃ",".n.",".m.$.sg.$.nom.",0.99],
-		["o","o",".n.",".m.$.sg.$.nom.",0.99],
-		["o","aṃ",".n.",".m.$.sg.$.nom.",0.99],
-		["as","o",".n.",".m.$.sg.$.voc.",0.3],
-		["as","aṃ",".n.",".m.$.sg.$.voc.",0.3],
-		["as","ā",".n.",".m.$.sg.$.voc.",0.3],
-		["as","a",".n.",".m.$.sg.$.voc.",0.3],
-		["o","o",".n.",".m.$.sg.$.voc.",0.3],
-		["o","aṃ",".n.",".m.$.sg.$.voc.",0.3],
-		["o","ā",".n.",".m.$.sg.$.voc.",0.3],
-		["o","a",".n.",".m.$.sg.$.voc.",0.3],
-		["as","o",".n.",".m.$.sg.$.acc.",0.99],
-		["as","aṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["o","o",".n.",".m.$.sg.$.acc.",0.99],
-		["o","aṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["as","aso",".n.",".m.$.sg.$.gen.",0.99],
-		["as","assa",".n.",".m.$.sg.$.gen.",0.99],
-		["o","aso",".n.",".m.$.sg.$.gen.",0.99],
-		["o","assa",".n.",".m.$.sg.$.gen.",0.99],
-		["as","aso",".n.",".m.$.sg.$.dat.",0.99],
-		["as","assa",".n.",".m.$.sg.$.dat.",0.99],
-		["o","aso",".n.",".m.$.sg.$.dat.",0.99],
-		["o","assa",".n.",".m.$.sg.$.dat.",0.99],
-		["as","asā",".n.",".m.$.sg.$.inst.",0.99],
-		["as","ena",".n.",".m.$.sg.$.inst.",0.99],
-		["o","asā",".n.",".m.$.sg.$.inst.",0.99],
-		["o","ena",".n.",".m.$.sg.$.inst.",0.99],
-		["as","asā",".n.",".m.$.sg.$.abl.",0.99],
-		["as","asmā",".n.",".m.$.sg.$.abl.",0.99],
-		["as","amhā",".n.",".m.$.sg.$.abl.",0.99],
-		["as","ā",".n.",".m.$.sg.$.abl.",0.99],
-		["o","asā",".n.",".m.$.sg.$.abl.",0.99],
-		["o","asmā",".n.",".m.$.sg.$.abl.",0.99],
-		["o","amhā",".n.",".m.$.sg.$.abl.",0.99],
-		["o","ā",".n.",".m.$.sg.$.abl.",0.99],
-		["as","asi",".n.",".m.$.sg.$.loc.",0.99],
-		["as","e",".n.",".m.$.sg.$.loc.",0.99],
-		["as","asmiṃ",".n.",".m.$.sg.$.loc.",0.99],
-		["as","amhi",".n.",".m.$.sg.$.loc.",0.99],
-		["o","asi",".n.",".m.$.sg.$.loc.",0.99],
-		["o","e",".n.",".m.$.sg.$.loc.",0.99],
-		["o","asmiṃ",".n.",".m.$.sg.$.loc.",0.99],
-		["o","amhi",".n.",".m.$.sg.$.loc.",0.99],
-		["as","ā",".n.",".m.$.pl.$.nom.",0.99],
-		["o","ā",".n.",".m.$.pl.$.nom.",0.99],
-		["as","ā",".n.",".m.$.pl.$.voc.",0.3],
-		["o","ā",".n.",".m.$.pl.$.voc.",0.3],
-		["as","e",".n.",".m.$.pl.$.acc.",0.99],
-		["o","e",".n.",".m.$.pl.$.acc.",0.99],
-		["as","ānaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["o","ānaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["as","ānaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["o","ānaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["as","ehi",".n.",".m.$.pl.$.inst.",0.99],
-		["as","ebhi",".n.",".m.$.pl.$.inst.",0.99],
-		["o","ehi",".n.",".m.$.pl.$.inst.",0.99],
-		["o","ebhi",".n.",".m.$.pl.$.inst.",0.99],
-		["as","ehi",".n.",".m.$.pl.$.abl.",0.99],
-		["as","ebhi",".n.",".m.$.pl.$.abl.",0.99],
-		["o","ehi",".n.",".m.$.pl.$.abl.",0.99],
-		["o","ebhi",".n.",".m.$.pl.$.abl.",0.99],
-		["as","esu",".n.",".m.$.pl.$.loc.",0.99],
-		["o","esu",".n.",".m.$.pl.$.loc.",0.99],
-		["as","o",".n.",".nt.$.sg.$.nom.",0.99],
-		["as","aṃ",".n.",".nt.$.sg.$.nom.",0.99],
-		["o","o",".n.",".nt.$.sg.$.nom.",0.99],
-		["o","aṃ",".n.",".nt.$.sg.$.nom.",0.99],
-		["as","o",".n.",".nt.$.sg.$.voc.",0.3],
-		["as","aṃ",".n.",".nt.$.sg.$.voc.",0.3],
-		["as","ā",".n.",".nt.$.sg.$.voc.",0.3],
-		["as","a",".n.",".nt.$.sg.$.voc.",0.3],
-		["o","o",".n.",".nt.$.sg.$.voc.",0.3],
-		["o","aṃ",".n.",".nt.$.sg.$.voc.",0.3],
-		["o","ā",".n.",".nt.$.sg.$.voc.",0.3],
-		["o","a",".n.",".nt.$.sg.$.voc.",0.3],
-		["as","o",".n.",".nt.$.sg.$.acc.",0.99],
-		["as","aṃ",".n.",".nt.$.sg.$.acc.",0.99],
-		["o","o",".n.",".nt.$.sg.$.acc.",0.99],
-		["o","aṃ",".n.",".nt.$.sg.$.acc.",0.99],
-		["as","aso",".n.",".nt.$.sg.$.gen.",0.99],
-		["as","assa",".n.",".nt.$.sg.$.gen.",0.99],
-		["o","aso",".n.",".nt.$.sg.$.gen.",0.99],
-		["o","assa",".n.",".nt.$.sg.$.gen.",0.99],
-		["as","aso",".n.",".nt.$.sg.$.dat.",0.99],
-		["as","assa",".n.",".nt.$.sg.$.dat.",0.99],
-		["o","aso",".n.",".nt.$.sg.$.dat.",0.99],
-		["o","assa",".n.",".nt.$.sg.$.dat.",0.99],
-		["as","asā",".n.",".nt.$.sg.$.inst.",0.99],
-		["as","ena",".n.",".nt.$.sg.$.inst.",0.99],
-		["o","asā",".n.",".nt.$.sg.$.inst.",0.99],
-		["o","ena",".n.",".nt.$.sg.$.inst.",0.99],
-		["as","asā",".n.",".nt.$.sg.$.abl.",0.99],
-		["as","asmā",".n.",".nt.$.sg.$.abl.",0.99],
-		["as","amhā",".n.",".nt.$.sg.$.abl.",0.99],
-		["as","ā",".n.",".nt.$.sg.$.abl.",0.99],
-		["o","asā",".n.",".nt.$.sg.$.abl.",0.99],
-		["o","asmā",".n.",".nt.$.sg.$.abl.",0.99],
-		["o","amhā",".n.",".nt.$.sg.$.abl.",0.99],
-		["o","ā",".n.",".nt.$.sg.$.abl.",0.99],
-		["as","asi",".n.",".nt.$.sg.$.loc.",0.99],
-		["as","e",".n.",".nt.$.sg.$.loc.",0.99],
-		["as","asmiṃ",".n.",".nt.$.sg.$.loc.",0.99],
-		["as","amhi",".n.",".nt.$.sg.$.loc.",0.99],
-		["o","asi",".n.",".nt.$.sg.$.loc.",0.99],
-		["o","e",".n.",".nt.$.sg.$.loc.",0.99],
-		["o","asmiṃ",".n.",".nt.$.sg.$.loc.",0.99],
-		["o","amhi",".n.",".nt.$.sg.$.loc.",0.99],
-		["as","ā",".n.",".nt.$.pl.$.nom.",0.99],
-		["o","ā",".n.",".nt.$.pl.$.nom.",0.99],
-		["as","ā",".n.",".nt.$.pl.$.voc.",0.3],
-		["o","ā",".n.",".nt.$.pl.$.voc.",0.3],
-		["as","e",".n.",".nt.$.pl.$.acc.",0.99],
-		["o","e",".n.",".nt.$.pl.$.acc.",0.99],
-		["as","ānaṃ",".n.",".nt.$.pl.$.gen.",0.99],
-		["o","ānaṃ",".n.",".nt.$.pl.$.gen.",0.99],
-		["as","ānaṃ",".n.",".nt.$.pl.$.dat.",0.99],
-		["o","ānaṃ",".n.",".nt.$.pl.$.dat.",0.99],
-		["as","ehi",".n.",".nt.$.pl.$.inst.",0.99],
-		["as","ebhi",".n.",".nt.$.pl.$.inst.",0.99],
-		["o","ehi",".n.",".nt.$.pl.$.inst.",0.99],
-		["o","ebhi",".n.",".nt.$.pl.$.inst.",0.99],
-		["as","ehi",".n.",".nt.$.pl.$.abl.",0.99],
-		["as","ebhi",".n.",".nt.$.pl.$.abl.",0.99],
-		["o","ehi",".n.",".nt.$.pl.$.abl.",0.99],
-		["o","ebhi",".n.",".nt.$.pl.$.abl.",0.99],
-		["as","esu",".n.",".nt.$.pl.$.loc.",0.99],
-		["o","esu",".n.",".nt.$.pl.$.loc.",0.99],
-		["an","ā",".n.",".m.$.sg.$.nom.",0.99],
-		["an","ā",".n.",".m.$.sg.$.voc.",0.3],
-		["an","a",".n.",".m.$.sg.$.voc.",0.3],
-		["an","aṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["an","ānaṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["an","anaṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["an","assa",".n.",".m.$.sg.$.gen.",0.99],
-		["an","ano",".n.",".m.$.sg.$.gen.",0.99],
-		["an","assa",".n.",".m.$.sg.$.dat.",0.99],
-		["an","ano",".n.",".m.$.sg.$.dat.",0.99],
-		["an","ena",".n.",".m.$.sg.$.inst.",0.99],
-		["an","anā",".n.",".m.$.sg.$.inst.",0.99],
-		["an","anā",".n.",".m.$.sg.$.abl.",0.99],
-		["an","asmā",".n.",".m.$.sg.$.abl.",0.99],
-		["an","amhā",".n.",".m.$.sg.$.abl.",0.99],
-		["an","ani",".n.",".m.$.sg.$.loc.",0.99],
-		["an","asmiṃ",".n.",".m.$.sg.$.loc.",0.99],
-		["an","amhi",".n.",".m.$.sg.$.loc.",0.99],
-		["an","ā",".n.",".m.$.pl.$.nom.",0.99],
-		["an","āno",".n.",".m.$.pl.$.nom.",0.99],
-		["an","ā",".n.",".m.$.pl.$.voc.",0.3],
-		["an","āno",".n.",".m.$.pl.$.voc.",0.3],
-		["an","āno",".n.",".m.$.pl.$.acc.",0.99],
-		["an","e",".n.",".m.$.pl.$.acc.",0.99],
-		["an","ānaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["an","ānaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["an","anehi",".n.",".m.$.pl.$.inst.",0.99],
-		["an","anebhi",".n.",".m.$.pl.$.inst.",0.99],
-		["an","anehi",".n.",".m.$.pl.$.abl.",0.99],
-		["an","anebhi",".n.",".m.$.pl.$.abl.",0.99],
-		["an","anesu",".n.",".m.$.pl.$.loc.",0.99],
-		["an","aṃ",".n.",".nt.$.sg.$.nom.",0.99],
-		["an","a",".n.",".nt.$.sg.$.voc.",0.3],
-		["an","aṃ",".n.",".nt.$.sg.$.acc.",0.99],
-		["an","assa",".n.",".nt.$.sg.$.gen.",0.99],
-		["an","assa",".n.",".nt.$.sg.$.dat.",0.99],
-		["an","āya",".n.",".nt.$.sg.$.dat.",0.99],
-		["an","ena",".n.",".nt.$.sg.$.inst.",0.99],
-		["an","ā",".n.",".nt.$.sg.$.abl.",0.99],
-		["an","asmā",".n.",".nt.$.sg.$.abl.",0.99],
-		["an","amhā",".n.",".nt.$.sg.$.abl.",0.99],
-		["an","ato",".n.",".nt.$.sg.$.abl.",0.99],
-		["an","e",".n.",".nt.$.sg.$.loc.",0.99],
-		["an","asmiṃ",".n.",".nt.$.sg.$.loc.",0.99],
-		["an","amhi",".n.",".nt.$.sg.$.loc.",0.99],
-		["an","āni",".n.",".nt.$.pl.$.nom.",0.99],
-		["an","ā",".n.",".nt.$.pl.$.nom.",0.99],
-		["an","āni",".n.",".nt.$.pl.$.voc.",0.3],
-		["an","ā",".n.",".nt.$.pl.$.voc.",0.3],
-		["an","āni",".n.",".nt.$.pl.$.acc.",0.99],
-		["an","e",".n.",".nt.$.pl.$.acc.",0.99],
-		["an","ānaṃ",".n.",".nt.$.pl.$.gen.",0.99],
-		["an","ānaṃ",".n.",".nt.$.pl.$.dat.",0.99],
-		["an","ehi",".n.",".nt.$.pl.$.inst.",0.99],
-		["an","ebhi",".n.",".nt.$.pl.$.inst.",0.99],
-		["an","ehi",".n.",".nt.$.pl.$.abl.",0.99],
-		["an","ebhi",".n.",".nt.$.pl.$.abl.",0.99],
-		["an","esu",".n.",".nt.$.pl.$.loc.",0.99],
-		["ar","ā",".n.",".f.$.sg.$.nom.",0.99],
-		["ar","ā",".n.",".f.$.sg.$.voc.",0.3],
-		["ar","aṃ",".n.",".f.$.sg.$.acc.",0.99],
-		["ar","ānaṃ",".n.",".f.$.sg.$.acc.",0.99],
-		["ar","assa",".n.",".f.$.sg.$.gen.",0.99],
-		["ar","ino",".n.",".f.$.sg.$.gen.",0.99],
-		["ar","assa",".n.",".f.$.sg.$.dat.",0.99],
-		["ar","ino",".n.",".f.$.sg.$.dat.",0.99],
-		["ar","ena",".n.",".f.$.sg.$.inst.",0.99],
-		["ar","inā",".n.",".f.$.sg.$.inst.",0.99],
-		["ar","asmā",".n.",".f.$.sg.$.abl.",0.99],
-		["ar","amhā",".n.",".f.$.sg.$.abl.",0.99],
-		["ar","ini",".n.",".f.$.sg.$.loc.",0.99],
-		["ar","asmiṃ",".n.",".f.$.sg.$.loc.",0.99],
-		["ar","amhi",".n.",".f.$.sg.$.loc.",0.99],
-		["ar","ā",".n.",".f.$.pl.$.nom.",0.99],
-		["ar","āno",".n.",".f.$.pl.$.nom.",0.99],
-		["ar","ā",".n.",".f.$.pl.$.voc.",0.3],
-		["ar","āno",".n.",".f.$.pl.$.voc.",0.3],
-		["ar","ā",".n.",".f.$.pl.$.acc.",0.99],
-		["ar","āno",".n.",".f.$.pl.$.acc.",0.99],
-		["ar","ānaṃ",".n.",".f.$.pl.$.gen.",0.99],
-		["ar","ānaṃ",".n.",".f.$.pl.$.dat.",0.99],
-		["ar","ehi",".n.",".f.$.pl.$.inst.",0.99],
-		["ar","āhi",".n.",".f.$.pl.$.inst.",0.99],
-		["ar","ehi",".n.",".f.$.pl.$.abl.",0.99],
-		["ar","āhi",".n.",".f.$.pl.$.abl.",0.99],
-		["ar","esu",".n.",".f.$.pl.$.loc.",0.99],
-		["ar","āsu",".n.",".f.$.pl.$.loc.",0.99],
-		["ar","ā",".n.",".nt.$.sg.$.nom.",0.99],
-		["ar","ā",".n.",".nt.$.sg.$.voc.",0.3],
-		["ar","aṃ",".n.",".nt.$.sg.$.acc.",0.99],
-		["ar","ānaṃ",".n.",".nt.$.sg.$.acc.",0.99],
-		["ar","assa",".n.",".nt.$.sg.$.gen.",0.99],
-		["ar","ino",".n.",".nt.$.sg.$.gen.",0.99],
-		["ar","assa",".n.",".nt.$.sg.$.dat.",0.99],
-		["ar","ino",".n.",".nt.$.sg.$.dat.",0.99],
-		["ar","ena",".n.",".nt.$.sg.$.inst.",0.99],
-		["ar","inā",".n.",".nt.$.sg.$.inst.",0.99],
-		["ar","asmā",".n.",".nt.$.sg.$.abl.",0.99],
-		["ar","amhā",".n.",".nt.$.sg.$.abl.",0.99],
-		["ar","ini",".n.",".nt.$.sg.$.loc.",0.99],
-		["ar","asmiṃ",".n.",".nt.$.sg.$.loc.",0.99],
-		["ar","amhi",".n.",".nt.$.sg.$.loc.",0.99],
-		["ar","ā",".n.",".nt.$.pl.$.nom.",0.99],
-		["ar","āno",".n.",".nt.$.pl.$.nom.",0.99],
-		["ar","ā",".n.",".nt.$.pl.$.voc.",0.3],
-		["ar","āno",".n.",".nt.$.pl.$.voc.",0.3],
-		["ar","ā",".n.",".nt.$.pl.$.acc.",0.99],
-		["ar","āno",".n.",".nt.$.pl.$.acc.",0.99],
-		["ar","ānaṃ",".n.",".nt.$.pl.$.gen.",0.99],
-		["ar","ānaṃ",".n.",".nt.$.pl.$.dat.",0.99],
-		["ar","ehi",".n.",".nt.$.pl.$.inst.",0.99],
-		["ar","āhi",".n.",".nt.$.pl.$.inst.",0.99],
-		["ar","ehi",".n.",".nt.$.pl.$.abl.",0.99],
-		["ar","āhi",".n.",".nt.$.pl.$.abl.",0.99],
-		["ar","esu",".n.",".nt.$.pl.$.loc.",0.99],
-		["ar","āsu",".n.",".nt.$.pl.$.loc.",0.99],
-		["a","e",".n.",".m.$.sg.$.nom.",0.3],
-		["a","ā",".n.",".m.$.sg.$.inst.",0.2],
-		["a","asā",".n.",".m.$.sg.$.inst.",0.99],
-		["a","ā",".n.",".m.$.sg.$.dat.",0.2],
-		["a","āya",".n.",".m.$.sg.$.gen.",0.99],
-		["a","ā",".n.",".m.$.sg.$.gen.",0.2],
-		["a","asi",".n.",".m.$.sg.$.loc.",0.99],
-		["a","e",".n.",".m.$.sg.$.voc.",0.3],
-		["a","āse",".n.",".m.$.pl.$.nom.",0.99],
-		["a","o",".n.",".m.$.pl.$.nom.",0.3],
-		["a","ān",".n.",".m.$.pl.$.acc.",0.99],
-		["a","e",".n.",".m.$.pl.$.inst.",0.3],
-		["a","ato",".n.",".m.$.pl.$.abl.",0.99],
-		["a","e",".n.",".nt.$.sg.$.nom.",0.99],
-		["a","ā",".n.",".nt.$.sg.$.inst.",0.2],
-		["a","asā",".n.",".nt.$.sg.$.inst.",0.2],
-		["a","ā",".n.",".nt.$.sg.$.dat.",0.2],
-		["a","asi",".n.",".nt.$.sg.$.loc.",0.99],
-		["a","ā",".n.",".nt.$.sg.$.voc.",0.3],
-		["a","aṃ",".n.",".nt.$.sg.$.voc.",0.3],
-		["a","āya",".n.",".nt.$.sg.$.gen.",0.99],
-		["a","ā",".n.",".nt.$.sg.$.gen.",0.2],
-		["a","o",".n.",".nt.$.pl.$.acc.",0.3],
-		["a","ato",".n.",".nt.$.pl.$.abl.",0.99],
-		["ā","ā",".n.",".f.$.sg.$.inst.",0.2],
-		["ā","āto",".n.",".f.$.sg.$.abl.",0.99],
-		["ā","a",".n.",".f.$.sg.$.voc.",0.3],
-		["ā","iyo",".n.",".f.$.pl.$.voc.",0.3],
-		["i","e",".n.",".m.$.sg.$.dat.",0.99],
-		["i","ito",".n.",".m.$.sg.$.abl.",0.99],
-		["i","e",".n.",".m.$.sg.$.gen.",0.99],
-		["i","ini",".n.",".m.$.sg.$.loc.",0.99],
-		["i","e",".n.",".m.$.sg.$.loc.",0.99],
-		["i","iyo",".n.",".m.$.pl.$.nom.",0.99],
-		["i","ino",".n.",".m.$.pl.$.nom.",0.99],
-		["i","iyo",".n.",".m.$.pl.$.acc.",0.99],
-		["i","ihi",".n.",".m.$.pl.$.inst.",0.99],
-		["i","ibhi",".n.",".m.$.pl.$.inst.",0.99],
-		["i","inaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["i","ihi",".n.",".m.$.pl.$.abl.",0.99],
-		["i","ibhi",".n.",".m.$.pl.$.abl.",0.99],
-		["i","inaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["i","isu",".n.",".m.$.pl.$.loc.",0.99],
-		["i","iyo",".n.",".m.$.pl.$.voc.",0.3],
-		["i","ihi",".n.",".nt.$.pl.$.inst.",0.99],
-		["i","ibhi",".n.",".nt.$.pl.$.inst.",0.99],
-		["i","ihi",".n.",".nt.$.pl.$.abl.",0.99],
-		["i","ibhi",".n.",".nt.$.pl.$.abl.",0.99],
-		["i","inaṃ",".n.",".nt.$.pl.$.gen.",0.99],
-		["i","inaṃ",".n.",".nt.$.pl.$.dat.",0.99],
-		["i","isu",".n.",".nt.$.pl.$.loc.",0.99],
-		["i","iṃ",".n.",".nt.$.sg.$.nom.",0.99],
-		["i","i",".n.",".nt.$.sg.$.acc.",0.99],
-		["i","e",".n.",".nt.$.sg.$.dat.",0.99],
-		["i","ito",".n.",".nt.$.sg.$.abl.",0.99],
-		["i","e",".n.",".nt.$.sg.$.gen.",0.2],
-		["i","ini",".n.",".nt.$.sg.$.loc.",0.99],
-		["i","e",".n.",".nt.$.sg.$.loc.",0.99],
-		["i","iṃ",".n.",".nt.$.sg.$.voc.",0.3],
-		["i","ī",".n.",".f.$.sg.$.nom.",0.99],
-		["i","ito",".n.",".f.$.sg.$.abl.",0.99],
-		["i","myā",".n.",".f.$.sg.$.gen.",0.99],
-		["i","āyaṃ",".n.",".f.$.sg.$.loc.",0.99],
-		["i","u",".n.",".f.$.sg.$.loc.",0.99],
-		["i","ī",".n.",".f.$.sg.$.voc.",0.3],
-		["ī","ini",".n.",".m.$.sg.$.loc.",0.99],
-		["ī","īnaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["ī","īnaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["ī","īsu",".n.",".m.$.pl.$.loc.",0.99],
-		["ī","i",".n.",".m.$.sg.$.nom.",0.99],
-		["ī","iyo",".n.",".m.$.pl.$.nom.",0.99],
-		["ī","iye",".n.",".m.$.pl.$.acc.",0.99],
-		["ī","iyaṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["ī","ito",".n.",".m.$.sg.$.abl.",0.99],
-		["ī","i",".n.",".f.$.sg.$.nom.",0.99],
-		["ī","iyaṃ",".n.",".f.$.sg.$.acc.",0.99],
-		["ī","ito",".n.",".f.$.sg.$.abl.",0.99],
-		["ī","īto",".n.",".f.$.sg.$.abl.",0.99],
-		["ī","āyo",".n.",".f.$.pl.$.nom.",0.99],
-		["ī","āyo",".n.",".f.$.pl.$.nom.",0.99],
-		["ī","āyo",".n.",".f.$.pl.$.nom.",0.99],
-		["ī","inaṃ",".n.",".f.$.pl.$.gen.",0.99],
-		["ī","inaṃ",".n.",".f.$.pl.$.dat.",0.99],
-		["ī","īyanaṃ",".n.",".f.$.pl.$.gen.",0.99],
-		["ī","īyanaṃ",".n.",".f.$.pl.$.dat.",0.99],
-		["ī","iyanaṃ",".n.",".f.$.pl.$.gen.",0.99],
-		["ī","iyanaṃ",".n.",".f.$.pl.$.dat.",0.99],
-		["ī","isu",".n.",".f.$.pl.$.loc.",0.99],
-		["ar","ā",".n.",".m.$.sg.$.nom.",0.99],
-		["ar","ā",".n.",".m.$.sg.$.voc.",0.3],
-		["ar","a",".n.",".m.$.sg.$.voc.",0.3],
-		["ar","araṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["ar","āraṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["ar","u",".n.",".m.$.sg.$.dat.",0.99],
-		["ar","ussa",".n.",".m.$.sg.$.dat.",0.99],
-		["ar","uno",".n.",".m.$.sg.$.dat.",0.99],
-		["ar","u",".n.",".m.$.sg.$.gen.",0.99],
-		["ar","ussa",".n.",".m.$.sg.$.gen.",0.99],
-		["ar","uno",".n.",".m.$.sg.$.gen.",0.99],
-		["ar","arā",".n.",".m.$.sg.$.inst.",0.99],
-		["ar","ara",".n.",".m.$.sg.$.inst.",0.99],
-		["ar","āra",".n.",".m.$.sg.$.inst.",0.99],
-		["ar","ārā",".n.",".m.$.sg.$.inst.",0.99],
-		["ar","unā",".n.",".m.$.sg.$.inst.",0.99],
-		["ar","arā",".n.",".m.$.sg.$.abl.",0.99],
-		["ar","ara",".n.",".m.$.sg.$.abl.",0.99],
-		["ar","āra",".n.",".m.$.sg.$.abl.",0.99],
-		["ar","ārā",".n.",".m.$.sg.$.abl.",0.99],
-		["ar","unā",".n.",".m.$.sg.$.abl.",0.99],
-		["ar","ari",".n.",".m.$.sg.$.loc.",0.99],
-		["ar","āro",".n.",".m.$.pl.$.nom.",0.99],
-		["ar","ā",".n.",".m.$.pl.$.nom.",0.99],
-		["ar","āro",".n.",".m.$.pl.$.voc.",0.3],
-		["ar","ā",".n.",".m.$.pl.$.voc.",0.3],
-		["ar","āro",".n.",".m.$.pl.$.acc.",0.99],
-		["ar","āre",".n.",".m.$.pl.$.acc.",0.99],
-		["ar","ānaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["ar","ārānaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["ar","ūnaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["ar","ānaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["ar","ārānaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["ar","ūnaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["ar","ārehi",".n.",".m.$.pl.$.inst.",0.99],
-		["ar","ārebhi",".n.",".m.$.pl.$.inst.",0.99],
-		["ar","ārehi",".n.",".m.$.pl.$.abl.",0.99],
-		["ar","ārebhi",".n.",".m.$.pl.$.abl.",0.99],
-		["ar","āresu",".n.",".m.$.pl.$.loc.",0.99],
-		["ar","ūsu",".n.",".m.$.pl.$.loc.",0.99],
-		["ar","āyo",".n.",".m.$.sg.$.voc.",0.3],
-		["ar","iyo",".n.",".m.$.sg.$.voc.",0.3],
-		["an","ane",".n.",".m.$.sg.$.loc.",0.99],
-		["an","ā",".n.",".m.$.pl.$.voc.",0.3],
-		["an","ubhi",".n.",".m.$.pl.$.inst.",0.99],
-		["an","ūbhi",".n.",".m.$.pl.$.inst.",0.99],
-		["an","uhi",".n.",".m.$.pl.$.inst.",0.99],
-		["an","ūhi",".n.",".m.$.pl.$.inst.",0.99],
-		["an","ūnaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["an","ūnaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["an","esu",".n.",".m.$.pl.$.loc.",0.99],
-		["an","ūsu",".n.",".m.$.pl.$.loc.",0.99],
-		["an","usu",".n.",".m.$.pl.$.loc.",0.99],
-		["an","a",".n.",".nt.$.sg.$.nom.",0.99],
-		["an","a",".n.",".nt.$.sg.$.acc.",0.99],
-		["an","anā",".n.",".nt.$.sg.$.inst.",0.99],
-		["an","unā",".n.",".nt.$.sg.$.inst.",0.99],
-		["an","no",".n.",".nt.$.sg.$.dat.",0.99],
-		["an","unā",".n.",".nt.$.sg.$.abl.",0.99],
-		["an","no",".n.",".nt.$.sg.$.dat.",0.99],
-		["an","ani",".n.",".nt.$.sg.$.loc.",0.99],
-		["an","ā",".n.",".nt.$.pl.$.voc.",0.3],
-		["as","āni",".n.",".m.$.pl.$.nom.",0.99],
-		["as","ā",".n.",".m.$.pl.$.acc.",0.99],
-		["as","āni",".n.",".m.$.pl.$.acc.",0.99],
-		["as","āni",".n.",".m.$.pl.$.voc.",0.3],
-		["as","āni",".n.",".m.$.pl.$.nom.",0.99],
-		["as","ā",".n.",".m.$.pl.$.acc.",0.99],
-		["as","āni",".n.",".m.$.pl.$.acc.",0.99],
-		["as","āni",".n.",".m.$.pl.$.voc.",0.3],
-		["as","āni",".n.",".m.$.pl.$.nom.",0.99],
-		["as","ā",".n.",".m.$.pl.$.acc.",0.99],
-		["as","āni",".n.",".m.$.pl.$.acc.",0.99],
-		["as","āni",".n.",".m.$.pl.$.voc.",0.3],
-		["us","u",".n.",".m.$.sg.$.nom.",0.99],
-		["us","uṃ",".n.",".m.$.sg.$.nom.",0.99],
-		["us","u",".n.",".m.$.sg.$.voc.",0.3],
-		["us","uṃ",".n.",".m.$.sg.$.voc.",0.3],
-		["us","u",".n.",".m.$.sg.$.acc.",0.99],
-		["us","uṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["us","ussa",".n.",".m.$.sg.$.dat.",0.99],
-		["us","uno",".n.",".m.$.sg.$.dat.",0.99],
-		["us","ussa",".n.",".m.$.sg.$.gen.",0.99],
-		["us","uno",".n.",".m.$.sg.$.gen.",0.99],
-		["us","unā",".n.",".m.$.sg.$.inst.",0.99],
-		["us","usā",".n.",".m.$.sg.$.inst.",0.99],
-		["us","unā",".n.",".m.$.sg.$.abl.",0.99],
-		["us","usā",".n.",".m.$.sg.$.abl.",0.99],
-		["us","uni",".n.",".m.$.sg.$.loc.",0.99],
-		["us","usi",".n.",".m.$.sg.$.loc.",0.99],
-		["us","ū",".n.",".m.$.pl.$.nom.",0.99],
-		["us","ūni",".n.",".m.$.pl.$.nom.",0.99],
-		["us","ū",".n.",".m.$.pl.$.voc.",0.3],
-		["us","ūni",".n.",".m.$.pl.$.voc.",0.3],
-		["us","ū",".n.",".m.$.pl.$.acc.",0.99],
-		["us","ūni",".n.",".m.$.pl.$.acc.",0.99],
-		["us","ūnaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["us","ūsaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["us","ūnaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["us","ūsaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["us","ūhi",".n.",".m.$.pl.$.inst.",0.99],
-		["us","ūbhi",".n.",".m.$.pl.$.inst.",0.99],
-		["us","ūhi",".n.",".m.$.pl.$.abl.",0.99],
-		["us","ūbhi",".n.",".m.$.pl.$.abl.",0.99],
-		["us","ūsu",".n.",".m.$.pl.$.loc.",0.99],
-		["a","assā",".n.",".m.$.sg.$.gen.",0.99],
-		["a","assā",".n.",".m.$.sg.$.dat.",0.99],
-		["a","enā",".n.",".m.$.sg.$.inst.",0.99],
-		["a","amhī",".n.",".m.$.sg.$.loc.",0.99],
-		["a","ehī",".n.",".m.$.pl.$.inst.",0.99],
-		["a","ebhī",".n.",".m.$.pl.$.inst.",0.99],
-		["a","ehī",".n.",".m.$.pl.$.abl.",0.99],
-		["a","ebhī",".n.",".m.$.pl.$.abl.",0.99],
-		["a","esū",".n.",".m.$.pl.$.loc.",0.99],
-		["a","assā",".n.",".nt.$.sg.$.gen.",0.99],
-		["a","assā",".n.",".nt.$.sg.$.dat.",0.99],
-		["a","enā",".n.",".nt.$.sg.$.inst.",0.99],
-		["a","amhī",".n.",".nt.$.sg.$.loc.",0.99],
-		["a","ānī",".n.",".nt.$.pl.$.nom.",0.99],
-		["a","ānī",".n.",".nt.$.pl.$.voc.",0.3],
-		["a","ānī",".n.",".nt.$.pl.$.acc.",0.99],
-		["a","ehī",".n.",".nt.$.pl.$.inst.",0.99],
-		["a","ebhī",".n.",".nt.$.pl.$.inst.",0.99],
-		["a","ehī",".n.",".nt.$.pl.$.abl.",0.99],
-		["a","ebhī",".n.",".nt.$.pl.$.abl.",0.99],
-		["a","esū",".n.",".nt.$.pl.$.loc.",0.99],
-		["ā","āhī",".n.",".f.$.pl.$.inst.",0.99],
-		["ā","ābhī",".n.",".f.$.pl.$.inst.",0.99],
-		["ā","āhī",".n.",".f.$.pl.$.abl.",0.99],
-		["ā","ābhī",".n.",".f.$.pl.$.abl.",0.99],
-		["ā","āsū",".n.",".f.$.pl.$.loc.",0.99],
-		["i","issā",".n.",".m.$.sg.$.gen.",0.99],
-		["i","issā",".n.",".m.$.sg.$.dat.",0.99],
-		["i","imhī",".n.",".m.$.sg.$.loc.",0.99],
-		["i","īhī",".n.",".m.$.pl.$.inst.",0.99],
-		["i","ībhī",".n.",".m.$.pl.$.inst.",0.99],
-		["i","īhī",".n.",".m.$.pl.$.abl.",0.99],
-		["i","ībhī",".n.",".m.$.pl.$.abl.",0.99],
-		["i","īsū",".n.",".m.$.pl.$.loc.",0.99],
-		["i","assā",".n.",".nt.$.sg.$.gen.",0.99],
-		["i","assā",".n.",".nt.$.sg.$.dat.",0.99],
-		["i","imhī",".n.",".nt.$.sg.$.loc.",0.99],
-		["i","īnī",".n.",".nt.$.pl.$.nom.",0.99],
-		["i","īnī",".n.",".nt.$.pl.$.voc.",0.3],
-		["i","īnī",".n.",".nt.$.pl.$.acc.",0.99],
-		["i","īhī",".n.",".nt.$.pl.$.inst.",0.99],
-		["i","ībhī",".n.",".nt.$.pl.$.inst.",0.99],
-		["i","īhī",".n.",".nt.$.pl.$.abl.",0.99],
-		["i","ībhī",".n.",".nt.$.pl.$.abl.",0.99],
-		["i","īsū",".n.",".nt.$.pl.$.loc.",0.99],
-		["i","īhī",".n.",".f.$.pl.$.inst.",0.99],
-		["i","ībhī",".n.",".f.$.pl.$.inst.",0.99],
-		["i","īhī",".n.",".f.$.pl.$.abl.",0.99],
-		["i","ībhī",".n.",".f.$.pl.$.abl.",0.99],
-		["i","īsū",".n.",".f.$.pl.$.loc.",0.99],
-		["ī","issā",".n.",".m.$.sg.$.gen.",0.99],
-		["in","issā",".n.",".m.$.sg.$.gen.",0.99],
-		["ī","issā",".n.",".m.$.sg.$.dat.",0.99],
-		["in","issā",".n.",".m.$.sg.$.dat.",0.99],
-		["ī","imhī",".n.",".m.$.sg.$.loc.",0.99],
-		["in","imhī",".n.",".m.$.sg.$.loc.",0.99],
-		["ī","īhī",".n.",".m.$.pl.$.inst.",0.99],
-		["ī","ībhī",".n.",".m.$.pl.$.inst.",0.99],
-		["in","īhī",".n.",".m.$.pl.$.inst.",0.99],
-		["in","ībhī",".n.",".m.$.pl.$.inst.",0.99],
-		["ī","īhī",".n.",".m.$.pl.$.abl.",0.99],
-		["ī","ībhī",".n.",".m.$.pl.$.abl.",0.99],
-		["in","īhī",".n.",".m.$.pl.$.abl.",0.99],
-		["in","ībhī",".n.",".m.$.pl.$.abl.",0.99],
-		["ī","īsū",".n.",".m.$.pl.$.loc.",0.99],
-		["in","īsū",".n.",".m.$.pl.$.loc.",0.99],
-		["ī","īhī",".n.",".f.$.pl.$.inst.",0.99],
-		["ī","ībhī",".n.",".f.$.pl.$.inst.",0.99],
-		["ī","īhī",".n.",".f.$.pl.$.abl.",0.99],
-		["ī","ībhī",".n.",".f.$.pl.$.abl.",0.99],
-		["ī","īsū",".n.",".f.$.pl.$.loc.",0.99],
-		["u","ussā",".n.",".m.$.sg.$.gen.",0.99],
-		["u","ussā",".n.",".m.$.sg.$.dat.",0.99],
-		["u","umhī",".n.",".m.$.sg.$.loc.",0.99],
-		["u","ūhī",".n.",".m.$.pl.$.inst.",0.99],
-		["u","ūbhī",".n.",".m.$.pl.$.inst.",0.99],
-		["u","ūhī",".n.",".m.$.pl.$.abl.",0.99],
-		["u","ūbhī",".n.",".m.$.pl.$.abl.",0.99],
-		["u","ūsū",".n.",".m.$.pl.$.loc.",0.99],
-		["u","ussā",".n.",".nt.$.sg.$.gen.",0.99],
-		["u","ussā",".n.",".nt.$.sg.$.dat.",0.99],
-		["u","umhī",".n.",".nt.$.sg.$.loc.",0.99],
-		["u","ūnī",".n.",".nt.$.pl.$.nom.",0.99],
-		["u","ūnī",".n.",".nt.$.pl.$.voc.",0.3],
-		["u","ūnī",".n.",".nt.$.pl.$.acc.",0.99],
-		["u","ūhī",".n.",".nt.$.pl.$.inst.",0.99],
-		["u","ūbhī",".n.",".nt.$.pl.$.inst.",0.99],
-		["u","ūhī",".n.",".nt.$.pl.$.abl.",0.99],
-		["u","ūbhī",".n.",".nt.$.pl.$.abl.",0.99],
-		["u","ūsū",".n.",".nt.$.pl.$.loc.",0.99],
-		["u","ūhī",".n.",".f.$.pl.$.inst.",0.99],
-		["u","ūbhī",".n.",".f.$.pl.$.inst.",0.99],
-		["u","ūhī",".n.",".f.$.pl.$.abl.",0.99],
-		["u","ūbhī",".n.",".f.$.pl.$.abl.",0.99],
-		["u","ūsū",".n.",".f.$.pl.$.loc.",0.99],
-		["ū","ussā",".n.",".m.$.sg.$.gen.",0.99],
-		["ū","ussā",".n.",".m.$.sg.$.dat.",0.99],
-		["ū","umhī",".n.",".m.$.sg.$.loc.",0.99],
-		["ū","ūhī",".n.",".m.$.pl.$.inst.",0.99],
-		["ū","ūbhī",".n.",".m.$.pl.$.inst.",0.99],
-		["ū","ūhī",".n.",".m.$.pl.$.abl.",0.99],
-		["ū","ūbhī",".n.",".m.$.pl.$.abl.",0.99],
-		["ū","ūsū",".n.",".m.$.pl.$.loc.",0.99],
-		["ū","ūhī",".n.",".f.$.pl.$.inst.",0.99],
-		["ū","ūbhī",".n.",".f.$.pl.$.inst.",0.99],
-		["ū","ūhī",".n.",".f.$.pl.$.abl.",0.99],
-		["ū","ūbhī",".n.",".f.$.pl.$.abl.",0.99],
-		["ū","ūsū",".n.",".f.$.pl.$.loc.",0.99],
-		["as","assā",".n.",".m.$.sg.$.gen.",0.99],
-		["o","assā",".n.",".m.$.sg.$.gen.",0.99],
-		["as","assā",".n.",".m.$.sg.$.dat.",0.99],
-		["o","assā",".n.",".m.$.sg.$.dat.",0.99],
-		["as","enā",".n.",".m.$.sg.$.inst.",0.99],
-		["o","enā",".n.",".m.$.sg.$.inst.",0.99],
-		["as","asī",".n.",".m.$.sg.$.loc.",0.99],
-		["as","amhī",".n.",".m.$.sg.$.loc.",0.99],
-		["o","asī",".n.",".m.$.sg.$.loc.",0.99],
-		["o","amhī",".n.",".m.$.sg.$.loc.",0.99],
-		["as","ehī",".n.",".m.$.pl.$.inst.",0.99],
-		["as","ebhī",".n.",".m.$.pl.$.inst.",0.99],
-		["o","ehī",".n.",".m.$.pl.$.inst.",0.99],
-		["o","ebhī",".n.",".m.$.pl.$.inst.",0.99],
-		["as","ehī",".n.",".m.$.pl.$.abl.",0.99],
-		["as","ebhī",".n.",".m.$.pl.$.abl.",0.99],
-		["o","ehī",".n.",".m.$.pl.$.abl.",0.99],
-		["o","ebhī",".n.",".m.$.pl.$.abl.",0.99],
-		["as","esū",".n.",".m.$.pl.$.loc.",0.99],
-		["o","esū",".n.",".m.$.pl.$.loc.",0.99],
-		["as","assā",".n.",".nt.$.sg.$.gen.",0.99],
-		["o","assā",".n.",".nt.$.sg.$.gen.",0.99],
-		["as","assā",".n.",".nt.$.sg.$.dat.",0.99],
-		["o","assā",".n.",".nt.$.sg.$.dat.",0.99],
-		["as","enā",".n.",".nt.$.sg.$.inst.",0.99],
-		["o","enā",".n.",".nt.$.sg.$.inst.",0.99],
-		["as","asī",".n.",".nt.$.sg.$.loc.",0.99],
-		["as","amhī",".n.",".nt.$.sg.$.loc.",0.99],
-		["o","asī",".n.",".nt.$.sg.$.loc.",0.99],
-		["o","amhī",".n.",".nt.$.sg.$.loc.",0.99],
-		["as","ehī",".n.",".nt.$.pl.$.inst.",0.99],
-		["as","ebhī",".n.",".nt.$.pl.$.inst.",0.99],
-		["o","ehī",".n.",".nt.$.pl.$.inst.",0.99],
-		["o","ebhī",".n.",".nt.$.pl.$.inst.",0.99],
-		["as","ehī",".n.",".nt.$.pl.$.abl.",0.99],
-		["as","ebhī",".n.",".nt.$.pl.$.abl.",0.99],
-		["o","ehī",".n.",".nt.$.pl.$.abl.",0.99],
-		["o","ebhī",".n.",".nt.$.pl.$.abl.",0.99],
-		["as","esū",".n.",".nt.$.pl.$.loc.",0.99],
-		["o","esū",".n.",".nt.$.pl.$.loc.",0.99],
-		["an","assā",".n.",".m.$.sg.$.gen.",0.99],
-		["an","assā",".n.",".m.$.sg.$.dat.",0.99],
-		["an","enā",".n.",".m.$.sg.$.inst.",0.99],
-		["an","anī",".n.",".m.$.sg.$.loc.",0.99],
-		["an","amhī",".n.",".m.$.sg.$.loc.",0.99],
-		["an","anehī",".n.",".m.$.pl.$.inst.",0.99],
-		["an","anebhī",".n.",".m.$.pl.$.inst.",0.99],
-		["an","anehī",".n.",".m.$.pl.$.abl.",0.99],
-		["an","anebhī",".n.",".m.$.pl.$.abl.",0.99],
-		["an","anesū",".n.",".m.$.pl.$.loc.",0.99],
-		["an","assā",".n.",".nt.$.sg.$.gen.",0.99],
-		["an","assā",".n.",".nt.$.sg.$.dat.",0.99],
-		["an","enā",".n.",".nt.$.sg.$.inst.",0.99],
-		["an","amhī",".n.",".nt.$.sg.$.loc.",0.99],
-		["an","ānī",".n.",".nt.$.pl.$.nom.",0.99],
-		["an","ānī",".n.",".nt.$.pl.$.voc.",0.3],
-		["an","ānī",".n.",".nt.$.pl.$.acc.",0.99],
-		["an","ehī",".n.",".nt.$.pl.$.inst.",0.99],
-		["an","ebhī",".n.",".nt.$.pl.$.inst.",0.99],
-		["an","ehī",".n.",".nt.$.pl.$.abl.",0.99],
-		["an","ebhī",".n.",".nt.$.pl.$.abl.",0.99],
-		["an","esū",".n.",".nt.$.pl.$.loc.",0.99],
-		["ar","assā",".n.",".f.$.sg.$.gen.",0.99],
-		["ar","assā",".n.",".f.$.sg.$.dat.",0.99],
-		["ar","enā",".n.",".f.$.sg.$.inst.",0.99],
-		["ar","amhī",".n.",".f.$.sg.$.loc.",0.99],
-		["ar","ehī",".n.",".f.$.pl.$.inst.",0.99],
-		["ar","āhī",".n.",".f.$.pl.$.inst.",0.99],
-		["ar","ehī",".n.",".f.$.pl.$.abl.",0.99],
-		["ar","āhī",".n.",".f.$.pl.$.abl.",0.99],
-		["ar","esū",".n.",".f.$.pl.$.loc.",0.99],
-		["ar","āsū",".n.",".f.$.pl.$.loc.",0.99],
-		["ar","assā",".n.",".nt.$.sg.$.gen.",0.99],
-		["ar","assā",".n.",".nt.$.sg.$.dat.",0.99],
-		["ar","enā",".n.",".nt.$.sg.$.inst.",0.99],
-		["ar","amhī",".n.",".nt.$.sg.$.loc.",0.99],
-		["ar","ehī",".n.",".nt.$.pl.$.inst.",0.99],
-		["ar","āhī",".n.",".nt.$.pl.$.inst.",0.99],
-		["ar","ehī",".n.",".nt.$.pl.$.abl.",0.99],
-		["ar","āhī",".n.",".nt.$.pl.$.abl.",0.99],
-		["ar","esū",".n.",".nt.$.pl.$.loc.",0.99],
-		["ar","āsū",".n.",".nt.$.pl.$.loc.",0.99],
-		["a","asī",".n.",".m.$.sg.$.loc.",0.99],
-		["a","asī",".n.",".nt.$.sg.$.loc.",0.99],
-		["i","ihī",".n.",".m.$.pl.$.inst.",0.99],
-		["i","ibhī",".n.",".m.$.pl.$.inst.",0.99],
-		["i","ihī",".n.",".m.$.pl.$.abl.",0.99],
-		["i","ibhī",".n.",".m.$.pl.$.abl.",0.99],
-		["i","isū",".n.",".m.$.pl.$.loc.",0.99],
-		["i","ihī",".n.",".nt.$.pl.$.inst.",0.99],
-		["i","ibhī",".n.",".nt.$.pl.$.inst.",0.99],
-		["i","ihī",".n.",".nt.$.pl.$.abl.",0.99],
-		["i","ibhī",".n.",".nt.$.pl.$.abl.",0.99],
-		["i","isū",".n.",".nt.$.pl.$.loc.",0.99],
-		["ī","īsū",".n.",".m.$.pl.$.loc.",0.99],
-		["ī","isū",".n.",".f.$.pl.$.loc.",0.99],
-		["ar","ussā",".n.",".m.$.sg.$.dat.",0.99],
-		["ar","ussā",".n.",".m.$.sg.$.gen.",0.99],
-		["ar","arī",".n.",".m.$.sg.$.loc.",0.99],
-		["ar","ārehī",".n.",".m.$.pl.$.inst.",0.99],
-		["ar","ārebhī",".n.",".m.$.pl.$.inst.",0.99],
-		["ar","ārehī",".n.",".m.$.pl.$.abl.",0.99],
-		["ar","ārebhī",".n.",".m.$.pl.$.abl.",0.99],
-		["ar","āresū",".n.",".m.$.pl.$.loc.",0.99],
-		["ar","ūsū",".n.",".m.$.pl.$.loc.",0.99],
-		["an","ubhī",".n.",".m.$.pl.$.inst.",0.99],
-		["an","ūbhī",".n.",".m.$.pl.$.inst.",0.99],
-		["an","uhī",".n.",".m.$.pl.$.inst.",0.99],
-		["an","ūhī",".n.",".m.$.pl.$.inst.",0.99],
-		["an","esū",".n.",".m.$.pl.$.loc.",0.99],
-		["an","ūsū",".n.",".m.$.pl.$.loc.",0.99],
-		["an","usū",".n.",".m.$.pl.$.loc.",0.99],
-		["an","anī",".n.",".nt.$.sg.$.loc.",0.99],
-		["as","ānī",".n.",".m.$.pl.$.nom.",0.99],
-		["as","ānī",".n.",".m.$.pl.$.acc.",0.99],
-		["as","ānī",".n.",".m.$.pl.$.voc.",0.3],
-		["as","ānī",".n.",".m.$.pl.$.nom.",0.99],
-		["as","ānī",".n.",".m.$.pl.$.acc.",0.99],
-		["as","ānī",".n.",".m.$.pl.$.voc.",0.3],
-		["as","ānī",".n.",".m.$.pl.$.nom.",0.99],
-		["as","ānī",".n.",".m.$.pl.$.acc.",0.99],
-		["as","ānī",".n.",".m.$.pl.$.voc.",0.3],
-		["us","ussā",".n.",".m.$.sg.$.dat.",0.99],
-		["us","ussā",".n.",".m.$.sg.$.gen.",0.99],
-		["us","unī",".n.",".m.$.sg.$.loc.",0.99],
-		["us","usī",".n.",".m.$.sg.$.loc.",0.99],
-		["us","ūnī",".n.",".m.$.pl.$.nom.",0.99],
-		["us","ūnī",".n.",".m.$.pl.$.voc.",0.3],
-		["us","ūnī",".n.",".m.$.pl.$.acc.",0.99],
-		["us","ūhī",".n.",".m.$.pl.$.inst.",0.99],
-		["us","ūbhī",".n.",".m.$.pl.$.inst.",0.99],
-		["us","ūhī",".n.",".m.$.pl.$.abl.",0.99],
-		["us","ūbhī",".n.",".m.$.pl.$.abl.",0.99],
-		["us","ūsū",".n.",".m.$.pl.$.loc.",0.99],
-		["ant","ā",".n.",".m.$.pl.$.nom.",0.99],
-		["ant","ā",".n.",".m.$.pl.$.voc.",0.3],
-		["ant","ā",".n.",".m.$.sg.$.nom.",0.99],
-		["ant","a",".n.",".m.$.sg.$.voc.",0.3],
-		["ant","ā",".n.",".m.$.sg.$.voc.",0.3],
-		["ant","ā",".n.",".nt.$.pl.$.nom.",0.99],
-		["ant","ā",".n.",".nt.$.pl.$.voc.",0.3],
-		["ant","a",".n.",".nt.$.sg.$.voc.",0.3],
-		["ant","ā",".n.",".nt.$.sg.$.voc.",0.3],
-		["ant","ā",".n.",".m.$.sg.$.voc.",0.3],
-		["ant","ā",".n.",".nt.$.sg.$.voc.",0.3],
-		["ant","aṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["ant","aṃ",".n.",".nt.$.sg.$.acc.",0.99],
-		["ant","aṃ",".n.",".nt.$.sg.$.nom.",0.99],
-		["ant","aṃ",".n.",".m.$.sg.$.nom.",0.99],
-		["ant","aṃ",".n.",".m.$.sg.$.voc.",0.3],
-		["ant","aṃ",".n.",".nt.$.sg.$.voc.",0.3],
-		["ant","aṃ",".n.",".m.$.sg.$.voc.",0.3],
-		["ant","aṃ",".n.",".nt.$.sg.$.voc.",0.3],
-		["ant","ānaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["ant","ānaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["ant","e",".n.",".m.$.pl.$.acc.",0.99],
-		["ant","ebhi",".n.",".m.$.pl.$.abl.",0.99],
-		["ant","ebhi",".n.",".m.$.pl.$.inst.",0.99],
-		["ant","ehi",".n.",".m.$.pl.$.abl.",0.99],
-		["ant","ehi",".n.",".m.$.pl.$.inst.",0.99],
-		["ant","esu",".n.",".m.$.pl.$.loc.",0.99],
-		["anta","ā",".n.",".m.$.pl.$.nom.",0.99],
-		["anta","ā",".n.",".m.$.pl.$.voc.",0.3],
-		["anta","ā",".n.",".m.$.sg.$.nom.",0.99],
-		["anta","a",".n.",".m.$.sg.$.voc.",0.3],
-		["anta","ā",".n.",".m.$.sg.$.voc.",0.3],
-		["anta","ā",".n.",".nt.$.pl.$.nom.",0.99],
-		["anta","ā",".n.",".nt.$.pl.$.voc.",0.3],
-		["anta","a",".n.",".nt.$.sg.$.voc.",0.3],
-		["anta","ā",".n.",".nt.$.sg.$.voc.",0.3],
-		["anta","ā",".n.",".m.$.sg.$.voc.",0.3],
-		["anta","ā",".n.",".nt.$.sg.$.voc.",0.3],
-		["anta","aṃ",".n.",".m.$.sg.$.acc.",0.99],
-		["anta","aṃ",".n.",".nt.$.sg.$.acc.",0.99],
-		["anta","aṃ",".n.",".nt.$.sg.$.nom.",0.99],
-		["anta","aṃ",".n.",".m.$.sg.$.nom.",0.99],
-		["anta","aṃ",".n.",".m.$.sg.$.voc.",0.3],
-		["anta","aṃ",".n.",".nt.$.sg.$.voc.",0.3],
-		["anta","aṃ",".n.",".m.$.sg.$.voc.",0.3],
-		["anta","aṃ",".n.",".nt.$.sg.$.voc.",0.3],
-		["anta","ānaṃ",".n.",".m.$.pl.$.dat.",0.99],
-		["anta","ānaṃ",".n.",".m.$.pl.$.gen.",0.99],
-		["anta","e",".n.",".m.$.pl.$.acc.",0.99],
-		["anta","ebhi",".n.",".m.$.pl.$.abl.",0.99],
-		["anta","ebhi",".n.",".m.$.pl.$.inst.",0.99],
-		["anta","ehi",".n.",".m.$.pl.$.abl.",0.99],
-		["anta","ehi",".n.",".m.$.pl.$.inst.",0.99],
-		["anta","esu",".n.",".m.$.pl.$.loc.",0.99],
-		["ti","ti",".v.",".3p.$.sg.$.pres.",0.99],
-		["ti","nti",".v.",".3p.$.pl.$.pres.",0.99],
-		["ti","te",".v.",".3p.$.sg.$.pres.",0.99],
-		["ti","nte",".v.",".3p.$.pl.$.pres.",0.99],
-		["ti","re",".v.",".3p.$.pl.$.pres.",0.99],
-		["ti","ssati",".v.",".3p.$.sg.$.fut.",0.99],
-		["ti","ssanti",".v.",".3p.$.pl.$.fut.",0.99],
-		["ti","ssate",".v.",".3p.$.sg.$.fut.",0.99],
-		["ti","ssante",".v.",".3p.$.pl.$.fut.",0.99],
-		["ti","ssare",".v.",".3p.$.pl.$.fut.",0.99],
-		["ti","tu",".v.",".3p.$.sg.$.imp.",0.99],
-		["ti","ntu",".v.",".3p.$.pl.$.imp.",0.99],
-		["ti","taṃ",".v.",".3p.$.sg.$.imp.",0.99],
-		["ti","ntaṃ",".v.",".3p.$.pl.$.imp.",0.99],
-		["ti","sā",".v.",".3p.$.sg.$.cond.",0.99],
-		["ti","ssa",".v.",".3p.$.sg.$.cond.",0.99],
-		["ti","ssati",".v.",".3p.$.sg.$.cond.",0.99],
-		["ti","ssaṃsu",".v.",".3p.$.pl.$.cond.",0.99],
-		["ti","ssatha",".v.",".3p.$.sg.$.cond.",0.99],
-		["ti","ssiṃsu",".v.",".3p.$.pl.$.cond.",0.99],
-		["ti","si",".v.",".3p.$.sg.$.aor.",0.99],
-		["ti","sī",".v.",".3p.$.sg.$.aor.",0.99],
-		["ti","sā",".v.",".3p.$.sg.$.aor.",0.99],
-		["ti","siṃsu",".v.",".3p.$.pl.$.aor.",0.99],
-		["ti","sṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["ti","suṃū",".v.",".3p.$.pl.$.aor.",0.99],
-		["ti","sā",".v.",".3p.$.sg.$.aor.",0.99],
-		["ti","sa",".v.",".3p.$.sg.$.aor.",0.99],
-		["ti","stthuṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["ti","satthuṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["ti","mi",".v.",".1p.$.sg.$.pres.",0.99],
-		["ti","ma",".v.",".1p.$.pl.$.pres.",0.99],
-		["ti","e",".v.",".1p.$.sg.$.pres.",0.99],
-		["ti","mhe",".v.",".1p.$.pl.$.pres.",0.99],
-		["ti","mahe",".v.",".1p.$.pl.$.pres.",0.99],
-		["ti","mha",".v.",".1p.$.pl.$.pres.",0.99],
-		["ti","mase",".v.",".1p.$.pl.$.pres.",0.99],
-		["ti","mhase",".v.",".1p.$.pl.$.pres.",0.99],
-		["ti","ssāmi",".v.",".1p.$.sg.$.fut.",0.99],
-		["ti","ssāma",".v.",".1p.$.pl.$.fut.",0.99],
-		["ti","ssaṃ",".v.",".1p.$.sg.$.fut.",0.99],
-		["ti","ssāmhe",".v.",".1p.$.pl.$.fut.",0.99],
-		["ti","ssāmase",".v.",".1p.$.pl.$.fut.",0.99],
-		["ti","mi",".v.",".1p.$.sg.$.imp.",0.99],
-		["ti","ma",".v.",".1p.$.pl.$.imp.",0.99],
-		["ti","ssa",".v.",".1p.$.sg.$.cond.",0.99],
-		["ti","ssamhā",".v.",".1p.$.pl.$.cond.",0.99],
-		["ti","ssaṃ",".v.",".1p.$.sg.$.cond.",0.99],
-		["ti","ssāmhase",".v.",".1p.$.pl.$.cond.",0.99],
-		["ti","siṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["ti","saṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["ti","sṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["ti","sa",".v.",".1p.$.sg.$.aor.",0.99],
-		["ti","sā",".v.",".1p.$.sg.$.aor.",0.99],
-		["ti","simha",".v.",".1p.$.pl.$.aor.",0.99],
-		["ti","simhā",".v.",".1p.$.pl.$.aor.",0.99],
-		["ti","sa",".v.",".1p.$.sg.$.aor.",0.99],
-		["ti","simhe",".v.",".1p.$.pl.$.aor.",0.99],
-		["ti","si",".v.",".2p.$.sg.$.pres.",0.99],
-		["ti","tha",".v.",".2p.$.pl.$.pres.",0.99],
-		["ti","se",".v.",".2p.$.sg.$.pres.",0.99],
-		["ti","vhe",".v.",".2p.$.pl.$.pres.",0.99],
-		["ti","ssasi",".v.",".2p.$.sg.$.fut.",0.99],
-		["ti","ssatha",".v.",".2p.$.pl.$.fut.",0.99],
-		["ti","ssase",".v.",".2p.$.sg.$.fut.",0.99],
-		["ti","ssavhe",".v.",".2p.$.pl.$.fut.",0.99],
-		["ti","hi",".v.",".2p.$.sg.$.imp.",0.99],
-		["ti","ta",".v.",".2p.$.pl.$.imp.",0.99],
-		["ti","ssu",".v.",".2p.$.sg.$.imp.",0.99],
-		["ti","vho",".v.",".2p.$.pl.$.imp.",0.99],
-		["ti","se",".v.",".2p.$.sg.$.cond.",0.99],
-		["ti","ssa",".v.",".2p.$.sg.$.cond.",0.99],
-		["ti","ssasi",".v.",".2p.$.sg.$.cond.",0.99],
-		["ti","ssatha",".v.",".2p.$.pl.$.cond.",0.99],
-		["ti","ssase",".v.",".2p.$.sg.$.cond.",0.99],
-		["ti","ssavhe",".v.",".2p.$.pl.$.cond.",0.99],
-		["ti","si",".v.",".2p.$.sg.$.aor.",0.99],
-		["ti","so",".v.",".2p.$.sg.$.aor.",0.99],
-		["ti","sā",".v.",".2p.$.sg.$.aor.",0.99],
-		["ti","sttha",".v.",".2p.$.pl.$.aor.",0.99],
-		["ti","sse",".v.",".2p.$.sg.$.aor.",0.99],
-		["ti","svhaṃ",".v.",".2p.$.pl.$.aor.",0.99],
-		["ti","eyya",".v.",".3p.$.sg.$.opt.",0.99],
-		["ati","eyyuṃ",".v.",".3p.$.pl.$.opt.",0.99],
-		["ati","etha",".v.",".3p.$.sg.$.opt.",0.99],
-		["ati","eraṃ",".v.",".3p.$.pl.$.opt.",0.99],
-		["ati","issati",".v.",".3p.$.sg.$.fut.",0.99],
-		["ati","issanti",".v.",".3p.$.pl.$.fut.",0.99],
-		["ati","issate",".v.",".3p.$.sg.$.fut.",0.99],
-		["ati","issante",".v.",".3p.$.pl.$.fut.",0.99],
-		["ati","issare",".v.",".3p.$.pl.$.fut.",0.99],
-		["ati","i",".v.",".3p.$.sg.$.aor.",0.99],
-		["ati","ī",".v.",".3p.$.sg.$.aor.",0.99],
-		["ati","ā",".v.",".3p.$.sg.$.aor.",0.99],
-		["ati","iṃsu",".v.",".3p.$.pl.$.aor.",0.99],
-		["ati","ṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["ati","uṃū",".v.",".3p.$.pl.$.aor.",0.99],
-		["ati","ā",".v.",".3p.$.sg.$.aor.",0.99],
-		["ati","a",".v.",".3p.$.sg.$.aor.",0.99],
-		["ati","tthuṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["ati","atthuṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["ati","āmi",".v.",".1p.$.sg.$.pres.",0.99],
-		["ati","āma",".v.",".1p.$.pl.$.pres.",0.99],
-		["ati","e",".v.",".1p.$.sg.$.imp.",0.99],
-		["ati","āmase",".v.",".1p.$.pl.$.imp.",0.99],
-		["ati","eyyāmi",".v.",".1p.$.sg.$.opt.",0.99],
-		["ati","eyyāma",".v.",".1p.$.pl.$.opt.",0.99],
-		["ati","eyyaṃ",".v.",".1p.$.sg.$.opt.",0.99],
-		["ati","eyyāmhe",".v.",".1p.$.pl.$.opt.",0.99],
-		["ati","issāmi",".v.",".1p.$.sg.$.fut.",0.99],
-		["ati","issāma",".v.",".1p.$.pl.$.fut.",0.99],
-		["ati","issaṃ",".v.",".1p.$.sg.$.fut.",0.99],
-		["ati","issāmhe",".v.",".1p.$.pl.$.fut.",0.99],
-		["ati","issāmase",".v.",".1p.$.pl.$.fut.",0.99],
-		["ati","iṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["ati","aṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["ati","ṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["ati","a",".v.",".1p.$.sg.$.aor.",0.99],
-		["ati","ā",".v.",".1p.$.sg.$.aor.",0.99],
-		["ati","imha",".v.",".1p.$.pl.$.aor.",0.99],
-		["ati","imhā",".v.",".1p.$.pl.$.aor.",0.99],
-		["ati","a",".v.",".1p.$.sg.$.aor.",0.99],
-		["ati","imhe",".v.",".1p.$.pl.$.aor.",0.99],
-		["ati","eyyāsi",".v.",".2p.$.sg.$.opt.",0.99],
-		["ati","eyyātha",".v.",".2p.$.pl.$.opt.",0.99],
-		["ati","etho",".v.",".2p.$.sg.$.opt.",0.99],
-		["ati","eyyavho",".v.",".2p.$.pl.$.opt.",0.99],
-		["ati","issasi",".v.",".2p.$.sg.$.fut.",0.99],
-		["ati","issatha",".v.",".2p.$.pl.$.fut.",0.99],
-		["ati","issase",".v.",".2p.$.sg.$.fut.",0.99],
-		["ati","issavhe",".v.",".2p.$.pl.$.fut.",0.99],
-		["ati","i",".v.",".2p.$.sg.$.aor.",0.99],
-		["ati","o",".v.",".2p.$.sg.$.aor.",0.99],
-		["ati","ā",".v.",".2p.$.sg.$.aor.",0.99],
-		["ati","ttha",".v.",".2p.$.pl.$.aor.",0.99],
-		["ati","se",".v.",".2p.$.sg.$.aor.",0.99],
-		["ati","vhaṃ",".v.",".2p.$.pl.$.aor.",0.99],
-		["āti","etha",".v.",".3p.$.sg.$.opt.",0.99],
-		["āti","eraṃ",".v.",".3p.$.pl.$.opt.",0.99],
-		["āti","issati",".v.",".3p.$.sg.$.fut.",0.99],
-		["āti","issanti",".v.",".3p.$.pl.$.fut.",0.99],
-		["āti","issate",".v.",".3p.$.sg.$.fut.",0.99],
-		["āti","issante",".v.",".3p.$.pl.$.fut.",0.99],
-		["āti","issare",".v.",".3p.$.pl.$.fut.",0.99],
-		["āti","i",".v.",".3p.$.sg.$.aor.",0.99],
-		["āti","ī",".v.",".3p.$.sg.$.aor.",0.99],
-		["āti","ā",".v.",".3p.$.sg.$.aor.",0.99],
-		["āti","iṃsu",".v.",".3p.$.pl.$.aor.",0.99],
-		["āti","ṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["āti","uṃū",".v.",".3p.$.pl.$.aor.",0.99],
-		["āti","ā",".v.",".3p.$.sg.$.aor.",0.99],
-		["āti","a",".v.",".3p.$.sg.$.aor.",0.99],
-		["āti","tthuṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["āti","atthuṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["āti","e",".v.",".1p.$.sg.$.imp.",0.99],
-		["āti","āmase",".v.",".1p.$.pl.$.imp.",0.99],
-		["āti","eyyuṃ",".v.",".3p.$.pl.$.opt.",0.99],
-		["āti","eyyāmi",".v.",".1p.$.sg.$.opt.",0.99],
-		["āti","eyyāma",".v.",".1p.$.pl.$.opt.",0.99],
-		["āti","eyyaṃ",".v.",".1p.$.sg.$.opt.",0.99],
-		["āti","eyyāmhe",".v.",".1p.$.pl.$.opt.",0.99],
-		["āti","issāmi",".v.",".1p.$.sg.$.fut.",0.99],
-		["āti","issāma",".v.",".1p.$.pl.$.fut.",0.99],
-		["āti","issaṃ",".v.",".1p.$.sg.$.fut.",0.99],
-		["āti","issāmhe",".v.",".1p.$.pl.$.fut.",0.99],
-		["āti","issāmase",".v.",".1p.$.pl.$.fut.",0.99],
-		["āti","iṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["āti","aṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["āti","ṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["āti","a",".v.",".1p.$.sg.$.aor.",0.99],
-		["āti","ā",".v.",".1p.$.sg.$.aor.",0.99],
-		["āti","imha",".v.",".1p.$.pl.$.aor.",0.99],
-		["āti","imhā",".v.",".1p.$.pl.$.aor.",0.99],
-		["āti","a",".v.",".1p.$.sg.$.aor.",0.99],
-		["āti","imhe",".v.",".1p.$.pl.$.aor.",0.99],
-		["āti","eyyāsi",".v.",".2p.$.sg.$.opt.",0.99],
-		["āti","eyyātha",".v.",".2p.$.pl.$.opt.",0.99],
-		["āti","etho",".v.",".2p.$.sg.$.opt.",0.99],
-		["āti","eyyavho",".v.",".2p.$.pl.$.opt.",0.99],
-		["āti","issasi",".v.",".2p.$.sg.$.fut.",0.99],
-		["āti","issatha",".v.",".2p.$.pl.$.fut.",0.99],
-		["āti","issase",".v.",".2p.$.sg.$.fut.",0.99],
-		["āti","issavhe",".v.",".2p.$.pl.$.fut.",0.99],
-		["āti","i",".v.",".2p.$.sg.$.aor.",0.99],
-		["āti","o",".v.",".2p.$.sg.$.aor.",0.99],
-		["āti","ā",".v.",".2p.$.sg.$.aor.",0.99],
-		["āti","ttha",".v.",".2p.$.pl.$.aor.",0.99],
-		["āti","se",".v.",".2p.$.sg.$.aor.",0.99],
-		["āti","vhaṃ",".v.",".2p.$.pl.$.aor.",0.99],
-		["eti","etha",".v.",".3p.$.sg.$.opt.",0.99],
-		["eti","eraṃ",".v.",".3p.$.pl.$.opt.",0.99],
-		["eti","issati",".v.",".3p.$.sg.$.fut.",0.99],
-		["eti","issanti",".v.",".3p.$.pl.$.fut.",0.99],
-		["eti","issate",".v.",".3p.$.sg.$.fut.",0.99],
-		["eti","issante",".v.",".3p.$.pl.$.fut.",0.99],
-		["eti","issare",".v.",".3p.$.pl.$.fut.",0.99],
-		["eti","i",".v.",".3p.$.sg.$.aor.",0.99],
-		["eti","ī",".v.",".3p.$.sg.$.aor.",0.99],
-		["eti","ā",".v.",".3p.$.sg.$.aor.",0.99],
-		["eti","iṃsu",".v.",".3p.$.pl.$.aor.",0.99],
-		["eti","ṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["eti","uṃū",".v.",".3p.$.pl.$.aor.",0.99],
-		["eti","ā",".v.",".3p.$.sg.$.aor.",0.99],
-		["eti","a",".v.",".3p.$.sg.$.aor.",0.99],
-		["eti","tthuṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["eti","atthuṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["eti","e",".v.",".1p.$.sg.$.imp.",0.99],
-		["eti","āmase",".v.",".1p.$.pl.$.imp.",0.99],
-		["eti","eyyāmi",".v.",".1p.$.sg.$.opt.",0.99],
-		["eti","eyyuṃ",".v.",".3p.$.pl.$.opt.",0.99],
-		["eti","eyyāma",".v.",".1p.$.pl.$.opt.",0.99],
-		["eti","eyyaṃ",".v.",".1p.$.sg.$.opt.",0.99],
-		["eti","eyyāmhe",".v.",".1p.$.pl.$.opt.",0.99],
-		["eti","issāmi",".v.",".1p.$.sg.$.fut.",0.99],
-		["eti","issāma",".v.",".1p.$.pl.$.fut.",0.99],
-		["eti","issaṃ",".v.",".1p.$.sg.$.fut.",0.99],
-		["eti","issāmhe",".v.",".1p.$.pl.$.fut.",0.99],
-		["eti","issāmase",".v.",".1p.$.pl.$.fut.",0.99],
-		["eti","iṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["eti","aṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["eti","ṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["eti","a",".v.",".1p.$.sg.$.aor.",0.99],
-		["eti","ā",".v.",".1p.$.sg.$.aor.",0.99],
-		["eti","imha",".v.",".1p.$.pl.$.aor.",0.99],
-		["eti","imhā",".v.",".1p.$.pl.$.aor.",0.99],
-		["eti","a",".v.",".1p.$.sg.$.aor.",0.99],
-		["eti","imhe",".v.",".1p.$.pl.$.aor.",0.99],
-		["eti","eyyāsi",".v.",".2p.$.sg.$.opt.",0.99],
-		["eti","eyyātha",".v.",".2p.$.pl.$.opt.",0.99],
-		["eti","etho",".v.",".2p.$.sg.$.opt.",0.99],
-		["eti","eyyavho",".v.",".2p.$.pl.$.opt.",0.99],
-		["eti","issasi",".v.",".2p.$.sg.$.fut.",0.99],
-		["eti","issatha",".v.",".2p.$.pl.$.fut.",0.99],
-		["eti","issase",".v.",".2p.$.sg.$.fut.",0.99],
-		["eti","issavhe",".v.",".2p.$.pl.$.fut.",0.99],
-		["eti","i",".v.",".2p.$.sg.$.aor.",0.99],
-		["eti","o",".v.",".2p.$.sg.$.aor.",0.99],
-		["eti","ā",".v.",".2p.$.sg.$.aor.",0.99],
-		["eti","ttha",".v.",".2p.$.pl.$.aor.",0.99],
-		["eti","se",".v.",".2p.$.sg.$.aor.",0.99],
-		["eti","vhaṃ",".v.",".2p.$.pl.$.aor.",0.99],
-		["oti","etha",".v.",".3p.$.sg.$.opt.",0.99],
-		["oti","eraṃ",".v.",".3p.$.pl.$.opt.",0.99],
-		["oti","issati",".v.",".3p.$.sg.$.fut.",0.99],
-		["oti","issanti",".v.",".3p.$.pl.$.fut.",0.99],
-		["oti","issate",".v.",".3p.$.sg.$.fut.",0.99],
-		["oti","issante",".v.",".3p.$.pl.$.fut.",0.99],
-		["oti","issare",".v.",".3p.$.pl.$.fut.",0.99],
-		["oti","i",".v.",".3p.$.sg.$.aor.",0.99],
-		["oti","ī",".v.",".3p.$.sg.$.aor.",0.99],
-		["oti","ā",".v.",".3p.$.sg.$.aor.",0.99],
-		["oti","iṃsu",".v.",".3p.$.pl.$.aor.",0.99],
-		["oti","ṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["oti","uṃū",".v.",".3p.$.pl.$.aor.",0.99],
-		["oti","ā",".v.",".3p.$.sg.$.aor.",0.99],
-		["oti","a",".v.",".3p.$.sg.$.aor.",0.99],
-		["oti","tthuṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["oti","atthuṃ",".v.",".3p.$.pl.$.aor.",0.99],
-		["oti","e",".v.",".1p.$.sg.$.imp.",0.99],
-		["oti","āmase",".v.",".1p.$.pl.$.imp.",0.99],
-		["oti","eyyuṃ",".v.",".3p.$.pl.$.opt.",0.99],
-		["oti","eyyāmi",".v.",".1p.$.sg.$.opt.",0.99],
-		["oti","eyyāma",".v.",".1p.$.pl.$.opt.",0.99],
-		["oti","eyyaṃ",".v.",".1p.$.sg.$.opt.",0.99],
-		["oti","eyyāmhe",".v.",".1p.$.pl.$.opt.",0.99],
-		["oti","issāmi",".v.",".1p.$.sg.$.fut.",0.99],
-		["oti","issāma",".v.",".1p.$.pl.$.fut.",0.99],
-		["oti","issaṃ",".v.",".1p.$.sg.$.fut.",0.99],
-		["oti","issāmhe",".v.",".1p.$.pl.$.fut.",0.99],
-		["oti","issāmase",".v.",".1p.$.pl.$.fut.",0.99],
-		["oti","iṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["oti","aṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["oti","ṃ",".v.",".1p.$.sg.$.aor.",0.99],
-		["oti","a",".v.",".1p.$.sg.$.aor.",0.99],
-		["oti","ā",".v.",".1p.$.sg.$.aor.",0.99],
-		["oti","imha",".v.",".1p.$.pl.$.aor.",0.99],
-		["oti","imhā",".v.",".1p.$.pl.$.aor.",0.99],
-		["oti","a",".v.",".1p.$.sg.$.aor.",0.99],
-		["oti","imhe",".v.",".1p.$.pl.$.aor.",0.99],
-		["oti","eyyāsi",".v.",".2p.$.sg.$.opt.",0.99],
-		["oti","eyyātha",".v.",".2p.$.pl.$.opt.",0.99],
-		["oti","etho",".v.",".2p.$.sg.$.opt.",0.99],
-		["oti","eyyavho",".v.",".2p.$.pl.$.opt.",0.99],
-		["oti","issasi",".v.",".2p.$.sg.$.fut.",0.99],
-		["oti","issatha",".v.",".2p.$.pl.$.fut.",0.99],
-		["oti","issase",".v.",".2p.$.sg.$.fut.",0.99],
-		["oti","issavhe",".v.",".2p.$.pl.$.fut.",0.99],
-		["oti","i",".v.",".2p.$.sg.$.aor.",0.99],
-		["oti","o",".v.",".2p.$.sg.$.aor.",0.99],
-		["oti","ā",".v.",".2p.$.sg.$.aor.",0.99],
-		["oti","ttha",".v.",".2p.$.pl.$.aor.",0.99],
-		["oti","se",".v.",".2p.$.sg.$.aor.",0.99],
-		["oti","vhaṃ",".v.",".2p.$.pl.$.aor.",0.99],
-		["ati","ittha",".v.",".2p.$.pl.$.aor.",0.99],
+class CaseEnding
+{
+    public $ending = [
+        ["ti", "tuṃ", ".v:ind.", ".inf.", 0.99],
+        ["ati", "ituṃ", ".v:ind.", ".inf.", 0.99],
+        ["ati", "itvā", ".v:ind.", ".abs.", 0.99],
+        ["ati", "atvā", ".v:ind.", ".abs.", 0.99],
+        ["ti", "tvā", ".v:ind.", ".abs.", 0.99],
+        ["ant", "antā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["ant", "antā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["ant", "antā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["ant", "anta", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["ant", "antā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["ant", "anta", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["ant", "antā", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["ant", "anta", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["ant", "antā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["ant", "anta", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["ant", "antā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["ant", "antā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["ant", "anta", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["ant", "antā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["ant", "antaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["ant", "antaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["ant", "antaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["ant", "antaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["ant", "antaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["ant", "antaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["ant", "antamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["ant", "antamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["ant", "antamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["ant", "antamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["ant", "antamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["ant", "antamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["ant", "antamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["ant", "antamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["ant", "antānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["ant", "antānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["ant", "antānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["ant", "antānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["ant", "antānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["ant", "antānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["ant", "antani", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["ant", "antāni", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["ant", "antani", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["ant", "antāni", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["ant", "antani", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["ant", "antāni", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["ant", "antasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["ant", "antasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["ant", "antasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["ant", "antasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["ant", "antasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["ant", "antasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["ant", "antasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["ant", "antasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["ant", "antassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["ant", "antassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["ant", "antassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["ant", "antassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["ant", "antassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["ant", "antassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["ant", "antassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["ant", "antassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["ant", "ante", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["ant", "ante", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["ant", "ante", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["ant", "ante", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["ant", "antebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["ant", "antebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["ant", "antebhi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["ant", "antebhi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["ant", "antehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["ant", "antehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["ant", "antehi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["ant", "antehi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["ant", "antesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["ant", "antesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["ant", "antesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["ant", "antī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["ant", "antī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["ant", "antī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["ant", "antī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["ant", "antī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["ant", "antībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["ant", "antībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["ant", "antīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["ant", "antīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["ant", "antiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["ant", "antīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["ant", "antīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["ant", "antīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["ant", "antiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["ant", "antiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["ant", "antiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["ant", "antiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["ant", "antiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["ant", "antiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["ant", "antiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["ant", "antiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["ant", "antiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["ant", "anto", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["ant", "anto", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["ant", "anto", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["ant", "anto", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["ant", "anto", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["ant", "anto", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["ant", "atā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["ant", "atā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["ant", "atā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["ant", "atā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["ant", "atā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["ant", "atā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["ant", "atā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["ant", "atā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["ant", "ataṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["ant", "ataṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["ant", "ataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["ant", "ataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["ant", "ataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["ant", "ataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["ant", "atena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["ant", "atena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["ant", "atena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["ant", "atena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["ant", "atī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["ant", "atī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["ant", "atī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["ant", "atī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["ant", "atī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["ant", "ati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["ant", "ati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["ant", "ati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["ant", "ati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["ant", "atībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["ant", "atībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["ant", "atīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["ant", "atīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["ant", "atiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["ant", "atīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["ant", "atīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["ant", "atīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["ant", "atiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["ant", "atiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["ant", "atiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["ant", "atiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["ant", "atiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["ant", "atiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["ant", "atiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["ant", "atiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["ant", "atiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["ant", "ato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["ant", "ato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["ant", "ato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["ant", "ato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["ant", "ato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["ant", "ato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["ant", "ato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["ant", "ato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["anta", "antā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["anta", "antā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["anta", "antā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["anta", "anta", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["anta", "antā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["anta", "anta", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["anta", "antā", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["anta", "anta", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["anta", "antā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["anta", "anta", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["anta", "antā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["anta", "antā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["anta", "anta", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["anta", "antā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["anta", "antaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["anta", "antaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["anta", "antaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["anta", "antaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["anta", "antaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["anta", "antaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["anta", "antamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["anta", "antamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["anta", "antamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["anta", "antamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["anta", "antamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["anta", "antamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["anta", "antamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["anta", "antamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["anta", "antānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["anta", "antānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["anta", "antānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["anta", "antānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["anta", "antānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["anta", "antānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["anta", "antani", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["anta", "antāni", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["anta", "antani", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["anta", "antāni", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["anta", "antani", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["anta", "antāni", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["anta", "antasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["anta", "antasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["anta", "antasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["anta", "antasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["anta", "antasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["anta", "antasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["anta", "antasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["anta", "antasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["anta", "antassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["anta", "antassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["anta", "antassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["anta", "antassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["anta", "antassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["anta", "antassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["anta", "antassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["anta", "antassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["anta", "ante", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["anta", "ante", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["anta", "ante", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["anta", "ante", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["anta", "antebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["anta", "antebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["anta", "antebhi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["anta", "antebhi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["anta", "antehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["anta", "antehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["anta", "antehi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["anta", "antehi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["anta", "antesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["anta", "antesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["anta", "antesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["anta", "antī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["anta", "antī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["anta", "antī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["anta", "antī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["anta", "antī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["anta", "antībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["anta", "antībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["anta", "antīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["anta", "antīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["anta", "antiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["anta", "antīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["anta", "antīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["anta", "antīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["anta", "antiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["anta", "antiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["anta", "antiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["anta", "antiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["anta", "antiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["anta", "antiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["anta", "antiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["anta", "antiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["anta", "antiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["anta", "anto", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["anta", "anto", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["anta", "anto", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["anta", "anto", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["anta", "anto", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["anta", "anto", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["anta", "atā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["anta", "atā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["anta", "atā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["anta", "atā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["anta", "atā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["anta", "atā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["anta", "atā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["anta", "atā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["anta", "ataṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["anta", "ataṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["anta", "ataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["anta", "ataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["anta", "ataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["anta", "ataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["anta", "atena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["anta", "atena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["anta", "atena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["anta", "atena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["anta", "atī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["anta", "atī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["anta", "atī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["anta", "atī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["anta", "atī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["anta", "ati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["anta", "ati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["anta", "ati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["anta", "ati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["anta", "atībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["anta", "atībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["anta", "atīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["anta", "atīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["anta", "atiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["anta", "atīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["anta", "atīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["anta", "atīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["anta", "atiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["anta", "atiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["anta", "atiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["anta", "atiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["anta", "atiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["anta", "atiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["anta", "atiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["anta", "atiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["anta", "atiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["anta", "ato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["anta", "ato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["anta", "ato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["anta", "ato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["anta", "ato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["anta", "ato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["anta", "ato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["anta", "ato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mant", "mā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["mant", "mā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["mant", "mā", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["mant", "ma", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mant", "mā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mant", "mā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mant", "mā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mant", "ma", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mant", "mā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mant", "mā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mant", "mā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mant", "maṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["mant", "maṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["mant", "maṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mant", "maṃ", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["mant", "maṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mant", "maṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mant", "maṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mant", "maṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mant", "mānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["mant", "mānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["mant", "mantā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["mant", "mantā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["mant", "mantā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mant", "manta", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mant", "mantā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mant", "manta", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mant", "mantā", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mant", "manta", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mant", "mantā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mant", "manta", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mant", "mantā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mant", "mantā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mant", "manta", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mant", "mantā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mant", "mantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["mant", "mantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["mant", "mantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mant", "mantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mant", "mantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["mant", "mantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["mant", "mantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mant", "mantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mant", "mantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mant", "mantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mant", "mantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mant", "mantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mant", "mantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mant", "mantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mant", "mantānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["mant", "mantānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["mant", "mantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mant", "mantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mant", "mantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mant", "mantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mant", "mantani", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mant", "mantāni", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mant", "mantani", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mant", "mantāni", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mant", "mantani", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mant", "mantāni", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mant", "mantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mant", "mantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mant", "mantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mant", "mantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mant", "mantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mant", "mantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mant", "mantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mant", "mantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mant", "mantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mant", "mantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mant", "mantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mant", "mantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mant", "mantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mant", "mantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mant", "mantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mant", "mantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mant", "mante", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["mant", "mante", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mant", "mante", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mant", "mante", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mant", "mantebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mant", "mantebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mant", "mantebhi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["mant", "mantebhi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["mant", "mantehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mant", "mantehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mant", "mantehi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["mant", "mantehi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["mant", "mantesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["mant", "mantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["mant", "mantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["mant", "mantī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mant", "mantī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mant", "mantī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mant", "mantī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["mant", "mantī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["mant", "mantībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mant", "mantībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mant", "mantīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mant", "mantīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mant", "mantiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["mant", "mantīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["mant", "mantīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["mant", "mantīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["mant", "mantiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["mant", "mantiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["mant", "mantiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["mant", "mantiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["mant", "mantiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mant", "mantiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mant", "mantiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mant", "mantiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mant", "mantiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mant", "manto", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["mant", "manto", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["mant", "manto", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["mant", "manto", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mant", "manto", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mant", "manto", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mant", "matā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mant", "matā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mant", "matā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mant", "matā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mant", "matā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mant", "matā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mant", "matā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mant", "matā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mant", "mataṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["mant", "mataṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["mant", "mataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mant", "mataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mant", "mataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mant", "mataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mant", "matena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mant", "matena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mant", "matena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mant", "matena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mant", "matī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mant", "matī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mant", "matī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mant", "matī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["mant", "matī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["mant", "mati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mant", "mati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mant", "mati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mant", "mati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mant", "matībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mant", "matībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mant", "matīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mant", "matīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mant", "matiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["mant", "matīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["mant", "matīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["mant", "matīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["mant", "matiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["mant", "matiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["mant", "matiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["mant", "matiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["mant", "matiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mant", "matiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mant", "matiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mant", "matiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mant", "matiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mant", "mato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mant", "mato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mant", "mato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mant", "mato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mant", "mato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mant", "mato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mant", "mato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mant", "mato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mant", "me", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["mant", "mebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mant", "mebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mant", "mehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mant", "mehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mant", "mesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["vant", "vā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vant", "vā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vant", "vā", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vant", "va", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vant", "vā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vant", "vā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vant", "vā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vant", "va", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vant", "vā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vant", "vā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vant", "vā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vant", "vaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vant", "vaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vant", "vaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vant", "vaṃ", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vant", "vaṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vant", "vaṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vant", "vaṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vant", "vaṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vant", "vānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vant", "vānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vant", "vantā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vant", "vantā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vant", "vantā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vant", "vanta", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vant", "vantā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vant", "vanta", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vant", "vantā", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vant", "vanta", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vant", "vantā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vant", "vanta", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vant", "vantā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vant", "vantā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vant", "vanta", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vant", "vantā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vant", "vantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vant", "vantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vant", "vantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vant", "vantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vant", "vantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vant", "vantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vant", "vantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vant", "vantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vant", "vantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vant", "vantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vant", "vantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vant", "vantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vant", "vantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vant", "vantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vant", "vantānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vant", "vantānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vant", "vantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vant", "vantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vant", "vantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vant", "vantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vant", "vantani", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vant", "vantāni", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vant", "vantani", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vant", "vantāni", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vant", "vantani", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vant", "vantāni", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vant", "vantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vant", "vantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vant", "vantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vant", "vantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vant", "vantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vant", "vantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vant", "vantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vant", "vantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vant", "vantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vant", "vantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vant", "vantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vant", "vantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vant", "vantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vant", "vantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vant", "vantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vant", "vantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vant", "vante", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["vant", "vante", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vant", "vante", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vant", "vante", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vant", "vantebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vant", "vantebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vant", "vantebhi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["vant", "vantebhi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["vant", "vantehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vant", "vantehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vant", "vantehi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["vant", "vantehi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["vant", "vantesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["vant", "vantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["vant", "vantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["vant", "vantī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vant", "vantī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vant", "vantī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vant", "vantī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["vant", "vantī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["vant", "vantībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vant", "vantībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vant", "vantīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vant", "vantīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vant", "vantiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["vant", "vantīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["vant", "vantīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["vant", "vantīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["vant", "vantiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["vant", "vantiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["vant", "vantiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["vant", "vantiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["vant", "vantiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vant", "vantiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vant", "vantiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vant", "vantiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vant", "vantiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vant", "vanto", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vant", "vanto", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vant", "vanto", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vant", "vanto", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vant", "vanto", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vant", "vanto", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vant", "vatā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vant", "vatā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vant", "vatā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vant", "vatā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vant", "vatā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vant", "vatā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vant", "vatā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vant", "vatā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vant", "vataṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vant", "vataṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vant", "vataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vant", "vataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vant", "vataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vant", "vataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vant", "vatena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vant", "vatena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vant", "vatena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vant", "vatena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vant", "vatī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vant", "vatī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vant", "vatī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vant", "vatī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["vant", "vatī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["vant", "vati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vant", "vati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vant", "vati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vant", "vati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vant", "vatībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vant", "vatībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vant", "vatīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vant", "vatīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vant", "vatiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["vant", "vatīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["vant", "vatīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["vant", "vatīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["vant", "vatiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["vant", "vatiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["vant", "vatiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["vant", "vatiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["vant", "vatiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vant", "vatiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vant", "vatiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vant", "vatiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vant", "vatiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vant", "vato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vant", "vato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vant", "vato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vant", "vato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vant", "vato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vant", "vato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vant", "vato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vant", "vato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vant", "ve", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["vant", "vebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vant", "vebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vant", "vehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vant", "vehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vant", "vesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["mantu", "mā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["mantu", "mā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["mantu", "mā", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["mantu", "ma", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mantu", "mā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mantu", "mā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mantu", "mā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mantu", "ma", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mantu", "mā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mantu", "mā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mantu", "mā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mantu", "maṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["mantu", "maṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["mantu", "maṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mantu", "maṃ", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["mantu", "maṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mantu", "maṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mantu", "maṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mantu", "maṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mantu", "mānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["mantu", "mānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["mantu", "mantā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["mantu", "mantā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["mantu", "mantā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mantu", "manta", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mantu", "mantā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mantu", "manta", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mantu", "mantā", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mantu", "manta", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mantu", "mantā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mantu", "manta", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mantu", "mantā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mantu", "mantā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mantu", "manta", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mantu", "mantā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mantu", "mantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["mantu", "mantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["mantu", "mantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mantu", "mantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mantu", "mantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["mantu", "mantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["mantu", "mantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mantu", "mantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mantu", "mantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mantu", "mantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mantu", "mantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mantu", "mantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mantu", "mantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mantu", "mantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mantu", "mantānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["mantu", "mantānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["mantu", "mantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mantu", "mantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mantu", "mantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mantu", "mantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mantu", "mantani", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mantu", "mantāni", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mantu", "mantani", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mantu", "mantāni", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mantu", "mantani", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mantu", "mantāni", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mantu", "mantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mantu", "mantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mantu", "mantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mantu", "mantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mantu", "mantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mantu", "mantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mantu", "mantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mantu", "mantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mantu", "mantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mantu", "mantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mantu", "mantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mantu", "mantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mantu", "mantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mantu", "mantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mantu", "mantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mantu", "mantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mantu", "mante", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["mantu", "mante", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mantu", "mante", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mantu", "mante", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mantu", "mantebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mantu", "mantebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mantu", "mantebhi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["mantu", "mantebhi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["mantu", "mantehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mantu", "mantehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mantu", "mantehi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["mantu", "mantehi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["mantu", "mantesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["mantu", "mantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["mantu", "mantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["mantu", "mantī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mantu", "mantī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mantu", "mantī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mantu", "mantī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["mantu", "mantī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["mantu", "mantībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mantu", "mantībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mantu", "mantīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mantu", "mantīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mantu", "mantiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["mantu", "mantīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["mantu", "mantīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["mantu", "mantīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["mantu", "mantiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["mantu", "mantiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["mantu", "mantiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["mantu", "mantiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["mantu", "mantiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mantu", "mantiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mantu", "mantiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mantu", "mantiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mantu", "mantiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mantu", "manto", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["mantu", "manto", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["mantu", "manto", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["mantu", "manto", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mantu", "manto", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mantu", "manto", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mantu", "matā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mantu", "matā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mantu", "matā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mantu", "matā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mantu", "matā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mantu", "matā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mantu", "matā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mantu", "matā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mantu", "mataṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["mantu", "mataṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["mantu", "mataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mantu", "mataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mantu", "mataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mantu", "mataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mantu", "matena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mantu", "matena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mantu", "matena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mantu", "matena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mantu", "matī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mantu", "matī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mantu", "matī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mantu", "matī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["mantu", "matī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["mantu", "mati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mantu", "mati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mantu", "mati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mantu", "mati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mantu", "matībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mantu", "matībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mantu", "matīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mantu", "matīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mantu", "matiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["mantu", "matīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["mantu", "matīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["mantu", "matīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["mantu", "matiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["mantu", "matiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["mantu", "matiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["mantu", "matiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["mantu", "matiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mantu", "matiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mantu", "matiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mantu", "matiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mantu", "matiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mantu", "mato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mantu", "mato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mantu", "mato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mantu", "mato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mantu", "mato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mantu", "mato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mantu", "mato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mantu", "mato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mantu", "me", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["mantu", "mebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mantu", "mebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mantu", "mehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mantu", "mehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mantu", "mesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["vantu", "vā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vantu", "vā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vantu", "vā", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vantu", "va", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vantu", "vā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vantu", "vā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vantu", "vā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vantu", "va", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vantu", "vā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vantu", "vā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vantu", "vā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vantu", "vaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vantu", "vaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vantu", "vaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vantu", "vaṃ", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vantu", "vaṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vantu", "vaṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vantu", "vaṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vantu", "vaṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vantu", "vānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vantu", "vānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vantu", "vantā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vantu", "vantā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vantu", "vantā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vantu", "vanta", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vantu", "vantā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vantu", "vanta", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vantu", "vantā", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vantu", "vanta", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vantu", "vantā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vantu", "vanta", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vantu", "vantā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vantu", "vantā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vantu", "vanta", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vantu", "vantā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vantu", "vantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vantu", "vantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vantu", "vantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vantu", "vantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vantu", "vantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vantu", "vantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vantu", "vantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vantu", "vantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vantu", "vantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vantu", "vantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vantu", "vantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vantu", "vantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vantu", "vantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vantu", "vantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vantu", "vantānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vantu", "vantānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vantu", "vantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vantu", "vantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vantu", "vantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vantu", "vantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vantu", "vantani", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vantu", "vantāni", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vantu", "vantani", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vantu", "vantāni", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vantu", "vantani", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vantu", "vantāni", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vantu", "vantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vantu", "vantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vantu", "vantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vantu", "vantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vantu", "vantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vantu", "vantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vantu", "vantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vantu", "vantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vantu", "vantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vantu", "vantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vantu", "vantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vantu", "vantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vantu", "vantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vantu", "vantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vantu", "vantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vantu", "vantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vantu", "vante", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["vantu", "vante", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vantu", "vante", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vantu", "vante", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vantu", "vantebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vantu", "vantebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vantu", "vantebhi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["vantu", "vantebhi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["vantu", "vantehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vantu", "vantehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vantu", "vantehi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["vantu", "vantehi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["vantu", "vantesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["vantu", "vantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["vantu", "vantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["vantu", "vantī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vantu", "vantī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vantu", "vantī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vantu", "vantī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["vantu", "vantī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["vantu", "vantībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vantu", "vantībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vantu", "vantīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vantu", "vantīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vantu", "vantiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["vantu", "vantīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["vantu", "vantīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["vantu", "vantīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["vantu", "vantiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["vantu", "vantiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["vantu", "vantiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["vantu", "vantiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["vantu", "vantiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vantu", "vantiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vantu", "vantiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vantu", "vantiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vantu", "vantiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vantu", "vanto", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vantu", "vanto", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vantu", "vanto", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vantu", "vanto", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vantu", "vanto", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vantu", "vanto", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vantu", "vatā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vantu", "vatā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vantu", "vatā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vantu", "vatā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vantu", "vatā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vantu", "vatā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vantu", "vatā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vantu", "vatā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vantu", "vataṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vantu", "vataṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vantu", "vataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vantu", "vataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vantu", "vataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vantu", "vataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vantu", "vatena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vantu", "vatena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vantu", "vatena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vantu", "vatena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vantu", "vatī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vantu", "vatī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vantu", "vatī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vantu", "vatī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["vantu", "vatī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["vantu", "vati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vantu", "vati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vantu", "vati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vantu", "vati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vantu", "vatībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vantu", "vatībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vantu", "vatīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vantu", "vatīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vantu", "vatiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["vantu", "vatīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["vantu", "vatīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["vantu", "vatīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["vantu", "vatiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["vantu", "vatiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["vantu", "vatiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["vantu", "vatiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["vantu", "vatiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vantu", "vatiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vantu", "vatiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vantu", "vatiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vantu", "vatiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vantu", "vato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vantu", "vato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vantu", "vato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vantu", "vato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vantu", "vato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vantu", "vato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vantu", "vato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vantu", "vato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vantu", "ve", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["vantu", "vebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vantu", "vebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vantu", "vehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vantu", "vehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vantu", "vesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["mat", "mā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["mat", "mā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["mat", "mā", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["mat", "ma", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mat", "mā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mat", "mā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mat", "mā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mat", "ma", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mat", "mā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mat", "mā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mat", "mā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mat", "maṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["mat", "maṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["mat", "maṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mat", "maṃ", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["mat", "maṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mat", "maṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mat", "maṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mat", "maṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mat", "mānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["mat", "mānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["mat", "mantā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["mat", "mantā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["mat", "mantā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mat", "manta", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mat", "mantā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["mat", "manta", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mat", "mantā", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mat", "manta", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mat", "mantā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mat", "manta", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mat", "mantā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mat", "mantā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mat", "manta", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mat", "mantā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["mat", "mantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["mat", "mantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["mat", "mantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mat", "mantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mat", "mantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["mat", "mantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["mat", "mantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mat", "mantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mat", "mantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mat", "mantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mat", "mantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mat", "mantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mat", "mantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mat", "mantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mat", "mantānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["mat", "mantānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["mat", "mantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mat", "mantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mat", "mantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mat", "mantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mat", "mantani", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mat", "mantāni", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mat", "mantani", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mat", "mantāni", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mat", "mantani", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mat", "mantāni", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mat", "mantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mat", "mantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mat", "mantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mat", "mantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mat", "mantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mat", "mantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mat", "mantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mat", "mantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mat", "mantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mat", "mantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mat", "mantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mat", "mantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mat", "mantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mat", "mantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mat", "mantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mat", "mantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mat", "mante", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["mat", "mante", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mat", "mante", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["mat", "mante", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mat", "mantebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mat", "mantebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mat", "mantebhi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["mat", "mantebhi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["mat", "mantehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mat", "mantehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mat", "mantehi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["mat", "mantehi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["mat", "mantesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["mat", "mantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["mat", "mantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["mat", "mantī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mat", "mantī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mat", "mantī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mat", "mantī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["mat", "mantī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["mat", "mantībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mat", "mantībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mat", "mantīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mat", "mantīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mat", "mantiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["mat", "mantīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["mat", "mantīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["mat", "mantīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["mat", "mantiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["mat", "mantiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["mat", "mantiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["mat", "mantiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["mat", "mantiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mat", "mantiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mat", "mantiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mat", "mantiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mat", "mantiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mat", "manto", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["mat", "manto", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["mat", "manto", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["mat", "manto", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["mat", "manto", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["mat", "manto", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["mat", "matā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mat", "matā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mat", "matā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mat", "matā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mat", "matā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["mat", "matā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mat", "matā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["mat", "matā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mat", "mataṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["mat", "mataṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["mat", "mataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mat", "mataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mat", "mataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["mat", "mataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["mat", "matena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mat", "matena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mat", "matena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["mat", "matena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["mat", "matī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mat", "matī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mat", "matī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mat", "matī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["mat", "matī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["mat", "mati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mat", "mati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mat", "mati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["mat", "mati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["mat", "matībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mat", "matībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mat", "matīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["mat", "matīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["mat", "matiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["mat", "matīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["mat", "matīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["mat", "matīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["mat", "matiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["mat", "matiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["mat", "matiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["mat", "matiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["mat", "matiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mat", "matiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["mat", "matiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["mat", "matiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["mat", "matiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["mat", "mato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mat", "mato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mat", "mato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mat", "mato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mat", "mato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["mat", "mato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["mat", "mato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["mat", "mato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["mat", "me", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["mat", "mebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mat", "mebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mat", "mehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["mat", "mehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["mat", "mesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["vat", "vā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vat", "vā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vat", "vā", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vat", "va", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vat", "vā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vat", "vā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vat", "vā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vat", "va", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vat", "vā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vat", "vā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vat", "vā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vat", "vaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vat", "vaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vat", "vaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vat", "vaṃ", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vat", "vaṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vat", "vaṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vat", "vaṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vat", "vaṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vat", "vānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vat", "vānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vat", "vantā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vat", "vantā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vat", "vantā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vat", "vanta", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vat", "vantā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vat", "vanta", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vat", "vantā", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vat", "vanta", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vat", "vantā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vat", "vanta", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vat", "vantā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vat", "vantā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vat", "vanta", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vat", "vantā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vat", "vantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vat", "vantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vat", "vantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vat", "vantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vat", "vantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vat", "vantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vat", "vantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vat", "vantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vat", "vantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vat", "vantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vat", "vantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vat", "vantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vat", "vantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vat", "vantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vat", "vantānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vat", "vantānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vat", "vantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vat", "vantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vat", "vantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vat", "vantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vat", "vantani", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vat", "vantāni", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vat", "vantani", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vat", "vantāni", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vat", "vantani", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vat", "vantāni", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vat", "vantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vat", "vantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vat", "vantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vat", "vantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vat", "vantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vat", "vantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vat", "vantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vat", "vantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vat", "vantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vat", "vantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vat", "vantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vat", "vantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vat", "vantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vat", "vantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vat", "vantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vat", "vantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vat", "vante", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["vat", "vante", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vat", "vante", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vat", "vante", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vat", "vantebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vat", "vantebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vat", "vantebhi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["vat", "vantebhi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["vat", "vantehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vat", "vantehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vat", "vantehi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["vat", "vantehi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["vat", "vantesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["vat", "vantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["vat", "vantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["vat", "vantī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vat", "vantī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vat", "vantī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vat", "vantī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["vat", "vantī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["vat", "vantībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vat", "vantībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vat", "vantīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vat", "vantīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vat", "vantiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["vat", "vantīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["vat", "vantīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["vat", "vantīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["vat", "vantiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["vat", "vantiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["vat", "vantiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["vat", "vantiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["vat", "vantiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vat", "vantiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vat", "vantiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vat", "vantiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vat", "vantiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vat", "vanto", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vat", "vanto", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vat", "vanto", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vat", "vanto", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vat", "vanto", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vat", "vanto", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vat", "vatā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vat", "vatā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vat", "vatā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vat", "vatā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vat", "vatā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vat", "vatā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vat", "vatā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vat", "vatā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vat", "vataṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vat", "vataṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vat", "vataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vat", "vataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vat", "vataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vat", "vataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vat", "vatena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vat", "vatena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vat", "vatena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vat", "vatena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vat", "vatī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vat", "vatī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vat", "vatī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vat", "vatī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["vat", "vatī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["vat", "vati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vat", "vati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vat", "vati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vat", "vati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vat", "vatībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vat", "vatībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vat", "vatīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vat", "vatīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vat", "vatiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["vat", "vatīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["vat", "vatīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["vat", "vatīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["vat", "vatiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["vat", "vatiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["vat", "vatiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["vat", "vatiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["vat", "vatiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vat", "vatiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vat", "vatiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vat", "vatiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vat", "vatiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vat", "vato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vat", "vato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vat", "vato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vat", "vato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vat", "vato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vat", "vato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vat", "vato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vat", "vato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vat", "ve", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["vat", "vebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vat", "vebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vat", "vehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vat", "vehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vat", "vesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["manta", "mā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["manta", "mā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["manta", "mā", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["manta", "ma", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["manta", "mā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["manta", "mā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["manta", "mā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["manta", "ma", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["manta", "mā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["manta", "mā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["manta", "mā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["manta", "maṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["manta", "maṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["manta", "maṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["manta", "maṃ", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["manta", "maṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["manta", "maṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["manta", "maṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["manta", "maṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["manta", "mānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["manta", "mānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["manta", "mantā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["manta", "mantā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["manta", "mantā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["manta", "manta", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["manta", "mantā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["manta", "manta", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["manta", "mantā", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["manta", "manta", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["manta", "mantā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["manta", "manta", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["manta", "mantā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["manta", "mantā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["manta", "manta", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["manta", "mantā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["manta", "mantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["manta", "mantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["manta", "mantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["manta", "mantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["manta", "mantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["manta", "mantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["manta", "mantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["manta", "mantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["manta", "mantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["manta", "mantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["manta", "mantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["manta", "mantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["manta", "mantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["manta", "mantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["manta", "mantānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["manta", "mantānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["manta", "mantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["manta", "mantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["manta", "mantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["manta", "mantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["manta", "mantani", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["manta", "mantāni", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["manta", "mantani", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["manta", "mantāni", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["manta", "mantani", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["manta", "mantāni", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["manta", "mantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["manta", "mantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["manta", "mantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["manta", "mantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["manta", "mantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["manta", "mantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["manta", "mantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["manta", "mantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["manta", "mantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["manta", "mantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["manta", "mantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["manta", "mantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["manta", "mantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["manta", "mantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["manta", "mantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["manta", "mantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["manta", "mante", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["manta", "mante", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["manta", "mante", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["manta", "mante", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["manta", "mantebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["manta", "mantebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["manta", "mantebhi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["manta", "mantebhi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["manta", "mantehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["manta", "mantehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["manta", "mantehi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["manta", "mantehi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["manta", "mantesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["manta", "mantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["manta", "mantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["manta", "mantī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["manta", "mantī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["manta", "mantī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["manta", "mantī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["manta", "mantī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["manta", "mantībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["manta", "mantībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["manta", "mantīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["manta", "mantīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["manta", "mantiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["manta", "mantīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["manta", "mantīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["manta", "mantīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["manta", "mantiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["manta", "mantiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["manta", "mantiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["manta", "mantiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["manta", "mantiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["manta", "mantiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["manta", "mantiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["manta", "mantiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["manta", "mantiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["manta", "manto", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["manta", "manto", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["manta", "manto", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["manta", "manto", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["manta", "manto", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["manta", "manto", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["manta", "matā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["manta", "matā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["manta", "matā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["manta", "matā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["manta", "matā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["manta", "matā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["manta", "matā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["manta", "matā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["manta", "mataṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["manta", "mataṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["manta", "mataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["manta", "mataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["manta", "mataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["manta", "mataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["manta", "matena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["manta", "matena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["manta", "matena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["manta", "matena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["manta", "matī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["manta", "matī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["manta", "matī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["manta", "matī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["manta", "matī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["manta", "mati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["manta", "mati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["manta", "mati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["manta", "mati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["manta", "matībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["manta", "matībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["manta", "matīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["manta", "matīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["manta", "matiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["manta", "matīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["manta", "matīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["manta", "matīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["manta", "matiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["manta", "matiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["manta", "matiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["manta", "matiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["manta", "matiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["manta", "matiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["manta", "matiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["manta", "matiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["manta", "matiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["manta", "mato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["manta", "mato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["manta", "mato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["manta", "mato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["manta", "mato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["manta", "mato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["manta", "mato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["manta", "mato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["manta", "me", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["manta", "mebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["manta", "mebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["manta", "mehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["manta", "mehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["manta", "mesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["vanta", "vā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vanta", "vā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vanta", "vā", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vanta", "va", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vanta", "vā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vanta", "vā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vanta", "vā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vanta", "va", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vanta", "vā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vanta", "vā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vanta", "vā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vanta", "vaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vanta", "vaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vanta", "vaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vanta", "vaṃ", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vanta", "vaṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vanta", "vaṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vanta", "vaṃ", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vanta", "vaṃ", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vanta", "vānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vanta", "vānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vanta", "vantā", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vanta", "vantā", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vanta", "vantā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vanta", "vanta", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vanta", "vantā", ".ti.", ".m.$.sg.$.voc.", 0.3],
+        ["vanta", "vanta", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vanta", "vantā", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vanta", "vanta", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vanta", "vantā", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vanta", "vanta", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vanta", "vantā", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vanta", "vantā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vanta", "vanta", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vanta", "vantā", ".ti.", ".nt.$.sg.$.voc.", 0.3],
+        ["vanta", "vantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vanta", "vantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vanta", "vantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vanta", "vantaṃ", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vanta", "vantaṃ", ".ti.", ".m.$.sg.$.acc.", 0.99],
+        ["vanta", "vantaṃ", ".ti.", ".nt.$.sg.$.acc.", 0.99],
+        ["vanta", "vantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vanta", "vantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vanta", "vantamhā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vanta", "vantamhā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vanta", "vantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vanta", "vantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vanta", "vantamhi", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vanta", "vantamhi", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vanta", "vantānaṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vanta", "vantānaṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vanta", "vantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vanta", "vantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vanta", "vantānaṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vanta", "vantānaṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vanta", "vantani", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vanta", "vantāni", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vanta", "vantani", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vanta", "vantāni", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vanta", "vantani", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vanta", "vantāni", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vanta", "vantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vanta", "vantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vanta", "vantasmā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vanta", "vantasmā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vanta", "vantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vanta", "vantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vanta", "vantasmiṃ", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vanta", "vantasmiṃ", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vanta", "vantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vanta", "vantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vanta", "vantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vanta", "vantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vanta", "vantassa", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vanta", "vantassa", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vanta", "vantassa", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vanta", "vantassa", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vanta", "vante", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["vanta", "vante", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vanta", "vante", ".ti.", ".nt.$.pl.$.acc.", 0.99],
+        ["vanta", "vante", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vanta", "vantebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vanta", "vantebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vanta", "vantebhi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["vanta", "vantebhi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["vanta", "vantehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vanta", "vantehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vanta", "vantehi", ".ti.", ".nt.$.pl.$.abl.", 0.99],
+        ["vanta", "vantehi", ".ti.", ".nt.$.pl.$.inst.", 0.99],
+        ["vanta", "vantesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["vanta", "vantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["vanta", "vantesu", ".ti.", ".nt.$.pl.$.loc.", 0.99],
+        ["vanta", "vantī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vanta", "vantī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vanta", "vantī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vanta", "vantī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["vanta", "vantī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["vanta", "vantībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vanta", "vantībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vanta", "vantīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vanta", "vantīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vanta", "vantiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["vanta", "vantīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["vanta", "vantīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["vanta", "vantīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["vanta", "vantiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["vanta", "vantiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["vanta", "vantiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["vanta", "vantiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["vanta", "vantiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vanta", "vantiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vanta", "vantiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vanta", "vantiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vanta", "vantiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vanta", "vanto", ".ti.", ".m.$.pl.$.nom.", 0.99],
+        ["vanta", "vanto", ".ti.", ".m.$.pl.$.voc.", 0.3],
+        ["vanta", "vanto", ".ti.", ".m.$.sg.$.nom.", 0.99],
+        ["vanta", "vanto", ".ti.", ".nt.$.pl.$.nom.", 0.99],
+        ["vanta", "vanto", ".ti.", ".nt.$.pl.$.voc.", 0.3],
+        ["vanta", "vanto", ".ti.", ".nt.$.sg.$.nom.", 0.99],
+        ["vanta", "vatā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vanta", "vatā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vanta", "vatā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vanta", "vatā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vanta", "vatā", ".ti.", ".m.$.sg.$.abl.", 0.99],
+        ["vanta", "vatā", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vanta", "vatā", ".ti.", ".nt.$.sg.$.abl.", 0.99],
+        ["vanta", "vatā", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vanta", "vataṃ", ".ti.", ".m.$.pl.$.dat.", 0.99],
+        ["vanta", "vataṃ", ".ti.", ".m.$.pl.$.gen.", 0.99],
+        ["vanta", "vataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vanta", "vataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vanta", "vataṃ", ".ti.", ".nt.$.pl.$.dat.", 0.99],
+        ["vanta", "vataṃ", ".ti.", ".nt.$.pl.$.gen.", 0.99],
+        ["vanta", "vatena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vanta", "vatena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vanta", "vatena", ".ti.", ".m.$.sg.$.inst.", 0.99],
+        ["vanta", "vatena", ".ti.", ".nt.$.sg.$.inst.", 0.99],
+        ["vanta", "vatī", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vanta", "vatī", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vanta", "vatī", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vanta", "vatī", ".ti.", ".f.$.sg.$.nom.", 0.99],
+        ["vanta", "vatī", ".ti.", ".f.$.sg.$.voc.", 0.3],
+        ["vanta", "vati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vanta", "vati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vanta", "vati", ".ti.", ".m.$.sg.$.loc.", 0.99],
+        ["vanta", "vati", ".ti.", ".nt.$.sg.$.loc.", 0.99],
+        ["vanta", "vatībhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vanta", "vatībhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vanta", "vatīhi", ".ti.", ".f.$.pl.$.abl.", 0.99],
+        ["vanta", "vatīhi", ".ti.", ".f.$.pl.$.inst.", 0.99],
+        ["vanta", "vatiṃ", ".ti.", ".f.$.sg.$.acc.", 0.99],
+        ["vanta", "vatīnaṃ", ".ti.", ".f.$.pl.$.dat.", 0.99],
+        ["vanta", "vatīnaṃ", ".ti.", ".f.$.pl.$.gen.", 0.99],
+        ["vanta", "vatīsu", ".ti.", ".f.$.pl.$.loc.", 0.99],
+        ["vanta", "vatiyā", ".ti.", ".f.$.sg.$.abl.", 0.99],
+        ["vanta", "vatiyā", ".ti.", ".f.$.sg.$.dat.", 0.99],
+        ["vanta", "vatiyā", ".ti.", ".f.$.sg.$.gen.", 0.99],
+        ["vanta", "vatiyā", ".ti.", ".f.$.sg.$.inst.", 0.99],
+        ["vanta", "vatiyā", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vanta", "vatiyaṃ", ".ti.", ".f.$.sg.$.loc.", 0.99],
+        ["vanta", "vatiyo", ".ti.", ".f.$.pl.$.acc.", 0.99],
+        ["vanta", "vatiyo", ".ti.", ".f.$.pl.$.nom.", 0.99],
+        ["vanta", "vatiyo", ".ti.", ".f.$.pl.$.voc.", 0.3],
+        ["vanta", "vato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vanta", "vato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vanta", "vato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vanta", "vato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vanta", "vato", ".ti.", ".m.$.sg.$.dat.", 0.99],
+        ["vanta", "vato", ".ti.", ".m.$.sg.$.gen.", 0.99],
+        ["vanta", "vato", ".ti.", ".nt.$.sg.$.dat.", 0.99],
+        ["vanta", "vato", ".ti.", ".nt.$.sg.$.gen.", 0.99],
+        ["vanta", "ve", ".ti.", ".m.$.pl.$.acc.", 0.99],
+        ["vanta", "vebhi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vanta", "vebhi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vanta", "vehi", ".ti.", ".m.$.pl.$.abl.", 0.99],
+        ["vanta", "vehi", ".ti.", ".m.$.pl.$.inst.", 0.99],
+        ["vanta", "vesu", ".ti.", ".m.$.pl.$.loc.", 0.99],
+        ["a", "o", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["a", "a", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["a", "ā", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["a", "aṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["a", "assa", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["a", "assa", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["a", "āya", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["a", "ena", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["a", "ā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["a", "asmā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["a", "amhā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["a", "ato", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["a", "e", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["a", "asmiṃ", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["a", "amhi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["a", "ā", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["a", "āse", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["a", "ā", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["a", "e", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["a", "ānaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["a", "ānaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["a", "ehi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["a", "ebhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["a", "ehi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["a", "ebhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["a", "esu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["a", "aṃ", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["a", "a", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["a", "aṃ", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["a", "assa", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["a", "assa", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["a", "āya", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["a", "ena", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["a", "ā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["a", "asmā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["a", "amhā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["a", "ato", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["a", "e", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["a", "asmiṃ", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["a", "amhi", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["a", "āni", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["a", "ā", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["a", "āni", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["a", "ā", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["a", "āni", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["a", "e", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["a", "ānaṃ", ".n.", ".nt.$.pl.$.gen.", 0.99],
+        ["a", "ānaṃ", ".n.", ".nt.$.pl.$.dat.", 0.99],
+        ["a", "ehi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["a", "ebhi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["a", "ehi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["a", "ebhi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["a", "esu", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["a", "esaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["a", "esaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["a", "esaṃ", ".n.", ".nt.$.pl.$.dat.", 0.99],
+        ["a", "esaṃ", ".n.", ".nt.$.pl.$.gen.", 0.99],
+        ["ā", "ā", ".n.", ".f.$.sg.$.nom.", 0.99],
+        ["ā", "ā", ".n.", ".f.$.sg.$.voc.", 0.3],
+        ["ā", "e", ".n.", ".f.$.sg.$.voc.", 0.3],
+        ["ā", "aṃ", ".n.", ".f.$.sg.$.acc.", 0.99],
+        ["ā", "āya", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["ā", "āya", ".n.", ".f.$.sg.$.dat.", 0.99],
+        ["ā", "āya", ".n.", ".f.$.sg.$.inst.", 0.99],
+        ["ā", "āya", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ā", "ato", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ā", "āya", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ā", "āyaṃ", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ā", "ā", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ā", "āyo", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ā", "ā", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["ā", "āyo", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["ā", "ā", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["ā", "āyo", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["ā", "ānaṃ", ".n.", ".f.$.pl.$.gen.", 0.99],
+        ["ā", "ānaṃ", ".n.", ".f.$.pl.$.dat.", 0.99],
+        ["ā", "āhi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ā", "ābhi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ā", "āhi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ā", "ābhi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ā", "āsu", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["i", "i", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["i", "i", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["i", "iṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["i", "issa", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["i", "ino", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["i", "issa", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["i", "ino", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["i", "inā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["i", "inā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["i", "ismā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["i", "imhā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["i", "ismiṃ", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["i", "imhi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["i", "ī", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["i", "ayo", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["i", "ī", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["i", "ayo", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["i", "ī", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["i", "ayo", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["i", "īnaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["i", "īnaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["i", "īhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["i", "ībhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["i", "īhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["i", "ībhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["i", "īsu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["i", "i", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["i", "i", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["i", "iṃ", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["i", "assa", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["i", "ino", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["i", "assa", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["i", "ino", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["i", "inā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["i", "inā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["i", "ismā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["i", "imhā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["i", "ismiṃ", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["i", "imhi", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["i", "īni", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["i", "ī", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["i", "īni", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["i", "ī", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["i", "īni", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["i", "ī", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["i", "īnaṃ", ".n.", ".nt.$.pl.$.gen.", 0.99],
+        ["i", "īnaṃ", ".n.", ".nt.$.pl.$.dat.", 0.99],
+        ["i", "īhi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["i", "ībhi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["i", "īhi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["i", "ībhi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["i", "īsu", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["i", "i", ".n.", ".f.$.sg.$.nom.", 0.99],
+        ["i", "i", ".n.", ".f.$.sg.$.voc.", 0.3],
+        ["i", "iṃ", ".n.", ".f.$.sg.$.acc.", 0.99],
+        ["i", "iyā", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["i", "yā", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["i", "iyā", ".n.", ".f.$.sg.$.dat.", 0.99],
+        ["i", "yā", ".n.", ".f.$.sg.$.dat.", 0.99],
+        ["i", "iyā", ".n.", ".f.$.sg.$.inst.", 0.99],
+        ["i", "yā", ".n.", ".f.$.sg.$.inst.", 0.99],
+        ["i", "iyā", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["i", "yā", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["i", "iyā", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["i", "yā", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["i", "iyaṃ", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["i", "yaṃ", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["i", "ī", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["i", "iyo", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["i", "yo", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["i", "ī", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["i", "iyo", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["i", "yo", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["i", "ī", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["i", "iyo", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["i", "yo", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["i", "īnaṃ", ".n.", ".f.$.pl.$.gen.", 0.99],
+        ["i", "īnaṃ", ".n.", ".f.$.pl.$.dat.", 0.99],
+        ["i", "īhi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["i", "ībhi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["i", "īhi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["i", "ībhi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["i", "īsu", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["ī", "ī", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["in", "ī", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["ī", "ī", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["ī", "inī", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["in", "ī", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["in", "inī", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["ī", "iṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["ī", "inaṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["in", "iṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["in", "inaṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["ī", "issa", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["ī", "ino", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["in", "issa", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["in", "ino", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["ī", "issa", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["ī", "ino", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["in", "issa", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["in", "ino", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["ī", "inā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["in", "inā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["ī", "inā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ī", "ismā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ī", "imhā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["in", "inā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["in", "ismā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["in", "imhā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ī", "ismiṃ", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["ī", "imhi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["in", "ismiṃ", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["in", "imhi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["ī", "ī", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["ī", "ino", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["in", "ī", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["in", "ino", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["ī", "ī", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["ī", "ino", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["in", "ī", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["in", "ino", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["ī", "ī", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["ī", "ino", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["in", "ī", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["in", "ino", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["ī", "inaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["in", "inaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["ī", "inaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["in", "inaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["ī", "īhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ī", "ībhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["in", "īhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["in", "ībhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ī", "īhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ī", "ībhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["in", "īhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["in", "ībhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ī", "īsu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["in", "īsu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["ī", "ī", ".n.", ".f.$.sg.$.nom.", 0.99],
+        ["ī", "ī", ".n.", ".f.$.sg.$.voc.", 0.3],
+        ["ī", "iṃ", ".n.", ".f.$.sg.$.acc.", 0.99],
+        ["ī", "iyā", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["ī", "ayā", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["ī", "yā", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["ī", "iyā", ".n.", ".f.$.sg.$.dat.", 0.99],
+        ["ī", "ayā", ".n.", ".f.$.sg.$.dat.", 0.99],
+        ["ī", "yā", ".n.", ".f.$.sg.$.dat.", 0.99],
+        ["ī", "iyā", ".n.", ".f.$.sg.$.inst.", 0.99],
+        ["ī", "ayā", ".n.", ".f.$.sg.$.inst.", 0.99],
+        ["ī", "yā", ".n.", ".f.$.sg.$.inst.", 0.99],
+        ["ī", "iyā", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ī", "ayā", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ī", "yā", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ī", "iyā", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ī", "ayā", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ī", "yā", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ī", "iyaṃ", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ī", "ayaṃ", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ī", "yaṃ", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ī", "ī", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ī", "iyo", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ī", "yo", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ī", "ī", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["ī", "iyo", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["ī", "yo", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["ī", "ī", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["ī", "iyo", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["ī", "yo", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["ī", "īnaṃ", ".n.", ".f.$.pl.$.gen.", 0.99],
+        ["ī", "īnaṃ", ".n.", ".f.$.pl.$.dat.", 0.99],
+        ["ī", "īhi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ī", "ībhi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ī", "īhi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ī", "ībhi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ī", "īsu", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["u", "u", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["u", "u", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["u", "uṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["u", "ussa", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["u", "uno", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["u", "ussa", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["u", "uno", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["u", "unā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["u", "unā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["u", "usmā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["u", "umhā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["u", "usmiṃ", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["u", "umhi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["u", "ū", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["u", "avo", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["u", "ū", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["u", "avo", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["u", "ave", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["u", "ū", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["u", "avo", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["u", "ūnaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["u", "ūnaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["u", "ūhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["u", "ūbhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["u", "ūhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["u", "ūbhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["u", "ūsu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["u", "u", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["u", "u", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["u", "uṃ", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["u", "ussa", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["u", "uno", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["u", "ussa", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["u", "uno", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["u", "unā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["u", "unā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["u", "usmā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["u", "umhā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["u", "usmiṃ", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["u", "umhi", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["u", "ū", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["u", "ūni", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["u", "ū", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["u", "ūni", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["u", "ū", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["u", "ūni", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["u", "ūnaṃ", ".n.", ".nt.$.pl.$.gen.", 0.99],
+        ["u", "ūnaṃ", ".n.", ".nt.$.pl.$.dat.", 0.99],
+        ["u", "ūhi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["u", "ūbhi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["u", "ūhi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["u", "ūbhi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["u", "ūsu", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["u", "u", ".n.", ".f.$.sg.$.nom.", 0.99],
+        ["u", "u", ".n.", ".f.$.sg.$.voc.", 0.3],
+        ["u", "uṃ", ".n.", ".f.$.sg.$.acc.", 0.99],
+        ["u", "uyā", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["u", "uyā", ".n.", ".f.$.sg.$.dat.", 0.99],
+        ["u", "uyā", ".n.", ".f.$.sg.$.inst.", 0.99],
+        ["u", "uyā", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["u", "uto", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["u", "uyā", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["u", "uyaṃ", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["u", "ū", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["u", "uyo", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["u", "ūvo", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["u", "ū", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["u", "uyo", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["u", "ū", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["u", "uyo", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["u", "ūnaṃ", ".n.", ".f.$.pl.$.gen.", 0.99],
+        ["u", "ūnaṃ", ".n.", ".f.$.pl.$.dat.", 0.99],
+        ["u", "ūhi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["u", "ūbhi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["u", "ūhi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["u", "ūbhi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["u", "ūsu", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["ū", "ū", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["ū", "ū", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["ū", "uṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["ū", "ussa", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["ū", "uno", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["ū", "ussa", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["ū", "uno", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["ū", "unā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["ū", "unā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ū", "usmā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ū", "umhā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ū", "usmiṃ", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["ū", "umhi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["ū", "ū", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["ū", "avo", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["ū", "ū", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["ū", "avo", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["ū", "ave", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["ū", "ū", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["ū", "avo", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["ū", "ūnaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["ū", "ūnaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["ū", "ūhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ū", "ūbhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ū", "ūhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ū", "ūbhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ū", "ūsu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["ū", "ū", ".n.", ".f.$.sg.$.nom.", 0.99],
+        ["ū", "ū", ".n.", ".f.$.sg.$.voc.", 0.3],
+        ["ū", "uṃ", ".n.", ".f.$.sg.$.acc.", 0.99],
+        ["ū", "uyā", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["ū", "uyā", ".n.", ".f.$.sg.$.dat.", 0.99],
+        ["ū", "uyā", ".n.", ".f.$.sg.$.inst.", 0.99],
+        ["ū", "uyā", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ū", "uto", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ū", "uyā", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ū", "uyaṃ", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ū", "ū", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ū", "uyo", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ū", "ū", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["ū", "uyo", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["ū", "ū", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["ū", "uyo", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["ū", "ūnaṃ", ".n.", ".f.$.pl.$.gen.", 0.99],
+        ["ū", "ūnaṃ", ".n.", ".f.$.pl.$.dat.", 0.99],
+        ["ū", "ūhi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ū", "ūbhi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ū", "ūhi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ū", "ūbhi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ū", "ūsu", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["as", "o", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["as", "aṃ", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["o", "o", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["o", "aṃ", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["as", "o", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["as", "aṃ", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["as", "ā", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["as", "a", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["o", "o", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["o", "aṃ", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["o", "ā", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["o", "a", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["as", "o", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["as", "aṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["o", "o", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["o", "aṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["as", "aso", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["as", "assa", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["o", "aso", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["o", "assa", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["as", "aso", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["as", "assa", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["o", "aso", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["o", "assa", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["as", "asā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["as", "ena", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["o", "asā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["o", "ena", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["as", "asā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["as", "asmā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["as", "amhā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["as", "ā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["o", "asā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["o", "asmā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["o", "amhā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["o", "ā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["as", "asi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["as", "e", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["as", "asmiṃ", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["as", "amhi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["o", "asi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["o", "e", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["o", "asmiṃ", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["o", "amhi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["as", "ā", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["o", "ā", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["as", "ā", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["o", "ā", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["as", "e", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["o", "e", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["as", "ānaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["o", "ānaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["as", "ānaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["o", "ānaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["as", "ehi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["as", "ebhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["o", "ehi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["o", "ebhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["as", "ehi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["as", "ebhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["o", "ehi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["o", "ebhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["as", "esu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["o", "esu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["as", "o", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["as", "aṃ", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["o", "o", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["o", "aṃ", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["as", "o", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["as", "aṃ", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["as", "ā", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["as", "a", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["o", "o", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["o", "aṃ", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["o", "ā", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["o", "a", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["as", "o", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["as", "aṃ", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["o", "o", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["o", "aṃ", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["as", "aso", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["as", "assa", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["o", "aso", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["o", "assa", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["as", "aso", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["as", "assa", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["o", "aso", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["o", "assa", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["as", "asā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["as", "ena", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["o", "asā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["o", "ena", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["as", "asā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["as", "asmā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["as", "amhā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["as", "ā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["o", "asā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["o", "asmā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["o", "amhā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["o", "ā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["as", "asi", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["as", "e", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["as", "asmiṃ", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["as", "amhi", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["o", "asi", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["o", "e", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["o", "asmiṃ", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["o", "amhi", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["as", "ā", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["o", "ā", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["as", "ā", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["o", "ā", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["as", "e", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["o", "e", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["as", "ānaṃ", ".n.", ".nt.$.pl.$.gen.", 0.99],
+        ["o", "ānaṃ", ".n.", ".nt.$.pl.$.gen.", 0.99],
+        ["as", "ānaṃ", ".n.", ".nt.$.pl.$.dat.", 0.99],
+        ["o", "ānaṃ", ".n.", ".nt.$.pl.$.dat.", 0.99],
+        ["as", "ehi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["as", "ebhi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["o", "ehi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["o", "ebhi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["as", "ehi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["as", "ebhi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["o", "ehi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["o", "ebhi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["as", "esu", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["o", "esu", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["an", "ā", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["an", "ā", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["an", "a", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["an", "aṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["an", "ānaṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["an", "anaṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["an", "assa", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["an", "ano", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["an", "assa", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["an", "ano", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["an", "ena", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["an", "anā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["an", "anā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["an", "asmā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["an", "amhā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["an", "ani", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["an", "asmiṃ", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["an", "amhi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["an", "ā", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["an", "āno", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["an", "ā", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["an", "āno", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["an", "āno", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["an", "e", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["an", "ānaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["an", "ānaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["an", "anehi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "anebhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "anehi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["an", "anebhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["an", "anesu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["an", "aṃ", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["an", "a", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["an", "aṃ", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["an", "assa", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["an", "assa", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["an", "āya", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["an", "ena", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["an", "ā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["an", "asmā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["an", "amhā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["an", "ato", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["an", "e", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["an", "asmiṃ", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["an", "amhi", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["an", "āni", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["an", "ā", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["an", "āni", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["an", "ā", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["an", "āni", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["an", "e", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["an", "ānaṃ", ".n.", ".nt.$.pl.$.gen.", 0.99],
+        ["an", "ānaṃ", ".n.", ".nt.$.pl.$.dat.", 0.99],
+        ["an", "ehi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["an", "ebhi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["an", "ehi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["an", "ebhi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["an", "esu", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["ar", "ā", ".n.", ".f.$.sg.$.nom.", 0.99],
+        ["ar", "ā", ".n.", ".f.$.sg.$.voc.", 0.3],
+        ["ar", "aṃ", ".n.", ".f.$.sg.$.acc.", 0.99],
+        ["ar", "ānaṃ", ".n.", ".f.$.sg.$.acc.", 0.99],
+        ["ar", "assa", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["ar", "ino", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["ar", "assa", ".n.", ".f.$.sg.$.dat.", 0.99],
+        ["ar", "ino", ".n.", ".f.$.sg.$.dat.", 0.99],
+        ["ar", "ena", ".n.", ".f.$.sg.$.inst.", 0.99],
+        ["ar", "inā", ".n.", ".f.$.sg.$.inst.", 0.99],
+        ["ar", "asmā", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ar", "amhā", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ar", "ini", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ar", "asmiṃ", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ar", "amhi", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ar", "ā", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ar", "āno", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ar", "ā", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["ar", "āno", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["ar", "ā", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["ar", "āno", ".n.", ".f.$.pl.$.acc.", 0.99],
+        ["ar", "ānaṃ", ".n.", ".f.$.pl.$.gen.", 0.99],
+        ["ar", "ānaṃ", ".n.", ".f.$.pl.$.dat.", 0.99],
+        ["ar", "ehi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ar", "āhi", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ar", "ehi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ar", "āhi", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ar", "esu", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["ar", "āsu", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["ar", "ā", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["ar", "ā", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["ar", "aṃ", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["ar", "ānaṃ", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["ar", "assa", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["ar", "ino", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["ar", "assa", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["ar", "ino", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["ar", "ena", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["ar", "inā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["ar", "asmā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["ar", "amhā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["ar", "ini", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["ar", "asmiṃ", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["ar", "amhi", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["ar", "ā", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["ar", "āno", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["ar", "ā", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["ar", "āno", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["ar", "ā", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["ar", "āno", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["ar", "ānaṃ", ".n.", ".nt.$.pl.$.gen.", 0.99],
+        ["ar", "ānaṃ", ".n.", ".nt.$.pl.$.dat.", 0.99],
+        ["ar", "ehi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["ar", "āhi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["ar", "ehi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["ar", "āhi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["ar", "esu", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["ar", "āsu", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["a", "e", ".n.", ".m.$.sg.$.nom.", 0.3],
+        ["a", "ā", ".n.", ".m.$.sg.$.inst.", 0.2],
+        ["a", "asā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["a", "ā", ".n.", ".m.$.sg.$.dat.", 0.2],
+        ["a", "āya", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["a", "ā", ".n.", ".m.$.sg.$.gen.", 0.2],
+        ["a", "asi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["a", "e", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["a", "āse", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["a", "o", ".n.", ".m.$.pl.$.nom.", 0.3],
+        ["a", "ān", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["a", "e", ".n.", ".m.$.pl.$.inst.", 0.3],
+        ["a", "ato", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["a", "e", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["a", "ā", ".n.", ".nt.$.sg.$.inst.", 0.2],
+        ["a", "asā", ".n.", ".nt.$.sg.$.inst.", 0.2],
+        ["a", "ā", ".n.", ".nt.$.sg.$.dat.", 0.2],
+        ["a", "asi", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["a", "ā", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["a", "aṃ", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["a", "āya", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["a", "ā", ".n.", ".nt.$.sg.$.gen.", 0.2],
+        ["a", "o", ".n.", ".nt.$.pl.$.acc.", 0.3],
+        ["a", "ato", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["ā", "ā", ".n.", ".f.$.sg.$.inst.", 0.2],
+        ["ā", "āto", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ā", "a", ".n.", ".f.$.sg.$.voc.", 0.3],
+        ["ā", "iyo", ".n.", ".f.$.pl.$.voc.", 0.3],
+        ["i", "e", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["i", "ito", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["i", "e", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["i", "ini", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["i", "e", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["i", "iyo", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["i", "ino", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["i", "iyo", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["i", "ihi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["i", "ibhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["i", "inaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["i", "ihi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["i", "ibhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["i", "inaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["i", "isu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["i", "iyo", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["i", "ihi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["i", "ibhi", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["i", "ihi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["i", "ibhi", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["i", "inaṃ", ".n.", ".nt.$.pl.$.gen.", 0.99],
+        ["i", "inaṃ", ".n.", ".nt.$.pl.$.dat.", 0.99],
+        ["i", "isu", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["i", "iṃ", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["i", "i", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["i", "e", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["i", "ito", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["i", "e", ".n.", ".nt.$.sg.$.gen.", 0.2],
+        ["i", "ini", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["i", "e", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["i", "iṃ", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["i", "ī", ".n.", ".f.$.sg.$.nom.", 0.99],
+        ["i", "ito", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["i", "myā", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["i", "āyaṃ", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["i", "u", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["i", "ī", ".n.", ".f.$.sg.$.voc.", 0.3],
+        ["ī", "ini", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["ī", "īnaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["ī", "īnaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["ī", "īsu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["ī", "i", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["ī", "iyo", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["ī", "iye", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["ī", "iyaṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["ī", "ito", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ī", "i", ".n.", ".f.$.sg.$.nom.", 0.99],
+        ["ī", "iyaṃ", ".n.", ".f.$.sg.$.acc.", 0.99],
+        ["ī", "ito", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ī", "īto", ".n.", ".f.$.sg.$.abl.", 0.99],
+        ["ī", "āyo", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ī", "āyo", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ī", "āyo", ".n.", ".f.$.pl.$.nom.", 0.99],
+        ["ī", "inaṃ", ".n.", ".f.$.pl.$.gen.", 0.99],
+        ["ī", "inaṃ", ".n.", ".f.$.pl.$.dat.", 0.99],
+        ["ī", "īyanaṃ", ".n.", ".f.$.pl.$.gen.", 0.99],
+        ["ī", "īyanaṃ", ".n.", ".f.$.pl.$.dat.", 0.99],
+        ["ī", "iyanaṃ", ".n.", ".f.$.pl.$.gen.", 0.99],
+        ["ī", "iyanaṃ", ".n.", ".f.$.pl.$.dat.", 0.99],
+        ["ī", "isu", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["ar", "ā", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["ar", "ā", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["ar", "a", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["ar", "araṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["ar", "āraṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["ar", "u", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["ar", "ussa", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["ar", "uno", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["ar", "u", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["ar", "ussa", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["ar", "uno", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["ar", "arā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["ar", "ara", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["ar", "āra", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["ar", "ārā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["ar", "unā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["ar", "arā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ar", "ara", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ar", "āra", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ar", "ārā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ar", "unā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["ar", "ari", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["ar", "āro", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["ar", "ā", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["ar", "āro", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["ar", "ā", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["ar", "āro", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["ar", "āre", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["ar", "ānaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["ar", "ārānaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["ar", "ūnaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["ar", "ānaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["ar", "ārānaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["ar", "ūnaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["ar", "ārehi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ar", "ārebhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ar", "ārehi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ar", "ārebhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ar", "āresu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["ar", "ūsu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["ar", "āyo", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["ar", "iyo", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["an", "ane", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["an", "ā", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["an", "ubhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "ūbhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "uhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "ūhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "ūnaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["an", "ūnaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["an", "esu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["an", "ūsu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["an", "usu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["an", "a", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["an", "a", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["an", "anā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["an", "unā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["an", "no", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["an", "unā", ".n.", ".nt.$.sg.$.abl.", 0.99],
+        ["an", "no", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["an", "ani", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["an", "ā", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["as", "āni", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["as", "ā", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["as", "āni", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["as", "āni", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["as", "āni", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["as", "ā", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["as", "āni", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["as", "āni", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["as", "āni", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["as", "ā", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["as", "āni", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["as", "āni", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["us", "u", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["us", "uṃ", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["us", "u", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["us", "uṃ", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["us", "u", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["us", "uṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["us", "ussa", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["us", "uno", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["us", "ussa", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["us", "uno", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["us", "unā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["us", "usā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["us", "unā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["us", "usā", ".n.", ".m.$.sg.$.abl.", 0.99],
+        ["us", "uni", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["us", "usi", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["us", "ū", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["us", "ūni", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["us", "ū", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["us", "ūni", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["us", "ū", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["us", "ūni", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["us", "ūnaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["us", "ūsaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["us", "ūnaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["us", "ūsaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["us", "ūhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["us", "ūbhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["us", "ūhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["us", "ūbhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["us", "ūsu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["a", "assā", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["a", "assā", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["a", "enā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["a", "amhī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["a", "ehī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["a", "ebhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["a", "ehī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["a", "ebhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["a", "esū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["a", "assā", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["a", "assā", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["a", "enā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["a", "amhī", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["a", "ānī", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["a", "ānī", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["a", "ānī", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["a", "ehī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["a", "ebhī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["a", "ehī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["a", "ebhī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["a", "esū", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["ā", "āhī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ā", "ābhī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ā", "āhī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ā", "ābhī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ā", "āsū", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["i", "issā", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["i", "issā", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["i", "imhī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["i", "īhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["i", "ībhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["i", "īhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["i", "ībhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["i", "īsū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["i", "assā", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["i", "assā", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["i", "imhī", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["i", "īnī", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["i", "īnī", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["i", "īnī", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["i", "īhī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["i", "ībhī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["i", "īhī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["i", "ībhī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["i", "īsū", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["i", "īhī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["i", "ībhī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["i", "īhī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["i", "ībhī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["i", "īsū", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["ī", "issā", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["in", "issā", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["ī", "issā", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["in", "issā", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["ī", "imhī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["in", "imhī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["ī", "īhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ī", "ībhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["in", "īhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["in", "ībhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ī", "īhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ī", "ībhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["in", "īhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["in", "ībhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ī", "īsū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["in", "īsū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["ī", "īhī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ī", "ībhī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ī", "īhī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ī", "ībhī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ī", "īsū", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["u", "ussā", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["u", "ussā", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["u", "umhī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["u", "ūhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["u", "ūbhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["u", "ūhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["u", "ūbhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["u", "ūsū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["u", "ussā", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["u", "ussā", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["u", "umhī", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["u", "ūnī", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["u", "ūnī", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["u", "ūnī", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["u", "ūhī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["u", "ūbhī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["u", "ūhī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["u", "ūbhī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["u", "ūsū", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["u", "ūhī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["u", "ūbhī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["u", "ūhī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["u", "ūbhī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["u", "ūsū", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["ū", "ussā", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["ū", "ussā", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["ū", "umhī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["ū", "ūhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ū", "ūbhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ū", "ūhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ū", "ūbhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ū", "ūsū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["ū", "ūhī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ū", "ūbhī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ū", "ūhī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ū", "ūbhī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ū", "ūsū", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["as", "assā", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["o", "assā", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["as", "assā", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["o", "assā", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["as", "enā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["o", "enā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["as", "asī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["as", "amhī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["o", "asī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["o", "amhī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["as", "ehī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["as", "ebhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["o", "ehī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["o", "ebhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["as", "ehī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["as", "ebhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["o", "ehī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["o", "ebhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["as", "esū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["o", "esū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["as", "assā", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["o", "assā", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["as", "assā", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["o", "assā", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["as", "enā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["o", "enā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["as", "asī", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["as", "amhī", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["o", "asī", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["o", "amhī", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["as", "ehī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["as", "ebhī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["o", "ehī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["o", "ebhī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["as", "ehī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["as", "ebhī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["o", "ehī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["o", "ebhī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["as", "esū", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["o", "esū", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["an", "assā", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["an", "assā", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["an", "enā", ".n.", ".m.$.sg.$.inst.", 0.99],
+        ["an", "anī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["an", "amhī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["an", "anehī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "anebhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "anehī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["an", "anebhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["an", "anesū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["an", "assā", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["an", "assā", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["an", "enā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["an", "amhī", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["an", "ānī", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["an", "ānī", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["an", "ānī", ".n.", ".nt.$.pl.$.acc.", 0.99],
+        ["an", "ehī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["an", "ebhī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["an", "ehī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["an", "ebhī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["an", "esū", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["ar", "assā", ".n.", ".f.$.sg.$.gen.", 0.99],
+        ["ar", "assā", ".n.", ".f.$.sg.$.dat.", 0.99],
+        ["ar", "enā", ".n.", ".f.$.sg.$.inst.", 0.99],
+        ["ar", "amhī", ".n.", ".f.$.sg.$.loc.", 0.99],
+        ["ar", "ehī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ar", "āhī", ".n.", ".f.$.pl.$.inst.", 0.99],
+        ["ar", "ehī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ar", "āhī", ".n.", ".f.$.pl.$.abl.", 0.99],
+        ["ar", "esū", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["ar", "āsū", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["ar", "assā", ".n.", ".nt.$.sg.$.gen.", 0.99],
+        ["ar", "assā", ".n.", ".nt.$.sg.$.dat.", 0.99],
+        ["ar", "enā", ".n.", ".nt.$.sg.$.inst.", 0.99],
+        ["ar", "amhī", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["ar", "ehī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["ar", "āhī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["ar", "ehī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["ar", "āhī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["ar", "esū", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["ar", "āsū", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["a", "asī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["a", "asī", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["i", "ihī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["i", "ibhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["i", "ihī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["i", "ibhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["i", "isū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["i", "ihī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["i", "ibhī", ".n.", ".nt.$.pl.$.inst.", 0.99],
+        ["i", "ihī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["i", "ibhī", ".n.", ".nt.$.pl.$.abl.", 0.99],
+        ["i", "isū", ".n.", ".nt.$.pl.$.loc.", 0.99],
+        ["ī", "īsū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["ī", "isū", ".n.", ".f.$.pl.$.loc.", 0.99],
+        ["ar", "ussā", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["ar", "ussā", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["ar", "arī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["ar", "ārehī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ar", "ārebhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ar", "ārehī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ar", "ārebhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ar", "āresū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["ar", "ūsū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["an", "ubhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "ūbhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "uhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "ūhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["an", "esū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["an", "ūsū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["an", "usū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["an", "anī", ".n.", ".nt.$.sg.$.loc.", 0.99],
+        ["as", "ānī", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["as", "ānī", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["as", "ānī", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["as", "ānī", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["as", "ānī", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["as", "ānī", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["as", "ānī", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["as", "ānī", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["as", "ānī", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["us", "ussā", ".n.", ".m.$.sg.$.dat.", 0.99],
+        ["us", "ussā", ".n.", ".m.$.sg.$.gen.", 0.99],
+        ["us", "unī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["us", "usī", ".n.", ".m.$.sg.$.loc.", 0.99],
+        ["us", "ūnī", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["us", "ūnī", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["us", "ūnī", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["us", "ūhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["us", "ūbhī", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["us", "ūhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["us", "ūbhī", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["us", "ūsū", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["ant", "ā", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["ant", "ā", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["ant", "ā", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["ant", "a", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["ant", "ā", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["ant", "ā", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["ant", "ā", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["ant", "a", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["ant", "ā", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["ant", "ā", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["ant", "ā", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["ant", "aṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["ant", "aṃ", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["ant", "aṃ", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["ant", "aṃ", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["ant", "aṃ", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["ant", "aṃ", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["ant", "aṃ", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["ant", "aṃ", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["ant", "ānaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["ant", "ānaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["ant", "e", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["ant", "ebhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ant", "ebhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ant", "ehi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["ant", "ehi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["ant", "esu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["anta", "ā", ".n.", ".m.$.pl.$.nom.", 0.99],
+        ["anta", "ā", ".n.", ".m.$.pl.$.voc.", 0.3],
+        ["anta", "ā", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["anta", "a", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["anta", "ā", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["anta", "ā", ".n.", ".nt.$.pl.$.nom.", 0.99],
+        ["anta", "ā", ".n.", ".nt.$.pl.$.voc.", 0.3],
+        ["anta", "a", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["anta", "ā", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["anta", "ā", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["anta", "ā", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["anta", "aṃ", ".n.", ".m.$.sg.$.acc.", 0.99],
+        ["anta", "aṃ", ".n.", ".nt.$.sg.$.acc.", 0.99],
+        ["anta", "aṃ", ".n.", ".nt.$.sg.$.nom.", 0.99],
+        ["anta", "aṃ", ".n.", ".m.$.sg.$.nom.", 0.99],
+        ["anta", "aṃ", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["anta", "aṃ", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["anta", "aṃ", ".n.", ".m.$.sg.$.voc.", 0.3],
+        ["anta", "aṃ", ".n.", ".nt.$.sg.$.voc.", 0.3],
+        ["anta", "ānaṃ", ".n.", ".m.$.pl.$.dat.", 0.99],
+        ["anta", "ānaṃ", ".n.", ".m.$.pl.$.gen.", 0.99],
+        ["anta", "e", ".n.", ".m.$.pl.$.acc.", 0.99],
+        ["anta", "ebhi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["anta", "ebhi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["anta", "ehi", ".n.", ".m.$.pl.$.abl.", 0.99],
+        ["anta", "ehi", ".n.", ".m.$.pl.$.inst.", 0.99],
+        ["anta", "esu", ".n.", ".m.$.pl.$.loc.", 0.99],
+        ["ti", "ti", ".v.", ".3p.$.sg.$.pres.", 0.99],
+        ["ti", "nti", ".v.", ".3p.$.pl.$.pres.", 0.99],
+        ["ti", "te", ".v.", ".3p.$.sg.$.pres.", 0.99],
+        ["ti", "nte", ".v.", ".3p.$.pl.$.pres.", 0.99],
+        ["ti", "re", ".v.", ".3p.$.pl.$.pres.", 0.99],
+        ["ti", "ssati", ".v.", ".3p.$.sg.$.fut.", 0.99],
+        ["ti", "ssanti", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["ti", "ssate", ".v.", ".3p.$.sg.$.fut.", 0.99],
+        ["ti", "ssante", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["ti", "ssare", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["ti", "tu", ".v.", ".3p.$.sg.$.imp.", 0.99],
+        ["ti", "ntu", ".v.", ".3p.$.pl.$.imp.", 0.99],
+        ["ti", "taṃ", ".v.", ".3p.$.sg.$.imp.", 0.99],
+        ["ti", "ntaṃ", ".v.", ".3p.$.pl.$.imp.", 0.99],
+        ["ti", "sā", ".v.", ".3p.$.sg.$.cond.", 0.99],
+        ["ti", "ssa", ".v.", ".3p.$.sg.$.cond.", 0.99],
+        ["ti", "ssati", ".v.", ".3p.$.sg.$.cond.", 0.99],
+        ["ti", "ssaṃsu", ".v.", ".3p.$.pl.$.cond.", 0.99],
+        ["ti", "ssatha", ".v.", ".3p.$.sg.$.cond.", 0.99],
+        ["ti", "ssiṃsu", ".v.", ".3p.$.pl.$.cond.", 0.99],
+        ["ti", "si", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["ti", "sī", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["ti", "sā", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["ti", "siṃsu", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["ti", "sṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["ti", "suṃū", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["ti", "sā", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["ti", "sa", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["ti", "stthuṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["ti", "satthuṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["ti", "mi", ".v.", ".1p.$.sg.$.pres.", 0.99],
+        ["ti", "ma", ".v.", ".1p.$.pl.$.pres.", 0.99],
+        ["ti", "e", ".v.", ".1p.$.sg.$.pres.", 0.99],
+        ["ti", "mhe", ".v.", ".1p.$.pl.$.pres.", 0.99],
+        ["ti", "mahe", ".v.", ".1p.$.pl.$.pres.", 0.99],
+        ["ti", "mha", ".v.", ".1p.$.pl.$.pres.", 0.99],
+        ["ti", "mase", ".v.", ".1p.$.pl.$.pres.", 0.99],
+        ["ti", "mhase", ".v.", ".1p.$.pl.$.pres.", 0.99],
+        ["ti", "ssāmi", ".v.", ".1p.$.sg.$.fut.", 0.99],
+        ["ti", "ssāma", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["ti", "ssaṃ", ".v.", ".1p.$.sg.$.fut.", 0.99],
+        ["ti", "ssāmhe", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["ti", "ssāmase", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["ti", "mi", ".v.", ".1p.$.sg.$.imp.", 0.99],
+        ["ti", "ma", ".v.", ".1p.$.pl.$.imp.", 0.99],
+        ["ti", "ssa", ".v.", ".1p.$.sg.$.cond.", 0.99],
+        ["ti", "ssamhā", ".v.", ".1p.$.pl.$.cond.", 0.99],
+        ["ti", "ssaṃ", ".v.", ".1p.$.sg.$.cond.", 0.99],
+        ["ti", "ssāmhase", ".v.", ".1p.$.pl.$.cond.", 0.99],
+        ["ti", "siṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ti", "saṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ti", "sṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ti", "sa", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ti", "sā", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ti", "simha", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["ti", "simhā", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["ti", "sa", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ti", "simhe", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["ti", "si", ".v.", ".2p.$.sg.$.pres.", 0.99],
+        ["ti", "tha", ".v.", ".2p.$.pl.$.pres.", 0.99],
+        ["ti", "se", ".v.", ".2p.$.sg.$.pres.", 0.99],
+        ["ti", "vhe", ".v.", ".2p.$.pl.$.pres.", 0.99],
+        ["ti", "ssasi", ".v.", ".2p.$.sg.$.fut.", 0.99],
+        ["ti", "ssatha", ".v.", ".2p.$.pl.$.fut.", 0.99],
+        ["ti", "ssase", ".v.", ".2p.$.sg.$.fut.", 0.99],
+        ["ti", "ssavhe", ".v.", ".2p.$.pl.$.fut.", 0.99],
+        ["ti", "hi", ".v.", ".2p.$.sg.$.imp.", 0.99],
+        ["ti", "ta", ".v.", ".2p.$.pl.$.imp.", 0.99],
+        ["ti", "ssu", ".v.", ".2p.$.sg.$.imp.", 0.99],
+        ["ti", "vho", ".v.", ".2p.$.pl.$.imp.", 0.99],
+        ["ti", "se", ".v.", ".2p.$.sg.$.cond.", 0.99],
+        ["ti", "ssa", ".v.", ".2p.$.sg.$.cond.", 0.99],
+        ["ti", "ssasi", ".v.", ".2p.$.sg.$.cond.", 0.99],
+        ["ti", "ssatha", ".v.", ".2p.$.pl.$.cond.", 0.99],
+        ["ti", "ssase", ".v.", ".2p.$.sg.$.cond.", 0.99],
+        ["ti", "ssavhe", ".v.", ".2p.$.pl.$.cond.", 0.99],
+        ["ti", "si", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["ti", "so", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["ti", "sā", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["ti", "sttha", ".v.", ".2p.$.pl.$.aor.", 0.99],
+        ["ti", "sse", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["ti", "svhaṃ", ".v.", ".2p.$.pl.$.aor.", 0.99],
+        ["ti", "eyya", ".v.", ".3p.$.sg.$.opt.", 0.99],
+        ["ati", "eyyuṃ", ".v.", ".3p.$.pl.$.opt.", 0.99],
+        ["ati", "etha", ".v.", ".3p.$.sg.$.opt.", 0.99],
+        ["ati", "eraṃ", ".v.", ".3p.$.pl.$.opt.", 0.99],
+        ["ati", "issati", ".v.", ".3p.$.sg.$.fut.", 0.99],
+        ["ati", "issanti", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["ati", "issate", ".v.", ".3p.$.sg.$.fut.", 0.99],
+        ["ati", "issante", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["ati", "issare", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["ati", "i", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["ati", "ī", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["ati", "ā", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["ati", "iṃsu", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["ati", "ṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["ati", "uṃū", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["ati", "ā", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["ati", "a", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["ati", "tthuṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["ati", "atthuṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["ati", "āmi", ".v.", ".1p.$.sg.$.pres.", 0.99],
+        ["ati", "āma", ".v.", ".1p.$.pl.$.pres.", 0.99],
+        ["ati", "e", ".v.", ".1p.$.sg.$.imp.", 0.99],
+        ["ati", "āmase", ".v.", ".1p.$.pl.$.imp.", 0.99],
+        ["ati", "eyyāmi", ".v.", ".1p.$.sg.$.opt.", 0.99],
+        ["ati", "eyyāma", ".v.", ".1p.$.pl.$.opt.", 0.99],
+        ["ati", "eyyaṃ", ".v.", ".1p.$.sg.$.opt.", 0.99],
+        ["ati", "eyyāmhe", ".v.", ".1p.$.pl.$.opt.", 0.99],
+        ["ati", "issāmi", ".v.", ".1p.$.sg.$.fut.", 0.99],
+        ["ati", "issāma", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["ati", "issaṃ", ".v.", ".1p.$.sg.$.fut.", 0.99],
+        ["ati", "issāmhe", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["ati", "issāmase", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["ati", "iṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ati", "aṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ati", "ṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ati", "a", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ati", "ā", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ati", "imha", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["ati", "imhā", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["ati", "a", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["ati", "imhe", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["ati", "eyyāsi", ".v.", ".2p.$.sg.$.opt.", 0.99],
+        ["ati", "eyyātha", ".v.", ".2p.$.pl.$.opt.", 0.99],
+        ["ati", "etho", ".v.", ".2p.$.sg.$.opt.", 0.99],
+        ["ati", "eyyavho", ".v.", ".2p.$.pl.$.opt.", 0.99],
+        ["ati", "issasi", ".v.", ".2p.$.sg.$.fut.", 0.99],
+        ["ati", "issatha", ".v.", ".2p.$.pl.$.fut.", 0.99],
+        ["ati", "issase", ".v.", ".2p.$.sg.$.fut.", 0.99],
+        ["ati", "issavhe", ".v.", ".2p.$.pl.$.fut.", 0.99],
+        ["ati", "i", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["ati", "o", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["ati", "ā", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["ati", "ttha", ".v.", ".2p.$.pl.$.aor.", 0.99],
+        ["ati", "se", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["ati", "vhaṃ", ".v.", ".2p.$.pl.$.aor.", 0.99],
+        ["āti", "etha", ".v.", ".3p.$.sg.$.opt.", 0.99],
+        ["āti", "eraṃ", ".v.", ".3p.$.pl.$.opt.", 0.99],
+        ["āti", "issati", ".v.", ".3p.$.sg.$.fut.", 0.99],
+        ["āti", "issanti", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["āti", "issate", ".v.", ".3p.$.sg.$.fut.", 0.99],
+        ["āti", "issante", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["āti", "issare", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["āti", "i", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["āti", "ī", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["āti", "ā", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["āti", "iṃsu", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["āti", "ṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["āti", "uṃū", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["āti", "ā", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["āti", "a", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["āti", "tthuṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["āti", "atthuṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["āti", "e", ".v.", ".1p.$.sg.$.imp.", 0.99],
+        ["āti", "āmase", ".v.", ".1p.$.pl.$.imp.", 0.99],
+        ["āti", "eyyuṃ", ".v.", ".3p.$.pl.$.opt.", 0.99],
+        ["āti", "eyyāmi", ".v.", ".1p.$.sg.$.opt.", 0.99],
+        ["āti", "eyyāma", ".v.", ".1p.$.pl.$.opt.", 0.99],
+        ["āti", "eyyaṃ", ".v.", ".1p.$.sg.$.opt.", 0.99],
+        ["āti", "eyyāmhe", ".v.", ".1p.$.pl.$.opt.", 0.99],
+        ["āti", "issāmi", ".v.", ".1p.$.sg.$.fut.", 0.99],
+        ["āti", "issāma", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["āti", "issaṃ", ".v.", ".1p.$.sg.$.fut.", 0.99],
+        ["āti", "issāmhe", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["āti", "issāmase", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["āti", "iṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["āti", "aṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["āti", "ṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["āti", "a", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["āti", "ā", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["āti", "imha", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["āti", "imhā", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["āti", "a", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["āti", "imhe", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["āti", "eyyāsi", ".v.", ".2p.$.sg.$.opt.", 0.99],
+        ["āti", "eyyātha", ".v.", ".2p.$.pl.$.opt.", 0.99],
+        ["āti", "etho", ".v.", ".2p.$.sg.$.opt.", 0.99],
+        ["āti", "eyyavho", ".v.", ".2p.$.pl.$.opt.", 0.99],
+        ["āti", "issasi", ".v.", ".2p.$.sg.$.fut.", 0.99],
+        ["āti", "issatha", ".v.", ".2p.$.pl.$.fut.", 0.99],
+        ["āti", "issase", ".v.", ".2p.$.sg.$.fut.", 0.99],
+        ["āti", "issavhe", ".v.", ".2p.$.pl.$.fut.", 0.99],
+        ["āti", "i", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["āti", "o", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["āti", "ā", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["āti", "ttha", ".v.", ".2p.$.pl.$.aor.", 0.99],
+        ["āti", "se", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["āti", "vhaṃ", ".v.", ".2p.$.pl.$.aor.", 0.99],
+        ["eti", "etha", ".v.", ".3p.$.sg.$.opt.", 0.99],
+        ["eti", "eraṃ", ".v.", ".3p.$.pl.$.opt.", 0.99],
+        ["eti", "issati", ".v.", ".3p.$.sg.$.fut.", 0.99],
+        ["eti", "issanti", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["eti", "issate", ".v.", ".3p.$.sg.$.fut.", 0.99],
+        ["eti", "issante", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["eti", "issare", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["eti", "i", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["eti", "ī", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["eti", "ā", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["eti", "iṃsu", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["eti", "ṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["eti", "uṃū", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["eti", "ā", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["eti", "a", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["eti", "tthuṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["eti", "atthuṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["eti", "e", ".v.", ".1p.$.sg.$.imp.", 0.99],
+        ["eti", "āmase", ".v.", ".1p.$.pl.$.imp.", 0.99],
+        ["eti", "eyyāmi", ".v.", ".1p.$.sg.$.opt.", 0.99],
+        ["eti", "eyyuṃ", ".v.", ".3p.$.pl.$.opt.", 0.99],
+        ["eti", "eyyāma", ".v.", ".1p.$.pl.$.opt.", 0.99],
+        ["eti", "eyyaṃ", ".v.", ".1p.$.sg.$.opt.", 0.99],
+        ["eti", "eyyāmhe", ".v.", ".1p.$.pl.$.opt.", 0.99],
+        ["eti", "issāmi", ".v.", ".1p.$.sg.$.fut.", 0.99],
+        ["eti", "issāma", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["eti", "issaṃ", ".v.", ".1p.$.sg.$.fut.", 0.99],
+        ["eti", "issāmhe", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["eti", "issāmase", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["eti", "iṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["eti", "aṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["eti", "ṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["eti", "a", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["eti", "ā", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["eti", "imha", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["eti", "imhā", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["eti", "a", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["eti", "imhe", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["eti", "eyyāsi", ".v.", ".2p.$.sg.$.opt.", 0.99],
+        ["eti", "eyyātha", ".v.", ".2p.$.pl.$.opt.", 0.99],
+        ["eti", "etho", ".v.", ".2p.$.sg.$.opt.", 0.99],
+        ["eti", "eyyavho", ".v.", ".2p.$.pl.$.opt.", 0.99],
+        ["eti", "issasi", ".v.", ".2p.$.sg.$.fut.", 0.99],
+        ["eti", "issatha", ".v.", ".2p.$.pl.$.fut.", 0.99],
+        ["eti", "issase", ".v.", ".2p.$.sg.$.fut.", 0.99],
+        ["eti", "issavhe", ".v.", ".2p.$.pl.$.fut.", 0.99],
+        ["eti", "i", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["eti", "o", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["eti", "ā", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["eti", "ttha", ".v.", ".2p.$.pl.$.aor.", 0.99],
+        ["eti", "se", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["eti", "vhaṃ", ".v.", ".2p.$.pl.$.aor.", 0.99],
+        ["oti", "etha", ".v.", ".3p.$.sg.$.opt.", 0.99],
+        ["oti", "eraṃ", ".v.", ".3p.$.pl.$.opt.", 0.99],
+        ["oti", "issati", ".v.", ".3p.$.sg.$.fut.", 0.99],
+        ["oti", "issanti", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["oti", "issate", ".v.", ".3p.$.sg.$.fut.", 0.99],
+        ["oti", "issante", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["oti", "issare", ".v.", ".3p.$.pl.$.fut.", 0.99],
+        ["oti", "i", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["oti", "ī", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["oti", "ā", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["oti", "iṃsu", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["oti", "ṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["oti", "uṃū", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["oti", "ā", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["oti", "a", ".v.", ".3p.$.sg.$.aor.", 0.99],
+        ["oti", "tthuṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["oti", "atthuṃ", ".v.", ".3p.$.pl.$.aor.", 0.99],
+        ["oti", "e", ".v.", ".1p.$.sg.$.imp.", 0.99],
+        ["oti", "āmase", ".v.", ".1p.$.pl.$.imp.", 0.99],
+        ["oti", "eyyuṃ", ".v.", ".3p.$.pl.$.opt.", 0.99],
+        ["oti", "eyyāmi", ".v.", ".1p.$.sg.$.opt.", 0.99],
+        ["oti", "eyyāma", ".v.", ".1p.$.pl.$.opt.", 0.99],
+        ["oti", "eyyaṃ", ".v.", ".1p.$.sg.$.opt.", 0.99],
+        ["oti", "eyyāmhe", ".v.", ".1p.$.pl.$.opt.", 0.99],
+        ["oti", "issāmi", ".v.", ".1p.$.sg.$.fut.", 0.99],
+        ["oti", "issāma", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["oti", "issaṃ", ".v.", ".1p.$.sg.$.fut.", 0.99],
+        ["oti", "issāmhe", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["oti", "issāmase", ".v.", ".1p.$.pl.$.fut.", 0.99],
+        ["oti", "iṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["oti", "aṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["oti", "ṃ", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["oti", "a", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["oti", "ā", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["oti", "imha", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["oti", "imhā", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["oti", "a", ".v.", ".1p.$.sg.$.aor.", 0.99],
+        ["oti", "imhe", ".v.", ".1p.$.pl.$.aor.", 0.99],
+        ["oti", "eyyāsi", ".v.", ".2p.$.sg.$.opt.", 0.99],
+        ["oti", "eyyātha", ".v.", ".2p.$.pl.$.opt.", 0.99],
+        ["oti", "etho", ".v.", ".2p.$.sg.$.opt.", 0.99],
+        ["oti", "eyyavho", ".v.", ".2p.$.pl.$.opt.", 0.99],
+        ["oti", "issasi", ".v.", ".2p.$.sg.$.fut.", 0.99],
+        ["oti", "issatha", ".v.", ".2p.$.pl.$.fut.", 0.99],
+        ["oti", "issase", ".v.", ".2p.$.sg.$.fut.", 0.99],
+        ["oti", "issavhe", ".v.", ".2p.$.pl.$.fut.", 0.99],
+        ["oti", "i", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["oti", "o", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["oti", "ā", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["oti", "ttha", ".v.", ".2p.$.pl.$.aor.", 0.99],
+        ["oti", "se", ".v.", ".2p.$.sg.$.aor.", 0.99],
+        ["oti", "vhaṃ", ".v.", ".2p.$.pl.$.aor.", 0.99],
+        ["ati", "ittha", ".v.", ".2p.$.pl.$.aor.", 0.99],
 
-		["ti","māna",".ti:base.",".prp.",0.99],
-		["ati","anta",".ti:base.",".prp.",0.99],
-		["ti","ta",".ti:base.",".pp.",0.99],
-		["ti","na",".ti:base.",".pp.",0.99],
-		["eti","enta",".ti:base.",".prp.",0.99],
-		["ati","eyya",".ti:base.",".fpp.",0.99],
-		["eti","eyya",".ti:base.",".fpp.",0.99],
-		["oti","eyya",".ti:base.",".fpp.",0.99],
-		["ti","tabba",".ti:base.",".fpp.",0.99],
-		["ati","itabba",".ti:base.",".fpp.",0.99],
-		["eti","itabba",".ti:base.",".fpp.",0.99],
-		["oti","itabba",".ti:base.",".fpp.",0.99],
-		["ati","anīya",".ti:base.",".fpp.",0.99],
-		["eti","anīya",".ti:base.",".fpp.",0.99],
-		["oti","anīya",".ti:base.",".fpp.",0.99],
-		["ati","āpeti",".v:base.",".caus.",0.99],
-		["ati","yati",".v:base.",".pp.",0.99],
-		["oti","āpeti",".v:base.",".caus.",0.99],
-		["oti","yati",".v:base.",".pp.",0.99],
-	];
+        ["ti", "māna", ".ti:base.", ".prp.", 0.99],
+        ["ati", "anta", ".ti:base.", ".prp.", 0.99],
+        ["ti", "ta", ".ti:base.", ".pp.", 0.99],
+        ["ti", "na", ".ti:base.", ".pp.", 0.99],
+        ["eti", "enta", ".ti:base.", ".prp.", 0.99],
+        ["ati", "eyya", ".ti:base.", ".fpp.", 0.99],
+        ["eti", "eyya", ".ti:base.", ".fpp.", 0.99],
+        ["oti", "eyya", ".ti:base.", ".fpp.", 0.99],
+        ["ti", "tabba", ".ti:base.", ".fpp.", 0.99],
+        ["ati", "itabba", ".ti:base.", ".fpp.", 0.99],
+        ["eti", "itabba", ".ti:base.", ".fpp.", 0.99],
+        ["oti", "itabba", ".ti:base.", ".fpp.", 0.99],
+        ["ati", "anīya", ".ti:base.", ".fpp.", 0.99],
+        ["eti", "anīya", ".ti:base.", ".fpp.", 0.99],
+        ["oti", "anīya", ".ti:base.", ".fpp.", 0.99],
+        ["ati", "āpeti", ".v:base.", ".caus.", 0.99],
+        ["ati", "yati", ".v:base.", ".pp.", 0.99],
+        ["oti", "āpeti", ".v:base.", ".caus.", 0.99],
+        ["oti", "yati", ".v:base.", ".pp.", 0.99],
+    ];
 
-	public $derivatives = [
-		["ti","māna",".ti:base.",".prp.",0.99],
-		["ati","anta",".ti:base.",".prp.",0.99],
-		["eti","anta",".ti:base.",".prp.",0.99],
-		["oti","anta",".ti:base.",".prp.",0.99],
-		["ti","ta",".ti:base.",".pp.",0.99],
-		["ti","na",".ti:base.",".pp.",0.99],
-		["ati","eyya",".ti:base.",".fpp.",0.99],
-		["eti","eyya",".ti:base.",".fpp.",0.99],
-		["oti","eyya",".ti:base.",".fpp.",0.99],
-		["ti","tabba",".ti:base.",".fpp.",0.99],
-		["ati","itabba",".ti:base.",".fpp.",0.99],
-		["eti","itabba",".ti:base.",".fpp.",0.99],
-		["oti","itabba",".ti:base.",".fpp.",0.99],
-		["ati","anīya",".ti:base.",".fpp.",0.99],
-		["eti","anīya",".ti:base.",".fpp.",0.99],
-		["oti","anīya",".ti:base.",".fpp.",0.99],
-		["ati","āpeti",".v:base.",".caus.",0.99],
-		["ati","yati",".v:base.",".pass.",0.99],
-		["oti","āpeti",".v:base.",".caus.",0.99],
-		["oti","yati",".v:base.",".pass.",0.99],
-	];
+    public $derivatives = [
+        ["ti", "māna", ".ti:base.", ".prp.", 0.99],
+        ["ati", "anta", ".ti:base.", ".prp.", 0.99],
+        ["eti", "anta", ".ti:base.", ".prp.", 0.99],
+        ["oti", "anta", ".ti:base.", ".prp.", 0.99],
+        ["ti", "ta", ".ti:base.", ".pp.", 0.99],
+        ["ti", "na", ".ti:base.", ".pp.", 0.99],
+        ["ati", "eyya", ".ti:base.", ".fpp.", 0.99],
+        ["eti", "eyya", ".ti:base.", ".fpp.", 0.99],
+        ["oti", "eyya", ".ti:base.", ".fpp.", 0.99],
+        ["ti", "tabba", ".ti:base.", ".fpp.", 0.99],
+        ["ati", "itabba", ".ti:base.", ".fpp.", 0.99],
+        ["eti", "itabba", ".ti:base.", ".fpp.", 0.99],
+        ["oti", "itabba", ".ti:base.", ".fpp.", 0.99],
+        ["ati", "anīya", ".ti:base.", ".fpp.", 0.99],
+        ["eti", "anīya", ".ti:base.", ".fpp.", 0.99],
+        ["oti", "anīya", ".ti:base.", ".fpp.", 0.99],
+        ["ati", "āpeti", ".v:base.", ".caus.", 0.99],
+        ["ati", "yati", ".v:base.", ".pass.", 0.99],
+        ["oti", "āpeti", ".v:base.", ".caus.", 0.99],
+        ["oti", "yati", ".v:base.", ".pass.", 0.99],
+    ];
 
-	public $union = [
-		["ssa","ssāpi",'api'],
-		["ssa","ssāti",'iti'],
-		["ena","enāti",'iti'],
-		["ena","enāpi",'api'],
-		["ṃ","ñca",'ca'],
-		["ṃ","ñhi",'hi'],
-		["ṃ","nti",'iti'],
-		["a","āti",'iti'],
-		["ā","āti",'iti'],
-        ["e","eti",'iti'],
-		["ī","īti",'iti'],
-		["i","īti",'iti'],
-		["o","oti",'iti'],
-		["u","ūti",'iti'],
-		["ū","ūti",'iti'],
-		["ā","āpi",'api'],
-		["a","āpi",'api'],
-		["e","epi",'api'],
-		["ī","īpi",'api'],
-		["i","īpi",'api'],
-		["o","opi",'api'],
-		["ū","upi",'api'],
-		["u","upi",'api'],
-		["ṃ","mpi",'api'],
-		["a","eva",'eva'],
-		["e","eva",'eva'],
-		["i","yeva",'eva'],
-		["o","ova",'eva'],
-		["u","veva",'eva'],
-		["ṃ","meva",'eva'],
-	];
+    public $union = [
+        ["ssa", "ssāpi", 'api'],
+        ["ssa", "ssāti", 'iti'],
+        ["ena", "enāti", 'iti'],
+        ["ena", "enāpi", 'api'],
+        ["ṃ", "ñca", 'ca'],
+        ["ṃ", "ñhi", 'hi'],
+        ["ṃ", "nti", 'iti'],
+        ["a", "āti", 'iti'],
+        ["ā", "āti", 'iti'],
+        ["e", "eti", 'iti'],
+        ["ī", "īti", 'iti'],
+        ["i", "īti", 'iti'],
+        ["o", "oti", 'iti'],
+        ["u", "ūti", 'iti'],
+        ["ū", "ūti", 'iti'],
+        ["ā", "āpi", 'api'],
+        ["a", "āpi", 'api'],
+        ["e", "epi", 'api'],
+        ["ī", "īpi", 'api'],
+        ["i", "īpi", 'api'],
+        ["o", "opi", 'api'],
+        ["ū", "upi", 'api'],
+        ["u", "upi", 'api'],
+        ["ṃ", "mpi", 'api'],
+        ["a", "eva", 'eva'],
+        ["e", "eva", 'eva'],
+        ["i", "yeva", 'eva'],
+        ["o", "ova", 'eva'],
+        ["u", "veva", 'eva'],
+        ["ṃ", "meva", 'eva'],
+    ];
 }

+ 25 - 9
api-v8/app/Tools/CaseMan.php

@@ -259,14 +259,25 @@ class CaseMan
                             if (!isset($newBase[$base])) {
                                 $newBase[$base] = array();
                             }
-                            array_push($newBase[$base], [
+                            $info = [
                                 'word' => $currWord,
                                 'type' => $ending[2],
                                 'grammar' => $ending[3],
                                 'parent' => $base,
                                 'factors' => "{$base}+[{$ending[1]}]",
                                 'confidence' => $ending[4],
-                            ]);
+                            ];
+                            array_push($newBase[$base], $info);
+                            if ($ending[2] === '.n.') {
+                                $info['type'] = '.ti.';
+                                array_push($newBase[$base], $info);
+                                $info['type'] = '.adj.';
+                                array_push($newBase[$base], $info);
+                            }
+                            if ($ending[2] === '.ti.') {
+                                $info['type'] = '.adj.';
+                                array_push($newBase[$base], $info);
+                            }
                         }
                     }
                 }
@@ -284,9 +295,7 @@ class CaseMan
             foreach ($newBase as $base => $rows) {
                 # code...
                 if (($verify = $this->VerifyBase($base, $rows)) !== false) {
-                    if (count($verify) > 0) {
-                        $output[$base] = $verify;
-                    }
+                    $output[$base] = $verify;
                 }
             }
             if (count($output) == 0) {
@@ -317,14 +326,21 @@ class CaseMan
     {
         #
         $output = array();
-        $dictWords = UserDict::where('word', $base)->select(['type', 'grammar'])->groupBy(['type', 'grammar'])->get();
+        $dictWords = UserDict::where('word', $base)
+            ->select(['type', 'grammar'])
+            ->groupBy(['type', 'grammar'])
+            ->get();
         if (count($dictWords) > 0) {
             $newBase[$base] = 1;
             $case = array();
             //字典中这个拼写的单词的语法信息
             foreach ($dictWords as $value) {
-                # code...
-                $case["{$value->type}{$value->grammar}"] = 1;
+                if ($value->type === '.n.') {
+                    $arrGrammar = explode('$', $value->grammar);
+                    $case[$value->type . $arrGrammar[0]] = 1;
+                } else {
+                    $case[$value->type] = 1;
+                }
             }
             foreach ($rows as $value) {
                 //根据输入的猜测的type,grammar拼接合理的 parent 语法信息
@@ -342,7 +358,7 @@ class CaseMan
                         $parentType = '';
                         break;
                 }
-                if (!empty($value['grammar']) && $value['type'] !== ".v.") {
+                if (!empty($value['grammar']) && $value['type'] === ".n.") {
                     $arrGrammar = explode('$', $value['grammar']);
                     $parentType .=  $arrGrammar[0];
                 }

+ 5 - 1
api-v8/composer.json

@@ -19,6 +19,7 @@
         "laravel/tinker": "^2.5",
         "league/flysystem-aws-s3-v3": "^1.0",
         "mustache/mustache": "^2.14",
+        "opensearch-project/opensearch-php": "^2.4",
         "php-amqplib/php-amqplib": ">=3.0",
         "php-ffmpeg/php-ffmpeg": "^1.1",
         "phpoffice/phpspreadsheet": "^1.28"
@@ -74,7 +75,10 @@
     "config": {
         "optimize-autoloader": true,
         "preferred-install": "dist",
-        "sort-packages": true
+        "sort-packages": true,
+        "allow-plugins": {
+            "php-http/discovery": true
+        }
     },
     "minimum-stability": "dev",
     "prefer-stable": true

+ 13 - 0
api-v8/config/mint.php

@@ -108,6 +108,7 @@ return [
     ],
 
     'ai' => [
+        'proxy' => env('OPENAI_PROXY', 'http://127.0.0.1:4000'),
         'assistant' => 'test161',
         'default' => 'kimi',
         'logo' => [
@@ -147,4 +148,16 @@ return [
             ],
         ],
     ],
+    'opensearch' => [
+        'index' => 'wikipali',
+        'config' => [
+            'scheme' => env('OPENSEARCH_SCHEME', 'http'),
+            'host' => env('OPENSEARCH_HOST', '127.0.0.1'),
+            'port' => env('OPENSEARCH_PORT', 9200),
+            'username' => env('OPENSEARCH_USERNAME', ''),
+            'password' => env('OPENSEARCH_PASSWORD', ''),
+            'ssl_verification' => env('OPENSEARCH_SSL_VERIFICATION', false),
+        ],
+
+    ],
 ];

+ 24 - 0
api-v8/database/factories/ChatFactory.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace Database\Factories;
+
+use App\Models\Chat;
+use Illuminate\Database\Eloquent\Factories\Factory;
+use Illuminate\Support\Str;
+
+class ChatFactory extends Factory
+{
+    /**
+     * Define the model's default state.
+     *
+     * @return array
+     */
+    public function definition()
+    {
+        return [
+            'uid' => (string) Str::uuid(),
+            'title' => $this->faker->sentence(3),
+            'user_id' => 'ba5463f3-72d1-4410-858e-eadd10884713', // 或者 User::factory() 如果有用户系统
+        ];
+    }
+}

+ 123 - 0
api-v8/database/factories/ChatMessageFactory.php

@@ -0,0 +1,123 @@
+<?php
+
+namespace Database\Factories;
+
+use App\Models\Chat;
+use App\Models\ChatMessage;
+use Illuminate\Database\Eloquent\Factories\Factory;
+use Illuminate\Support\Str;
+
+class ChatMessageFactory extends Factory
+{
+    /**
+     * Define the model's default state.
+     *
+     * @return array
+     */
+    public function definition()
+    {
+        return [
+            'uid' => (string) Str::uuid(),
+            'chat_id' => Chat::factory(),
+            'parent_id' => null,
+            'session_id' => (string) Str::uuid(),
+            'role' => $this->faker->randomElement(['user', 'assistant', 'tool']),
+            'content' => $this->faker->paragraph,
+            'model_id' => null,
+            'tool_calls' => null,
+            'tool_call_id' => null,
+            'is_active' => true,
+        ];
+    }
+
+    public function user()
+    {
+        return $this->state(function (array $attributes) {
+            return [
+                'role' => 'user',
+                'content' => $this->faker->sentence,
+                'model_name' => null,
+                'tool_calls' => null,
+                'tool_call_id' => null,
+            ];
+        });
+    }
+
+    public function assistant()
+    {
+        return $this->state(function (array $attributes) {
+            return [
+                'role' => 'assistant',
+                'content' => $this->faker->paragraph,
+                'model_name' => $this->faker->randomElement(['gpt-4', 'gpt-3.5-turbo', 'claude-3']),
+                'tool_calls' => null,
+                'tool_call_id' => null,
+            ];
+        });
+    }
+
+    public function tool()
+    {
+        return $this->state(function (array $attributes) {
+            return [
+                'role' => 'tool',
+                'content' => $this->faker->paragraph,
+                'model_name' => null,
+                'tool_calls' => null,
+                'tool_call_id' => 'call_' . $this->faker->randomNumber(8),
+            ];
+        });
+    }
+
+    public function withToolCalls()
+    {
+        return $this->state(function (array $attributes) {
+            return [
+                'role' => 'assistant',
+                'content' => null,
+                'tool_calls' => [
+                    [
+                        'id' => 'call_' . $this->faker->randomNumber(8),
+                        'function' => $this->faker->randomElement(['get_weather', 'search_web', 'calculate']),
+                        'arguments' => [
+                            'query' => $this->faker->sentence,
+                            'city' => $this->faker->city
+                        ]
+                    ]
+                ]
+            ];
+        });
+    }
+
+    public function inactive()
+    {
+        return $this->state(function (array $attributes) {
+            return [
+                'is_active' => false,
+            ];
+        });
+    }
+
+    public function withMetadata($metadata = null)
+    {
+        return $this->state(function (array $attributes) use ($metadata) {
+            return [
+                'metadata' => $metadata ?: [
+                    'temperature' => $this->faker->randomFloat(2, 0, 2),
+                    'tokens' => $this->faker->numberBetween(50, 500),
+                    'max_tokens' => $this->faker->numberBetween(500, 2000),
+                    'model_version' => $this->faker->randomElement(['1.0', '1.1', '2.0'])
+                ],
+            ];
+        });
+    }
+
+    public function withEditor($editorId = null)
+    {
+        return $this->state(function (array $attributes) use ($editorId) {
+            return [
+                'editor_id' => $editorId ?: (string) Str::uuid(),
+            ];
+        });
+    }
+}

+ 39 - 0
api-v8/database/migrations/2025_09_07_154047_create_chats_table.php

@@ -0,0 +1,39 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateChatsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('chats', function (Blueprint $table) {
+            $table->id();
+            $table->uuid('uid')->unique()->comment('UUID唯一标识');
+            $table->string('title')->comment('聊天标题');
+            $table->uuid('user_id')->comment('用户ID');
+            $table->timestamps();
+            $table->softDeletes(); // deleted_at
+
+            $table->index('uid');
+            $table->index('user_id');
+            $table->index('created_at');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('chats');
+    }
+}

+ 54 - 0
api-v8/database/migrations/2025_09_07_154243_create_chat_messages_table.php

@@ -0,0 +1,54 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateChatMessagesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('chat_messages', function (Blueprint $table) {
+            $table->id();
+            $table->uuid('uid')->unique()->comment('UUID唯一标识');
+            $table->uuid('chat_id')->comment('关联chats.uid');
+            $table->uuid('parent_id')->nullable()->comment('关联chat_messages.uid');
+            $table->uuid('session_id')->comment('会话段ID');
+
+            $table->enum('role', ['system', 'user', 'assistant', 'tool'])->comment('消息角色');
+            $table->text('content')->nullable()->comment('消息内容');
+            $table->uuid('model_id')->nullable()->comment('使用的模型UUID');
+            $table->json('tool_calls')->nullable()->comment('函数调用信息');
+            $table->string('tool_call_id', 100)->nullable()->comment('工具调用ID');
+
+            $table->json('metadata')->nullable()->comment('元数据信息(temperature, tokens等)');
+            $table->uuid('editor_id')->nullable()->comment('编辑者UUID');
+
+            $table->boolean('is_active')->default(true)->comment('是否为当前激活版本');
+            $table->timestamps();
+            $table->softDeletes(); // deleted_at
+
+
+            $table->index('uid');
+            $table->index('chat_id');
+            $table->index('parent_id');
+            $table->index('session_id');
+            $table->index(['chat_id', 'is_active']);
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('chat_messages');
+    }
+}

+ 16 - 1
api-v8/routes/api.php

@@ -117,6 +117,11 @@ use App\Http\Controllers\ModelLogController;
 use App\Http\Controllers\SentenceAttachmentController;
 use App\Http\Controllers\EmailCertificationController;
 use App\Http\Controllers\MockOpenAIController;
+use App\Http\Controllers\SysModelController;
+use App\Http\Controllers\ChatController;
+use App\Http\Controllers\ChatMessageController;
+use App\Http\Controllers\SearchPlusController;
+use App\Http\Controllers\SearchSuggestController;
 
 
 
@@ -211,7 +216,6 @@ Route::group(['prefix' => 'v2'], function () {
     Route::apiResource('user-statistic', UserStatisticController::class);
     Route::apiResource('sent-sim', SentSimController::class);
     Route::apiResource('nissaya-ending', NissayaEndingController::class);
-    Route::get('nissaya-ending-card', [NissayaEndingController::class, "nissaya_card"]);
     Route::get('nissaya-ending-export', [NissayaEndingController::class, "export"]);
     Route::get('nissaya-ending-import', [NissayaEndingController::class, "import"]);
     Route::get('nissaya-ending-vocabulary', [NissayaEndingController::class, "vocabulary"]);
@@ -291,8 +295,19 @@ Route::group(['prefix' => 'v2'], function () {
     Route::apiResource('sentence-attachment', SentenceAttachmentController::class);
     Route::apiResource('email-certification', EmailCertificationController::class);
     Route::apiResource('sentence-info', SentenceInfoController::class);
+    Route::apiResource('system-model', SysModelController::class);
+    Route::apiResource('chats', ChatController::class);
+    Route::apiResource('chat-messages', ChatMessageController::class);
 
     Route::post('mock/openai/chat/completions', [MockOpenAIController::class, 'chatCompletions']);
     Route::post('mock/openai/completions', [MockOpenAIController::class, 'completions']);
     Route::get('mock/openai/models', [MockOpenAIController::class, 'models']);
+
+    Route::apiResource('chat-messages', ChatMessageController::class);
+});
+
+
+Route::group(['prefix' => 'v3'], function () {
+    Route::apiResource('search', SearchPlusController::class);
+    Route::apiResource('search-suggest', SearchSuggestController::class);
 });

+ 89 - 0
api-v8/tests/Feature/ChatControllerTest.php

@@ -0,0 +1,89 @@
+<?php
+
+namespace Tests\Feature;
+
+use App\Models\Chat;
+use App\Models\ChatMessage;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Foundation\Testing\WithFaker;
+use Tests\TestCase;
+
+class ChatControllerTest extends TestCase
+{
+    use  WithFaker;
+
+    public function test_can_create_chat()
+    {
+        $data = [
+            'title' => $this->faker->sentence,
+            'user_id' => "ba5463f3-72d1-4410-858e-eadd10884713"
+        ];
+
+        $response = $this->postJson('/api/v2/chats', $data);
+
+        $response->assertStatus(200)
+            ->assertJsonStructure([
+                'data' => [
+                    'id',
+                    'title',
+                    'user_id',
+                    'created_at',
+                    'updated_at'
+                ]
+            ]);
+
+        $this->assertDatabaseHas('chats', [
+            'title' => $data['title']
+        ]);
+    }
+
+    public function test_can_list_chats()
+    {
+        Chat::factory()->count(1)->create();
+
+        $response = $this->getJson('/api/v2/chats?user_id=ba5463f3-72d1-4410-858e-eadd10884713');
+
+        $response->assertStatus(200)
+            ->assertJsonStructure([
+                'data' => [
+                    'rows' => [
+                        '*' => [
+                            'id',
+                            'title',
+                            'created_at',
+                            'updated_at'
+                        ]
+                    ]
+                ]
+            ]);
+    }
+
+    public function test_can_show_chat()
+    {
+        $chat = Chat::factory()->create();
+
+        $response = $this->getJson("/api/v2/chats/{$chat->uid}");
+
+        $response->assertStatus(200)
+            ->assertJson([
+                'data' => [
+                    'id' => $chat->uid,
+                    'title' => $chat->title
+                ]
+            ]);
+    }
+
+
+
+    public function test_can_delete_chat()
+    {
+        $chat = Chat::factory()->create();
+
+        $response = $this->deleteJson("/api/chats/{$chat->uid}");
+
+        $response->assertStatus(200);
+        $this->assertDatabaseMissing('chats', [
+            'id' => $chat->id
+        ]);
+    }
+}

+ 56 - 0
api-v8/tests/Feature/ChatMessageControllerTest.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace Tests\Feature;
+
+use App\Models\Chat;
+use App\Models\ChatMessage;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Foundation\Testing\WithFaker;
+use Tests\TestCase;
+
+class ChatMessageControllerTest extends TestCase
+{
+    use  WithFaker;
+
+    protected $chat;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $this->chat = Chat::factory()->create();
+    }
+
+    public function test_can_create_chat_message()
+    {
+        $data = [
+            'chat_id' => $this->chat->uid,
+            'messages' => [
+                [
+                    'role' => 'user',
+                    'content' => $this->faker->sentence
+                ]
+            ]
+        ];
+
+        $response = $this->postJson("/api/v2/chat-messages", $data);
+
+        $response->assertStatus(200);
+
+        $this->assertDatabaseHas('chat_messages', [
+            'chat_id' => $this->chat->uid,
+            'role' => 'user',
+            'content' => $data['messages'][0]['content']
+        ]);
+    }
+
+    public function test_can_list_chat_messages()
+    {
+        ChatMessage::factory()->count(3)->create([
+            'chat_id' => $this->chat->id
+        ]);
+
+        $response = $this->getJson("/api/v2/chat-messages?chat={$this->chat->id}");
+
+        $response->assertStatus(200);
+    }
+}

+ 1 - 1
api-v8/tests/Feature/MockOpenAIApiTest.php

@@ -15,7 +15,7 @@ class MockOpenAIApiTest extends TestCase
     /**
      * 测试聊天完成 API - 成功响应
      */
-    public function test_chat_completions_success_response()
+    public function test_openai_completions_success_response()
     {
         $response = $this->postJson($this->baseUrl . '/chat/completions', [
             'model' => 'gpt-3.5-turbo',

+ 14 - 0
dashboard-v4/dashboard/src/Router.tsx

@@ -38,6 +38,9 @@ import AdminUsersShow from "./pages/admin/users/show";
 import AdminInvite from "./pages/admin/invite";
 import AdminInviteList from "./pages/admin/invite/list";
 
+import AdminAI from "./pages/admin/ai";
+import AdminAIList from "./pages/admin/ai/list";
+
 import LibraryHome from "./pages/library";
 
 import LibraryCommunity from "./pages/library/community";
@@ -89,6 +92,10 @@ import LibraryDownloadPage from "./pages/library/download/Download";
 import LibraryNotifications from "./pages/library/notifications";
 import LibraryNotificationsList from "./pages/library/notifications/list";
 
+import LibraryChat from "./pages/library/chat";
+import LibraryChatAI from "./pages/library/chat/ai";
+import LibraryChatNew from "./pages/library/chat/new";
+
 import Studio from "./pages/studio";
 import StudioHome from "./pages/studio/home";
 
@@ -189,6 +196,9 @@ const Widget = () => {
           <Route path="invite" element={<AdminInvite />}>
             <Route path="list" element={<AdminInviteList />} />
           </Route>
+          <Route path="ai" element={<AdminAI />}>
+            <Route path="list" element={<AdminAIList />} />
+          </Route>
         </Route>
 
         <Route path="users" element={<Users />}>
@@ -302,6 +312,10 @@ const Widget = () => {
           <Route path="home" element={<LibrarySearchKey />} />
           <Route path="key/:key" element={<LibrarySearchKey />} />
         </Route>
+        <Route path="chat" element={<LibraryChat />}>
+          <Route path="new" element={<LibraryChatNew />} />
+          <Route path="c/:id" element={<LibraryChatAI />} />
+        </Route>
 
         <Route path="download" element={<LibraryDownload />}>
           <Route path="download" element={<LibraryDownloadPage />} />

+ 4 - 0
dashboard-v4/dashboard/src/components/admin/LeftSider.tsx

@@ -39,6 +39,10 @@ const LeftSiderWidget = ({ selectedKeys = "" }: IWidgetHeadBar) => {
           label: <Link to="/admin/nissaya-ending/list">Nissaya Ending</Link>,
           key: "nissaya-ending",
         },
+        {
+          label: <Link to="/admin/ai/list">AI</Link>,
+          key: "ai",
+        },
         {
           label: "Dictionary",
           key: "dict",

+ 13 - 1
dashboard-v4/dashboard/src/components/api/Corpus.ts

@@ -34,7 +34,7 @@ export interface IApiResponsePaliChapter {
   data: IApiPaliChapterList;
 }
 
-export interface IApiResponsePaliPara {
+export interface IPaliPara {
   book: number;
   paragraph: number;
   level: number;
@@ -49,6 +49,18 @@ export interface IApiResponsePaliPara {
   parent: number;
   chapter_strlen: number;
   path: string;
+  uid: string;
+}
+
+export interface IPaliParagraphResponse {
+  ok: boolean;
+  message: string;
+  data: IPaliPara;
+}
+export interface IPaliListResponse {
+  ok: boolean;
+  message: string;
+  data: { rows: IPaliPara[]; count: number };
 }
 
 /**

+ 5 - 0
dashboard-v4/dashboard/src/components/api/ai.ts

@@ -98,3 +98,8 @@ export interface IAiModelLogListResponse {
   message: string;
   data: { rows: IAiModelLogData[]; total: number };
 }
+
+export interface IAiModelSystem {
+  view: string;
+  models: string[];
+}

+ 423 - 0
dashboard-v4/dashboard/src/components/article/TreeText.tsx

@@ -0,0 +1,423 @@
+import React, { useState, useCallback, useEffect } from "react";
+import { Tree, Segmented, Spin } from "antd";
+import type { TreeDataNode } from "antd";
+import {
+  BookOutlined,
+  FileTextOutlined,
+  FolderOutlined,
+  FontSizeOutlined,
+  TranslationOutlined,
+} from "@ant-design/icons";
+import { get } from "../../request";
+import {
+  IPaliListResponse,
+  IPaliParagraphResponse,
+  ISentenceListResponse,
+} from "../api/Corpus";
+
+// 定义节点类型
+type NodeType =
+  | "book"
+  | "chapter"
+  | "paragraph"
+  | "sentence"
+  | "text"
+  | "resources"
+  | "translations"
+  | "similar"
+  | "preview";
+
+// 定义模式类型
+type ParagraphMode = "preview" | "edit";
+
+// 定义基础节点数据接口
+interface BaseNodeData {
+  id: string;
+  title: string;
+  type: NodeType;
+  isLeaf?: boolean;
+  preview?: string;
+  content?: React.ReactNode;
+  children?: BaseNodeData[];
+}
+
+// 定义树节点接口
+interface TreeNode extends TreeDataNode {
+  key: string;
+  type: NodeType;
+  isLeaf?: boolean;
+  children?: TreeNode[];
+}
+
+// 定义API响应接口
+interface ApiResponse extends BaseNodeData {}
+
+// 定义组件状态接口
+interface IWidget {
+  type?: NodeType;
+  rootId?: string;
+  channelsId?: string[];
+}
+const TreeTextComponent = ({ type, rootId, channelsId }: IWidget) => {
+  const [treeData, setTreeData] = useState<BaseNodeData[]>([]);
+  const [loadingKeys, setLoadingKeys] = useState<string[]>([]);
+  const [paragraphModes, setParagraphModes] = useState<
+    Record<string, ParagraphMode>
+  >({});
+
+  useEffect(() => {
+    if (type === "chapter") {
+      const url = `/v2/palitext/${rootId}`;
+      get<IPaliParagraphResponse>(url).then((json) => {
+        if (json.ok) {
+          setTreeData([
+            {
+              id: json.data.uid,
+              title: json.data.text,
+              type: "chapter",
+            },
+          ]);
+        }
+      });
+    }
+  }, [rootId, type]);
+
+  // 模拟API调用
+  const mockApiCall = useCallback(
+    async (type: NodeType, key: string): Promise<ApiResponse[]> => {
+      console.log("Calling API:", type, key);
+      //await new Promise((resolve) => setTimeout(resolve, 1000)); // 模拟网络延迟
+
+      // 模拟不同类型节点的响应数据
+      if (type === "book") {
+        return [
+          { id: "chapter_1", title: "第一章", type: "chapter" },
+          { id: "chapter_2", title: "第二章", type: "chapter" },
+          { id: "chapter_3", title: "第三章", type: "chapter" },
+        ];
+      } else if (type === "chapter") {
+        const url = `/v2/palitext?view=children&id=${key}`;
+        const paragraphs = await get<IPaliListResponse>(url);
+        return paragraphs.data.rows.map((item) => {
+          if (item.level < 8) {
+            return {
+              id: item.uid,
+              title: item.toc,
+              type: "chapter",
+            };
+          } else {
+            return {
+              id: `${item.book}-${item.paragraph}`,
+              title: item.paragraph.toString(),
+              type: "paragraph",
+              preview: item.text,
+            };
+          }
+        });
+      } else if (type === "paragraph") {
+        const [book, paragraph] = key.split("-");
+        const url = `/v2/sentence?view=paragraph&book=${book}&para=${paragraph}&channels=${channelsId?.join()}`;
+        const res = await get<ISentenceListResponse>(url);
+        return res.data.rows.map((item) => {
+          return {
+            id: item.id ?? "123",
+            title: `${item.book}-${item.paragraph}-${item.word_start}-${item.word_end}`,
+            type: "sentence",
+            children: [
+              {
+                id: "text_node",
+                title: item.content,
+                type: "text",
+                isLeaf: true,
+              },
+              {
+                id: "resources",
+                title: "资源",
+                type: "resources",
+                children: [
+                  {
+                    id: "translations",
+                    title: "参考译文",
+                    type: "translations",
+                  },
+                  {
+                    id: "similar",
+                    title: "相似句",
+                    type: "similar",
+                  },
+                ],
+              },
+            ],
+          };
+        });
+      } else if (type === "similar") {
+        return [
+          {
+            id: "text_node",
+            title: "句子文本:This is the original sentence text.",
+            type: "text",
+            isLeaf: true,
+          },
+          {
+            id: "resources",
+            title: "资源",
+            type: "resources",
+            children: [
+              {
+                id: "translations",
+                title: "参考译文",
+                type: "translations",
+              },
+              {
+                id: "similar",
+                title: "相似句",
+                type: "similar",
+              },
+            ],
+          },
+        ];
+      }
+      return [];
+    },
+    [channelsId]
+  );
+
+  // 获取节点图标
+  const getNodeIcon = (type: NodeType): React.ReactNode => {
+    switch (type) {
+      case "book":
+        return <BookOutlined />;
+      case "chapter":
+        return <FolderOutlined />;
+      case "paragraph":
+        return <FileTextOutlined />;
+      case "sentence":
+        return <FontSizeOutlined />;
+      case "translations":
+        return <TranslationOutlined />;
+      case "similar":
+        return <FileTextOutlined />;
+      default:
+        return null;
+    }
+  };
+
+  // 构建树节点
+  const buildTreeNode = (
+    node: BaseNodeData,
+    parentKey: string = ""
+  ): TreeNode => {
+    const key = parentKey
+      ? `${parentKey}_${node.id}`
+      : `${node.type}_${node.id}`;
+    const isLoading = loadingKeys.includes(key);
+
+    let children: TreeNode[] = [];
+    let hasChildren = false;
+
+    if (node.type === "paragraph") {
+      const mode = paragraphModes[key] || "preview";
+
+      if (mode === "preview" && node.preview) {
+        // 预览模式:只显示预览文字节点
+        children = [
+          {
+            title: `预览:${node.preview}`,
+            key: `${key}_preview`,
+            type: "preview" as NodeType,
+            isLeaf: true,
+            icon: <FontSizeOutlined style={{ color: "#1890ff" }} />,
+          },
+        ];
+      } else if (mode === "edit" && node.children) {
+        // 编辑模式:显示子sentence节点
+        children = node.children.map((child) => buildTreeNode(child, key));
+      }
+
+      hasChildren = Boolean(node.children && node.children.length > 0);
+    } else if (node.children) {
+      children = node.children.map((child) => buildTreeNode(child, key));
+      hasChildren = true;
+    } else if (
+      !node.isLeaf &&
+      ["book", "chapter", "paragraph", "sentence"].includes(node.type)
+    ) {
+      hasChildren = true;
+    }
+
+    const handleModeChange = (value: string | number): void => {
+      setParagraphModes((prev) => ({
+        ...prev,
+        [key]: value as ParagraphMode,
+      }));
+    };
+
+    const handleSegmentedClick = (e: React.MouseEvent): void => {
+      e.stopPropagation();
+    };
+
+    const treeNode: TreeNode = {
+      title: (
+        <div style={{ display: "inline-block" }}>
+          <div
+            style={{
+              display: "flex",
+              alignItems: "center",
+              justifyContent: "space-between",
+              width: "100%",
+            }}
+          >
+            {node.content ?? <span>{node.title}</span>}
+            {node.type === "paragraph" && (
+              <Segmented
+                size="small"
+                value={paragraphModes[key] || "preview"}
+                onChange={handleModeChange}
+                options={[
+                  { label: "预览", value: "preview" },
+                  { label: "编辑", value: "edit" },
+                ]}
+                style={{ marginLeft: 8 }}
+                onClick={handleSegmentedClick}
+              />
+            )}
+          </div>
+        </div>
+      ),
+      key,
+      type: node.type,
+      icon: isLoading ? <Spin size="small" /> : getNodeIcon(node.type),
+      isLeaf: node.isLeaf || (!hasChildren && node.type === "text"),
+      children: children.length > 0 ? children : undefined,
+    };
+
+    return treeNode;
+  };
+
+  // 懒加载处理
+  const onLoadData = async (node: TreeNode): Promise<void> => {
+    const { key, type } = node;
+
+    if (loadingKeys.includes(key)) return;
+
+    setLoadingKeys((prev) => [...prev, key]);
+
+    try {
+      let apiUrl = "";
+      const id = key.split("_").pop() || "";
+
+      switch (type) {
+        case "book":
+          apiUrl = `/v2/book/${id}`;
+          break;
+        case "chapter":
+          apiUrl = `/v2/chapter/${id}`;
+          break;
+        case "paragraph":
+          apiUrl = `/v2/paragraph/${id}`;
+          break;
+        case "sentence":
+          apiUrl = `/v2/sentence/${id}`;
+          break;
+        case "similar":
+          apiUrl = `/v2/similar/${id}`;
+          break;
+        default:
+          return;
+      }
+
+      const data = await mockApiCall(type, id);
+
+      // 更新树数据
+      const updateTreeData = (
+        nodes: BaseNodeData[],
+        parentKey: string = ""
+      ): BaseNodeData[] => {
+        return nodes.map((node) => {
+          const currentKey = parentKey
+            ? `${parentKey}_${node.id}`
+            : `${node.type}_${node.id}`;
+          if (currentKey === key) {
+            return {
+              ...node,
+              children: data.map((child) => ({
+                ...child,
+                children: child.children || [],
+              })),
+            };
+          } else if (node.children) {
+            return {
+              ...node,
+              children: updateTreeData(node.children, currentKey),
+            };
+          }
+          return node;
+        });
+      };
+
+      setTreeData((prev) => updateTreeData(prev));
+    } catch (error) {
+      console.error("加载数据失败:", error);
+    } finally {
+      setLoadingKeys((prev) => prev.filter((k) => k !== key));
+    }
+  };
+
+  return (
+    <div
+      style={{ padding: 20, backgroundColor: "#f5f5f5", minHeight: "100vh" }}
+    >
+      <div
+        style={{
+          backgroundColor: "white",
+          padding: 20,
+          borderRadius: 8,
+          boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
+        }}
+      >
+        <h2 style={{ marginBottom: 20, color: "#1890ff" }}>
+          树状文本展示组件 (TypeScript)
+        </h2>
+        <Tree
+          showIcon
+          showLine={true}
+          loadData={onLoadData}
+          treeData={treeData.map((node) => buildTreeNode(node))}
+          style={{ fontSize: 14 }}
+          blockNode
+        />
+      </div>
+
+      {/* 使用说明 */}
+      <div
+        style={{
+          marginTop: 20,
+          backgroundColor: "white",
+          padding: 20,
+          borderRadius: 8,
+          boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
+        }}
+      >
+        <h3>功能说明:</h3>
+        <ul style={{ lineHeight: 1.8 }}>
+          <li>📚 点击book节点懒加载chapter数据</li>
+          <li>📄 点击chapter节点懒加载paragraph数据</li>
+          <li>📝 paragraph节点右侧可切换预览/编辑模式</li>
+          <li>👁️ 预览模式:只显示预览文字</li>
+          <li>✏️ 编辑模式:显示子sentence节点</li>
+          <li>📖 sentence节点包含句子文本和资源(参考译文、相似句)</li>
+        </ul>
+
+        <h4 style={{ marginTop: 20 }}>TypeScript 特性:</h4>
+        <ul style={{ lineHeight: 1.8 }}>
+          <li>🔒 完整的类型定义和类型安全</li>
+          <li>📝 接口定义清晰,便于维护</li>
+          <li>⚡ 更好的IDE支持和代码提示</li>
+          <li>🛡️ 编译时错误检查</li>
+        </ul>
+      </div>
+    </div>
+  );
+};
+
+export default TreeTextComponent;

+ 30 - 1
dashboard-v4/dashboard/src/components/channel/ChannelMy.tsx

@@ -10,6 +10,7 @@ import {
   Select,
   Skeleton,
   Space,
+  Tag,
   Tooltip,
   Tree,
 } from "antd";
@@ -37,6 +38,7 @@ import CopyToModal from "./CopyToModal";
 import { ArticleType } from "../article/Article";
 import { ChannelInfoModal } from "./ChannelInfo";
 import TokenModal from "../article/TokenModal";
+import NissayaAlignerModal from "../corpus/NissayaAlignerModal";
 
 const { Search } = Input;
 
@@ -89,6 +91,7 @@ const ChannelMy = ({
   const [search, setSearch] = useState<string>();
   const [loading, setLoading] = useState(true);
   const [copyChannel, setCopyChannel] = useState<IChannel>();
+  const [nissayaOpen, setNissayaOpen] = useState(false);
   const [copyOpen, setCopyOpen] = useState<boolean>(false);
   const [infoOpen, setInfoOpen] = useState<boolean>(false);
   const [statistic, setStatistic] = useState<IItem>();
@@ -450,7 +453,12 @@ const ChannelMy = ({
                       <Button type="link">
                         <Space>
                           <StudioName data={node.channel.studio} hideName />
-                          {node.channel.title}
+                          <>{node.channel.title}</>
+                          <Tag>
+                            {intl.formatMessage({
+                              id: `channel.type.${node.channel.type}.label`,
+                            })}
+                          </Tag>
                         </Space>
                       </Button>
                     </div>
@@ -471,6 +479,13 @@ const ChannelMy = ({
                               }),
                               icon: <CopyOutlined />,
                             },
+                            {
+                              key: "import-nissaya",
+                              label: intl.formatMessage({
+                                id: "buttons.import",
+                              }),
+                              icon: <CopyOutlined />,
+                            },
                             {
                               key: "statistic",
                               label: intl.formatMessage({
@@ -496,6 +511,14 @@ const ChannelMy = ({
                                 });
                                 setCopyOpen(true);
                                 break;
+                              case "import-nissaya":
+                                setCopyChannel({
+                                  id: node.channel.uid,
+                                  name: node.channel.title,
+                                  type: node.channel.type,
+                                });
+                                setNissayaOpen(true);
+                                break;
                               case "statistic":
                                 setInfoOpen(true);
                                 setStatistic(node.channel);
@@ -535,6 +558,12 @@ const ChannelMy = ({
         open={copyOpen}
         onClose={() => setCopyOpen(false)}
       />
+      <NissayaAlignerModal
+        sentencesId={sentencesId}
+        channel={copyChannel}
+        open={nissayaOpen}
+        onClose={() => setNissayaOpen(false)}
+      />
       <ChannelInfoModal
         sentenceCount={sentenceCount}
         channel={statistic}

+ 2 - 2
dashboard-v4/dashboard/src/components/channel/CopyToModal.tsx

@@ -12,7 +12,7 @@ interface IWidget {
   important?: boolean;
   onClose?: Function;
 }
-const CopyToModalWidget = ({
+const CopyToModal = ({
   trigger,
   channel,
   sentencesId,
@@ -72,4 +72,4 @@ const CopyToModalWidget = ({
   );
 };
 
-export default CopyToModalWidget;
+export default CopyToModal;

+ 149 - 38
dashboard-v4/dashboard/src/components/chat/AiChat.tsx

@@ -25,15 +25,18 @@ import MsgError from "./MsgError";
 import PromptButtonGroup from "./PromptButtonGroup";
 import { useAppSelector } from "../../hooks";
 import { currentUser } from "../../reducers/current-user";
+import { IFtsResponse } from "../fts/FullTextSearchResult";
+import { siteInfo } from "../../reducers/layout";
 
 const { TextArea } = Input;
 
+type AIRole = "system" | "user" | "assistant" | "function";
 // 类型定义
 export interface MessageVersion {
   id: number;
   content: string;
   model: string;
-  role: "system" | "user" | "assistant";
+  role: AIRole;
   timestamp: string;
 }
 
@@ -44,8 +47,9 @@ export interface Message {
 }
 
 interface OpenAIMessage {
-  role: "system" | "user" | "assistant";
+  role: AIRole;
   content: string;
+  name?: string;
 }
 
 interface StreamTypeController {
@@ -73,7 +77,11 @@ interface IWidget {
 
 const AIChatComponent = ({
   initMessage,
-  systemPrompt = "你是一个巴利语专家",
+  systemPrompt = `你是一个巴利语专家和佛教术语解释助手。当用户询问佛教术语时,你可以调用 searchTerm 函数来查询详细信息。
+
+  使用方法:
+  - 当用户输入类似"术语:dhamma"、"查询:karma"、"什么是 buddha"等时,调用函数查询
+  - 查询结果会以结构化的方式展示,包含定义、词源、分类、详细说明等信息`,
   onChat,
 }: IWidget) => {
   const [messages, setMessages] = useState<Message[]>([]);
@@ -93,6 +101,7 @@ const AIChatComponent = ({
   const [error, setError] = useState<string>();
 
   const user = useAppSelector(currentUser);
+  const site = useAppSelector(siteInfo);
 
   const scrollToBottom = useCallback(() => {
     messagesEndRef.current?.scrollIntoView({
@@ -102,17 +111,14 @@ const AIChatComponent = ({
   }, []);
 
   useEffect(() => {
-    const url = `/v2/ai-model?view=chat`;
-    console.info("api request", url);
-    get<IAiModelListResponse>(url).then((json) => {
-      if (json.ok) {
-        setModels(json.data.rows);
-        if (json.data.rows.length > 0) {
-          setSelectedModel(json.data.rows[0].uid);
-        }
-      }
-    });
-  }, []);
+    setModels(site?.settings?.models?.chat ?? []);
+    if (
+      site?.settings?.models?.chat &&
+      site?.settings?.models?.chat.length > 0
+    ) {
+      setSelectedModel(site?.settings?.models?.chat[0].uid);
+    }
+  }, [site?.settings?.models?.chat]);
 
   useEffect(() => {
     scrollToBottom();
@@ -155,12 +161,25 @@ const AIChatComponent = ({
     []
   );
 
+  const searchTerm = async (term: string) => {
+    // 示例:请求你后端的百科 API
+    const url = `/v2/search-pali-wbw?view=pali&key=${term}&limit=20&offset=0`;
+    console.info("search api request", url);
+    const res = await get<IFtsResponse>(url);
+    if (res.ok) {
+      console.info("search 搜索结果", res.data.rows);
+      return res.data.rows;
+    }
+    return { error: "没有找到相关术语" };
+  };
+
   const callOpenAI = useCallback(
     async (
       messages: OpenAIMessage[],
       modelId: string,
       isRegenerate: boolean = false,
-      messageIndex?: number
+      messageIndex?: number,
+      _depth: number = 0
     ): Promise<{ success: boolean; content?: string; error?: string }> => {
       setError(undefined);
       if (typeof process.env.REACT_APP_OPENAI_PROXY === "undefined") {
@@ -168,27 +187,46 @@ const AIChatComponent = ({
         return { success: false, error: "API配置错误" };
       }
 
+      const functions = [
+        {
+          name: "searchTerm",
+          description: "查询佛教术语,返回百科词条",
+          parameters: {
+            type: "object",
+            properties: {
+              term: {
+                type: "string",
+                description: "要查询的巴利语或佛学术语",
+              },
+            },
+            required: ["term"],
+          },
+        },
+      ];
       try {
         setFetchModel(modelId);
-        const payload = {
+        const payload: any = {
           model: models?.find((value) => value.uid === modelId)?.model,
-          messages: messages,
+          messages,
           stream: true,
-          temperature: 0.7,
-          max_tokens: 3000, //本次回复”最大输出长度
+          temperature: 0.5,
+          max_tokens: 3000,
+          functions,
+          function_call: "auto", // 让模型决定是否调用函数
         };
         const url = process.env.REACT_APP_OPENAI_PROXY;
         const data = {
           model_id: modelId,
-          payload: payload,
+          payload,
         };
         console.info("api request", url, data);
         setIsLoading(true);
+
         const response = await fetch(url, {
           method: "POST",
           headers: {
             "Content-Type": "application/json",
-            Authorization: `Bearer AIzaSyCzr8KqEdaQ3cRCxsFwSHh8c7kF3RZTZWw`,
+            Authorization: `Bearer ${process.env.REACT_APP_OPENAI_KEY}`,
           },
           body: JSON.stringify(data),
         });
@@ -205,6 +243,11 @@ const AIChatComponent = ({
         const decoder = new TextDecoder();
         let buffer = "";
 
+        // 🔑 新增 function_call 拼接缓冲
+        let functionCallName: string | null = null;
+        let functionCallArgsBuffer = "";
+        let functionCallInProgress = false;
+
         const typeController = streamTypeWriter(
           (content: string) => {},
           (finalContent: string) => {
@@ -241,13 +284,56 @@ const AIChatComponent = ({
           }
         );
 
+        // ✅ 安全 parse
+        const safeParseArgs = (s: string) => {
+          try {
+            return JSON.parse(s);
+          } catch {
+            return {};
+          }
+        };
+
+        // 🔑 处理 function_call 完成时执行函数 + 再次请求
+        const handleFunctionCallAndReask = async () => {
+          const argsObj = safeParseArgs(functionCallArgsBuffer);
+          console.log("完整 arguments:", functionCallArgsBuffer, argsObj);
+
+          if (functionCallName === "searchTerm") {
+            const result = await searchTerm(
+              argsObj.term || argsObj.query || ""
+            );
+            const followUp: OpenAIMessage[] = [
+              ...messages,
+              {
+                role: "function",
+                name: "searchTerm",
+                content: JSON.stringify(result),
+              },
+            ];
+            console.log("search 再次请求", followUp);
+            return await callOpenAI(
+              followUp,
+              modelId,
+              isRegenerate,
+              messageIndex,
+              _depth + 1
+            );
+          }
+          return { success: false, error: "未知函数: " + functionCallName };
+        };
+
         try {
           while (true) {
             const { done, value } = await reader.read();
-
             if (done) {
+              if (functionCallInProgress && functionCallName) {
+                const res = await handleFunctionCallAndReask();
+                setIsLoading(false);
+                return res;
+              }
               typeController.complete();
-              return { success: true, content: currentTypingMessage };
+              setIsLoading(false);
+              return { success: true, content: "" };
             }
 
             buffer += decoder.decode(value, { stream: true });
@@ -255,25 +341,50 @@ const AIChatComponent = ({
             buffer = lines.pop() || "";
 
             for (const line of lines) {
-              if (line.trim() === "") continue;
-              if (line.startsWith("data: ")) {
-                const data = line.slice(6);
-
-                if (data === "[DONE]") {
-                  typeController.complete();
-                  return { success: true, content: currentTypingMessage };
+              if (!line.trim() || !line.startsWith("data: ")) continue;
+              const data = line.slice(6);
+              if (data === "[DONE]") {
+                if (functionCallInProgress && functionCallName) {
+                  const res = await handleFunctionCallAndReask();
+                  setIsLoading(false);
+                  return res;
                 }
+                typeController.complete();
+                setIsLoading(false);
+                return { success: true, content: "" };
+              }
 
-                try {
-                  const parsed: OpenAIStreamResponse = JSON.parse(data);
-                  const delta = parsed.choices?.[0]?.delta;
+              let parsed: any = null;
+              try {
+                parsed = JSON.parse(data);
+              } catch {
+                continue;
+              }
 
-                  if (delta?.content) {
-                    typeController.addToken(delta.content);
-                  }
-                } catch (e) {
-                  console.warn("解析SSE数据失败:", e);
+              const delta = parsed.choices?.[0]?.delta;
+              const finish_reason = parsed.choices?.[0]?.finish_reason;
+
+              // 🔑 拼接 function_call
+              if (delta?.function_call) {
+                if (delta.function_call.name) {
+                  functionCallName = delta.function_call.name;
                 }
+                if (typeof delta.function_call.arguments === "string") {
+                  functionCallInProgress = true;
+                  functionCallArgsBuffer += delta.function_call.arguments;
+                }
+              }
+
+              // 正常文本输出
+              if (delta?.content && !functionCallInProgress) {
+                typeController.addToken(delta.content);
+              }
+
+              // function_call 完成
+              if (finish_reason === "function_call") {
+                const res = await handleFunctionCallAndReask();
+                setIsLoading(false);
+                return res;
               }
             }
           }

+ 133 - 0
dashboard-v4/dashboard/src/components/chat/AssistantMessage.tsx

@@ -0,0 +1,133 @@
+import React from "react";
+import { Button, Space } from "antd";
+import {
+  RedoOutlined,
+  LikeOutlined,
+  DislikeOutlined,
+  CopyOutlined,
+  ShareAltOutlined,
+} from "@ant-design/icons";
+import { AssistantMessageProps } from "../../types/chat";
+import Marked from "../general/Marked";
+import { VersionSwitcher } from "./VersionSwitcher";
+import ToolMessage from "./ToolMessage";
+
+const AssistantMessage = ({
+  session,
+  onRefresh,
+  onEdit,
+  isPending,
+  onLike,
+  onDislike,
+  onCopy,
+  onShare,
+  onVersionSwitch,
+}: AssistantMessageProps) => {
+  const messages = session.ai_messages;
+
+  const mainMessage = messages.find((m) => m.role === "assistant" && m.content);
+  const toolMessages = messages.filter((m) => m.role === "tool");
+
+  const handleCopy = () => {
+    if (mainMessage?.content && onCopy) {
+      onCopy(mainMessage.uid);
+    }
+  };
+
+  const handleShare = async () => {
+    if (mainMessage && onShare) {
+      try {
+        const shareUrl = await onShare(mainMessage.uid);
+        // 可以显示分享链接或复制到剪贴板
+        navigator.clipboard.writeText(shareUrl);
+      } catch (err) {
+        console.error("分享失败:", err);
+      }
+    }
+  };
+
+  return (
+    <div className="assistant-message">
+      <div className="message-header">
+        <span className="role-label">
+          {mainMessage?.model_id && (
+            <span className="model-info">{mainMessage.model_id}</span>
+          )}
+        </span>
+      </div>
+
+      <div className="message-content" style={{ backgroundColor: "unset" }}>
+        {/* Tool calls 显示 */}
+        <ToolMessage session={session} />
+        {/* 主要回答内容 */}
+        {mainMessage?.content && (
+          <div className="message-text">
+            <Marked text={mainMessage.content} />
+            {isPending && (
+              <span className="status-indicator pending">生成中...</span>
+            )}
+          </div>
+        )}
+
+        {/* Token 使用信息 */}
+        {mainMessage?.metadata?.token_usage && (
+          <div className="token-info">
+            Token: {mainMessage.metadata.token_usage.total_tokens}
+          </div>
+        )}
+      </div>
+      {!isPending && (
+        <div className="message-actions">
+          <Space size="small">
+            <Button
+              size="small"
+              type="text"
+              icon={<CopyOutlined />}
+              onClick={handleCopy}
+            />
+
+            <Button
+              size="small"
+              type="text"
+              icon={<LikeOutlined />}
+              onClick={() => mainMessage && onLike && onLike(mainMessage.uid)}
+            />
+            <Button
+              size="small"
+              type="text"
+              icon={<DislikeOutlined />}
+              onClick={() =>
+                mainMessage && onDislike && onDislike(mainMessage.uid)
+              }
+            />
+            <Button
+              size="small"
+              type="text"
+              icon={<ShareAltOutlined />}
+              onClick={handleShare}
+            />
+            {/* 版本切换器 */}
+            {session.versions && session.versions.length > 1 && (
+              <VersionSwitcher
+                versions={session.versions}
+                currentVersion={session.current_version}
+                onSwitch={(versionIndex) =>
+                  onVersionSwitch &&
+                  onVersionSwitch(session.versions[versionIndex].message_id)
+                }
+              />
+            )}
+            <Button
+              size="small"
+              type="text"
+              icon={<RedoOutlined />}
+              onClick={onRefresh}
+            />
+          </Space>
+        </div>
+      )}
+    </div>
+  );
+};
+
+export default AssistantMessage;

+ 56 - 0
dashboard-v4/dashboard/src/components/chat/ChatContainer.tsx

@@ -0,0 +1,56 @@
+// dashboard-v4/dashboard/src/components/chat/ChatContainer.tsx
+import { useChatData } from "../../hooks/useChatData";
+import { SessionGroup } from "./SessionGroup";
+import { ChatInput } from "./ChatInput";
+import { StreamingMessage } from "./StreamingMessage";
+
+import "./style.css";
+
+interface ChatContainerProps {
+  chatId: string;
+}
+
+export function ChatContainer({ chatId }: ChatContainerProps) {
+  const { chatState, actions } = useChatData(chatId);
+
+  return (
+    <div className="chat-container">
+      <div className="messages-area">
+        {chatState.session_groups.map((session) => (
+          <SessionGroup
+            key={session.session_id}
+            session={session}
+            onVersionSwitch={actions.switchVersion}
+            onRefresh={actions.refreshResponse}
+            onEdit={actions.editMessage}
+            onRetry={actions.retryMessage}
+            onLike={actions.likeMessage}
+            onDislike={actions.dislikeMessage}
+            onCopy={actions.copyMessage}
+            onShare={actions.shareMessage}
+          />
+        ))}
+
+        {/* 流式消息显示 */}
+        {chatState.streaming_message && (
+          <StreamingMessage
+            content={chatState.streaming_message}
+            sessionId={chatState.streaming_session_id}
+          />
+        )}
+
+        {/* 错误提示 */}
+        {chatState.error && (
+          <div className="error-message">{chatState.error}</div>
+        )}
+      </div>
+
+      <ChatInput
+        onSend={(content) => actions.editMessage("new", content)}
+        onModelChange={actions.setModel}
+        disabled={chatState.is_loading}
+        placeholder="输入你的问题..."
+      />
+    </div>
+  );
+}

+ 404 - 0
dashboard-v4/dashboard/src/components/chat/ChatInput.tsx

@@ -0,0 +1,404 @@
+import React, { useState, useCallback, useEffect, useRef } from "react";
+import {
+  Affix,
+  AutoComplete,
+  Button,
+  Card,
+  Dropdown,
+  Input,
+  MenuProps,
+  Select,
+  Space,
+  Tooltip,
+  Typography,
+  Tag,
+} from "antd";
+import {
+  SendOutlined,
+  PaperClipOutlined,
+  DownOutlined,
+  SearchOutlined,
+} from "@ant-design/icons";
+import { ChatInputProps } from "../../types/chat";
+import PromptButtonGroup from "./PromptButtonGroup";
+import { IAiModel } from "../api/ai";
+import { useAppSelector } from "../../hooks";
+import { siteInfo } from "../../reducers/layout";
+import { backend, get } from "../../request";
+import { SuggestionsResponse } from "../../types/search";
+
+const { TextArea } = Input;
+const { Text } = Typography;
+
+// 定义建议项类型
+interface SuggestionOption {
+  value: string;
+  label: React.ReactNode;
+  text: string;
+  source: string;
+  score: number;
+  resource_type?: string;
+  language?: string;
+  doc_id?: string;
+}
+
+// 定义搜索模式类型
+type SearchMode = "auto" | "none" | "team" | "word" | "explain" | "title";
+
+export function ChatInput({
+  onSend,
+  onModelChange,
+  disabled,
+  placeholder,
+}: ChatInputProps) {
+  const [inputValue, setInputValue] = useState("");
+  const [selectedModel, setSelectedModel] = useState<string>("");
+  const [models, setModels] = useState<IAiModel[]>();
+  const [searchMode, setSearchMode] = useState<SearchMode>("auto");
+  const [suggestions, setSuggestions] = useState<SuggestionOption[]>([]);
+  const [loading, setLoading] = useState(false);
+  const site = useAppSelector(siteInfo);
+
+  // 使用 ref 来防止过于频繁的请求
+  const abortControllerRef = useRef<AbortController | null>(null);
+  const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);
+
+  useEffect(() => {
+    const allModels = site?.settings?.models?.chat ?? [];
+    setModels(allModels);
+    if (
+      site?.settings?.models?.chat &&
+      site?.settings?.models?.chat.length > 0
+    ) {
+      const modelId = site?.settings?.models?.chat[0].uid;
+      setSelectedModel(modelId);
+      onModelChange && onModelChange(allModels?.find((m) => m.uid === modelId));
+    }
+  }, [onModelChange, site?.settings?.models?.chat]);
+
+  // 获取搜索建议
+  const fetchSuggestions = useCallback(
+    async (query: string) => {
+      // 取消之前的请求
+      if (abortControllerRef.current) {
+        abortControllerRef.current.abort();
+      }
+
+      // 如果查询为空或搜索模式为 none,清空建议
+      if (!query.trim() || searchMode === "none") {
+        setSuggestions([]);
+        return;
+      }
+
+      // 创建新的 AbortController
+      abortControllerRef.current = new AbortController();
+
+      setLoading(true);
+
+      try {
+        // 根据搜索模式确定查询字段
+        let fields: string | undefined;
+        switch (searchMode) {
+          case "title":
+            fields = "title";
+            break;
+          case "team":
+          case "word":
+          case "explain":
+            fields = "title,content";
+            break;
+          case "auto":
+          default:
+            // 不指定 fields,查询所有字段
+            fields = undefined;
+        }
+
+        // 构建查询参数
+        const params = new URLSearchParams({
+          q: query,
+          limit: "10",
+        });
+
+        if (fields) {
+          params.append("fields", fields);
+        }
+
+        // 发起请求
+        const url = `/v3/search-suggest?${params.toString()}`;
+        // 发起请求
+        const response = await fetch(backend(url), {
+          signal: abortControllerRef.current.signal,
+        });
+
+        if (!response.ok) {
+          throw new Error("搜索建议请求失败");
+        }
+
+        const data: SuggestionsResponse = await response.json();
+
+        if (data.success && data.data.suggestions) {
+          // 转换为 AutoComplete 选项格式
+          const options: SuggestionOption[] = data.data.suggestions.map(
+            (item: any) => ({
+              value: item.text,
+              label: renderSuggestionItem(item),
+              text: item.text,
+              source: item.source,
+              score: item.score,
+              resource_type: item.resource_type,
+              language: item.language,
+              doc_id: item.doc_id,
+            })
+          );
+
+          setSuggestions(options);
+        } else {
+          setSuggestions([]);
+        }
+      } catch (error: any) {
+        // 忽略取消的请求
+        if (error.name === "AbortError") {
+          return;
+        }
+        console.error("获取搜索建议失败:", error);
+        setSuggestions([]);
+      } finally {
+        setLoading(false);
+      }
+    },
+    [searchMode]
+  );
+
+  // 渲染建议项
+  const renderSuggestionItem = (item: any) => {
+    // 来源标签颜色映射
+    const sourceColors: Record<string, string> = {
+      title: "blue",
+      content: "green",
+      page_refs: "orange",
+    };
+
+    // 语言标签
+    const languageLabels: Record<string, string> = {
+      pali: "巴利文",
+      zh: "中文",
+      en: "英文",
+    };
+
+    return (
+      <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
+        <span style={{ flex: 1 }}>{item.text}</span>
+        <Space size={4}>
+          {item.source && (
+            <Tag
+              color={sourceColors[item.source] || "default"}
+              style={{ margin: 0, fontSize: "12px" }}
+            >
+              {item.source}
+            </Tag>
+          )}
+          {item.language && (
+            <Tag style={{ margin: 0, fontSize: "12px" }}>
+              {languageLabels[item.language] || item.language}
+            </Tag>
+          )}
+        </Space>
+      </div>
+    );
+  };
+
+  // 处理输入变化(带防抖)
+  const handleInputChange = useCallback(
+    (value: string) => {
+      setInputValue(value);
+
+      // 清除之前的定时器
+      if (debounceTimerRef.current) {
+        clearTimeout(debounceTimerRef.current);
+      }
+
+      // 如果输入为空,直接清空建议
+      if (!value.trim()) {
+        setSuggestions([]);
+        return;
+      }
+
+      // 设置新的防抖定时器(300ms)
+      debounceTimerRef.current = setTimeout(() => {
+        fetchSuggestions(value);
+      }, 300);
+    },
+    [fetchSuggestions]
+  );
+
+  // 处理选择建议项
+  const handleSelect = useCallback(
+    (value: string, option: SuggestionOption) => {
+      setInputValue(value);
+      // 选择后清空建议列表
+      setSuggestions([]);
+    },
+    []
+  );
+
+  const handleSend = useCallback(() => {
+    if (!inputValue.trim() || disabled) return;
+
+    onSend(inputValue.trim());
+    setInputValue("");
+    setSuggestions([]);
+  }, [inputValue, disabled, onSend]);
+
+  const handleKeyPress = useCallback(
+    (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
+      if (e.key === "Enter" && !e.shiftKey) {
+        e.preventDefault();
+        handleSend();
+      }
+    },
+    [handleSend]
+  );
+
+  const modelMenu: MenuProps = {
+    selectedKeys: [selectedModel],
+    onClick: ({ key }) => {
+      console.log("setSelectedModel", key);
+      setSelectedModel(key);
+      onModelChange && onModelChange(models?.find((m) => m.uid === key));
+    },
+    items: models?.map((model) => ({
+      key: model.uid,
+      label: model.name,
+    })),
+  };
+
+  const handleSearchModeChange = (value: SearchMode) => {
+    setSearchMode(value);
+    // 模式改变时,如果有输入内容,重新获取建议
+    if (inputValue.trim() && value !== "none") {
+      fetchSuggestions(inputValue);
+    } else {
+      setSuggestions([]);
+    }
+  };
+
+  // 组件卸载时清理
+  useEffect(() => {
+    return () => {
+      if (abortControllerRef.current) {
+        abortControllerRef.current.abort();
+      }
+      if (debounceTimerRef.current) {
+        clearTimeout(debounceTimerRef.current);
+      }
+    };
+  }, []);
+
+  return (
+    <Affix offsetBottom={10}>
+      <Card style={{ borderRadius: "10px", borderColor: "#d9d9d9" }}>
+        <div style={{ maxWidth: "1200px", margin: "0 auto" }}>
+          <div style={{ display: "flex", marginBottom: "8px", gap: "8px" }}>
+            <Space>
+              <SearchOutlined />
+              <Select
+                placement="topLeft"
+                value={searchMode}
+                style={{ width: 120 }}
+                onChange={handleSearchModeChange}
+                options={[
+                  {
+                    value: "auto",
+                    label: (
+                      <div>
+                        <div>{"自动"}</div>
+                        <div>
+                          <Text type="secondary" style={{ fontSize: "85%" }}>
+                            关键词+语义模糊搜索
+                          </Text>
+                        </div>
+                      </div>
+                    ),
+                  },
+                  {
+                    value: "none",
+                    label: "关闭",
+                  },
+                  {
+                    value: "team",
+                    label: "术语百科",
+                  },
+                  {
+                    value: "word",
+                    label: "词义辨析",
+                  },
+                  {
+                    value: "explain",
+                    label: "经文解析",
+                  },
+                  {
+                    value: "title",
+                    label: "标题搜索",
+                  },
+                ]}
+              />
+            </Space>
+
+            <AutoComplete
+              style={{ flex: 1 }}
+              placement="topLeft"
+              value={inputValue}
+              options={suggestions}
+              onSelect={handleSelect}
+              onChange={handleInputChange}
+              notFoundContent={loading ? "搜索中..." : null}
+              disabled={disabled}
+            >
+              <TextArea
+                onKeyPress={handleKeyPress}
+                placeholder={
+                  placeholder || "提出你的问题,如:总结下面的内容..."
+                }
+                autoSize={{ minRows: 1, maxRows: 6 }}
+                style={{ resize: "none", paddingRight: "48px" }}
+              />
+            </AutoComplete>
+          </div>
+
+          <div
+            style={{
+              display: "flex",
+              justifyContent: "space-between",
+              alignItems: "center",
+            }}
+          >
+            <Space>
+              <Tooltip title="附加文件">
+                <Button size="small" type="text" icon={<PaperClipOutlined />} />
+              </Tooltip>
+              <PromptButtonGroup onText={setInputValue} />
+            </Space>
+            <Space>
+              <Dropdown
+                placement="topLeft"
+                menu={modelMenu}
+                trigger={["click"]}
+              >
+                <Button size="small" type="text">
+                  {models?.find((m) => m.uid === selectedModel)?.name}
+                  <DownOutlined />
+                </Button>
+              </Dropdown>
+              <Button
+                type="primary"
+                icon={<SendOutlined />}
+                onClick={handleSend}
+                disabled={!inputValue.trim() || disabled}
+              />
+            </Space>
+          </div>
+        </div>
+      </Card>
+    </Affix>
+  );
+}

+ 4 - 2
dashboard-v4/dashboard/src/components/chat/PromptButtonGroup.tsx

@@ -74,9 +74,10 @@ export function parseMarkdownToPromptNodes(markdown: string): IPromptNode[] {
 
 interface IWidget {
   onText?: (prompt: string) => void;
+  disabled?: boolean;
 }
 // 按钮组组件
-const PromptButtonGroup = ({ onText }: IWidget) => {
+const PromptButtonGroup = ({ disabled = false, onText }: IWidget) => {
   const user = useAppSelector(currentUser);
   const [data, setData] = useState<IPromptNode[]>([]);
 
@@ -123,7 +124,7 @@ const PromptButtonGroup = ({ onText }: IWidget) => {
 
           return (
             <Dropdown key={node.text} menu={{ items }} trigger={["click"]}>
-              <Button type="link" size="small">
+              <Button type="link" size="small" disabled={disabled}>
                 {node.text}
               </Button>
             </Dropdown>
@@ -132,6 +133,7 @@ const PromptButtonGroup = ({ onText }: IWidget) => {
           return (
             <Button
               key={node.text}
+              disabled={disabled}
               onClick={() => onText && onText(node.prompt || "")}
             >
               {node.text}

+ 60 - 0
dashboard-v4/dashboard/src/components/chat/SearchResults.tsx

@@ -0,0 +1,60 @@
+import React, { useState } from "react";
+import { List, Pagination, Typography, Card, Space } from "antd";
+import { CalendarOutlined, FileTextOutlined } from "@ant-design/icons";
+import { ElasticsearchResponse, WikipaliDocument } from "../../types/search";
+
+const { Paragraph } = Typography;
+
+interface SearchResultsProps {
+  data: ElasticsearchResponse<WikipaliDocument>;
+  onPageChange?: (page: number, pageSize: number) => void;
+  pageSize?: number;
+}
+
+const SearchResults: React.FC<SearchResultsProps> = ({
+  data,
+  onPageChange,
+  pageSize = 20,
+}) => {
+  return (
+    <div className="search-results">
+      {/* 搜索结果列表 */}
+      <List
+        size="small"
+        dataSource={data.hits.hits}
+        pagination={{
+          onChange: onPageChange,
+          onShowSizeChange: onPageChange,
+          pageSize: pageSize,
+          total: data.hits.total.value,
+          showQuickJumper: true,
+          showTotal: (total, range) =>
+            `第 ${range[0]}-${range[1]} 条,共 ${total} 条`,
+        }}
+        renderItem={(item, index) => {
+          const previewText = item._source.content.text;
+          return (
+            <List.Item key={item._id}>
+              <List.Item.Meta
+                title={item._source.title.text}
+                description={
+                  <>
+                    <Paragraph
+                      type="secondary"
+                      ellipsis={{ rows: 2, expandable: true }}
+                    >
+                      {previewText}
+                    </Paragraph>
+                    <div>{item._source.path}</div>
+                  </>
+                }
+              />
+            </List.Item>
+          );
+        }}
+      />
+    </div>
+  );
+};
+
+export default SearchResults;

+ 73 - 0
dashboard-v4/dashboard/src/components/chat/SessionGroup.tsx

@@ -0,0 +1,73 @@
+import React from "react";
+import { Button } from "antd";
+
+import UserMessage from "./UserMessage";
+import { SessionGroupProps } from "../../types/chat";
+import { VersionSwitcher } from "./VersionSwitcher";
+import AssistantMessage from "./AssistantMessage";
+
+export function SessionGroup({
+  session,
+  onVersionSwitch,
+  onRefresh,
+  onEdit,
+  onRetry,
+  onLike,
+  onDislike,
+  onCopy,
+  onShare,
+}: SessionGroupProps) {
+  const hasFailed = session.messages.some((m) => m.save_status === "failed");
+  const isPending = session.messages.some((m) => m.save_status === "pending");
+  const hasMultipleVersions = session.versions.length > 1;
+
+  return (
+    <div
+      className={`session-group ${isPending ? "pending" : ""} ${
+        hasFailed ? "failed" : ""
+      }`}
+    >
+      {/* 用户消息 */}
+      {session.user_message && (
+        <UserMessage
+          session={session}
+          onEdit={(content) => onEdit && onEdit(session.session_id, content)}
+          onCopy={() => onCopy && onCopy(session.user_message!.uid)}
+          onVersionSwitch={onVersionSwitch}
+        />
+      )}
+
+      {/* AI回答区域 */}
+      <div className="ai-response">
+        {/* 失败重试提示 */}
+        {hasFailed && onRetry && (
+          <div className="retry-section">
+            <span className="error-message">回答生成失败</span>
+            <Button
+              size="small"
+              type="primary"
+              onClick={() => onRetry(session.messages[0].temp_id!)}
+            >
+              重试
+            </Button>
+          </div>
+        )}
+
+        {/* AI消息内容 */}
+        {!hasFailed && session.ai_messages.length > 0 && (
+          <AssistantMessage
+            session={session}
+            onRefresh={() => onRefresh && onRefresh(session.session_id)}
+            onEdit={(content) => onEdit && onEdit(session.session_id, content)}
+            isPending={isPending}
+            onLike={onLike}
+            onDislike={onDislike}
+            onCopy={onCopy}
+            onShare={onShare}
+            onVersionSwitch={onVersionSwitch}
+          />
+        )}
+      </div>
+    </div>
+  );
+}

+ 25 - 0
dashboard-v4/dashboard/src/components/chat/StreamingMessage.tsx

@@ -0,0 +1,25 @@
+import React from "react";
+import Marked from "../general/Marked";
+
+interface StreamingMessageProps {
+  content: string;
+  sessionId?: string;
+}
+
+export function StreamingMessage({ content }: StreamingMessageProps) {
+  return (
+    <div className="streaming-message">
+      <div className="message-header">
+        <span className="role-label">Assistant</span>
+        <span className="streaming-indicator">正在生成中...</span>
+      </div>
+
+      <div className="message-content">
+        <div className="message-text">
+          <Marked text={content} />
+          <span className="cursor">|</span>
+        </div>
+      </div>
+    </div>
+  );
+}

+ 53 - 0
dashboard-v4/dashboard/src/components/chat/ToolMessage.tsx

@@ -0,0 +1,53 @@
+import { Collapse } from "antd";
+import { SessionInfo } from "../../types/chat";
+import { getArgs, WikipaliSearchResponse } from "../../types/search";
+import SearchResults from "./SearchResults";
+
+const { Panel } = Collapse;
+
+interface IWidget {
+  session?: SessionInfo;
+}
+const ToolMessage = ({ session }: IWidget) => {
+  console.debug("ai chat render", session);
+  //找到llm请求的message 可能有多个
+  const toolCallMessages = session?.messages.filter((msg) => msg.tool_calls);
+  return (
+    <div key={"tool_calls"} className="tool-result">
+      {toolCallMessages?.map((msg, index) => {
+        return (
+          <Collapse key={index} style={{ borderRadius: 12 }}>
+            {msg.tool_calls?.map((tool) => {
+              //找到对应的结果
+              const search = session?.messages.find(
+                (msg) => msg.tool_call_id === tool.id
+              );
+              if (!search?.content) {
+                return <>没有结果</>;
+              } else {
+                const searchResult = getArgs<WikipaliSearchResponse>(
+                  search.content
+                );
+                return (
+                  search?.content && (
+                    <Panel
+                      header={`${tool?.function.name} ${tool?.function.arguments}`}
+                      key="1"
+                      extra={<>{`${searchResult.hits.total.value}个结果`}</>}
+                    >
+                      <div className="tool-content">
+                        <SearchResults data={searchResult} />
+                      </div>
+                    </Panel>
+                  )
+                );
+              }
+            })}
+          </Collapse>
+        );
+      })}
+    </div>
+  );
+};
+
+export default ToolMessage;

+ 105 - 0
dashboard-v4/dashboard/src/components/chat/UserMessage.tsx

@@ -0,0 +1,105 @@
+import React, { useState } from "react";
+import { Button, Input, Space, Typography } from "antd";
+import { EditOutlined, CopyOutlined } from "@ant-design/icons";
+import { UserMessageProps } from "../../types/chat";
+import { VersionSwitcher } from "./VersionSwitcher";
+
+const { TextArea } = Input;
+const { Text } = Typography;
+
+const UserMessage = ({
+  session,
+  onEdit,
+  onCopy,
+  onVersionSwitch,
+}: UserMessageProps) => {
+  const message = session.user_message;
+
+  const [isEditing, setIsEditing] = useState(false);
+  const [editContent, setEditContent] = useState(message?.content || "");
+
+  const handleEdit = () => {
+    if (onEdit && editContent.trim()) {
+      onEdit(editContent.trim());
+      setIsEditing(false);
+    }
+  };
+
+  const handleCancel = () => {
+    setEditContent(session.user_message?.content || "");
+    setIsEditing(false);
+  };
+  if (!message) {
+    return <></>;
+  }
+  return (
+    <div className="user-message">
+      <div style={{ maxWidth: "90%" }}>
+        <div className="message-content">
+          {isEditing ? (
+            <div className="edit-area">
+              <TextArea
+                value={editContent}
+                onChange={(e) => setEditContent(e.target.value)}
+                autoSize={{ minRows: 2, maxRows: 8 }}
+                autoFocus
+              />
+              <div className="edit-actions">
+                <Button size="small" onClick={handleCancel}>
+                  取消
+                </Button>
+                <Button size="small" type="primary" onClick={handleEdit}>
+                  保存
+                </Button>
+              </div>
+            </div>
+          ) : (
+            <div className="message-text">
+              <Text>{message.content}</Text>
+              {message.save_status === "pending" && (
+                <span className="status-indicator pending">发送中...</span>
+              )}
+              {message.save_status === "failed" && (
+                <span className="status-indicator failed">发送失败</span>
+              )}
+            </div>
+          )}
+        </div>
+        <div className="message-header">
+          <span className="role-label"></span>
+          <div className="message-actions">
+            {!isEditing && (
+              <Space size="small">
+                <Button
+                  size="small"
+                  type="text"
+                  icon={<EditOutlined />}
+                  onClick={() => setIsEditing(true)}
+                />
+                <Button
+                  size="small"
+                  type="text"
+                  icon={<CopyOutlined />}
+                  onClick={onCopy}
+                />
+                {/* 版本切换器 */}
+                {session.versions && session.versions.length > 1 && (
+                  <VersionSwitcher
+                    versions={session.versions}
+                    currentVersion={session.current_version}
+                    onSwitch={(versionIndex) =>
+                      onVersionSwitch &&
+                      onVersionSwitch(session.versions[versionIndex].message_id)
+                    }
+                  />
+                )}
+              </Space>
+            )}
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default UserMessage;

+ 54 - 0
dashboard-v4/dashboard/src/components/chat/VersionSwitcher.tsx

@@ -0,0 +1,54 @@
+import React from "react";
+import { Button, Space, Tooltip } from "antd";
+import { LeftOutlined, RightOutlined } from "@ant-design/icons";
+import { VersionSwitcherProps } from "../../types/chat";
+
+export function VersionSwitcher({
+  versions,
+  currentVersion,
+  onSwitch,
+}: VersionSwitcherProps) {
+  if (versions.length <= 1) return null;
+
+  const canGoPrev = currentVersion > 0;
+  const canGoNext = currentVersion < versions.length - 1;
+
+  const currentVersionInfo = versions[currentVersion];
+
+  return (
+    <div className="version-switcher">
+      <Space align="center">
+        <Button
+          size="small"
+          type="text"
+          icon={<LeftOutlined />}
+          disabled={!canGoPrev}
+          onClick={() => canGoPrev && onSwitch(currentVersion - 1)}
+        />
+
+        <Tooltip
+          title={
+            <div>
+              <div>
+                版本 {currentVersion + 1} / {versions.length}
+              </div>
+              <div>模型: {currentVersionInfo.model_id || "未知"}</div>
+            </div>
+          }
+        >
+          <span className="version-info">
+            {currentVersion + 1} / {versions.length}
+          </span>
+        </Tooltip>
+
+        <Button
+          size="small"
+          type="text"
+          icon={<RightOutlined />}
+          disabled={!canGoNext}
+          onClick={() => canGoNext && onSwitch(currentVersion + 1)}
+        />
+      </Space>
+    </div>
+  );
+}

+ 202 - 0
dashboard-v4/dashboard/src/components/chat/style.css

@@ -0,0 +1,202 @@
+.chat-container {
+  display: flex;
+  flex-direction: column;
+  min-height: 100vh;
+}
+
+.messages-area {
+  flex: 1;
+  padding: 16px;
+}
+
+.session-group {
+  margin-bottom: 24px;
+  border-radius: 8px;
+  padding: 16px;
+}
+
+.session-group.pending {
+  opacity: 0.7;
+}
+
+.session-group.failed {
+  border: 1px solid #ff4d4f;
+  background-color: #fff2f0;
+}
+
+.user-message,
+.assistant-message {
+  margin-bottom: 12px;
+}
+
+.user-message {
+  display: flex;
+  justify-content: flex-end;
+}
+.user-message .message-content {
+  border: 1px solid rgba(128, 128, 128, 0.5);
+  background-color: rgba(255, 255, 255, 0.5);
+}
+
+.message-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 8px;
+}
+
+.role-label {
+  font-weight: bold;
+  color: #1890ff;
+}
+
+.message-content {
+  padding: 12px;
+  border-radius: 6px;
+  background-color: #f5f5f5;
+}
+
+.version-switcher {
+  margin: 8px 0;
+  text-align: center;
+}
+
+.chat-input {
+  border-top: 1px solid #d9d9d9;
+  padding: 16px;
+}
+
+.streaming-message .cursor {
+  animation: blink 1s infinite;
+}
+
+@keyframes blink {
+  0%,
+  50% {
+    opacity: 1;
+  }
+  51%,
+  100% {
+    opacity: 0;
+  }
+}
+
+.retry-section {
+  padding: 12px;
+  background-color: #fff2f0;
+  border: 1px solid #ffccc7;
+  border-radius: 6px;
+  margin-bottom: 12px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.error-message {
+  color: #ff4d4f;
+  font-size: 14px;
+}
+
+.status-indicator {
+  margin-left: 8px;
+  font-size: 12px;
+}
+
+.status-indicator.pending {
+  color: #1890ff;
+}
+
+.status-indicator.failed {
+  color: #ff4d4f;
+}
+
+.tool-calls {
+  margin-bottom: 12px;
+  padding: 8px;
+  background-color: #f0f0f0;
+  border-radius: 4px;
+}
+
+.tool-result {
+  margin-bottom: 8px;
+}
+
+.tool-label {
+  font-size: 12px;
+  color: #666;
+  font-weight: bold;
+}
+
+.tool-content {
+  margin-top: 4px;
+  font-family: monospace;
+  font-size: 12px;
+  padding: 4px;
+  background-color: #fff;
+  border-radius: 2px;
+}
+
+.token-info {
+  margin-top: 8px;
+  font-size: 12px;
+  color: #666;
+  text-align: right;
+}
+
+.edit-area {
+  margin-top: 8px;
+}
+
+.edit-actions {
+  margin-top: 8px;
+  text-align: right;
+}
+
+.edit-actions .ant-btn {
+  margin-left: 8px;
+}
+
+.input-area {
+  position: relative;
+}
+
+.input-actions {
+  position: absolute;
+  right: 8px;
+  bottom: 8px;
+  display: flex;
+  align-items: center;
+}
+
+.version-info {
+  font-size: 12px;
+  color: #666;
+  padding: 0 8px;
+  user-select: none;
+}
+
+.model-info {
+  font-size: 12px;
+  color: #666;
+  background-color: #f0f0f0;
+  padding: 2px 6px;
+  border-radius: 4px;
+}
+
+.streaming-indicator {
+  font-size: 12px;
+  color: #1890ff;
+  animation: pulse 1.5s infinite;
+}
+
+@keyframes pulse {
+  0% {
+    opacity: 0.6;
+  }
+  50% {
+    opacity: 1;
+  }
+  100% {
+    opacity: 0.6;
+  }
+}

+ 339 - 0
dashboard-v4/dashboard/src/components/corpus/NissayaAligner.tsx

@@ -0,0 +1,339 @@
+import React, { useEffect, useState } from "react";
+import {
+  Steps,
+  Upload,
+  Button,
+  Table,
+  Input,
+  message,
+  Typography,
+  Space,
+} from "antd";
+import type { UploadChangeParam, UploadFile } from "antd/es/upload/interface";
+import {
+  InboxOutlined,
+  CopyOutlined,
+  UpSquareOutlined,
+  DownSquareOutlined,
+} from "@ant-design/icons";
+import { post } from "../../request";
+import { ISentenceDiffRequest, ISentenceDiffResponse } from "../api/Corpus";
+
+const { Step } = Steps;
+const { Dragger } = Upload;
+const { TextArea } = Input;
+const { Title } = Typography;
+
+interface WordData {
+  id: number;
+  pali: string;
+  nissaya: string;
+  note?: string;
+}
+
+interface SentenceData {
+  id: string;
+  content: string;
+}
+
+interface AlignResult {
+  id: string;
+  words: string;
+}
+
+interface IWidget {
+  sentencesId?: string[];
+}
+
+const NissayaAligner = ({ sentencesId }: IWidget) => {
+  const [current, setCurrent] = useState<number>(0);
+  const [csvData, setCsvData] = useState<WordData[]>([]);
+  const [jsonlInput, setJsonlInput] = useState<string>("");
+  const [alignResults, setAlignResults] = useState<AlignResult[]>([]);
+  const [original, setOriginal] = useState<SentenceData[]>([]);
+
+  useEffect(() => {
+    if (sentencesId) {
+      post<ISentenceDiffRequest, ISentenceDiffResponse>(`/v2/sent-in-channel`, {
+        sentences: sentencesId,
+        channels: ["_System_Pali_VRI_"],
+      }).then((json) => {
+        if (json.ok) {
+          setOriginal(
+            json.data.rows
+              .sort((a, b) => {
+                if (a.book_id !== b.book_id) {
+                  return a.book_id - b.book_id;
+                }
+                if (a.paragraph !== b.paragraph) {
+                  return a.paragraph - b.paragraph;
+                }
+                return a.word_start - b.word_start;
+              })
+              .map((item) => {
+                return {
+                  id: `${item.book_id}-${item.paragraph}-${item.word_start}-${item.word_end}`,
+                  content: item.content ?? "",
+                };
+              })
+          );
+        }
+      });
+    }
+  }, [sentencesId]);
+
+  const handleUpload = (info: UploadChangeParam<UploadFile<any>>) => {
+    console.log("Upload change event:", info);
+    const file = info.fileList?.[0]?.originFileObj || info.file.originFileObj;
+    if (!file) {
+      console.error("No valid file found in upload event:", info);
+      message.error("未检测到文件,请重新选择");
+      return;
+    }
+    console.log("Selected file:", file.name, file);
+    const reader = new FileReader();
+    reader.onload = (e) => {
+      const text = e.target?.result as string;
+      console.log("✅ File read complete. Length:", text?.length || 0);
+      parseCSV(text);
+    };
+    reader.onerror = (err) => {
+      console.error("❌ File read error:", err);
+      message.error("读取文件失败");
+    };
+    console.log("📖 Start reading file as text...");
+    reader.readAsText(file as Blob, "utf-8");
+  };
+
+  const parseCSV = (text: string) => {
+    console.log(
+      "Parsing CSV... Raw preview (first 300 chars):",
+      text.slice(0, 300)
+    );
+    const delimiter = text.includes("\t") ? "\t" : ",";
+    console.log("Detected delimiter:", delimiter === "\t" ? "TAB" : "COMMA");
+    const lines = text.trim().split(/\r?\n/);
+    const headers = lines[0]
+      .split(delimiter)
+      .map((h) => h.replace(/\"/g, "").trim());
+    console.log("Detected headers:", headers);
+
+    const data: WordData[] = lines.slice(1).map((line, i) => {
+      const cols = line
+        .split(delimiter)
+        .map((c) => c.replace(/\"/g, "").trim());
+      return {
+        id: i + 1,
+        pali:
+          cols[headers.findIndex((h) => h.toLowerCase().includes("pali"))] ||
+          "",
+        nissaya:
+          cols[headers.findIndex((h) => h.toLowerCase().includes("nissaya"))] ||
+          "",
+        note:
+          cols[headers.findIndex((h) => h.toLowerCase().includes("note"))] ||
+          "",
+      };
+    });
+
+    console.log("✅ Parsed CSV rows count:", data.length);
+    console.table(data.slice(0, 5));
+    setCsvData(data);
+    message.success(`CSV 文件解析成功,共 ${data.length} 行`);
+  };
+
+  const generatePrompt = (): string => {
+    const sentenceJsonl = original
+      .map((s) => `{"id": "${s.id}", "content": "${s.content}"}`)
+      .join("\n");
+    const csvText = ["id,pali,nissaya,note"]
+      .concat(
+        csvData.map(
+          (r) => `${r.id},"${r.pali}","${r.nissaya}","${r.note || ""}"`
+        )
+      )
+      .join("\n");
+    const prompt =
+      "将逐词解析数据与句子对应,一个句子对多个逐词解析数据。不是每个单词都有逐词解析数据,保持逐词解析数据的顺序不变,不可以有遗漏。对齐结果jsonl格式,每行一个句子,每个句子有三个字段 , id, content,words. 前两个字段与句子数据相同。逐词解析数据放在words字段中 , words字段里的数据为逐词解析数据的id字段,多个单词之间用逗号隔开";
+    return `# 句子数据\n\n\n\`\`\`jsonl\n${sentenceJsonl}\n\`\`\`\n\n# 逐词解析数据\n\n\`\`\`csv\n${csvText}\n\`\`\`\n\n${prompt}`;
+  };
+
+  const parseJsonlResults = () => {
+    try {
+      console.log("Parsing JSONL input...");
+      const lines = jsonlInput.trim().split(/\r?\n/);
+      const results = lines.map((line) => JSON.parse(line)) as AlignResult[];
+      console.log("Parsed results:", results);
+      setAlignResults(results);
+      message.success("结果解析成功");
+      setCurrent(3);
+    } catch (err) {
+      console.error("❌ JSONL parse error:", err);
+      message.error("JSONL 格式错误");
+    }
+  };
+
+  const moveWord = (sentenceIndex: number, direction: "prev" | "next") => {
+    console.log(
+      `Moving word: sentenceIndex=${sentenceIndex}, direction=${direction}`
+    );
+    const targetIndex =
+      direction === "prev" ? sentenceIndex - 1 : sentenceIndex + 1;
+    if (targetIndex < 0 || targetIndex >= alignResults.length) return;
+
+    const newResults = [...alignResults];
+    const currentWords = newResults[sentenceIndex].words.split(",");
+    const movingWord =
+      direction === "prev" ? currentWords.shift() : currentWords.pop();
+    if (!movingWord) return;
+
+    const targetWords = newResults[targetIndex].words.split(",");
+    if (direction === "prev") targetWords.push(movingWord);
+    else targetWords.unshift(movingWord);
+
+    newResults[sentenceIndex].words = currentWords.join(",");
+    newResults[targetIndex].words = targetWords.join(",");
+
+    console.log("Updated alignment:", newResults);
+    setAlignResults(newResults);
+  };
+
+  const steps = [
+    {
+      title: "上传 CSV",
+      content: (
+        <>
+          <Dragger
+            accept=".csv,.tsv,.txt"
+            showUploadList={false}
+            beforeUpload={() => false}
+            onChange={handleUpload}
+          >
+            <p className="ant-upload-drag-icon">
+              <InboxOutlined />
+            </p>
+            <p className="ant-upload-text">点击或拖拽上传 CSV 文件</p>
+          </Dragger>
+          {csvData.length > 0 && (
+            <Table
+              dataSource={csvData}
+              rowKey="id"
+              pagination={{ pageSize: 50 }}
+              scroll={{ y: 340 }}
+              columns={[
+                { title: "行号", dataIndex: "id", width: 120 },
+                { title: "Pali", dataIndex: "pali", width: 420 },
+                { title: "Nissaya", dataIndex: "nissaya" },
+              ]}
+            />
+          )}
+        </>
+      ),
+    },
+    {
+      title: "生成提示词",
+      content: (
+        <>
+          <Title level={5}>生成的提示词:</Title>
+          <TextArea rows={20} value={generatePrompt()} readOnly />
+          <Button
+            icon={<CopyOutlined />}
+            onClick={() => {
+              navigator.clipboard.writeText(generatePrompt());
+              message.success("提示词已复制");
+            }}
+          >
+            复制提示词
+          </Button>
+        </>
+      ),
+    },
+    {
+      title: "粘贴 LLM 结果",
+      content: (
+        <>
+          <TextArea
+            rows={12}
+            placeholder="粘贴 LLM 输出的 JSONL 结果"
+            value={jsonlInput}
+            onChange={(e) => setJsonlInput(e.target.value)}
+          />
+          <Button type="primary" onClick={parseJsonlResults}>
+            解析结果
+          </Button>
+        </>
+      ),
+    },
+    {
+      title: "对齐预览",
+      content: (
+        <>
+          {alignResults.map((res, idx) => {
+            const sentence = original.find((s) => s.id === res.id);
+            const wordIds = res.words.split(",").map(Number);
+            const wordList = wordIds
+              .map((id) => csvData.find((d) => d.id === id))
+              .filter(Boolean) as WordData[];
+
+            return (
+              <div key={res.id} style={{ marginBottom: 24 }}>
+                <Title level={5}>
+                  {res.id} — {sentence?.content}
+                </Title>
+                <Space wrap>
+                  {wordList.map((w, i) => {
+                    const isFirst = i === 0;
+                    const isLast = i === wordList.length - 1;
+                    return (
+                      <Button
+                        key={w.id}
+                        type={isFirst || isLast ? "primary" : "default"}
+                        icon={isFirst ? <UpSquareOutlined /> : undefined}
+                        onClick={() => {
+                          if (isFirst) moveWord(idx, "prev");
+                          if (isLast) moveWord(idx, "next");
+                        }}
+                      >
+                        {`${w.pali} (${w.nissaya})`}
+                        {isLast && (
+                          <DownSquareOutlined style={{ marginLeft: 4 }} />
+                        )}
+                      </Button>
+                    );
+                  })}
+                </Space>
+              </div>
+            );
+          })}
+        </>
+      ),
+    },
+  ];
+
+  return (
+    <div style={{ padding: 24 }}>
+      <Steps current={current}>
+        {steps.map((item) => (
+          <Step key={item.title} title={item.title} />
+        ))}
+      </Steps>
+      <div style={{ marginTop: 24 }}>{steps[current].content}</div>
+      <div style={{ marginTop: 24 }}>
+        {current > 0 && (
+          <Button onClick={() => setCurrent(current - 1)}>上一步</Button>
+        )}
+        {current < steps.length - 1 && (
+          <Button
+            type="primary"
+            style={{ marginLeft: 8 }}
+            onClick={() => setCurrent(current + 1)}
+          >
+            下一步
+          </Button>
+        )}
+      </div>
+    </div>
+  );
+};
+
+export default NissayaAligner;

+ 60 - 0
dashboard-v4/dashboard/src/components/corpus/NissayaAlignerModal.tsx

@@ -0,0 +1,60 @@
+import { Modal } from "antd";
+import NissayaAligner from "./NissayaAligner";
+import { useEffect, useState } from "react";
+import { IChannel } from "../channel/Channel";
+
+interface IWidget {
+  trigger?: JSX.Element | string;
+  sentencesId?: string[];
+  channel?: IChannel;
+  open?: boolean;
+  onClose?: Function;
+}
+
+const NissayaAlignerModal = ({
+  trigger,
+  sentencesId,
+  channel,
+  open,
+  onClose,
+}: IWidget) => {
+  const [isModalOpen, setIsModalOpen] = useState(open);
+
+  useEffect(() => setIsModalOpen(open), [open]);
+
+  const showModal = () => {
+    setIsModalOpen(true);
+  };
+
+  const modalClose = () => {
+    setIsModalOpen(false);
+    onClose && onClose();
+  };
+  const handleOk = () => {
+    modalClose();
+  };
+
+  const handleCancel = () => {
+    modalClose();
+  };
+
+  return (
+    <>
+      <span onClick={showModal}>{trigger}</span>
+      <Modal
+        width={"95%"}
+        style={{ maxWidth: 1500 }}
+        title="版本间复制"
+        open={isModalOpen}
+        onOk={handleOk}
+        onCancel={handleCancel}
+        destroyOnClose={true}
+        footer={[]}
+      >
+        <NissayaAligner sentencesId={sentencesId} />
+      </Modal>
+    </>
+  );
+};
+
+export default NissayaAlignerModal;

+ 7 - 4
dashboard-v4/dashboard/src/components/general/NissayaCard.tsx

@@ -157,9 +157,12 @@ const NissayaCardWidget = ({
         </Title>
         <div>
           <Link to={`/nissaya/ending/${term?.word}`} target="_blank">
-            {intl.formatMessage({
-              id: "buttons.open.in.new.tab",
-            },{item:''})}
+            {intl.formatMessage(
+              {
+                id: "buttons.open.in.new.tab",
+              },
+              { item: "" }
+            )}
           </Link>
           <Button
             type="link"
@@ -170,7 +173,7 @@ const NissayaCardWidget = ({
       </div>
       <Paragraph>{term?.meaning}</Paragraph>
       <MdView html={term?.html} />
-      {cardData ? <NissayaCardTable data={cardData} /> : <></>}
+      {cardData && <NissayaCardTable data={cardData} />}
     </div>
   );
 };

+ 30 - 0
dashboard-v4/dashboard/src/components/general/PaliEnding.ts

@@ -16,6 +16,36 @@ export const getPaliBase = (word: string): string[] => {
   output.sort((a, b) => a.length - b.length);
   return output;
 };
+export const paliEndingType = ["n", "ti", "v", "ind", "pron", "num", "adj"];
+export const paliEndingGrammar = [
+  "nom",
+  "acc",
+  "gen",
+  "dat",
+  "inst",
+  "abl",
+  "loc",
+  "voc",
+  "sg",
+  "pl",
+  "m",
+  "nt",
+  "f",
+  "1p",
+  "2p",
+  "3p",
+  "pres",
+  "aor",
+  "fut",
+  "pf",
+  "imp",
+  "cond",
+  "adv",
+  "conj",
+  "abs",
+  "ger",
+  "inf",
+];
 export const paliEnding = [
   {
     end1: "a",

+ 332 - 0
dashboard-v4/dashboard/src/components/template/AIWbw.ts

@@ -0,0 +1,332 @@
+import { useState, useCallback } from "react";
+import { IWbw } from "./Wbw/WbwWord";
+import { paliEndingGrammar, paliEndingType } from "../general/PaliEnding";
+import { useIntl } from "react-intl";
+import { useAppSelector } from "../../hooks";
+import { siteInfo } from "../../reducers/layout";
+
+// 类型定义
+export interface WbwElement<T> {
+  value: T;
+  status: number;
+}
+
+interface StreamController {
+  addData: (jsonlLine: string) => void;
+  complete: () => void;
+}
+
+interface ProcessWbwStreamOptions {
+  modelId: string;
+  data: IWbw[];
+  endingType: string[];
+  endingGrammar: string[];
+  onProgress?: (data: IWbw[], isComplete: boolean) => void;
+  onComplete?: (finalData: IWbw[]) => void;
+  onError?: (error: string) => void;
+}
+
+/**
+ * 处理JSONL流式输出的函数
+ */
+export const processWbwStream = async ({
+  modelId,
+  data,
+  endingType,
+  endingGrammar,
+  onProgress,
+  onComplete,
+  onError,
+}: ProcessWbwStreamOptions): Promise<{
+  success: boolean;
+  data?: IWbw[];
+  error?: string;
+}> => {
+  if (typeof process.env.REACT_APP_OPENAI_PROXY === "undefined") {
+    console.error("no REACT_APP_OPENAI_PROXY");
+    const error = "API配置错误";
+    onError?.(error);
+    return { success: false, error };
+  }
+  const sys_prompt = `
+  你是一个巴利语专家。用户提供的jsonl 数据 是巴利文句子的全部单词
+请根据每个单词的拼写 real.value 填写如下字段
+巴利单词的词典原型:parent.value  
+单词的中文意思:meaning.value
+巴利单词的拆分:factors.value  
+语尾请加[]
+拆分后每个组成部分的中文意思factorMeaning.value
+请按照下表填写巴利语单词的类型 type.value
+\`\`\`csv
+${endingType.join("\n")}
+\`\`\`
+
+请按照下表填写巴利语单词的语法信息 grammar.value
+名词和形容词填写 性,数,格
+动词填写 人称,数,时态语气
+用 $ 作为分隔符
+\`\`\`csv
+${endingGrammar.join("\n")}
+\`\`\`
+ 直接输出JSONL格式数据
+`;
+
+  const jsonl = data.map((obj) => JSON.stringify(obj)).join("\n");
+  const prompt = `
+\`\`\`jsonl
+${jsonl}
+\`\`\`
+`;
+  console.debug("ai wbw system prompt", sys_prompt, prompt);
+  try {
+    const payload = {
+      model: "grok-3", // 或者从models数组中获取实际模型名称
+      messages: [
+        {
+          role: "system",
+          content: sys_prompt,
+        },
+        { role: "user", content: prompt },
+      ],
+      stream: true,
+      temperature: 0.3,
+      max_tokens: 4000,
+    };
+
+    const url = process.env.REACT_APP_OPENAI_PROXY;
+    const requestData = {
+      model_id: modelId,
+      payload: payload,
+    };
+
+    console.info("api request", url, requestData);
+
+    const response = await fetch(url, {
+      method: "POST",
+      headers: {
+        "Content-Type": "application/json",
+        Authorization: `Bearer AIzaSyCzr8KqEdaQ3cRCxsFwSHh8c7kF3RZTZWw`,
+      },
+      body: JSON.stringify(requestData),
+    });
+
+    if (!response.ok) {
+      throw new Error(`HTTP error! status: ${response.status}`);
+    }
+
+    const reader = response.body?.getReader();
+    if (!reader) {
+      throw new Error("无法获取响应流");
+    }
+
+    const decoder = new TextDecoder();
+    let buffer = "";
+    let jsonlBuffer = ""; // 用于累积JSONL内容
+    const resultData: IWbw[] = [];
+
+    // 创建流控制器
+    const streamController: StreamController = {
+      addData: (jsonlLine: string) => {
+        try {
+          // 解析JSONL行
+          const parsedData = JSON.parse(jsonlLine.trim());
+          console.info("ai wbw stream ok", parsedData);
+          // 转换为IWbw格式
+          const wbwData: IWbw = {
+            book: parsedData.book || 0,
+            para: parsedData.para || 0,
+            sn: parsedData.sn || [],
+            word: parsedData.word || { value: "", status: 0 },
+            real: parsedData.real || { value: null, status: 0 },
+            meaning: parsedData.meaning,
+            type: parsedData.type,
+            grammar: parsedData.grammar,
+            style: parsedData.style,
+            case: parsedData.case,
+            parent: parsedData.parent,
+            parent2: parsedData.parent2,
+            grammar2: parsedData.grammar2,
+            factors: parsedData.factors,
+            factorMeaning: parsedData.factorMeaning,
+            relation: parsedData.relation,
+            note: parsedData.note,
+            bookMarkColor: parsedData.bookMarkColor,
+            bookMarkText: parsedData.bookMarkText,
+            locked: parsedData.locked || false,
+            confidence: parsedData.confidence || 0.5,
+            attachments: parsedData.attachments,
+            hasComment: parsedData.hasComment,
+            grammarId: parsedData.grammarId,
+            bookName: parsedData.bookName,
+            editor: parsedData.editor,
+            created_at: parsedData.created_at,
+            updated_at: parsedData.updated_at,
+          };
+
+          resultData.push(wbwData);
+
+          // 调用进度回调
+          onProgress?.(resultData, false);
+        } catch (e) {
+          console.warn("解析JSONL行失败:", e, "内容:", jsonlLine);
+        }
+      },
+      complete: () => {
+        onProgress?.(resultData, true);
+        onComplete?.(resultData);
+      },
+    };
+
+    try {
+      while (true) {
+        const { done, value } = await reader.read();
+
+        if (done) {
+          // 处理最后的缓冲内容
+          if (jsonlBuffer.trim()) {
+            const lines = jsonlBuffer.trim().split("\n");
+            for (const line of lines) {
+              if (line.trim()) {
+                streamController.addData(line);
+              }
+            }
+          }
+          streamController.complete();
+          return { success: true, data: resultData };
+        }
+
+        buffer += decoder.decode(value, { stream: true });
+        const lines = buffer.split("\n");
+        buffer = lines.pop() || "";
+
+        for (const line of lines) {
+          if (line.trim() === "") continue;
+
+          if (line.startsWith("data: ")) {
+            const data = line.slice(6);
+
+            if (data === "[DONE]") {
+              // 处理剩余的JSONL内容
+              if (jsonlBuffer.trim()) {
+                const jsonlLines = jsonlBuffer.trim().split("\n");
+                for (const jsonlLine of jsonlLines) {
+                  if (jsonlLine.trim()) {
+                    streamController.addData(jsonlLine);
+                  }
+                }
+              }
+              streamController.complete();
+              return { success: true, data: resultData };
+            }
+
+            try {
+              const parsed = JSON.parse(data);
+              const delta = parsed.choices?.[0]?.delta;
+
+              if (delta?.content) {
+                // 累积内容到JSONL缓冲区
+                jsonlBuffer += delta.content;
+
+                // 检查是否有完整的JSONL行
+                const jsonlLines = jsonlBuffer.split("\n");
+
+                // 保留最后一行(可能不完整)
+                jsonlBuffer = jsonlLines.pop() || "";
+
+                // 处理完整的行
+                for (const jsonlLine of jsonlLines) {
+                  if (jsonlLine.trim()) {
+                    streamController.addData(jsonlLine);
+                  }
+                }
+              }
+            } catch (e) {
+              console.warn("解析SSE数据失败:", e);
+            }
+          }
+        }
+      }
+    } catch (error) {
+      console.error("读取流数据失败:", error);
+      const errorMessage = "读取响应流失败";
+      onError?.(errorMessage);
+      return { success: false, error: errorMessage };
+    }
+  } catch (error) {
+    console.error("API调用失败:", error);
+    const errorMessage = "API调用失败,请重试";
+    onError?.(errorMessage);
+    return { success: false, error: errorMessage };
+  }
+};
+
+/**
+ * React Hook 用法示例
+ */
+export const useWbwStreamProcessor = () => {
+  const [isProcessing, setIsProcessing] = useState<boolean>(false);
+  const [wbwData, setWbwData] = useState<IWbw[]>([]);
+  const [error, setError] = useState<string>();
+
+  const intl = useIntl(); // 在Hook中使用
+
+  const endingType = paliEndingType.map((item) => {
+    return (
+      intl.formatMessage({ id: `dict.fields.type.${item}.label` }) +
+      `:.${item}.`
+    );
+  });
+
+  const endingGrammar = paliEndingGrammar.map((item) => {
+    return (
+      intl.formatMessage({ id: `dict.fields.type.${item}.label` }) +
+      `:.${item}.`
+    );
+  });
+
+  const processStream = useCallback(
+    async (modelId: string, data: IWbw[]) => {
+      setIsProcessing(true);
+      setWbwData([]);
+      setError(undefined);
+
+      const result = await processWbwStream({
+        modelId,
+        data,
+        endingType,
+        endingGrammar,
+        onProgress: (data, isComplete) => {
+          console.info("onProgress", data);
+          setWbwData([...data]); // 创建新数组触发重渲染
+        },
+        onComplete: (finalData) => {
+          setWbwData(finalData);
+          setIsProcessing(false);
+        },
+        onError: (errorMessage) => {
+          setError(errorMessage);
+          setIsProcessing(false);
+        },
+      });
+
+      if (!result.success) {
+        setError(result.error || "处理失败");
+        setIsProcessing(false);
+      }
+
+      return result;
+    },
+    [endingGrammar, endingType]
+  );
+
+  return {
+    processStream,
+    isProcessing,
+    wbwData,
+    error,
+    clearData: useCallback(() => {
+      setWbwData([]);
+      setError(undefined);
+    }, []),
+  };
+};

+ 107 - 4
dashboard-v4/dashboard/src/components/template/WbwSent.tsx

@@ -1,4 +1,4 @@
-import { Button, Dropdown, message, Progress, Space, Tree } from "antd";
+import { Alert, Button, Dropdown, message, Progress, Space, Tree } from "antd";
 import { useEffect, useState } from "react";
 import { MoreOutlined, ExclamationCircleOutlined } from "@ant-design/icons";
 
@@ -31,6 +31,8 @@ import moment from "moment";
 import { courseInfo } from "../../reducers/current-course";
 import { ISentenceWbwListResponse } from "../api/Corpus";
 import { IDeleteResponse } from "../api/Article";
+import { useWbwStreamProcessor } from "./AIWbw";
+import { siteInfo } from "../../reducers/layout";
 
 export const getWbwProgress = (data: IWbw[], answer?: IWbw[]) => {
   //计算完成度
@@ -277,12 +279,20 @@ export const WbwSentCtl = ({
   const [showProgress, setShowProgress] = useState(false);
   const [check, setCheck] = useState(answer ? true : false);
   const [courseAnswer, setCourseAnswer] = useState<IWbw[]>();
+  const { processStream, isProcessing, wbwData, error } =
+    useWbwStreamProcessor();
 
   const user = useAppSelector(currentUser);
   const course = useAppSelector(courseInfo);
 
+  const site = useAppSelector(siteInfo);
+  const wbwModel = site?.settings?.models?.wbw
+    ? site?.settings?.models?.wbw[0] ?? null
+    : null;
+
   console.debug("wbw sent lang", channelLang);
 
+  console.debug("wbw sent wordData", wordData);
   const loadAnswer = () => {
     if (courseAnswer) {
       return;
@@ -312,6 +322,56 @@ export const WbwSentCtl = ({
     }
   };
 
+  useEffect(() => {
+    setWordData((origin) => {
+      const newData = origin.map((item) => {
+        let newItem = item;
+        const aiWbw = wbwData.find(
+          (v) =>
+            v.sn.join() === item.sn.join() || v.real.value === item.real.value
+        );
+        if (aiWbw) {
+          if (newItem.meaning && aiWbw.meaning) {
+            newItem.meaning.value = aiWbw.meaning.value;
+          }
+          if (newItem.factors && aiWbw.factors) {
+            newItem.factors.value = aiWbw.factors.value;
+          }
+          if (newItem.factorMeaning && aiWbw.factorMeaning) {
+            newItem.factorMeaning.value = aiWbw.factorMeaning.value;
+          }
+          if (newItem.parent && aiWbw.parent) {
+            if (aiWbw.parent.value && aiWbw.parent.value !== "") {
+              newItem.parent.value = aiWbw.parent.value;
+            }
+          }
+          if (newItem.type && aiWbw.type && aiWbw.type.value) {
+            newItem.type.value = aiWbw.type.value.replaceAll(" ", "");
+            if (newItem.grammar && aiWbw.grammar && aiWbw.grammar.value) {
+              newItem.grammar.value = aiWbw.grammar.value.replaceAll(" ", "");
+              console.debug(
+                "ai wbw origin case",
+                newItem.real.value,
+                newItem.case?.value
+              );
+              if (newItem.case?.value === "") {
+                newItem.case.value = `${aiWbw.type.value}#${aiWbw.grammar.value}`;
+                console.debug(
+                  "ai wbw new case",
+                  newItem.real.value,
+                  newItem.case.value
+                );
+              }
+            }
+          }
+          console.debug("ai wbw replace", newItem.real.value, newItem);
+        }
+        return newItem;
+      });
+      return newData;
+    });
+  }, [wbwData]);
+
   useEffect(() => setShowProgress(wbwProgress), [wbwProgress]);
 
   const settings = useAppSelector(settingInfo);
@@ -324,9 +384,25 @@ export const WbwSentCtl = ({
 
   const newMode = useAppSelector(_mode);
 
-  const update = (data: IWbw[]) => {
-    console.debug("wbw update");
-    setWordData(paraMark(data));
+  const update = (data: IWbw[], replace: boolean = true) => {
+    if (replace) {
+      setWordData(paraMark(data));
+    } else {
+      setWordData((origin) => {
+        origin.forEach((value, index, array) => {
+          const newOne = data.find(
+            (v) =>
+              v.sn.join() === value.sn.join() ||
+              v.real.value === value.real.value
+          );
+          if (newOne) {
+            array[index] = newOne;
+          }
+        });
+        return origin;
+      });
+    }
+
     if (typeof onChange !== "undefined") {
       onChange(data);
     }
@@ -808,11 +884,23 @@ export const WbwSentCtl = ({
         <div className="progress" style={{ width: 400 }}>
           <Progress percent={progress} size="small" />
         </div>
+
         <Space>
           <Studio data={studio} hideAvatar />
           {<TimeShow updatedAt={updatedAt.toString()} />}
         </Space>
       </div>
+      {error ? <Alert message={error} /> : <></>}
+      {isProcessing ? (
+        <div>
+          <Progress
+            percent={Math.round((wbwData.length * 100) / wordData.length)}
+            size="small"
+          />
+        </div>
+      ) : (
+        <></>
+      )}
       <div className={`layout-${layoutDirection}`}>
         <Dropdown
           menu={{
@@ -823,6 +911,11 @@ export const WbwSentCtl = ({
                   id: "buttons.magic-dict",
                 }),
               },
+              {
+                key: "ai-magic-dict-current",
+                label: "ai-magic-dict",
+                disabled: !wbwModel,
+              },
               {
                 key: "progress",
                 label: "显示/隐藏进度条",
@@ -870,6 +963,9 @@ export const WbwSentCtl = ({
                   setLoading(true);
                   magicDictLookup();
                   break;
+                case "ai-magic-dict-current":
+                  wbwModel && processStream(wbwModel.uid, wordData);
+                  break;
                 case "wbw-dict-publish-all":
                   wbwPublish(
                     wordData,
@@ -932,6 +1028,13 @@ export const WbwSentCtl = ({
         </Dropdown>
         {layoutDirection === "h" ? (
           wordData
+            .map((item) => {
+              const newData = wbwData.find(
+                (value) => value.sn.join() === item.sn.join()
+              );
+
+              return newData ?? item;
+            })
             .map((item, index) => {
               let newItem = item;
               const spell = item.real.value;

+ 45 - 0
dashboard-v4/dashboard/src/hooks/useActivePath.ts

@@ -0,0 +1,45 @@
+import { useMemo, useCallback } from "react";
+import { MessageNode } from "../types/chat";
+
+export function useActivePath(
+  rawMessages: MessageNode[],
+  activePoint?: string
+) {
+  const computeActivePath = useCallback(() => {
+    // 从root消息开始,最新消息的路径构建激活链
+    console.debug("ai chat", rawMessages);
+    const activePath: MessageNode[] = [];
+
+    // 找到system消息(根节点)
+    let rootMsg = rawMessages.find((m) => !m.parent_id);
+    if (!rootMsg) return [];
+
+    if (activePoint) {
+      //向上
+      const activeMsg = rawMessages.find((v) => v.uid === activePoint);
+      if (!activeMsg) {
+        return [];
+      }
+      let currParent: MessageNode | undefined = rawMessages.find(
+        (m) => m.uid === activeMsg.parent_id
+      );
+      while (currParent) {
+        const pId = currParent.parent_id;
+        activePath.unshift(currParent);
+        currParent = rawMessages.find((v) => v.uid === pId);
+      }
+      rootMsg = activeMsg;
+    }
+    let current: MessageNode | undefined = rootMsg;
+    while (current) {
+      const currId: string = current.uid;
+      activePath.push(current);
+      // 找到当前消息的激活子消息
+      current = rawMessages.filter((value) => value.parent_id === currId).pop();
+    }
+
+    return activePath;
+  }, [activePoint, rawMessages]);
+
+  return useMemo(() => computeActivePath(), [computeActivePath]);
+}

+ 631 - 0
dashboard-v4/dashboard/src/hooks/useChatData.ts

@@ -0,0 +1,631 @@
+// dashboard-v4/dashboard/src/hooks/useChatData.ts
+import { useState, useCallback, useMemo, useEffect } from "react";
+import {
+  MessageNode,
+  ChatState,
+  ChatActions,
+  PendingMessage,
+  OpenAIMessage,
+  TOpenAIRole,
+  ParsedChunk,
+  ToolCall,
+  CreateMessageRequest,
+} from "../types/chat";
+
+import { useActivePath } from "./useActivePath";
+import { useSessionGroups } from "./useSessionGroups";
+//import { messageApi } from "../services/messageApi";
+import { mockMessageApi as messageApi } from "../services/mockMessageApi";
+import { getModelAdapter } from "../services/modelAdapters";
+import { IAiModel } from "../components/api/ai";
+
+export function useChatData(chatId: string): {
+  chatState: ChatState;
+  actions: ChatActions;
+} {
+  // Mock模式:直接使用mock数据
+  const [rawMessages, setRawMessages] = useState<MessageNode[]>([]);
+  const [pendingMessages, setPendingMessages] = useState<PendingMessage[]>([]);
+  const [isLoading, setIsLoading] = useState(false);
+  const [isInitialized, setIsInitialized] = useState(false); // 新增:标记是否已初始化
+  const [streamingMessage, setStreamingMessage] = useState<string>();
+  const [streamingSessionId, setStreamingSessionId] = useState<string>();
+  const [error, setError] = useState<string>();
+  const [activePoint, setActivePoint] = useState<string>();
+  const [currModel, setCurrModel] = useState<IAiModel>();
+
+  // 合并已保存和待保存的消息用于显示
+  const allMessages = useMemo(() => {
+    const pending = pendingMessages.flatMap((p) => p.messages);
+    return [...rawMessages, ...pending];
+  }, [rawMessages, pendingMessages]);
+
+  const activePath = useActivePath(allMessages, activePoint);
+  const sessionGroups = useSessionGroups(activePath, allMessages);
+
+  // 加载消息列表
+  const loadMessages = useCallback(async () => {
+    // 如果 chatId 为空或无效,不执行加载
+    /*
+    if (!chatId || chatId.trim() === "") {
+      return;
+    }
+*/
+    try {
+      setIsLoading(true);
+      setError(undefined); // 清除之前的错误
+
+      const response = await messageApi.getMessages(chatId);
+      setRawMessages(response.data.rows);
+      setIsInitialized(true);
+    } catch (err) {
+      const errorMessage = err instanceof Error ? err.message : "加载消息失败";
+      setError(errorMessage);
+      console.error("加载消息失败:", err);
+    } finally {
+      setIsLoading(false);
+    }
+  }, [chatId]);
+
+  // 当 chatId 变化时自动加载消息
+  useEffect(() => {
+    // 重置状态
+    setIsInitialized(false);
+    setRawMessages([]);
+    setPendingMessages([]);
+    setError(undefined);
+    setActivePoint(undefined);
+
+    // 加载新的消息
+    loadMessages();
+  }, [chatId, loadMessages]);
+
+  // 手动刷新方法(供外部调用)
+  const refreshMessages = useCallback(async () => {
+    setIsInitialized(false);
+    await loadMessages();
+  }, [loadMessages]);
+
+  // 构建对话历史(用于AI API调用)
+  const buildConversationHistory = useCallback(
+    (baseMessages: MessageNode[], newUserMessage?: MessageNode) => {
+      const history: OpenAIMessage[] = activePath.map((m) => ({
+        role: m.role,
+        content: m.content || "",
+        tool_calls: m.tool_calls,
+        tool_call_id: m.tool_call_id,
+      }));
+
+      if (newUserMessage) {
+        history.push({
+          role: "user",
+          content: newUserMessage.content || "",
+        });
+      }
+
+      return history;
+    },
+    [activePath]
+  );
+
+  // 保存消息组到数据库
+  const saveMessageGroup = useCallback(
+    async (tempId: string, messages: MessageNode[]) => {
+      try {
+        const data: CreateMessageRequest = {
+          messages: messages.map((m) => ({
+            uid: m.uid,
+            parent_id: m.parent_id,
+            role: m.role,
+            content: m.content,
+            session_id: m.session_id,
+            model_id: m.model_id,
+            tool_calls: m.tool_calls,
+            tool_call_id: m.tool_call_id,
+            metadata: m.metadata,
+          })),
+        };
+        const savedMessages = await messageApi.createMessages(chatId, data);
+
+        // 更新本地状态:移除pending,添加到已保存消息
+        setPendingMessages((prev) => prev.filter((p) => p.temp_id !== tempId));
+        setRawMessages((prev) => [...prev, ...savedMessages.data]);
+      } catch (err) {
+        console.error("保存消息组失败:", err);
+        setPendingMessages((prev) =>
+          prev.map((p) =>
+            p.temp_id === tempId
+              ? {
+                  ...p,
+                  error: err instanceof Error ? err.message : "保存失败",
+                  messages: p.messages.map((m) => ({
+                    ...m,
+                    save_status: "failed" as const,
+                  })),
+                }
+              : p
+          )
+        );
+      }
+    },
+    [chatId]
+  );
+  // 一个安全 JSON 解析函数
+  function safeJsonParse(str: string): any {
+    try {
+      return JSON.parse(str);
+    } catch {
+      return str; // 返回原始字符串,避免崩溃
+    }
+  }
+  // 发送消息给AI并处理响应
+  const sendMessageToAI = useCallback(
+    async (userMessage: MessageNode, pendingGroup: PendingMessage) => {
+      try {
+        if (!currModel) {
+          console.error("no model selected");
+          return;
+        }
+        console.debug("ai chat send message current model", currModel);
+        setIsLoading(true);
+        setStreamingSessionId(pendingGroup.session_id);
+
+        const conversationHistory = buildConversationHistory(
+          rawMessages,
+          userMessage
+        );
+        const adapter = getModelAdapter(currModel);
+
+        // 处理Function Call的循环逻辑
+        let currentMessages = conversationHistory;
+        let maxIterations = 10;
+        let allAiMessages: MessageNode[] = [];
+
+        while (maxIterations-- > 0) {
+          // 流式处理AI响应
+          let responseContent = "";
+          let functionCalls: ToolCall[] = [];
+          let metadata: any = {};
+
+          const streamResponse = await adapter.sendMessage(currentMessages, {
+            temperature: 0.7,
+            max_tokens: 2048,
+          });
+
+          // 用于存储流式拼接的 tool_calls
+          const toolCallBuffer = new Map<number, ToolCall>();
+
+          // 流式输出处理
+          await new Promise((resolve, reject) => {
+            const processStream = async () => {
+              try {
+                for await (const chunk of streamResponse) {
+                  const parsed: ParsedChunk | null =
+                    adapter.parseStreamChunk(chunk);
+
+                  // 处理内容流
+                  if (parsed?.content) {
+                    responseContent += parsed.content;
+                    setStreamingMessage(responseContent);
+                  }
+
+                  // 处理 tool_calls
+                  if (parsed?.tool_calls) {
+                    for (const call of parsed.tool_calls) {
+                      //console.info("ai chat call", call);
+                      const existing = toolCallBuffer.get(call.index);
+                      if (existing) {
+                        // 拼接 arguments
+                        existing.function.arguments +=
+                          call.function.arguments || "";
+                        //console.debug("ai chat 拼接 arguments", existing);
+                      } else {
+                        // 初始化新 tool_call
+                        //console.debug("ai chat 初始化新 tool_call", call);
+                        toolCallBuffer.set(call.index, {
+                          ...call,
+                          function: {
+                            ...call.function,
+                            arguments: call.function.arguments || "",
+                          },
+                        });
+                      }
+                    }
+
+                    console.info(
+                      "ai chat function call (buffer)",
+                      toolCallBuffer
+                    );
+                  }
+
+                  // 如果模型说明调用结束
+                  if (parsed?.finish_reason === "tool_calls") {
+                    // 在这里 arguments 已经拼接完整,可以解析
+                    const toolCalls: ToolCall[] = [];
+                    toolCallBuffer.forEach((value: ToolCall, key: number) => {
+                      toolCalls.push(value);
+                    });
+
+                    console.info("ai chat Final tool calls", toolCalls);
+
+                    // TODO: 在这里触发你实际的函数调用逻辑
+                    functionCalls = toolCalls;
+                  }
+                }
+                resolve(undefined);
+              } catch (err) {
+                reject(err);
+              }
+            };
+            processStream();
+          });
+
+          // 创建AI请求消息
+          const toolCallsMessage: MessageNode = {
+            id: 0,
+            uid: `temp_ai_${pendingGroup.temp_id}_${allAiMessages.length}`,
+            temp_id: pendingGroup.temp_id,
+            chat_id: chatId,
+            session_id: pendingGroup.session_id,
+            parent_id:
+              allAiMessages.length === 0
+                ? userMessage.uid
+                : allAiMessages[allAiMessages.length - 1].uid,
+            role: "assistant",
+            content: responseContent,
+            model_id: currModel.uid,
+            tool_calls: functionCalls.length > 0 ? functionCalls : undefined,
+            metadata,
+            is_active: true,
+            save_status: "pending",
+            created_at: new Date().toISOString(),
+            updated_at: new Date().toISOString(),
+          };
+
+          allAiMessages.push(toolCallsMessage);
+
+          // 如果有function calls,处理它们
+          if (functionCalls.length > 0) {
+            const toolResults = await Promise.all(
+              functionCalls.map((call) => adapter.handleFunctionCall(call))
+            );
+            //ai相应消息
+            const toolMessages: MessageNode[] = functionCalls.map(
+              (call, index) => ({
+                id: 0,
+                uid: `temp_tool_${pendingGroup.temp_id}_${index}`,
+                temp_id: pendingGroup.temp_id,
+                chat_id: chatId,
+                session_id: pendingGroup.session_id,
+                parent_id: toolCallsMessage.uid,
+                role: "tool" as const,
+                content: JSON.stringify(toolResults[index]),
+                tool_call_id: call.id,
+                is_active: true,
+                save_status: "pending" as const,
+                created_at: new Date().toISOString(),
+                updated_at: new Date().toISOString(),
+              })
+            );
+
+            allAiMessages.push(...toolMessages);
+            console.debug("ai chat allAiMessages", allAiMessages);
+            // 更新对话历史,继续循环
+            currentMessages.push(
+              {
+                role: "assistant",
+                content: responseContent,
+                tool_calls: functionCalls,
+              },
+              ...toolMessages.map((tm) => ({
+                role: "tool" as const,
+                content: tm.content || "",
+                tool_call_id: tm.tool_call_id,
+              }))
+            );
+            console.debug("ai chat currentMessages", currentMessages);
+
+            continue;
+          }
+
+          // 没有function call,结束循环
+          break;
+        }
+
+        // 更新pending消息组
+        setPendingMessages((prev) =>
+          prev.map((p) =>
+            p.temp_id === pendingGroup.temp_id
+              ? { ...p, messages: [...p.messages, ...allAiMessages] }
+              : p
+          )
+        );
+
+        // 保存整个消息组到数据库
+        await saveMessageGroup(pendingGroup.temp_id, [
+          userMessage,
+          ...allAiMessages,
+        ]);
+      } catch (err) {
+        console.error("AI响应失败:", err);
+        setPendingMessages((prev) =>
+          prev.map((p) =>
+            p.temp_id === pendingGroup.temp_id
+              ? {
+                  ...p,
+                  error: err instanceof Error ? err.message : "未知错误",
+                  retry_count: p.retry_count + 1,
+                }
+              : p
+          )
+        );
+      } finally {
+        setIsLoading(false);
+        setStreamingMessage(undefined);
+        setStreamingSessionId(undefined);
+      }
+    },
+    [currModel, buildConversationHistory, rawMessages, saveMessageGroup, chatId]
+  );
+
+  // 编辑消息 - 创建新版本
+  const editMessage = useCallback(
+    async (sessionId: string, content: string, role: TOpenAIRole = "user") => {
+      const tempId = `temp_${Date.now()}`;
+
+      try {
+        // 找到要编辑的消息的父消息
+        let parentId: string | undefined;
+
+        if (sessionId === "new") {
+          // 新消息,找到最后一个激活消息作为父消息
+          const lastMessage = activePath[activePath.length - 1];
+          parentId = lastMessage?.uid;
+        } else {
+          // 编辑现有session,找到该session的父消息
+          const sessionMessages = activePath.filter(
+            (m) => m.session_id === sessionId
+          );
+          const firstMessage = sessionMessages[0];
+          parentId = firstMessage?.parent_id;
+        }
+
+        const newSessionId =
+          sessionId === "new" ? `session_${tempId}` : `session_${tempId}`;
+
+        const maxId = Math.max(...rawMessages.map((msg) => msg.id));
+        // 创建新的用户消息
+        const newUserMessage: MessageNode = {
+          id: maxId + 1,
+          uid: `temp_user_${tempId}`,
+          temp_id: tempId,
+          chat_id: chatId,
+          parent_id: parentId,
+          session_id: newSessionId,
+          role: "user",
+          content,
+          is_active: true,
+          save_status: "pending",
+          created_at: new Date().toISOString(),
+          updated_at: new Date().toISOString(),
+        };
+
+        // 创建待保存消息组
+        const pendingGroup: PendingMessage = {
+          temp_id: tempId,
+          session_id: newSessionId,
+          messages: [newUserMessage],
+          retry_count: 0,
+          created_at: new Date().toISOString(),
+        };
+
+        setPendingMessages((prev) => [...prev, pendingGroup]);
+        console.debug("ai chat", pendingGroup);
+
+        // 如果是用户消息,发送给AI
+        if (role === "user") {
+          await sendMessageToAI(newUserMessage, pendingGroup);
+        }
+      } catch (err) {
+        console.error("编辑消息失败:", err);
+        setPendingMessages((prev) =>
+          prev.map((p) =>
+            p.temp_id === tempId
+              ? {
+                  ...p,
+                  messages: p.messages.map((m) => ({
+                    ...m,
+                    save_status: "failed" as const,
+                  })),
+                  error: err instanceof Error ? err.message : "编辑失败",
+                }
+              : p
+          )
+        );
+      }
+    },
+    [rawMessages, chatId, activePath, sendMessageToAI]
+  );
+
+  // 重试失败的消息
+  const retryMessage = useCallback(
+    async (tempId: string) => {
+      const pendingGroup = pendingMessages.find((p) => p.temp_id === tempId);
+      if (!pendingGroup) return;
+
+      const userMessage = pendingGroup.messages.find((m) => m.role === "user");
+      if (!userMessage) return;
+
+      // 重置状态并重试
+      setPendingMessages((prev) =>
+        prev.map((p) =>
+          p.temp_id === tempId
+            ? {
+                ...p,
+                messages: [{ ...userMessage, save_status: "pending" }],
+                error: undefined,
+              }
+            : p
+        )
+      );
+
+      await sendMessageToAI(userMessage, {
+        ...pendingGroup,
+        messages: [userMessage],
+      });
+    },
+    [pendingMessages, sendMessageToAI]
+  );
+
+  // 切换版本
+  const switchVersion = useCallback((activeMsgId: string) => {
+    console.debug("activeMsgId", activeMsgId);
+    setActivePoint(activeMsgId);
+  }, []);
+
+  // 刷新AI回答
+  const refreshResponse = useCallback(
+    async (sessionId: string, modelId?: string) => {
+      const session = sessionGroups.find((sg) => sg.session_id === sessionId);
+      if (!session?.user_message) return;
+
+      const tempId = `temp_refresh_${Date.now()}`;
+
+      try {
+        // 创建基于原用户消息的新AI回答
+        const userMsg = session.user_message;
+        const newSessionId = `session_${tempId}`;
+
+        const pendingGroup: PendingMessage = {
+          temp_id: tempId,
+          session_id: newSessionId,
+          messages: [
+            {
+              ...userMsg,
+              temp_id: tempId,
+              session_id: newSessionId,
+              save_status: "pending",
+            },
+          ],
+          retry_count: 0,
+          created_at: new Date().toISOString(),
+        };
+
+        setPendingMessages((prev) => [...prev, pendingGroup]);
+
+        // 发送给AI获取新回答
+        await sendMessageToAI(pendingGroup.messages[0], pendingGroup);
+      } catch (err) {
+        console.error("刷新回答失败:", err);
+        setError(err instanceof Error ? err.message : "刷新失败");
+      }
+    },
+    [sessionGroups, sendMessageToAI]
+  );
+
+  // 消息操作功能
+  const likeMessage = useCallback(async (messageId: string) => {
+    try {
+      await messageApi.likeMessage(messageId);
+      // 可以添加本地状态更新
+    } catch (err) {
+      console.error("点赞失败:", err);
+    }
+  }, []);
+
+  const dislikeMessage = useCallback(async (messageId: string) => {
+    try {
+      await messageApi.dislikeMessage(messageId);
+      // 可以添加本地状态更新
+    } catch (err) {
+      console.error("点踩失败:", err);
+    }
+  }, []);
+
+  const copyMessage = useCallback(
+    (messageId: string) => {
+      const message = allMessages.find((m) => m.uid === messageId);
+      if (message?.content) {
+        navigator.clipboard.writeText(message.content);
+      }
+    },
+    [allMessages]
+  );
+
+  const shareMessage = useCallback(
+    async (messageId: string): Promise<string> => {
+      try {
+        const response = await messageApi.shareMessage(messageId);
+        return response.data.shareUrl;
+      } catch (err) {
+        console.error("分享失败:", err);
+        throw err;
+      }
+    },
+    []
+  );
+
+  const deleteMessage = useCallback(
+    async (messageId: string) => {
+      try {
+        await messageApi.deleteMessage(messageId);
+        await refreshMessages(); // 使用 refreshMessages 而不是 loadMessages
+      } catch (err) {
+        console.error("删除失败:", err);
+        setError(err instanceof Error ? err.message : "删除失败");
+      }
+    },
+    [refreshMessages]
+  );
+
+  const setModel = useCallback((model: IAiModel | undefined) => {
+    setCurrModel(model);
+  }, []);
+
+  const actions = useMemo(
+    () => ({
+      switchVersion,
+      editMessage,
+      retryMessage,
+      refreshResponse,
+      loadMessages: refreshMessages, // 对外暴露的是 refreshMessages
+      likeMessage,
+      dislikeMessage,
+      copyMessage,
+      shareMessage,
+      deleteMessage,
+      setModel,
+    }),
+    [
+      switchVersion,
+      editMessage,
+      retryMessage,
+      refreshResponse,
+      refreshMessages,
+      likeMessage,
+      dislikeMessage,
+      copyMessage,
+      shareMessage,
+      deleteMessage,
+      setModel,
+    ]
+  );
+
+  return {
+    chatState: {
+      chat_id: chatId,
+      title: "", // 可以从props传入或另行管理
+      raw_messages: rawMessages,
+      active_path: activePath,
+      session_groups: sessionGroups,
+      pending_messages: pendingMessages,
+      is_loading: isLoading,
+      is_initialized: isInitialized, // 新增:初始化状态
+      streaming_message: streamingMessage,
+      streaming_session_id: streamingSessionId,
+      current_model: currModel,
+      error,
+    },
+    actions,
+  };
+}

+ 109 - 0
dashboard-v4/dashboard/src/hooks/useSessionGroups.ts

@@ -0,0 +1,109 @@
+// dashboard-v4/dashboard/src/hooks/useSessionGroups.ts
+import { useMemo, useCallback } from "react";
+import { MessageNode, SessionInfo, VersionInfo } from "../types/chat";
+
+export function useSessionGroups(
+  activePath: MessageNode[],
+  rawMessages: MessageNode[]
+) {
+  const computeSessionVersions = useCallback(
+    (sessionId: string): VersionInfo[] => {
+      /**
+       * 找到session的parent message
+       * parent message children 就是versions
+       */
+      // 找到该session的所有消息
+      const sessionMessages = rawMessages.filter(
+        (m) => m.session_id === sessionId
+      );
+
+      if (sessionMessages.length === 0) {
+        return [];
+      }
+      const firstMsg = sessionMessages.sort((a, b) => a.id - b.id)[0];
+      const parentMsg = rawMessages.find(
+        (value) => value.uid === firstMsg.parent_id
+      );
+
+      if (!parentMsg) {
+        return [];
+      }
+      const childrenMsg = rawMessages.filter(
+        (value) => value.parent_id === parentMsg.uid
+      );
+      console.debug("parentMsg", parentMsg, childrenMsg);
+
+      // 转换为VersionInfo数组
+      const versions: VersionInfo[] = childrenMsg.map((msg, index) => {
+        return {
+          version_index: index,
+          message_id: msg.uid,
+        };
+      });
+
+      return versions;
+    },
+    [rawMessages]
+  );
+
+  const findCurrentVersion = useCallback(
+    (sessionMessages: MessageNode[], versions: VersionInfo[]): number => {
+      // 找到当前激活的AI消息
+      const activeAiMsg = sessionMessages.find(
+        (m) => m.role === "assistant" && m.is_active
+      );
+      if (!activeAiMsg) return versions.length - 1;
+
+      // 根据创建时间找到对应的版本索引
+      const versionIndex = versions.findIndex(
+        (v) => v.message_id === activeAiMsg.uid
+      );
+      return Math.max(0, versionIndex);
+    },
+    []
+  );
+
+  const computeSessionGroups = useCallback((): SessionInfo[] => {
+    const sessionMap = new Map<string, MessageNode[]>();
+
+    // 按session_id分组激活路径上的消息(排除system消息)
+    activePath.forEach((msg) => {
+      if (msg.role !== "system") {
+        const sessionId = msg.session_id;
+        if (!sessionMap.has(sessionId)) {
+          sessionMap.set(sessionId, []);
+        }
+        sessionMap.get(sessionId)!.push(msg);
+      }
+    });
+
+    // 为每个session计算版本信息
+    const sessionGroups: SessionInfo[] = [];
+
+    sessionMap.forEach((messages, sessionId) => {
+      const versions = computeSessionVersions(sessionId);
+      const currentVersion = findCurrentVersion(messages, versions);
+
+      const userMessage = messages.find((m) => m.role === "user");
+      const aiMessages = messages.filter((m) => m.role !== "user");
+
+      sessionGroups.push({
+        session_id: sessionId,
+        messages,
+        versions,
+        current_version: currentVersion,
+        user_message: userMessage,
+        ai_messages: aiMessages,
+      });
+    });
+
+    // 按消息ID排序,保证显示顺序
+    return sessionGroups.sort((a, b) => {
+      const aFirstId = Math.min(...a.messages.map((m) => m.id));
+      const bFirstId = Math.min(...b.messages.map((m) => m.id));
+      return aFirstId - bFirstId;
+    });
+  }, [activePath, computeSessionVersions, findCurrentVersion]);
+
+  return useMemo(() => computeSessionGroups(), [computeSessionGroups]);
+}

+ 13 - 15
dashboard-v4/dashboard/src/load.ts

@@ -22,9 +22,17 @@ import { IRelation, IRelationListResponse } from "./pages/admin/relation/list";
 import { pushRelation } from "./reducers/relation";
 import { IGroupMemberListResponse } from "./components/api/Group";
 import { IStudio } from "./components/auth/Studio";
+import { IAiModel } from "./components/api/ai";
 
+export interface ISettingModels {
+  wbw?: IAiModel[];
+  chat?: IAiModel[];
+}
 export interface ISiteInfoResponse {
+  logo: string;
   title: string;
+  subhead: string;
+  models?: ISettingModels;
 }
 interface IUserData {
   id: string;
@@ -73,22 +81,12 @@ export const grammarTermFetch = () => {
 };
 
 const init = () => {
-  get<ISiteInfoResponse | IErrorResponse>("/v2/site-info/en").then(
-    (response) => {
-      if ("title" in response) {
-        const it: ISite = {
-          title: response.title,
-          subhead: "",
-          keywords: [],
-          description: "",
-          copyright: "",
-          logo: "",
-          author: { name: "", email: "" },
-        };
-        store.dispatch(refreshLayout(it));
-      }
+  get<ISite | IErrorResponse>("/v2/site-info/en").then((response) => {
+    if ("title" in response) {
+      const it: ISite = response;
+      store.dispatch(refreshLayout(it));
     }
-  );
+  });
   //获取用户登录信息
   const token = getToken();
   if (token) {

+ 15 - 0
dashboard-v4/dashboard/src/pages/admin/ai/index.tsx

@@ -0,0 +1,15 @@
+import { Outlet } from "react-router-dom";
+import { Layout } from "antd";
+import { styleStudioContent } from "../../studio/style";
+
+const { Content } = Layout;
+
+const Widget = () => {
+  return (
+    <Content style={styleStudioContent}>
+      <Outlet />
+    </Content>
+  );
+};
+
+export default Widget;

+ 124 - 0
dashboard-v4/dashboard/src/pages/admin/ai/list.tsx

@@ -0,0 +1,124 @@
+import { Divider, Transfer } from "antd";
+import { useEffect, useState } from "react";
+import { TransferDirection } from "antd/es/transfer";
+
+import { get, post } from "../../../request";
+import {
+  IAiModelListResponse,
+  IAiModelResponse,
+  IAiModelSystem,
+} from "../../../components/api/ai";
+import { useAppSelector } from "../../../hooks";
+import { siteInfo } from "../../../reducers/layout";
+
+type IType = "wbw" | "chat" | "summarize";
+const selectors: IType[] = ["wbw", "chat", "summarize"];
+interface IWidget {
+  type: IType;
+  models?: RecordType[];
+}
+const ModelSelect = ({ type, models }: IWidget) => {
+  const [targetKeys, setTargetKeys] = useState<string[]>([]);
+  const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
+
+  const site = useAppSelector(siteInfo);
+
+  useEffect(() => {
+    let target: string[] = [];
+    switch (type) {
+      case "wbw":
+        target = site?.settings?.models?.wbw?.map((item) => item.uid) ?? [];
+        break;
+      case "chat":
+        target = site?.settings?.models?.chat?.map((item) => item.uid) ?? [];
+        break;
+    }
+    setTargetKeys(target);
+  }, [site?.settings?.models, type]);
+
+  const onChange = (
+    nextTargetKeys: string[],
+    direction: TransferDirection,
+    moveKeys: string[]
+  ) => {
+    setTargetKeys(nextTargetKeys);
+    const url = `/v2/system-model`;
+    post<IAiModelSystem, IAiModelResponse>(url, {
+      view: type,
+      models: nextTargetKeys,
+    })
+      .then((json) => {
+        if (json.ok) {
+          console.info("system model save ok");
+        } else {
+          console.error("system model save");
+        }
+      })
+      .catch((e) => console.error(e));
+  };
+
+  const onSelectChange = (
+    sourceSelectedKeys: string[],
+    targetSelectedKeys: string[]
+  ) => {
+    console.log("sourceSelectedKeys:", sourceSelectedKeys);
+    console.log("targetSelectedKeys:", targetSelectedKeys);
+    setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
+  };
+
+  return (
+    <Transfer
+      dataSource={models}
+      titles={["All", "Selected"]}
+      targetKeys={targetKeys}
+      selectedKeys={selectedKeys}
+      onChange={onChange}
+      onSelectChange={onSelectChange}
+      render={(item) => item.title}
+    />
+  );
+};
+
+interface RecordType {
+  key: string;
+  title: string;
+  description?: string;
+}
+
+const Widget = () => {
+  const [models, setModels] = useState<RecordType[]>();
+
+  useEffect(() => {
+    const url = `/v2/ai-model?view=chat`;
+    console.log("api request", url);
+    get<IAiModelListResponse>(url).then((json) => {
+      console.log("api response", json);
+      if (json.ok) {
+        setModels(
+          json.data.rows.map((item) => {
+            return {
+              key: item.uid,
+              title: item.name,
+              description: item.model,
+            };
+          })
+        );
+      }
+    });
+  }, []);
+
+  return (
+    <div>
+      {selectors.map((item, id) => {
+        return (
+          <div key={id}>
+            <Divider>{item}</Divider>
+            <ModelSelect models={models} type={item} />
+          </div>
+        );
+      })}
+    </div>
+  );
+};
+
+export default Widget;

+ 16 - 0
dashboard-v4/dashboard/src/pages/library/chat/ai.tsx

@@ -0,0 +1,16 @@
+import { useParams } from "react-router-dom";
+import { ChatContainer } from "../../../components/chat/ChatContainer";
+
+const AI = () => {
+  const { id } = useParams();
+
+  return (
+    <div>
+      <div style={{ width: 1000, marginLeft: "auto", marginRight: "auto" }}>
+        <ChatContainer chatId={id ?? ""} />
+      </div>
+    </div>
+  );
+};
+
+export default AI;

+ 19 - 0
dashboard-v4/dashboard/src/pages/library/chat/index.tsx

@@ -0,0 +1,19 @@
+import { Layout } from "antd";
+
+import HeadBar from "../../../components/library/HeadBar";
+import FooterBar from "../../../components/library/FooterBar";
+import { Outlet } from "react-router-dom";
+
+const Widget = () => {
+  return (
+    <>
+      <Layout>
+        <HeadBar />
+        <Outlet />
+        <FooterBar />
+      </Layout>
+    </>
+  );
+};
+
+export default Widget;

+ 19 - 0
dashboard-v4/dashboard/src/pages/library/chat/new.tsx

@@ -0,0 +1,19 @@
+import { ChatContainer } from "../../../components/chat/ChatContainer";
+
+const AI = () => {
+  return (
+    <div>
+      <div
+        style={{
+          width: 1000,
+          marginLeft: "auto",
+          marginRight: "auto",
+        }}
+      >
+        <ChatContainer chatId={""} />
+      </div>
+    </div>
+  );
+};
+
+export default AI;

+ 23 - 5
dashboard-v4/dashboard/src/pages/nut/index.tsx

@@ -1,17 +1,35 @@
 import FooterBar from "../../components/library/FooterBar";
 
 import HeadBar from "../../components/library/HeadBar";
-import AIChatComponent from "../../components/chat/AiChat";
-import { Content } from "antd/lib/layout/layout";
+import TreeText from "../../components/article/TreeText";
+import { ChatContainer } from "../../components/chat/ChatContainer";
+import NissayaAligner from "../../components/corpus/NissayaAligner";
 
 const Widget = () => {
   return (
     <div>
       <HeadBar />
-      <Content>
+      <div>
         <div>Home Page</div>
-        <AIChatComponent />
-      </Content>
+        <div style={{ backgroundColor: "white" }}>
+          <NissayaAligner />
+        </div>
+        <TreeText
+          type="chapter"
+          rootId="140-92"
+          channelsId={["7fea264d-7a26-40f8-bef7-bc95102760fb"]}
+        />
+        <div
+          style={{
+            backgroundColor: "white",
+            color: "black",
+            border: "2px solid red",
+            margin: 10,
+          }}
+        >
+          <ChatContainer chatId={"123"} />
+        </div>
+      </div>
       <FooterBar />
     </div>
   );

+ 4 - 0
dashboard-v4/dashboard/src/reducers/layout.ts

@@ -1,6 +1,7 @@
 import { createSlice, PayloadAction } from "@reduxjs/toolkit";
 
 import type { RootState } from "../store";
+import { ISettingModels } from "../load";
 
 export interface IAuthor {
   name: string;
@@ -15,6 +16,9 @@ export interface ISite {
   description: string;
   copyright: string;
   author: IAuthor;
+  settings?: {
+    models?: ISettingModels;
+  };
 }
 
 interface IState {

+ 289 - 0
dashboard-v4/dashboard/src/services/agentApi.ts

@@ -0,0 +1,289 @@
+import { FunctionDefinition } from "../types/chat";
+import {
+  SearchByQueryArgs,
+  SearchByPageRefArgs,
+  GetTermDefinitionArgs,
+  SearchPaliArgs,
+  SearchResponse,
+} from "../types/search"; // 假设你的类型定义文件名为 apiTypes.ts
+
+/**
+ * 基础 API URL
+ * 请替换为你的实际后端 API 地址
+ */
+const API_BASE_URL = "http://localhost:8000/api/v3";
+
+export const system_prompt = `
+你是一个专业的、精通巴利语和汉语的佛教文献检索助手。你的任务是分析用户的查询,并利用你拥有的工具(函数)来获取信息。
+
+严格遵守以下原则:
+1.  优先并恰当地使用提供的工具来满足用户的查询需求。
+2.  你的回答必须简洁、直接,仅包含从工具中获得的信息,不添加任何额外闲聊。
+3.  如果一个查询无法被任何工具处理,或者需要与用户进行澄清,请清晰地说明。
+4.  当用户的查询包含**页码标记**(例如:M3.58, V3.81)时,必须使用 search_by_page_ref 函数。
+5.  当用户的查询是**明确的佛教术语或词汇**(例如:四圣谛, mettā)时,必须使用 search_pali 和 get_term_definition 函数 进行两次搜索,获取巴利文原文和术语字典结果。
+6.  当用户的查询是**描述性、自然语言问题**(例如:佛陀关于慈悲的教导)时,必须使用 search_by_query 函数。
+7.  当用户的查询是**普通关键词**(例如:比丘, 袈裟)时,使用 search_by_query 函数。
+
+以下是你的工具箱:
+- search_by_query: 用于通用的模糊和语义搜索。
+- search_by_page_ref: 专门用于处理页码搜索。
+- get_term_definition: 专门用于获取术语定义。
+- search_pali: 专门用于处理巴利文搜索。
+
+请严格根据上述原则,选择最恰当的工具来处理用户的请求。
+如果用户追问的问题可以使用之前的数据回答,那么无需再次调用工具。
+`;
+
+export type AICallbackFunction = {
+  name:
+    | "search_by_query"
+    | "search_by_page_ref"
+    | "get_term_definition"
+    | "search_pali";
+  arguments:
+    | SearchByQueryArgs
+    | SearchByPageRefArgs
+    | GetTermDefinitionArgs
+    | SearchPaliArgs;
+};
+// ---------------------------------------------------------------- //
+//                  低层 API 客户端(使用 fetch)                  //
+// ---------------------------------------------------------------- //
+
+const apiClient = async <T>(
+  endpoint: string,
+  params: Record<string, any>
+): Promise<T> => {
+  const searchParams = new URLSearchParams();
+  for (const key in params) {
+    if (params[key] !== undefined && params[key] !== null) {
+      if (Array.isArray(params[key])) {
+        searchParams.append(key, params[key].join(","));
+      } else {
+        searchParams.append(key, String(params[key]));
+      }
+    }
+  }
+
+  const url = `${API_BASE_URL}${endpoint}?${searchParams.toString()}`;
+
+  try {
+    const response = await fetch(url);
+    if (!response.ok) {
+      throw new Error(`HTTP error! Status: ${response.status}`);
+    }
+
+    const data: SearchResponse = await response.json();
+    if (data.success) {
+      return data.data as T;
+    } else {
+      throw new Error("API request was not successful.");
+    }
+  } catch (error) {
+    console.error("API call failed:", error);
+    throw new Error("An unexpected error occurred.");
+  }
+};
+
+// ---------------------------------------------------------------- //
+//                  封装的搜索函数(每个函数对应一个意图)          //
+// ---------------------------------------------------------------- //
+
+/**
+ * 通用搜索函数,处理模糊和语义查询。
+ */
+export const searchByQuery = async (
+  args: SearchByQueryArgs
+): Promise<SearchResponse> => {
+  return apiClient<SearchResponse>("/search", {
+    q: args.query,
+  });
+};
+
+/**
+ * 专门处理页码搜索的函数。
+ */
+export const searchByPageRef = async (
+  args: SearchByPageRefArgs
+): Promise<SearchResponse> => {
+  return apiClient<SearchResponse>("/search", {
+    q: args.page_refs, // query参数使用页码
+    search_mode: "page_search", // 固定搜索模式为页码搜索
+    page_refs: args.page_refs,
+  });
+};
+
+/**
+ * 专门用于获取术语定义的函数。
+ */
+export const getTermDefinition = async (
+  args: GetTermDefinitionArgs
+): Promise<SearchResponse> => {
+  return apiClient<SearchResponse>("/search", {
+    q: args.term,
+    resource_type: "term",
+  });
+};
+
+/**
+ * 专门用于巴利文精确搜索的函数。
+ */
+export const searchPali = async (
+  args: SearchPaliArgs
+): Promise<SearchResponse> => {
+  return apiClient<SearchResponse>("/search", {
+    q: args.query,
+    resource_type: "original_text", // 仅搜索原文
+    language: "pali", // 仅搜索巴利文
+  });
+};
+
+// ---------------------------------------------------------------- //
+//               核心 Function Calling 处理函数                     //
+// ---------------------------------------------------------------- //
+
+/**
+ * 核心函数:根据 AI 助手返回的函数调用对象,执行相应的操作。
+ *
+ * @param functionCall AI 助手返回的函数调用对象。
+ * @returns 返回一个 Promise,包含搜索结果。
+ */
+export const handleFunctionCall = async (
+  functionCall: AICallbackFunction
+): Promise<SearchResponse> => {
+  switch (functionCall.name) {
+    case "search_by_query":
+      return searchByQuery(functionCall.arguments as SearchByQueryArgs);
+
+    case "search_by_page_ref":
+      return searchByPageRef(functionCall.arguments as SearchByPageRefArgs);
+
+    case "get_term_definition":
+      return getTermDefinition(functionCall.arguments as GetTermDefinitionArgs);
+
+    case "search_pali":
+      return searchPali(functionCall.arguments as SearchPaliArgs);
+
+    default:
+      throw new Error(`Unknown function call: ${functionCall.name}`);
+  }
+};
+
+export const tools: FunctionDefinition[] = [
+  {
+    type: "function",
+    function: {
+      name: "search_by_query",
+      description: "通用搜索函数,支持模糊与语义查询。",
+      parameters: {
+        type: "object",
+        properties: {
+          query: {
+            type: "string",
+            description: "用户输入的查询语句(如: 佛陀关于慈悲的教导)",
+          },
+          search_mode: {
+            type: "string",
+            enum: ["fuzzy", "semantic"],
+            description: "搜索模式: fuzzy=模糊, semantic=语义",
+          },
+        },
+        required: ["query", "search_mode"],
+        additionalProperties: false,
+      },
+    },
+    strict: true,
+  },
+  {
+    type: "function",
+    function: {
+      name: "search_by_page_ref",
+      description: "根据页码标记(如 M3.58, V3.81)搜索对应内容。",
+      parameters: {
+        type: "object",
+        properties: {
+          page_refs: {
+            type: "string",
+            description: "经文页码标记(如 M3.58)",
+          },
+        },
+        required: ["page_refs"],
+        additionalProperties: false,
+      },
+    },
+    strict: true,
+  },
+  {
+    type: "function",
+    function: {
+      name: "get_term_definition",
+      description: "获取佛教术语的精确定义,主要从字典资源。",
+      parameters: {
+        type: "object",
+        properties: {
+          term: {
+            type: "string",
+            description: "佛教术语(如: 四圣谛, 五蕴, 涅槃)",
+          },
+        },
+        required: ["term"],
+        additionalProperties: false,
+      },
+    },
+    strict: true,
+  },
+  {
+    type: "function",
+    function: {
+      name: "search_pali",
+      description:
+        "在巴利文语料中进行关键词搜索,被搜索词可以是巴利文或者其他语言。",
+      parameters: {
+        type: "object",
+        properties: {
+          query: {
+            type: "string",
+            description:
+              "被搜索词,巴利文词汇或短语(如: mettā, anicca)或者其他语言的佛教专有名词",
+          },
+        },
+        required: ["query"],
+        additionalProperties: false,
+      },
+    },
+    strict: true,
+  },
+];
+
+// ---------------------------------------------------------------- //
+//                  使用示例                                       //
+// ---------------------------------------------------------------- //
+/**
+ * 
+ * 
+
+const main = async () => {
+  // 模拟从 AI 助手获得的函数调用对象
+  const mockCalls: AICallbackFunction[] = [
+    {
+      name: "search_by_query",
+      arguments: { query: "佛陀关于慈悲的教导", search_mode: "semantic" },
+    },
+    { name: "search_by_page_ref", arguments: { page_refs: "M3.58" } },
+    { name: "get_term_definition", arguments: { term: "四圣谛" } },
+    { name: "search_pali", arguments: { query: "mettā" } },
+  ];
+
+  for (const call of mockCalls) {
+    try {
+      console.log(`\n正在处理函数调用:${call.name}`);
+      const result = await handleFunctionCall(call);
+      console.log("搜索成功,找到结果数量:", result.data.hits.total.value);
+      // 根据你的需求,你可以在这里处理并展示结果
+    } catch (error) {
+      console.error(`处理函数调用失败:${call.name}`, error);
+    }
+  }
+};
+ */

+ 38 - 0
dashboard-v4/dashboard/src/services/chatApi.ts

@@ -0,0 +1,38 @@
+import { CreateChatRequest, ChatResponse, ApiResponse } from "../types/chat";
+
+export const chatApi = {
+  async createChat(
+    request: CreateChatRequest
+  ): Promise<ApiResponse<ChatResponse>> {
+    const response = await fetch("/api/v2/chats", {
+      method: "POST",
+      headers: { "Content-Type": "application/json" },
+      body: JSON.stringify(request),
+    });
+    return response.json();
+  },
+
+  async getChat(chatId: string): Promise<ApiResponse<ChatResponse>> {
+    const response = await fetch(`/api/v2/chats/${chatId}`);
+    return response.json();
+  },
+
+  async updateChat(
+    chatId: string,
+    updates: Partial<CreateChatRequest>
+  ): Promise<ApiResponse<ChatResponse>> {
+    const response = await fetch(`/api/v2/chats/${chatId}`, {
+      method: "PUT",
+      headers: { "Content-Type": "application/json" },
+      body: JSON.stringify(updates),
+    });
+    return response.json();
+  },
+
+  async deleteChat(chatId: string): Promise<ApiResponse<void>> {
+    const response = await fetch(`/api/v2/chats/${chatId}`, {
+      method: "DELETE",
+    });
+    return response.json();
+  },
+};

+ 74 - 0
dashboard-v4/dashboard/src/services/messageApi.ts

@@ -0,0 +1,74 @@
+// dashboard-v4/dashboard/src/services/messageApi.ts
+import {
+  CreateMessageRequest,
+  MessageListResponse,
+  ApiResponse,
+  MessageNode,
+} from "../types/chat";
+
+export const messageApi = {
+  async getMessages(chatId: string): Promise<ApiResponse<MessageListResponse>> {
+    const response = await fetch(`/api/v2/chat-messages?chat=${chatId}`);
+    return response.json();
+  },
+
+  async createMessages(
+    chatId: string,
+    request: CreateMessageRequest
+  ): Promise<ApiResponse<MessageNode[]>> {
+    const response = await fetch("/api/v2/chat-messages", {
+      method: "POST",
+      headers: { "Content-Type": "application/json" },
+      body: JSON.stringify({
+        chat_id: chatId,
+        ...request,
+      }),
+    });
+    return response.json();
+  },
+
+  async switchVersion(
+    chatId: string,
+    messageUids: string[]
+  ): Promise<ApiResponse<void>> {
+    const response = await fetch("/api/v2/chat-messages/switch-version", {
+      method: "POST",
+      headers: { "Content-Type": "application/json" },
+      body: JSON.stringify({
+        chat_id: chatId,
+        message_uids: messageUids,
+      }),
+    });
+    return response.json();
+  },
+
+  async likeMessage(messageId: string): Promise<ApiResponse<void>> {
+    const response = await fetch(`/api/v2/chat-messages/${messageId}/like`, {
+      method: "POST",
+    });
+    return response.json();
+  },
+
+  async dislikeMessage(messageId: string): Promise<ApiResponse<void>> {
+    const response = await fetch(`/api/v2/chat-messages/${messageId}/dislike`, {
+      method: "POST",
+    });
+    return response.json();
+  },
+
+  async shareMessage(
+    messageId: string
+  ): Promise<ApiResponse<{ shareUrl: string }>> {
+    const response = await fetch(`/api/v2/chat-messages/${messageId}/share`, {
+      method: "POST",
+    });
+    return response.json();
+  },
+
+  async deleteMessage(messageId: string): Promise<ApiResponse<void>> {
+    const response = await fetch(`/api/v2/chat-messages/${messageId}`, {
+      method: "DELETE",
+    });
+    return response.json();
+  },
+};

+ 269 - 0
dashboard-v4/dashboard/src/services/mockChatApi.ts

@@ -0,0 +1,269 @@
+import { CreateChatRequest, ChatResponse, ApiResponse } from "../types/chat";
+
+// Mock 存储,模拟数据库
+let mockChats: ChatResponse[] = [
+  {
+    id: "550e8400-e29b-41d4-a716-446655440000",
+    title: "天气查询助手",
+    user_id: "ba5463f3-72d1-4410-858e-eadd10884713",
+    created_at: "2025-01-15T10:30:00.000000Z",
+    updated_at: "2025-01-15T10:30:00.000000Z",
+  },
+  {
+    id: "660f8400-e29b-41d4-a716-446655440001",
+    title: "编程问题讨论",
+    user_id: "ba5463f3-72d1-4410-858e-eadd10884713",
+    created_at: "2025-01-14T15:20:00.000000Z",
+    updated_at: "2025-01-14T15:20:00.000000Z",
+  },
+  {
+    id: "770e8400-e29b-41d4-a716-446655440002",
+    title: "数学问题求解",
+    user_id: "ba5463f3-72d1-4410-858e-eadd10884713",
+    created_at: "2025-01-13T09:15:00.000000Z",
+    updated_at: "2025-01-13T09:15:00.000000Z",
+  },
+];
+
+// 工具函数:生成UUID
+function generateUUID(): string {
+  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
+    const r = (Math.random() * 16) | 0;
+    const v = c === "x" ? r : (r & 0x3) | 0x8;
+    return v.toString(16);
+  });
+}
+
+// 工具函数:模拟网络延迟
+function mockDelay(ms: number = 500): Promise<void> {
+  return new Promise((resolve) => setTimeout(resolve, ms));
+}
+
+// 工具函数:创建成功响应
+function createSuccessResponse<T>(data: T): ApiResponse<T> {
+  return {
+    ok: true,
+    message: "ok",
+    data,
+  };
+}
+
+// 工具函数:创建错误响应
+function createErrorResponse(
+  message: string,
+  errors?: Record<string, string[]>
+): ApiResponse<any> {
+  return {
+    ok: false,
+    message,
+    data: "",
+    errors,
+  };
+}
+
+// Mock Chat API 实现
+export const mockChatApi = {
+  async createChat(
+    request: CreateChatRequest
+  ): Promise<ApiResponse<ChatResponse>> {
+    console.log("[Mock API] Creating chat:", request);
+
+    await mockDelay(300);
+
+    // 验证请求
+    if (!request.title || request.title.trim() === "") {
+      return createErrorResponse("标题不能为空", {
+        title: ["标题是必填字段"],
+      });
+    }
+
+    if (request.title.length > 255) {
+      return createErrorResponse("标题过长", {
+        title: ["标题长度不能超过255个字符"],
+      });
+    }
+
+    // 创建新聊天
+    const newChat: ChatResponse = {
+      id: generateUUID(),
+      title: request.title.trim(),
+      user_id: request.user_id,
+      created_at: new Date().toISOString(),
+      updated_at: new Date().toISOString(),
+    };
+
+    mockChats.unshift(newChat); // 新聊天放在最前面
+    console.log("[Mock API] Chat created:", newChat);
+
+    return createSuccessResponse(newChat);
+  },
+
+  async getChat(chatId: string): Promise<ApiResponse<ChatResponse>> {
+    console.log("[Mock API] Getting chat:", chatId);
+
+    await mockDelay(200);
+
+    const chat = mockChats.find((c) => c.id === chatId);
+
+    if (!chat) {
+      return createErrorResponse("聊天不存在");
+    }
+
+    return createSuccessResponse(chat);
+  },
+
+  async updateChat(
+    chatId: string,
+    updates: Partial<CreateChatRequest>
+  ): Promise<ApiResponse<ChatResponse>> {
+    console.log("[Mock API] Updating chat:", chatId, updates);
+
+    await mockDelay(300);
+
+    const chatIndex = mockChats.findIndex((c) => c.id === chatId);
+
+    if (chatIndex === -1) {
+      return createErrorResponse("聊天不存在");
+    }
+
+    // 验证更新数据
+    if (updates.title !== undefined) {
+      if (!updates.title || updates.title.trim() === "") {
+        return createErrorResponse("标题不能为空", {
+          title: ["标题是必填字段"],
+        });
+      }
+
+      if (updates.title.length > 255) {
+        return createErrorResponse("标题过长", {
+          title: ["标题长度不能超过255个字符"],
+        });
+      }
+    }
+
+    // 更新聊天
+    const updatedChat: ChatResponse = {
+      ...mockChats[chatIndex],
+      ...updates,
+      title: updates.title?.trim() || mockChats[chatIndex].title,
+      updated_at: new Date().toISOString(),
+    };
+
+    mockChats[chatIndex] = updatedChat;
+    console.log("[Mock API] Chat updated:", updatedChat);
+
+    return createSuccessResponse(updatedChat);
+  },
+
+  async deleteChat(chatId: string): Promise<ApiResponse<void>> {
+    console.log("[Mock API] Deleting chat:", chatId);
+
+    await mockDelay(200);
+
+    const chatIndex = mockChats.findIndex((c) => c.id === chatId);
+
+    if (chatIndex === -1) {
+      return createErrorResponse("聊天不存在");
+    }
+
+    // 软删除:实际项目中会设置 deleted_at 字段
+    // 这里为了简化,直接从数组中移除
+    mockChats.splice(chatIndex, 1);
+    console.log("[Mock API] Chat deleted");
+
+    return createSuccessResponse(undefined as any);
+  },
+
+  // 额外的辅助方法,便于测试和开发
+  async getChats(params?: {
+    limit?: number;
+    user_id?: string;
+    offset?: number;
+  }): Promise<
+    ApiResponse<{
+      rows: ChatResponse[];
+      total: number;
+    }>
+  > {
+    console.log("[Mock API] Getting chats:", params);
+
+    await mockDelay(300);
+
+    let filteredChats = [...mockChats];
+
+    // 按用户过滤
+    if (params?.user_id) {
+      filteredChats = filteredChats.filter(
+        (chat) => chat.user_id === params.user_id
+      );
+    }
+
+    // 分页
+    const total = filteredChats.length;
+    const offset = params?.offset || 0;
+    const limit = params?.limit || 20;
+    const paginatedChats = filteredChats.slice(offset, offset + limit);
+
+    return createSuccessResponse({
+      rows: paginatedChats,
+      total,
+    });
+  },
+
+  // 重置 Mock 数据(用于测试)
+  resetMockData(): void {
+    console.log("[Mock API] Resetting mock data");
+    mockChats = [
+      {
+        id: "550e8400-e29b-41d4-a716-446655440000",
+        title: "天气查询助手",
+        user_id: "ba5463f3-72d1-4410-858e-eadd10884713",
+        created_at: "2025-01-15T10:30:00.000000Z",
+        updated_at: "2025-01-15T10:30:00.000000Z",
+      },
+      {
+        id: "660f8400-e29b-41d4-a716-446655440001",
+        title: "编程问题讨论",
+        user_id: "ba5463f3-72d1-4410-858e-eadd10884713",
+        created_at: "2025-01-14T15:20:00.000000Z",
+        updated_at: "2025-01-14T15:20:00.000000Z",
+      },
+      {
+        id: "770e8400-e29b-41d4-a716-446655440002",
+        title: "数学问题求解",
+        user_id: "ba5463f3-72d1-4410-858e-eadd10884713",
+        created_at: "2025-01-13T09:15:00.000000Z",
+        updated_at: "2025-01-13T09:15:00.000000Z",
+      },
+    ];
+  },
+
+  // 获取当前 Mock 数据(用于调试)
+  getMockData(): ChatResponse[] {
+    return [...mockChats];
+  },
+
+  // 模拟网络错误
+  async createChatWithNetworkError(): Promise<ApiResponse<ChatResponse>> {
+    await mockDelay(1000);
+    throw new Error("网络连接失败");
+  },
+
+  // 模拟服务器错误
+  async createChatWithServerError(): Promise<ApiResponse<ChatResponse>> {
+    await mockDelay(500);
+    return {
+      ok: false,
+      message: "服务器内部错误",
+    } as ApiResponse<any>;
+  },
+
+  // 设置延迟时间(用于测试不同网络条件)
+  setMockDelay(ms: number): void {
+    // 这里可以实现动态调整延迟的逻辑
+    console.log(`[Mock API] Mock delay set to ${ms}ms`);
+  },
+};
+
+// 导出类型,便于在其他地方使用
+export type MockChatApi = typeof mockChatApi;

File diff suppressed because it is too large
+ 24 - 0
dashboard-v4/dashboard/src/services/mockMessageApi.ts


+ 105 - 0
dashboard-v4/dashboard/src/services/modelAdapters/base.ts

@@ -0,0 +1,105 @@
+// dashboard-v4/dashboard/src/services/modelAdapters/base.ts
+
+import { IAiModel } from "../../components/api/ai";
+import {
+  ModelAdapter,
+  OpenAIMessage,
+  SendOptions,
+  ParsedChunk,
+  ToolCall,
+} from "../../types/chat";
+import {
+  getArgs,
+  GetTermDefinitionArgs,
+  SearchByPageRefArgs,
+  SearchByQueryArgs,
+  SearchPaliArgs,
+  SearchResponse,
+} from "../../types/search";
+import {
+  getTermDefinition,
+  searchByPageRef,
+  searchByQuery,
+  searchPali,
+  tools,
+} from "../agentApi";
+
+export abstract class BaseModelAdapter implements ModelAdapter {
+  abstract name: string;
+  abstract supportsFunctionCall: boolean;
+  abstract model: IAiModel | undefined;
+
+  abstract sendMessage(
+    messages: OpenAIMessage[],
+    options: SendOptions
+  ): Promise<AsyncIterable<string>>;
+  abstract parseStreamChunk(chunk: string): ParsedChunk | null;
+
+  public setModel(model: IAiModel) {
+    this.model = model;
+  }
+
+  protected createStreamController() {
+    return {
+      addToken: (token: string) => {
+        // 流式输出控制逻辑
+      },
+      complete: () => {
+        // 完成处理逻辑
+      },
+    };
+  }
+
+  protected buildRequestPayload(
+    messages: OpenAIMessage[],
+    options: SendOptions
+  ): SendOptions {
+    return {
+      model: this.model?.name,
+      messages,
+      stream: true,
+      temperature: options.temperature || 0.7,
+      max_tokens: options.max_tokens || 2048,
+      top_p: options.top_p || 1,
+      tools: tools,
+      tool_choice: "auto",
+    };
+  }
+  // ---------------------------------------------------------------- //
+  //               核心 Function Calling 处理函数                     //
+  // ---------------------------------------------------------------- //
+
+  /**
+   * 核心函数:根据 AI 助手返回的函数调用对象,执行相应的操作。
+   *
+   * @param functionCall AI 助手返回的函数调用对象。
+   * @returns 返回一个 Promise,包含搜索结果。
+   */
+  async handleFunctionCall(functionCall: ToolCall): Promise<SearchResponse> {
+    console.info("ai chat function call", functionCall);
+    switch (functionCall.function.name) {
+      case "search_by_query":
+        return searchByQuery(
+          getArgs<SearchByQueryArgs>(functionCall.function.arguments)
+        );
+
+      case "search_by_page_ref":
+        return searchByPageRef(
+          getArgs<SearchByPageRefArgs>(functionCall.function.arguments)
+        );
+
+      case "get_term_definition":
+        return getTermDefinition(
+          getArgs<GetTermDefinitionArgs>(functionCall.function.arguments)
+        );
+
+      case "search_pali":
+        return searchPali(
+          getArgs<SearchPaliArgs>(functionCall.function.arguments)
+        );
+
+      default:
+        throw new Error(`Unknown function call: ${functionCall.function.name}`);
+    }
+  }
+}

+ 25 - 0
dashboard-v4/dashboard/src/services/modelAdapters/index.ts

@@ -0,0 +1,25 @@
+import { IAiModel } from "../../components/api/ai";
+import { ModelAdapter } from "../../types/chat";
+import { MockOpenAIAdapter } from "./mockOpenAI";
+import { OpenAIAdapter } from "./openai";
+
+const adapters = new Map<string, ModelAdapter>();
+
+// 注册适配器
+adapters.set("gpt-4.1", new OpenAIAdapter());
+adapters.set("gpt-4.1-mini", new OpenAIAdapter());
+adapters.set("deepseek-v3", new MockOpenAIAdapter());
+
+export function getModelAdapter(model: IAiModel): ModelAdapter {
+  const adapter = adapters.get(model.name);
+
+  if (!adapter) {
+    throw new Error(`未找到模型适配器: ${model.name}`);
+  }
+  adapter.setModel(model);
+  return adapter;
+}
+
+export function registerAdapter(modelId: string, adapter: ModelAdapter) {
+  adapters.set(modelId, adapter);
+}

+ 419 - 0
dashboard-v4/dashboard/src/services/modelAdapters/mockOpenAI.ts

@@ -0,0 +1,419 @@
+// services/modelAdapters/mockOpenAI.ts
+import { BaseModelAdapter } from "./base";
+import {
+  OpenAIMessage,
+  SendOptions,
+  ParsedChunk,
+  ToolCall,
+} from "../../types/chat";
+import { IAiModel } from "../../components/api/ai";
+
+export class MockOpenAIAdapter extends BaseModelAdapter {
+  model: IAiModel | undefined;
+
+  name = "mock-gpt-4";
+  supportsFunctionCall = true;
+
+  protected mockDelay = (ms: number) =>
+    new Promise((resolve) => setTimeout(resolve, ms));
+
+  async sendMessage(
+    messages: OpenAIMessage[],
+    options: SendOptions
+  ): Promise<AsyncIterable<string>> {
+    const payload = this.buildRequestPayload(messages, options);
+
+    console.log("[Mock OpenAI] Sending message with payload:", payload);
+
+    return this.createMockStreamIterable(messages, options);
+  }
+
+  private async *createMockStreamIterable(
+    messages: OpenAIMessage[],
+    options: SendOptions
+  ): AsyncIterable<string> {
+    // 模拟初始延迟
+    await this.mockDelay(100);
+
+    const lastMessage = messages[messages.length - 1];
+    const userContent = lastMessage?.content || "";
+
+    // 检查是否需要函数调用
+    const needsFunctionCall = this.shouldCallFunction(userContent);
+
+    if (needsFunctionCall) {
+      // 模拟函数调用流程
+      yield* this.generateFunctionCallResponse(userContent);
+    } else {
+      // 模拟普通文本响应
+      yield* this.generateTextResponse(userContent);
+    }
+  }
+
+  private shouldCallFunction(content: string): boolean {
+    const functionTriggers = [
+      "天气",
+      "weather",
+      "温度",
+      "气温",
+      "搜索",
+      "search",
+      "查找",
+      "find",
+      "翻译",
+      "translate",
+      "巴利",
+      "pali",
+    ];
+
+    return functionTriggers.some((trigger) =>
+      content.toLowerCase().includes(trigger.toLowerCase())
+    );
+  }
+
+  private async *generateFunctionCallResponse(
+    userContent: string
+  ): AsyncIterable<string> {
+    // 第一步:生成函数调用意图的响应
+    const functionCallChunk = {
+      choices: [
+        {
+          delta: {
+            content: null,
+            function_call: this.determineFunctionCall(userContent),
+          },
+          finish_reason: "function_call",
+        },
+      ],
+    };
+
+    yield JSON.stringify(functionCallChunk);
+    await this.mockDelay(200);
+
+    // 模拟函数执行后的最终响应
+    const finalResponseText = this.generateFunctionBasedResponse(userContent);
+    yield* this.streamText(finalResponseText);
+  }
+
+  private determineFunctionCall(content: string): any {
+    if (content.includes("天气") || content.toLowerCase().includes("weather")) {
+      const city = this.extractCityFromContent(content);
+      return {
+        name: "getWeather",
+        arguments: JSON.stringify({ city }),
+      };
+    } else if (
+      content.includes("搜索") ||
+      content.toLowerCase().includes("search")
+    ) {
+      const term = this.extractSearchTermFromContent(content);
+      return {
+        name: "searchTerm",
+        arguments: JSON.stringify({ term }),
+      };
+    }
+
+    return {
+      name: "getWeather",
+      arguments: JSON.stringify({ city: "北京" }),
+    };
+  }
+
+  private extractCityFromContent(content: string): string {
+    const cities = [
+      "北京",
+      "上海",
+      "广州",
+      "深圳",
+      "杭州",
+      "成都",
+      "西安",
+      "武汉",
+      "New York",
+      "London",
+      "Tokyo",
+      "Paris",
+      "Sydney",
+    ];
+
+    for (const city of cities) {
+      if (content.includes(city)) {
+        return city;
+      }
+    }
+    return "北京"; // 默认城市
+  }
+
+  private extractSearchTermFromContent(content: string): string {
+    // 简单提取逻辑,实际应用中可能需要更复杂的NLP处理
+    const matches = content.match(/搜索["']?([^"']+)["']?/);
+    if (matches) {
+      return matches[1];
+    }
+
+    const searchMatches = content.match(/search\s+["']?([^"']+)["']?/i);
+    if (searchMatches) {
+      return searchMatches[1];
+    }
+
+    return "佛法"; // 默认搜索词
+  }
+
+  private generateFunctionBasedResponse(userContent: string): string {
+    if (
+      userContent.includes("天气") ||
+      userContent.toLowerCase().includes("weather")
+    ) {
+      const city = this.extractCityFromContent(userContent);
+      return `根据天气查询结果,${city}今天的天气情况如下:\n\n🌤️ **天气状况**:晴朗\n🌡️ **温度**:25°C\n💧 **湿度**:60%\n\n今天是个出行的好日子!记得适当补充水分。`;
+    } else if (
+      userContent.includes("搜索") ||
+      userContent.toLowerCase().includes("search")
+    ) {
+      const term = this.extractSearchTermFromContent(userContent);
+      return `我已经为您搜索了"${term}"相关的内容。以下是搜索结果:\n\n📚 **搜索结果**:\n• 找到了 15 个相关条目\n• 包含词汇解释、语法分析等\n• 提供了详细的语言学资料\n\n如需查看具体内容,请告诉我您感兴趣的具体方面。`;
+    }
+
+    return "我理解您的请求,已经为您处理完成。如有其他需要帮助的地方,请随时告诉我。";
+  }
+
+  private async *generateTextResponse(
+    userContent: string
+  ): AsyncIterable<string> {
+    const responses = [
+      "我很高兴为您提供帮助!",
+      "这是一个很有趣的问题。",
+      "让我为您详细解答一下。",
+      "根据我的理解,我认为...",
+      "这个问题涉及到多个方面,让我逐一为您分析。",
+      "希望这个回答对您有所帮助。",
+    ];
+
+    // 根据用户输入选择合适的响应
+    let responseText = "";
+
+    if (userContent.length > 50) {
+      responseText = `您提出了一个详细的问题。${
+        responses[Math.floor(Math.random() * responses.length)]
+      }
+
+针对您的问题,我可以从以下几个角度来回答:
+
+1. **主要观点**:${userContent.substring(0, 20)}...这个话题确实值得深入讨论。
+
+2. **相关背景**:这类问题通常需要综合考虑多个因素。
+
+3. **建议方案**:我建议您可以从实际情况出发,结合具体需求来选择最合适的方法。
+
+如果您需要更详细的解释或有其他相关问题,请随时告诉我!`;
+    } else {
+      responseText = `${responses[Math.floor(Math.random() * responses.length)]}
+
+关于"${userContent}"这个问题,我的理解是这样的:
+
+这确实是一个值得探讨的话题。根据我的知识,我认为最重要的是要考虑实际的应用场景和具体需求。
+
+希望我的回答对您有帮助。如果您还有任何疑问,欢迎继续提问!`;
+    }
+
+    yield* this.streamText(responseText);
+  }
+
+  private async *streamText(text: string): AsyncIterable<string> {
+    const words = text.split("");
+
+    for (let i = 0; i < words.length; i++) {
+      const chunk = {
+        choices: [
+          {
+            delta: {
+              content: words[i],
+            },
+            finish_reason: i === words.length - 1 ? "stop" : null,
+          },
+        ],
+      };
+
+      yield JSON.stringify(chunk);
+
+      // 模拟打字机效果,随机延迟
+      const delay = Math.random() * 50 + 10; // 10-60ms 随机延迟
+      await this.mockDelay(delay);
+    }
+
+    // 发送结束标记
+    const finishChunk = {
+      choices: [
+        {
+          delta: {},
+          finish_reason: "stop",
+        },
+      ],
+    };
+
+    yield JSON.stringify(finishChunk);
+  }
+
+  parseStreamChunk(chunk: string): ParsedChunk | null {
+    try {
+      const parsed = JSON.parse(chunk);
+      const delta = parsed.choices?.[0]?.delta;
+      const finishReason = parsed.choices?.[0]?.finish_reason;
+
+      return {
+        content: delta?.content,
+        tool_calls: delta?.function_call,
+        finish_reason: finishReason,
+      };
+    } catch (error) {
+      console.warn("[Mock OpenAI] Failed to parse chunk:", chunk, error);
+      return null;
+    }
+  }
+
+  async handleFunctionCall(functionCall: ToolCall): Promise<any> {
+    console.log("[Mock OpenAI] Handling function call:", functionCall);
+
+    // 模拟函数执行延迟
+    await this.mockDelay(300);
+
+    switch (functionCall.function.name) {
+      case "searchTerm":
+        return await this.mockSearchTerm(functionCall.function.arguments);
+      case "getWeather":
+        return await this.mockGetWeather(functionCall.function.arguments);
+      default:
+        console.warn(
+          `[Mock OpenAI] Unknown function: ${functionCall.function.name}`
+        );
+        throw new Error(`未知函数: ${functionCall.function.name}`);
+    }
+  }
+
+  private async mockSearchTerm(term: string): Promise<any> {
+    console.log(`[Mock OpenAI] Searching for term: ${term}`);
+
+    // 模拟搜索延迟
+    await this.mockDelay(500);
+
+    // 生成模拟的搜索结果
+    const mockResults = [
+      {
+        id: 1,
+        word: term,
+        definition: `${term}的定义:这是一个重要的概念`,
+        grammar: "名词",
+        example: `使用${term}的例句示例`,
+      },
+      {
+        id: 2,
+        word: `${term}相关词`,
+        definition: `与${term}相关的另一个概念`,
+        grammar: "动词",
+        example: `相关用法示例`,
+      },
+      {
+        id: 3,
+        word: `${term}变体`,
+        definition: `${term}的变体形式`,
+        grammar: "形容词",
+        example: `变体使用示例`,
+      },
+    ];
+
+    return {
+      ok: true,
+      data: {
+        rows: mockResults,
+        total: mockResults.length,
+      },
+    };
+  }
+
+  private async mockGetWeather(city: string): Promise<any> {
+    console.log(`[Mock OpenAI] Getting weather for city: ${city}`);
+
+    // 模拟天气API延迟
+    await this.mockDelay(300);
+
+    // 生成随机天气数据
+    const conditions = ["晴朗", "多云", "小雨", "阴天", "晴转多云"];
+    const temperatures = ["22°C", "25°C", "18°C", "28°C", "20°C"];
+    const humidities = ["45%", "60%", "75%", "55%", "65%"];
+
+    return {
+      city,
+      temperature:
+        temperatures[Math.floor(Math.random() * temperatures.length)],
+      condition: conditions[Math.floor(Math.random() * conditions.length)],
+      humidity: humidities[Math.floor(Math.random() * humidities.length)],
+      timestamp: new Date().toISOString(),
+      source: "Mock Weather API",
+    };
+  }
+
+  // 工具方法:构建请求负载(继承自BaseModelAdapter)
+  protected buildRequestPayload(
+    messages: OpenAIMessage[],
+    options: SendOptions
+  ) {
+    return {
+      model: this.name, // 添加required的model字段
+      messages: messages, // 直接使用原始messages,不需要重新映射
+      stream: true,
+      temperature: options.temperature || 0.7,
+      max_tokens: options.max_tokens || 2000,
+      top_p: options.top_p || 1,
+      tools: options.tools ?? [],
+      tool_choice: "auto", // 确保不为undefined
+    };
+  }
+}
+
+// 导出工厂函数,便于在不同环境中使用
+export function createMockOpenAIAdapter(): MockOpenAIAdapter {
+  return new MockOpenAIAdapter();
+}
+
+// 导出配置选项
+export interface MockOpenAIOptions {
+  responseDelay?: number; // 响应延迟
+  streamDelay?: number; // 流式输出延迟
+  enableFunctionCall?: boolean; // 是否启用函数调用
+  mockErrorRate?: number; // 模拟错误率 (0-1)
+}
+
+// 可配置的Mock适配器
+export class ConfigurableMockOpenAIAdapter extends MockOpenAIAdapter {
+  constructor(private options: MockOpenAIOptions = {}) {
+    super();
+    this.name = "configurable-mock-gpt-4";
+  }
+
+  private get responseDelay() {
+    return this.options.responseDelay || 100;
+  }
+
+  private get streamDelay() {
+    return this.options.streamDelay || 30;
+  }
+
+  protected mockDelay = (ms?: number) =>
+    new Promise((resolve) => setTimeout(resolve, ms || this.responseDelay));
+
+  async handleFunctionCall(functionCall: ToolCall): Promise<any> {
+    if (!this.options.enableFunctionCall) {
+      throw new Error("Function call disabled in mock adapter");
+    }
+
+    // 模拟随机错误
+    if (
+      this.options.mockErrorRate &&
+      Math.random() < this.options.mockErrorRate
+    ) {
+      throw new Error("Mock function call error");
+    }
+
+    return super.handleFunctionCall(functionCall);
+  }
+}

+ 108 - 0
dashboard-v4/dashboard/src/services/modelAdapters/openai.ts

@@ -0,0 +1,108 @@
+// dashboard-v4/dashboard/src/services/modelAdapters/openai.ts
+
+import { BaseModelAdapter } from "./base";
+import {
+  OpenAIMessage,
+  SendOptions,
+  ParsedChunk,
+  ChatCompletionChunk,
+} from "../../types/chat";
+import { IAiModel } from "../../components/api/ai";
+import { tools } from "../agentApi";
+
+export class OpenAIAdapter extends BaseModelAdapter {
+  model: IAiModel | undefined;
+  name = "gpt-4";
+  supportsFunctionCall = true;
+
+  protected buildRequestPayload(
+    messages: OpenAIMessage[],
+    options: SendOptions
+  ) {
+    return {
+      model: this.model?.name,
+      messages,
+      stream: true,
+      temperature: options.temperature || 0.7,
+      max_completion_tokens: options.max_tokens || 2048,
+      top_p: options.top_p || 1,
+      tools: tools,
+      tool_choice: "auto",
+    };
+  }
+
+  // 修改这个方法
+  async sendMessage(
+    messages: OpenAIMessage[],
+    options: SendOptions
+  ): Promise<AsyncIterable<string>> {
+    const payload = this.buildRequestPayload(messages, options);
+
+    return this.createStreamIterable(payload);
+  }
+
+  private async *createStreamIterable(payload: any): AsyncIterable<string> {
+    console.log("ai chat send message", payload);
+    const response = await fetch(process.env.REACT_APP_OPENAI_PROXY!, {
+      method: "POST",
+      headers: {
+        "Content-Type": "application/json",
+        Authorization: `Bearer ${process.env.REACT_APP_OPENAI_KEY}`,
+      },
+      body: JSON.stringify({
+        model_id: this.model?.uid,
+        payload,
+      }),
+    });
+
+    if (!response.ok) {
+      throw new Error(`HTTP error! status: ${response.status}`);
+    }
+
+    const reader = response.body?.getReader();
+    if (!reader) {
+      throw new Error("无法获取响应流");
+    }
+
+    const decoder = new TextDecoder();
+    let buffer = "";
+
+    try {
+      while (true) {
+        const { done, value } = await reader.read();
+        if (done) break;
+
+        buffer += decoder.decode(value, { stream: true });
+        const lines = buffer.split("\n");
+        buffer = lines.pop() || "";
+
+        for (const line of lines) {
+          if (!line.trim() || !line.startsWith("data: ")) continue;
+          const data = line.slice(6);
+          if (data === "[DONE]") return;
+
+          yield data;
+        }
+      }
+    } finally {
+      reader.releaseLock();
+    }
+  }
+
+  // 其他方法保持不变
+  parseStreamChunk(chunk: string): ParsedChunk | null {
+    try {
+      const parsed: ChatCompletionChunk = JSON.parse(chunk);
+      const delta = parsed.choices?.[0]?.delta;
+      const finishReason = parsed.choices?.[0]?.finish_reason;
+
+      return {
+        content: delta?.content,
+        tool_calls: delta?.tool_calls,
+        finish_reason: finishReason,
+      };
+    } catch {
+      return null;
+    }
+  }
+}

+ 330 - 0
dashboard-v4/dashboard/src/types/chat.ts

@@ -0,0 +1,330 @@
+import { IAiModel } from "../components/api/ai";
+
+export type TOpenAIRole = "system" | "user" | "assistant" | "function" | "tool";
+
+//
+// 流输出数据
+export interface ChatCompletionChunk {
+  id: string;
+  object: "chat.completion.chunk";
+  created: number;
+  model: string;
+  service_tier: string;
+  system_fingerprint: string;
+  choices: Choice[];
+  obfuscation: string;
+}
+
+export interface Choice {
+  index: number;
+  delta: Delta;
+  logprobs: null | any;
+  finish_reason: string | null;
+}
+
+export interface Delta {
+  role?: "assistant" | "user" | "system";
+  content?: string | null;
+  tool_calls?: ToolCall[];
+  refusal?: string | null;
+}
+// 工具调用相关类型
+export interface ToolCall {
+  index: number;
+  id?: string;
+  type: "function";
+  function: ToolFunction;
+  result?: string;
+}
+
+export interface ToolFunction {
+  name: string;
+  arguments: string;
+}
+
+export interface ParsedToolFunction<T = any> {
+  name: string;
+  arguments: T; // 解析后的对象
+}
+
+// 消息元数据
+export interface MessageMetadata {
+  generation_params?: {
+    temperature?: number;
+    max_tokens?: number;
+    top_p?: number;
+    frequency_penalty?: number;
+    presence_penalty?: number;
+  };
+  token_usage?: {
+    prompt_tokens?: number;
+    completion_tokens?: number;
+    total_tokens?: number;
+  };
+  performance?: {
+    response_time_ms?: number;
+    first_token_time_ms?: number;
+  };
+  tool_stats?: {
+    total_calls?: number;
+    successful_calls?: number;
+    execution_time_ms?: number;
+  };
+  custom_data?: Record<string, any>;
+}
+
+// 消息节点(对应数据库结构)
+export interface MessageNode {
+  id: number; // DB自增ID,用于版本排序
+  uid: string; // UUID
+  chat_id: string;
+  parent_id?: string;
+  session_id: string;
+  role: TOpenAIRole;
+  content?: string;
+  model_id?: string;
+  tool_calls?: ToolCall[];
+  tool_call_id?: string;
+  metadata?: MessageMetadata;
+  is_active: boolean;
+  editor_id?: string;
+  created_at: string;
+  updated_at: string;
+  deleted_at?: string;
+
+  // 临时状态字段(前端使用)
+  save_status?: "saved" | "pending" | "failed";
+  temp_id?: string; // 临时ID,用于未保存消息
+}
+
+// 版本信息
+export interface VersionInfo {
+  version_index: number; // 版本索引(0,1,2...)
+  message_id: string; //该版本第一个message uid
+  model_id?: string; // 该版本使用的模型
+}
+
+// Session 信息
+export interface SessionInfo {
+  session_id: string;
+  messages: MessageNode[]; // 该session的所有消息(按激活路径过滤)
+  versions: VersionInfo[]; // 该session所有版本信息
+  current_version: number; // 当前显示的版本索引
+  user_message?: MessageNode; // 该session的用户消息(便于访问)
+  ai_messages: MessageNode[]; // 该session的AI消息列表
+}
+
+// 待保存消息组
+export interface PendingMessage {
+  temp_id: string;
+  session_id: string;
+  messages: MessageNode[]; // 待保存的消息组
+  retry_count: number;
+  error?: string;
+  created_at: string;
+}
+
+// 聊天状态
+export interface ChatState {
+  chat_id: string;
+  title: string;
+  raw_messages: MessageNode[]; // 从DB加载的原始线性数据
+  active_path: MessageNode[]; // 当前激活路径上的消息
+  session_groups: SessionInfo[]; // 按session分组的显示数据
+  pending_messages: PendingMessage[]; // 待保存的消息组
+  is_loading: boolean;
+  streaming_message?: string;
+  streaming_session_id?: string;
+  current_model?: IAiModel;
+  error?: string;
+  is_initialized?: boolean;
+}
+
+// 聊天操作接口
+export interface ChatActions {
+  switchVersion: (activeMsgId: string) => void;
+  editMessage: (
+    sessionId: string,
+    content: string,
+    role?: TOpenAIRole
+  ) => Promise<void>;
+  retryMessage: (tempId: string) => Promise<void>;
+  refreshResponse: (sessionId: string, modelId?: string) => Promise<void>;
+  loadMessages: () => Promise<void>;
+  likeMessage: (messageId: string) => Promise<void>;
+  dislikeMessage: (messageId: string) => Promise<void>;
+  copyMessage: (messageId: string) => void;
+  shareMessage: (messageId: string) => Promise<string>;
+  deleteMessage: (messageId: string) => Promise<void>;
+  setModel: (model: IAiModel | undefined) => void;
+}
+
+// API 请求类型
+
+export interface CreateMessageRequest {
+  messages: Array<{
+    uid?: string;
+    parent_id?: string;
+    role: TOpenAIRole;
+    content?: string;
+    session_id?: string;
+    model_id?: string;
+    tool_calls?: ToolCall[];
+    tool_call_id?: string;
+    metadata?: MessageMetadata;
+  }>;
+}
+
+export interface CreateChatRequest {
+  title: string;
+  user_id?: string;
+}
+
+// API 响应类型
+export interface ApiResponse<T> {
+  ok: boolean;
+  message: string;
+  data: T;
+  errors?: Record<string, string[]>; // 添加可选的错误字段
+}
+
+export interface ChatResponse {
+  id: string;
+  title: string;
+  user_id?: string;
+  created_at: string;
+  updated_at: string;
+}
+
+export interface MessageListResponse {
+  rows: MessageNode[];
+  total: number;
+}
+
+// 模型适配器相关类型
+
+export interface ModelAdapter {
+  name: string;
+  supportsFunctionCall: boolean;
+  model: IAiModel | undefined;
+  sendMessage(
+    messages: OpenAIMessage[],
+    options: SendOptions
+  ): Promise<AsyncIterable<string>>; // 修改这里
+  parseStreamChunk(chunk: string): ParsedChunk | null;
+  handleFunctionCall(functionCall: ToolCall): Promise<any>;
+  setModel(model: IAiModel): void;
+}
+export interface OpenAIMessage {
+  role: TOpenAIRole;
+  content?: string;
+  name?: string;
+  tool_calls?: ToolCall[];
+  tool_call_id?: string;
+}
+
+// 支持的 JSON Schema 基础类型
+export type JSONSchemaPrimitiveType =
+  | "object"
+  | "array"
+  | "string"
+  | "number"
+  | "boolean"
+  | "null";
+
+// 通用 JSON Schema 定义
+export interface JSONSchema {
+  type: JSONSchemaPrimitiveType;
+  description?: string;
+
+  // object 专属
+  properties?: Record<string, JSONSchema>;
+  required?: string[];
+  additionalProperties?: boolean;
+
+  // array 专属
+  items?: JSONSchema;
+
+  // string 专属
+  enum?: string[];
+}
+
+// Function 定义接口
+export interface FunctionDefinition {
+  type: "function";
+  function: {
+    name: string;
+    description?: string;
+    parameters: JSONSchema & { type: "object" }; // 根必须是 object
+  };
+  strict?: boolean;
+}
+
+export interface SendOptions {
+  model?: string;
+  messages?: OpenAIMessage[];
+  stream?: boolean;
+  temperature?: number;
+  max_tokens?: number;
+  max_completion_tokens?: number; //stream模式使用
+  top_p?: number;
+  tools?: Array<FunctionDefinition>;
+  tool_choice?: string | "auto" | "none";
+}
+
+export interface StreamResponse {
+  messages: MessageNode[];
+  metadata?: MessageMetadata;
+}
+
+export interface ParsedChunk {
+  content?: string | null;
+  tool_calls?: ToolCall[];
+  finish_reason?: string | null;
+}
+
+// 组件 Props 类型
+export interface SessionGroupProps {
+  session: SessionInfo;
+  onVersionSwitch: (nexMsgId: string) => void;
+  onRefresh: (sessionId: string, modelId?: string) => void;
+  onEdit: (sessionId: string, content: string) => void;
+  onRetry?: (tempId: string) => void;
+  onLike?: (messageId: string) => void;
+  onDislike?: (messageId: string) => void;
+  onCopy?: (messageId: string) => void;
+  onShare?: (messageId: string) => Promise<string>;
+  onModelChange?: (model: IAiModel) => void;
+}
+
+export interface UserMessageProps {
+  session: SessionInfo;
+  onEdit?: (content: string) => void;
+  onCopy?: () => void;
+  onVersionSwitch?: (message_id: string) => void;
+}
+
+export interface AssistantMessageProps {
+  session: SessionInfo;
+  onRefresh?: () => void;
+  onEdit?: (content: string) => void;
+  isPending?: boolean;
+  onLike?: (messageId: string) => void;
+  onDislike?: (messageId: string) => void;
+  onCopy?: (messageId: string) => void;
+  onShare?: (messageId: string) => Promise<string>;
+  onVersionSwitch?: (message_id: string) => void;
+}
+
+export interface VersionSwitcherProps {
+  versions: VersionInfo[];
+  currentVersion: number;
+  onSwitch: (versionIndex: number) => void;
+}
+
+export interface ChatInputProps {
+  onSend: (content: string) => void;
+  onModelChange?: (model: IAiModel | undefined) => void;
+  disabled?: boolean;
+  placeholder?: string;
+}

+ 284 - 0
dashboard-v4/dashboard/src/types/search.ts

@@ -0,0 +1,284 @@
+// ---------------------------------------------------------------- //
+//             核心搜索函数参数类型:search_documents               //
+// ---------------------------------------------------------------- //
+
+/**
+ * 搜索模式的枚举,用于指定不同类型的搜索。
+ * - 'fuzzy': 模糊搜索,支持巴利文变音符号、简繁体等。
+ * - 'exact': 精确匹配,用于专有名词或特定短语。
+ * - 'semantic': 语义搜索,基于向量检索。
+ * - 'hybrid': 混合搜索 fuzzy+semantic。
+ */
+export type SearchMode = "fuzzy" | "exact" | "semantic" | "hybrid";
+
+/**
+ * 文档类型的枚举,用于筛选不同来源的文档。
+ */
+export type ResourceType =
+  | "article"
+  | "term"
+  | "dictionary"
+  | "translation"
+  | "original_text"
+  | "nissaya";
+
+/**
+ * 语言代码的枚举。
+ */
+export type Language = "pali" | "zh-Hans" | "zh-Hant" | "en-US" | "my";
+
+/**
+ * search_documents 函数的参数类型。
+ * 这将作为 Function Calling 的 `arguments` 参数传递。
+ */
+export interface SearchDocumentsArgs {
+  /**
+   * 用户的搜索关键词或句子。
+   */
+  query: string;
+
+  /**
+   * 指定搜索模式,由 AI 助手根据用户意图判断。
+   */
+  search_mode: SearchMode;
+
+  /**
+   * 文档类型数组,用于过滤搜索结果。
+   */
+  resource_type?: ResourceType[];
+
+  /**
+   * 语言数组,用于过滤搜索结果。
+   */
+  language?: Language[];
+
+  /**
+   * 页码标记,仅在 search_mode 为 'page_search' 时使用。
+   */
+  page_refs?: string;
+
+  /**
+   * 主题标签数组,用于进一步过滤。
+   */
+  tags?: string[];
+}
+
+// ---------------------------------------------------------------- //
+//             术语定义函数参数类型:get_term_definition            //
+// ---------------------------------------------------------------- //
+
+/**
+ * get_term_definition 函数的参数类型。
+ */
+export interface GetTermDefinitionArgs {
+  /**
+   * 需要查询的佛教术语或词汇。
+   */
+  term: string;
+}
+
+export function getArgs<T>(input: string): T {
+  try {
+    const parsed = JSON.parse(input);
+    return parsed as T;
+  } catch (err) {
+    throw new Error(
+      `Invalid arguments JSON: ${
+        err instanceof Error ? err.message : String(err)
+      }`
+    );
+  }
+}
+// ---------------------------------------------------------------- //
+//              AI 助手返回的 Function Call 类型                    //
+// ---------------------------------------------------------------- //
+
+/**
+ * AI 助手返回的函数调用对象。
+ */
+
+export interface SearchByQueryArgs {
+  query: string;
+  search_mode: SearchMode;
+}
+
+export interface SearchByPageRefArgs {
+  page_refs: string;
+}
+
+export interface GetTermDefinitionArgs {
+  term: string;
+}
+
+export interface SearchPaliArgs {
+  query: string;
+}
+
+// ---------------------------------------------------------------- //
+//              后端 API 响应类型(示例)                           //
+// ---------------------------------------------------------------- //
+
+/**
+ * 核心文档卡片的数据结构。
+ */
+export interface DocumentResult {
+  id: string;
+  resource_id: string;
+  resource_type: ResourceType;
+  title: string;
+  content: {
+    display: string;
+    text: string;
+    vector?: number[];
+  };
+  related_id: string[];
+  page_refs?: string[];
+  language: Language;
+  score: number;
+  similarity?: number;
+}
+
+/**
+ * API 搜索响应的完整结构。
+ */
+export interface SearchResponse {
+  success: boolean;
+  data: {
+    total: number;
+    page: number;
+    page_size: number;
+    took: string;
+    results: DocumentResult[];
+  };
+  query_info: {
+    original_query: string;
+    search_type: SearchMode | "term_definition";
+  };
+}
+
+/**
+ * openSearch response
+ */
+
+// 基础响应接口
+export interface ElasticsearchResponse<T> {
+  took: number;
+  timed_out: boolean;
+  _shards: ShardsInfo;
+  hits: Hits<T>;
+  aggregations?: Aggregations;
+}
+
+// 分片信息接口
+export interface ShardsInfo {
+  total: number;
+  successful: number;
+  skipped: number;
+  failed: number;
+}
+
+// 命中结果接口
+export interface Hits<T> {
+  total: TotalHits;
+  max_score: number;
+  hits: Hit<T>[];
+}
+
+// 命中总数接口
+export interface TotalHits {
+  value: number;
+  relation: "eq" | "gte" | "lte";
+}
+
+// 单个命中结果接口
+interface Hit<T> {
+  _index: string;
+  _id: string;
+  _score: number;
+  _source: T;
+}
+
+// 聚合结果接口
+interface Aggregations {
+  granularity?: TermsAggregation;
+  resource_type?: TermsAggregation;
+  language?: TermsAggregation;
+  category?: TermsAggregation;
+}
+
+// 词条聚合接口
+interface TermsAggregation {
+  doc_count_error_upper_bound: number;
+  sum_other_doc_count: number;
+  buckets: Bucket[];
+}
+
+// 聚合桶接口
+interface Bucket {
+  key: string;
+  doc_count: number;
+}
+
+// 文档数据接口 - 对应 _source 字段
+export interface WikipaliDocument {
+  id: string;
+  resource_id: string;
+  resource_type: string;
+  title: Title;
+  summary: Summary;
+  content: Content;
+  bold_single: string;
+  bold_multi: string;
+  related_id: number;
+  category: string;
+  language: string;
+  updated_at: string;
+  granularity: string;
+  path?: string;
+}
+
+// 标题接口
+interface Title {
+  text: string;
+}
+
+// 摘要接口
+interface Summary {
+  text: string;
+}
+
+// 内容接口
+interface Content {
+  display: string;
+  text: string;
+  exact: string;
+}
+
+// 特定于搜索结果的类型别名,便于使用
+export type WikipaliSearchResponse = ElasticsearchResponse<WikipaliDocument>;
+
+// 示例使用方式:
+// const response: WikipaliSearchResponse = await fetchSearchResults();
+// const documents = response.hits.hits.map(hit => hit._source);
+
+export interface Suggestion {
+  text: string;
+  source: string;
+  score: number;
+  resource_type: string;
+  language: string;
+  doc_id: string;
+  category: string;
+  granularity: string;
+}
+
+export interface SuggestionsData {
+  query: string;
+  suggestions: Suggestion[];
+  total: number;
+}
+
+export interface SuggestionsResponse {
+  success: boolean;
+  data: SuggestionsData;
+}

+ 405 - 0
dashboard-v4/documents/development/chat/README.md

@@ -0,0 +1,405 @@
+# 聊天系统数据库设计文档
+
+## 1. 项目概述
+
+本项目旨在实现一个类似 Claude 的聊天系统,支持以下核心功能:
+
+- 多轮对话管理
+- Function Call 集成
+- 消息树结构(支持消息分支和版本控制)
+- 用户可修改问题并生成新的回答分支
+- 支持切换不同版本的回答
+- 支持更换模型重新回答同一问题
+- 消息生成参数跟踪(temperature、tokens 等)
+
+## 2. 核心设计理念
+
+### 2.1 消息组织结构
+
+- **Chat**: 每次点击"新建聊天"创建一个独立的消息树
+- **Session**: 将相关的消息组织成会话段,前端显示为一个消息组
+- **Message Tree**: 通过 parent_id 维护消息间的依赖关系
+- **Version Control**: 支持同一节点的多个版本,用户可切换查看
+
+### 2.2 Function Call 集成
+
+系统支持标准的 Function Call 流程:
+
+```text
+user → assistant(tool_calls) → tool(result) → assistant(final_response)
+```
+
+所有相关消息归属同一个 session,前端显示为一个完整的 AI 回复。
+
+### 2.3 软删除机制
+
+系统采用软删除策略,保护用户数据安全:
+
+- 所有删除操作仅标记 `deleted_at` 字段
+- 查询时默认过滤已删除数据
+- 支持数据恢复和审计需求
+
+## 3. 数据库表设计
+
+### 3.1 chats 表(聊天会话)
+
+存储每个独立的聊天会话。
+
+```sql
+CREATE TABLE chats (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    uid CHAR(36) NOT NULL UNIQUE COMMENT 'UUID唯一标识',
+    title VARCHAR(255) NOT NULL COMMENT '聊天标题',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    deleted_at TIMESTAMP NULL COMMENT '软删除时间戳',
+    user_id CHAR(36) COMMENT '用户ID',
+
+    INDEX idx_chats_uid (uid),
+    INDEX idx_chats_user_id (user_id),
+    INDEX idx_chats_created_at (created_at),
+    INDEX idx_chats_deleted_at (deleted_at)
+) COMMENT '聊天会话表';
+```
+
+### 3.2 chat_messages 表(消息节点)
+
+存储所有消息,支持树形结构和版本控制。role=system 为消息树的唯一根节点。不可修改,不可删除。
+
+```sql
+CREATE TABLE chat_messages (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '自增主键,提供天然时间排序',
+    uid CHAR(36) NOT NULL UNIQUE COMMENT 'UUID唯一标识',
+    chat_id CHAR(36) NOT NULL COMMENT '关联chats.uid',
+    parent_id CHAR(36) COMMENT '关联chat_messages.uid,NULL表示根节点',
+    session_id CHAR(36) NOT NULL COMMENT '会话段ID,同一消息组共享',
+
+    role ENUM('system','user', 'assistant', 'tool') NOT NULL COMMENT '消息角色',
+    content TEXT COMMENT '消息内容',
+    model_id CHAR(36) COMMENT '使用的模型id(assistant消息)',
+    tool_calls JSON COMMENT '函数调用信息(assistant消息)',
+    tool_call_id VARCHAR(100) COMMENT '工具调用ID(tool消息)',
+    metadata JSON COMMENT '消息元数据:生成参数、token统计等',
+
+    is_active BOOLEAN DEFAULT TRUE COMMENT '是否为当前激活版本',
+    editor_id CHAR(36) COMMENT '最后编辑用户ID',
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    deleted_at TIMESTAMP NULL COMMENT '软删除时间戳',
+
+    INDEX idx_messages_uid (uid),
+    INDEX idx_messages_chat_id (chat_id),
+    INDEX idx_messages_parent_id (parent_id),
+    INDEX idx_messages_session_id (session_id),
+    INDEX idx_messages_active (chat_id, is_active),
+    INDEX idx_messages_deleted_at (deleted_at)
+) COMMENT '聊天消息表';
+```
+
+## 4. 数据结构说明
+
+### 4.1 字段详解
+
+#### chats 表字段
+
+- `id`: 自增主键,数据库内部使用
+- `uid`: UUID 标识,用于外部引用和 API
+- `title`: 聊天标题,可从首条消息自动生成
+- `user_id`: 用户标识(可选,如果需要多用户支持)
+- `deleted_at`: 软删除时间戳,NULL 表示未删除
+
+#### chat_messages 表字段
+
+- `id`: 自增主键,提供天然的消息时间顺序
+- `uid`: UUID 标识,用于 parent_id 引用,保证跨系统稳定性
+- `parent_id`: 指向父消息的 uid,构建技术依赖关系
+- `session_id`: 消息组标识,相同 session_id 的消息在前端显示为一组
+- `role`: 消息类型(user 用户/assistant 助手/tool 工具结果)
+- `tool_calls`: JSON 格式存储函数调用信息
+- `tool_call_id`: 关联 tool 消息到具体的函数调用
+- `metadata`: 消息生成相关参数和统计信息
+- `is_active`: 标记用户当前查看的版本
+- `deleted_at`: 软删除时间戳,NULL 表示未删除
+
+### 4.2 metadata 字段结构
+
+metadata 字段存储与消息生成相关的参数和统计信息:
+
+```json
+{
+  // AI生成参数(assistant消息)
+  "generation_params": {
+    "temperature": 0.7,
+    "max_tokens": 2048,
+    "top_p": 0.9,
+    "frequency_penalty": 0.0,
+    "presence_penalty": 0.0
+  },
+
+  // Token使用统计
+  "token_usage": {
+    "prompt_tokens": 150,
+    "completion_tokens": 320,
+    "total_tokens": 470
+  },
+
+  // 性能指标
+  "performance": {
+    "response_time_ms": 1250,
+    "first_token_time_ms": 450
+  },
+
+  // 工具调用统计(如适用)
+  "tool_stats": {
+    "total_calls": 2,
+    "successful_calls": 2,
+    "execution_time_ms": 340
+  },
+
+  // 其他扩展信息
+  "custom_data": {}
+}
+```
+
+### 4.3 消息关系说明
+
+#### parent_id 关系(技术依赖)
+
+维护 Function Call 的执行链:
+
+```text
+user(id=1)
+  ↓ parent_id=uuid1
+assistant(id=2, tool_calls=[...])
+  ↓ parent_id=uuid2
+tool(id=3, tool_call_id=xxx)
+  ↓ parent_id=uuid3
+assistant(id=4, final_response)
+```
+
+#### session_id 关系(显示分组)
+
+将相关消息组织成前端显示单元:
+
+```text
+Session 1: [user消息]
+Session 2: [assistant + tool + assistant] -> 显示为一个AI回复
+Session 3: [user消息]
+```
+
+## 5. 软删除实现
+
+### 5.1 删除操作
+
+```sql
+-- 软删除聊天(级联删除所有消息)
+UPDATE chats SET deleted_at = CURRENT_TIMESTAMP WHERE uid = ?;
+UPDATE chat_messages SET deleted_at = CURRENT_TIMESTAMP WHERE chat_id = ?;
+
+-- 软删除单个消息
+UPDATE chat_messages SET deleted_at = CURRENT_TIMESTAMP WHERE uid = ?;
+```
+
+### 5.2 查询过滤
+
+所有业务查询都需要过滤已删除数据:
+
+```sql
+-- 查询示例
+SELECT * FROM chats WHERE deleted_at IS NULL;
+SELECT * FROM chat_messages WHERE deleted_at IS NULL;
+```
+
+### 5.3 数据恢复
+
+```sql
+-- 恢复聊天
+UPDATE chats SET deleted_at = NULL WHERE uid = ?;
+
+-- 恢复消息
+UPDATE chat_messages SET deleted_at = NULL WHERE uid = ?;
+```
+
+## 6. 典型数据示例
+
+### 6.1 Function Call 对话示例
+
+```sql
+-- Chat记录
+INSERT INTO chats (id, uid, title) VALUES
+(1, 'chat-uuid-1', '天气查询对话');
+
+-- 消息记录
+INSERT INTO chat_messages (id, uid, chat_id, parent_id, session_id, role, content, metadata) VALUES
+-- Session 1: 用户提问
+(1, 'msg-uuid-1', 'chat-uuid-1', NULL, 'session-uuid-1', 'user', '查询今天天气', NULL),
+
+-- Session 2: AI处理流程
+(2, 'msg-uuid-2', 'chat-uuid-1', 'msg-uuid-1', 'session-uuid-2', 'assistant', NULL,
+ '{"generation_params":{"temperature":0.7,"max_tokens":2048},"token_usage":{"prompt_tokens":20,"completion_tokens":50,"total_tokens":70}}'),
+
+(3, 'msg-uuid-3', 'chat-uuid-1', 'msg-uuid-2', 'session-uuid-2', 'tool', '今天晴天,25°C',
+ '{"tool_stats":{"execution_time_ms":340}}'),
+
+(4, 'msg-uuid-4', 'chat-uuid-1', 'msg-uuid-3', 'session-uuid-2', 'assistant', '今天天气晴朗,气温25度...',
+ '{"generation_params":{"temperature":0.7},"token_usage":{"prompt_tokens":100,"completion_tokens":80,"total_tokens":180},"performance":{"response_time_ms":1250}}'),
+
+-- Session 3: 用户继续提问
+(5, 'msg-uuid-5', 'chat-uuid-1', 'msg-uuid-4', 'session-uuid-3', 'user', '那明天呢?', NULL);
+```
+
+### 6.2 tool_calls JSON 结构示例
+
+```json
+[
+  {
+    "id": "call_123",
+    "function": "get_weather",
+    "arguments": {
+      "city": "北京",
+      "date": "today"
+    }
+  }
+]
+```
+
+## 7. 核心业务场景
+
+### 7.1 用户修改问题
+
+1. 软删除原消息及其后续回答链
+2. 创建新版本消息
+3. 生成新的回答链,记录生成参数到 metadata
+
+### 7.2 重新生成回答
+
+1. 软删除当前 assistant 回答
+2. 使用相同或不同的参数重新生成
+3. 在 metadata 中记录新的生成参数和统计信息
+
+### 7.3 消息分支管理
+
+- 每个分支保持独立的 session_id
+- 通过 parent_id 维护分支关系
+- 软删除支持分支恢复
+
+## 8. 常用查询模式
+
+### 8.1 获取聊天的消息组列表
+
+```sql
+SELECT DISTINCT session_id, MIN(id) as first_message_id
+FROM chat_messages
+WHERE chat_id = ? AND is_active = true AND deleted_at IS NULL
+ORDER BY first_message_id;
+```
+
+### 8.2 获取某个 session 的所有消息
+
+```sql
+SELECT * FROM chat_messages
+WHERE session_id = ? AND is_active = true AND deleted_at IS NULL
+ORDER BY id;
+```
+
+### 8.3 获取完整对话历史(用于 AI Context)
+
+```sql
+-- 获取当前激活路径的所有消息
+WITH RECURSIVE active_path AS (
+  SELECT * FROM chat_messages
+  WHERE chat_id = ? AND parent_id IS NULL AND is_active = true AND deleted_at IS NULL
+
+  UNION ALL
+
+  SELECT m.* FROM chat_messages m
+  JOIN active_path p ON m.parent_id = p.uid
+  WHERE m.is_active = true AND m.deleted_at IS NULL
+)
+SELECT * FROM active_path ORDER BY id;
+```
+
+### 8.4 查询消息的所有版本(包含已删除)
+
+```sql
+SELECT *,
+       CASE WHEN deleted_at IS NULL THEN 'active' ELSE 'deleted' END as status
+FROM chat_messages
+WHERE parent_id = ? AND role = ?
+ORDER BY created_at;
+```
+
+### 8.5 Token 使用统计查询
+
+```sql
+-- 查询聊天的总token使用量
+SELECT
+    chat_id,
+    SUM(JSON_EXTRACT(metadata, '$.token_usage.total_tokens')) as total_tokens,
+    AVG(JSON_EXTRACT(metadata, '$.performance.response_time_ms')) as avg_response_time
+FROM chat_messages
+WHERE chat_id = ? AND role = 'assistant' AND deleted_at IS NULL
+GROUP BY chat_id;
+```
+
+## 9. 性能优化建议
+
+### 9.1 索引策略
+
+- `chat_id`: 快速查询某个聊天的所有消息
+- `session_id`: 快速获取消息组
+- `parent_id`: 支持树形查询和兄弟节点查询
+- `(chat_id, is_active)`: 快速获取激活消息
+- `deleted_at`: 快速过滤软删除数据
+
+### 9.2 查询优化
+
+- 使用递归 CTE 进行树形查询
+- 考虑 materialized path 优化深层树查询
+- 对于频繁的 session 查询,考虑适当的缓存策略
+- metadata JSON 字段可根据需要创建虚拟列索引
+
+### 9.3 软删除优化
+
+- 定期清理长期删除的数据(如 30 天后物理删除)
+- 考虑分区表优化查询性能
+- 为 deleted_at 字段建立部分索引(仅索引非 NULL 值)
+
+## 10. 扩展性考虑
+
+### 10.1 多模态支持
+
+- content 字段可存储 JSON,支持文本、图片、文件等多种内容类型
+- tool_calls 可扩展支持更多函数类型
+- metadata 可扩展记录多模态内容的处理参数
+
+### 10.2 权限控制
+
+- 通过 user_id 支持多用户隔离
+- 可扩展支持聊天分享、协作等功能
+- 软删除支持权限恢复场景
+
+### 10.3 审计和监控
+
+- created_at/updated_at 支持操作时间追踪
+- deleted_at 提供删除审计
+- metadata 记录详细的生成和性能数据
+- 可扩展添加操作日志表记录详细变更历史
+
+## 11. 注意事项
+
+1. **UUID 生成**: 确保 uid 字段使用标准 UUID v4 格式
+2. **JSON 字段**: 使用数据库原生 JSON 类型,支持索引和查询
+3. **外键约束**: 合理使用外键约束保证数据一致性
+4. **软删除一致性**: 确保级联删除的数据一致性
+5. **并发控制**: 在版本更新时注意并发冲突处理
+6. **数据清理**: 制定合理的物理删除策略,避免数据无限增长
+7. **查询习惯**: 所有业务查询都必须包含 `deleted_at IS NULL` 条件
+8. **JSON 索引**: 根据实际查询需求为 metadata 字段创建合适的索引
+
+---
+
+**文档版本**: 1.1  
+**创建时间**: 2025-09-07  
+**更新时间**: 2025-09-09  
+**修订说明**: 增加 metadata 字段和软删除机制

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