PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.4
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.4
4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 All 202 releases
betterdocs / includes / AI / ModelRegistry.php

ModelRegistry.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.9.4, at includes/AI/ModelRegistry.php

214 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPDeveloper\BetterDocs\AI;
4
5 /**
6 * Curated, static catalogue of platforms and their chat models.
7 *
8 * Single source of truth for:
9 * - the platform selector + model dropdown in Settings (localized to React),
10 * - server-side validation that a (platform, model) pair is allowed,
11 * - the per-platform default model used when none is stored.
12 *
13 * Model identifiers move fast; update the lists here on new releases, or filter
14 * `betterdocs_ai_models` to add/replace entries without touching core.
15 *
16 * @since 4.4.0
17 */
18 class ModelRegistry {
19
20 /**
21 * Ordered list of supported platforms (id => label).
22 *
23 * @return array<string,string>
24 */
25 public static function platforms() {
26 return apply_filters( 'betterdocs_ai_platforms', array(
27 'openai' => 'OpenAI',
28 'gemini' => 'Google Gemini',
29 'claude' => 'Anthropic Claude',
30 'deepseek' => 'DeepSeek',
31 'openrouter' => 'OpenRouter',
32 ) );
33 }
34
35 /**
36 * Full model catalogue: platform => array( model_id => label ).
37 *
38 * NOTE: verify model ids against each provider's current docs at release
39 * time. Anthropic/Gemini/OpenRouter ids in particular rotate frequently.
40 *
41 * @return array<string,array<string,string>>
42 */
43 public static function catalogue() {
44 $catalogue = array(
45 'openai' => array(
46 'gpt-4o-mini' => 'GPT-4o Mini',
47 'gpt-4o' => 'GPT-4o',
48 'gpt-4.1-nano' => 'GPT-4.1 Nano',
49 'gpt-4.1-mini' => 'GPT-4.1 Mini',
50 'gpt-4.1' => 'GPT-4.1',
51 'gpt-5-nano' => 'GPT-5 Nano',
52 'gpt-5-mini' => 'GPT-5 Mini',
53 'gpt-5' => 'GPT-5',
54 'gpt-5.5' => 'GPT-5.5',
55 ),
56 // Cheapest first. Every id here is verified callable with a newly issued
57 // Google API key. `gemini-2.5-flash` / `-flash-lite` were removed: Google
58 // closed them to new users, and they still appear in ListModels while
59 // :generateContent answers 404 "no longer available to new users" — so the
60 // failure only surfaces at the first real request. The `-latest` aliases
61 // lead because Google re-points them and they cannot go stale that way.
62 'gemini' => array(
63 'gemini-flash-lite-latest' => 'Gemini Flash Lite (latest)',
64 'gemini-flash-latest' => 'Gemini Flash (latest)',
65 'gemini-3.5-flash' => 'Gemini 3.5 Flash',
66 'gemini-3.6-flash' => 'Gemini 3.6 Flash',
67 'gemini-2.5-pro' => 'Gemini 2.5 Pro',
68 'gemini-pro-latest' => 'Gemini Pro (latest)',
69 ),
70 // Cheapest/fastest first. `claude-opus-4-1` was removed because Anthropic
71 // retires it on 2026-08-05 — offering it now would hand a new install a
72 // model that starts 404ing within days of release.
73 //
74 // Opus 4.8, Opus 5 and Sonnet 5 reject `temperature` outright (400), and
75 // Opus 5 / Sonnet 5 think by default with `max_tokens` covering thinking
76 // AND the answer. ClaudeProvider handles both — see rejects_sampling()
77 // and thinks_by_default() there before adding a model here.
78 'claude' => array(
79 'claude-haiku-4-5' => 'Claude Haiku 4.5',
80 'claude-sonnet-4-5' => 'Claude Sonnet 4.5',
81 'claude-sonnet-5' => 'Claude Sonnet 5',
82 'claude-opus-4-8' => 'Claude Opus 4.8',
83 'claude-opus-5' => 'Claude Opus 5',
84 ),
85 'deepseek' => array(
86 'deepseek-chat' => 'DeepSeek Chat',
87 'deepseek-reasoner' => 'DeepSeek Reasoner',
88 ),
89 'openrouter' => array(
90 'openai/gpt-4o-mini' => 'OpenAI: GPT-4o Mini',
91 'openai/gpt-4o' => 'OpenAI: GPT-4o',
92 'anthropic/claude-sonnet-4.5' => 'Anthropic: Claude Sonnet 4.5',
93 'google/gemini-2.5-flash' => 'Google: Gemini 2.5 Flash',
94 'deepseek/deepseek-chat' => 'DeepSeek: Chat',
95 'meta-llama/llama-3.3-70b-instruct' => 'Meta: Llama 3.3 70B',
96 ),
97 );
98
99 return apply_filters( 'betterdocs_ai_models', $catalogue );
100 }
101
102 /**
103 * Default model id per platform.
104 *
105 * @return array<string,string>
106 */
107 public static function defaults() {
108 return apply_filters( 'betterdocs_ai_default_models', array(
109 'openai' => 'gpt-4o-mini',
110 // Auto-rolling alias, not a pinned version: the previous default here was
111 // gemini-2.5-flash, which Google has closed to new API keys, so every new
112 // Gemini install started on a model that 404s.
113 'gemini' => 'gemini-flash-latest',
114 // Sonnet 5 is the best speed/intelligence balance in the Claude line and
115 // is safe as a default now that ClaudeProvider drops `temperature` and
116 // raises the token floor for thinking models.
117 'claude' => 'claude-sonnet-5',
118 'deepseek' => 'deepseek-chat',
119 'openrouter' => 'openai/gpt-4o-mini',
120 ) );
121 }
122
123 /**
124 * Speech-to-text model per platform, for audio and video attachments.
125 *
126 * Kept apart from the chat catalogue above because it is not a user choice:
127 * the Settings model picker selects the model that *writes the doc*, while
128 * transcription is a fixed preprocessing step. A platform absent from this
129 * map cannot transcribe, which is what Core\WriteWithAI::platform_supports()
130 * reads — so adding a key here is all it takes to light up a new provider.
131 *
132 * @since 4.9.4
133 *
134 * @return array<string,string>
135 */
136 public static function transcription_models() {
137 return apply_filters( 'betterdocs_ai_transcription_models', array(
138 // Cheaper and faster than whisper-1 at comparable accuracy, and it
139 // accepts the same container list — including video, whose audio
140 // track the endpoint extracts server-side.
141 'openai' => 'gpt-4o-mini-transcribe',
142 // Gemini has no speech endpoint; the media rides inline in an
143 // ordinary generateContent call, so this is a normal chat model.
144 'gemini' => 'gemini-flash-latest',
145 ) );
146 }
147
148 /**
149 * The transcription model for a platform, or '' when it cannot transcribe.
150 *
151 * @since 4.9.4
152 *
153 * @param string $platform
154 * @return string
155 */
156 public static function transcription_model( $platform ) {
157 $models = self::transcription_models();
158 return isset( $models[ $platform ] ) ? (string) $models[ $platform ] : '';
159 }
160
161 /**
162 * Models for one platform (model_id => label). Empty array if unknown.
163 *
164 * @param string $platform
165 * @return array<string,string>
166 */
167 public static function models( $platform ) {
168 $catalogue = self::catalogue();
169 return isset( $catalogue[ $platform ] ) ? $catalogue[ $platform ] : array();
170 }
171
172 /**
173 * Default model id for a platform, falling back to its first listed model.
174 *
175 * @param string $platform
176 * @return string
177 */
178 public static function default_model( $platform ) {
179 $defaults = self::defaults();
180 if ( ! empty( $defaults[ $platform ] ) ) {
181 return $defaults[ $platform ];
182 }
183 $models = self::models( $platform );
184 if ( empty( $models ) ) {
185 return '';
186 }
187 reset( $models );
188 return (string) key( $models );
189 }
190
191 /**
192 * Whether a platform id is supported.
193 *
194 * @param string $platform
195 * @return bool
196 */
197 public static function has_platform( $platform ) {
198 $platforms = self::platforms();
199 return isset( $platforms[ $platform ] );
200 }
201
202 /**
203 * Whether a (platform, model) pair exists in the catalogue.
204 *
205 * @param string $platform
206 * @param string $model
207 * @return bool
208 */
209 public static function has_model( $platform, $model ) {
210 $models = self::models( $platform );
211 return isset( $models[ $model ] );
212 }
213 }
214