*/ public static function rows(): array { $settings = get_plugin_settings(); $light = trim((string) ($settings['light_model'] ?? '')); $tasks = isset($settings['light_tasks']) && is_array($settings['light_tasks']) ? $settings['light_tasks'] : TaskContext::DEFAULT_LIGHT_TASKS; $labels = array_map(static fn($t): string => task_label((string) $t), array_slice($tasks, 0, 4)); $rows = []; if (Gateway::compatMode()) { $rows[] = [ __('Writing and short tasks', 'aipcf-ai-provider-for-cloudflare'), /* translators: %s: dynamic route name */ sprintf(__('Gateway route "%s"', 'aipcf-ai-provider-for-cloudflare'), Gateway::dynamicRoute()), __('The AI Gateway dynamic route picks the model; the models below apply only to image requests.', 'aipcf-ai-provider-for-cloudflare'), ]; } else { $rows[] = [ __('Writing (drafts, summaries, anything not listed below)', 'aipcf-ai-provider-for-cloudflare'), pretty_model_name(get_default_model_id()), __('Default text model.', 'aipcf-ai-provider-for-cloudflare'), ]; $rows[] = [ __('Short tasks', 'aipcf-ai-provider-for-cloudflare'), $light !== '' ? pretty_model_name($light) : pretty_model_name(get_default_model_id()), $light !== '' && $tasks !== [] ? sprintf( /* translators: %s: list of tasks */ __('Light model, for: %s. A model picked for a feature in the AI plugin is used as picked.', 'aipcf-ai-provider-for-cloudflare'), count($tasks) > 4 ? sprintf( /* translators: 1: first task names, 2: how many more tasks */ _n('%1$s and %2$d more task', '%1$s and %2$d more tasks', count($tasks) - 4, 'aipcf-ai-provider-for-cloudflare'), implode(', ', $labels), count($tasks) - 4 ) : implode(', ', $labels) ) : __('Light model is off, so the default model answers.', 'aipcf-ai-provider-for-cloudflare'), ]; } $rows[] = [ __('Reading images (alt text, image descriptions)', 'aipcf-ai-provider-for-cloudflare'), pretty_model_name(vision_model_id()), __('Vision model. Text models cannot see images, so this is the only one used for them.', 'aipcf-ai-provider-for-cloudflare'), ]; $rows[] = [ __('Generating images', 'aipcf-ai-provider-for-cloudflare'), pretty_model_name((string) (($settings['image_model'] ?? '') ?: '@cf/black-forest-labs/flux-1-schnell')), __('Image model.', 'aipcf-ai-provider-for-cloudflare'), ]; // Translation has no screen of its own: it runs only when a theme or plugin calls // aipcf_translate(), so the row shows only once that has happened recently. if (self::translationUsed()) { $rows[] = [ __('Translation', 'aipcf-ai-provider-for-cloudflare'), 'M2M100 / IndicTrans2', __('Used when a theme or plugin calls aipcf_translate(): IndicTrans2 for Indian languages, M2M100 for the rest.', 'aipcf-ai-provider-for-cloudflare'), ]; } if (UsageTracker::budgetEnabled()) { $rows[] = [ __('After the daily budget is used up', 'aipcf-ai-provider-for-cloudflare'), UsageTracker::budgetAction() === 'cheapest' ? pretty_model_name(UsageTracker::cheapestTextModelId()) : __('Paused', 'aipcf-ai-provider-for-cloudflare'), UsageTracker::budgetAction() === 'cheapest' ? __('Text requests switch to the cheapest model; Backfill, the content index, Link assistant chat, the Site assistant, Search, Search insights, image generation, image reading and translation pause until midnight UTC.', 'aipcf-ai-provider-for-cloudflare') : __('All requests pause until midnight UTC.', 'aipcf-ai-provider-for-cloudflare'), ]; } return $rows; } /** * Whether a translation model answered any request in the last 30 days (the usage history * keeps requests per model per day). */ public static function translationUsed(int $days = 30): bool { $since = gmdate('Y-m-d', time() - $days * DAY_IN_SECONDS); foreach (UsageTracker::all() as $day => $entry) { if ((string) $day < $since || !is_array($entry)) { continue; } foreach (array_keys((array) ($entry['models'] ?? [])) as $model) { if (\WordPress\CloudflareWorkersAiProvider\Models\CloudflareWorkersAiTranslationModel::supports((string) $model)) { return true; } } } return false; } }