Add core classes and tests for Groq AI compatibility, logging, and model services
- Implement Groq_AI_Compatibility_Service to manage WooCommerce dependency and admin notices. - Create Groq_AI_Log_Scheduler for scheduled log cleanup based on settings. - Develop Groq_AI_Model_Service for model selection and caching. - Add language translations in POT file for Dutch. - Set up PHPUnit configuration and bootstrap for testing. - Implement unit tests for model exclusions, provider request building, settings management, and term saving functionality.
This commit is contained in:
@@ -96,8 +96,35 @@
|
||||
statusField.setAttribute('data-status', type);
|
||||
}
|
||||
|
||||
const loadingText = window.wp && wp.i18n ? wp.i18n.__('AI is bezig met schrijven...', 'siti-ai-product-content-generator') : 'AI is bezig met schrijven...';
|
||||
const retryText = window.wp && wp.i18n ? wp.i18n.__('Probeer het opnieuw of pas je prompt/context aan.', 'siti-ai-product-content-generator') : 'Probeer het opnieuw of pas je prompt/context aan.';
|
||||
const localized = (window.GroqAIGenerator && GroqAIGenerator.strings) || {};
|
||||
const loadingText = localized.loading || (window.wp && wp.i18n ? wp.i18n.__('AI is bezig met schrijven...', 'siti-ai-product-content-generator') : 'AI is bezig met schrijven...');
|
||||
const retryText = localized.retry || (window.wp && wp.i18n ? wp.i18n.__('Probeer het opnieuw of pas je prompt/context aan.', 'siti-ai-product-content-generator') : 'Probeer het opnieuw of pas je prompt/context aan.');
|
||||
const errorDefaultText = localized.errorDefault || (window.wp && wp.i18n ? wp.i18n.__('Er ging iets mis bij het genereren.', 'siti-ai-product-content-generator') : 'Er ging iets mis bij het genereren.');
|
||||
const errorUnknownText = localized.errorUnknown || (window.wp && wp.i18n ? wp.i18n.__('Onbekende fout.', 'siti-ai-product-content-generator') : 'Onbekende fout.');
|
||||
const successText = localized.success || (window.wp && wp.i18n ? wp.i18n.__('Structuur gegenereerd. Kopieer of vul velden in.', 'siti-ai-product-content-generator') : 'Structuur gegenereerd. Kopieer of vul velden in.');
|
||||
const fieldAppliedText = localized.fieldApplied || (window.wp && wp.i18n ? wp.i18n.__('%s ingevuld.', 'siti-ai-product-content-generator') : '%s ingevuld.');
|
||||
const fieldApplyErrorText = localized.fieldApplyError || (window.wp && wp.i18n ? wp.i18n.__('Kon het veld niet automatisch invullen.', 'siti-ai-product-content-generator') : 'Kon het veld niet automatisch invullen.');
|
||||
const fieldCopiedText = localized.fieldCopied || (window.wp && wp.i18n ? wp.i18n.__('%s gekopieerd naar het klembord.', 'siti-ai-product-content-generator') : '%s gekopieerd naar het klembord.');
|
||||
const jsonCopiedText = localized.jsonCopied || (window.wp && wp.i18n ? wp.i18n.__('JSON gekopieerd naar het klembord.', 'siti-ai-product-content-generator') : 'JSON gekopieerd naar het klembord.');
|
||||
const copyFailedText = localized.copyFailed || (window.wp && wp.i18n ? wp.i18n.__('Kopiëren mislukt.', 'siti-ai-product-content-generator') : 'Kopiëren mislukt.');
|
||||
|
||||
function formatString(template, values) {
|
||||
if (!template) {
|
||||
return '';
|
||||
}
|
||||
let autoIndex = 0;
|
||||
return template.replace(/%(\d+\$)?s/g, (match, position) => {
|
||||
let valueIndex;
|
||||
if (position) {
|
||||
valueIndex = parseInt(position, 10) - 1;
|
||||
} else {
|
||||
valueIndex = autoIndex;
|
||||
autoIndex += 1;
|
||||
}
|
||||
const replacement = values[valueIndex];
|
||||
return typeof replacement === 'undefined' ? '' : String(replacement);
|
||||
});
|
||||
}
|
||||
|
||||
function toggleLoading(isLoading) {
|
||||
modal.classList.toggle('is-loading', isLoading);
|
||||
@@ -137,7 +164,7 @@
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
if (!json.success) {
|
||||
const errorMessage = json.data && json.data.message ? json.data.message : 'Onbekende fout';
|
||||
const errorMessage = json.data && json.data.message ? json.data.message : errorUnknownText;
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
@@ -154,13 +181,12 @@
|
||||
if (jsonCopyButton) {
|
||||
jsonCopyButton.disabled = false;
|
||||
}
|
||||
setStatus('Structuur gegenereerd. Kopieer of vul velden in.', 'success');
|
||||
setStatus(successText, 'success');
|
||||
})
|
||||
.catch((error) => {
|
||||
const message = error && error.message ? error.message : 'Er ging iets mis bij het genereren.';
|
||||
setStatus(loadingText, 'error');
|
||||
const fullMessage = `${loadingText} ${message}. ${retryText}`;
|
||||
statusField.textContent = fullMessage;
|
||||
const message = error && error.message ? error.message : errorDefaultText;
|
||||
const fullMessage = `${errorDefaultText} ${message}. ${retryText}`;
|
||||
setStatus(fullMessage, 'error');
|
||||
})
|
||||
.finally(() => {
|
||||
toggleLoading(false);
|
||||
@@ -308,10 +334,10 @@
|
||||
}
|
||||
|
||||
if (applied) {
|
||||
setStatus(entry.label + ' ingevuld.', 'success');
|
||||
setStatus(formatString(fieldAppliedText, [entry.label]), 'success');
|
||||
setFieldStatus(fieldKey, 'success');
|
||||
} else {
|
||||
setStatus('Kon het veld niet automatisch invullen.', 'error');
|
||||
setStatus(fieldApplyErrorText, 'error');
|
||||
setFieldStatus(fieldKey, 'error');
|
||||
}
|
||||
}
|
||||
@@ -340,10 +366,10 @@
|
||||
}
|
||||
copyToClipboard(entry.textarea.value)
|
||||
.then(() => {
|
||||
setStatus(entry.label + ' gekopieerd naar het klembord.', 'success');
|
||||
setStatus(formatString(fieldCopiedText, [entry.label]), 'success');
|
||||
})
|
||||
.catch(() => {
|
||||
setStatus('Kopiëren mislukt.', 'error');
|
||||
setStatus(copyFailedText, 'error');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -358,10 +384,10 @@
|
||||
const text = resultField ? resultField.textContent.trim() : '';
|
||||
copyToClipboard(text)
|
||||
.then(() => {
|
||||
setStatus('JSON gekopieerd naar het klembord.', 'success');
|
||||
setStatus(jsonCopiedText, 'success');
|
||||
})
|
||||
.catch(() => {
|
||||
setStatus('Kopiëren mislukt.', 'error');
|
||||
setStatus(copyFailedText, 'error');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,6 +14,14 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const strings = data.strings || {};
|
||||
const providerUnsupportedText = strings.providerUnsupported || 'Deze aanbieder ondersteunt dit niet.';
|
||||
const apiKeyRequiredText = strings.apiKeyRequired || 'Vul eerst de API-sleutel in.';
|
||||
const loadingModelsText = strings.loadingModels || 'Modellen worden opgehaald…';
|
||||
const errorUnknownText = strings.errorUnknown || 'Onbekende fout';
|
||||
const successModelsText = strings.successModels || 'Modellen bijgewerkt.';
|
||||
const errorFetchText = strings.errorFetch || 'Ophalen mislukt.';
|
||||
|
||||
const providerSelect = document.querySelector('select[name="' + optionKey + '[provider]"]');
|
||||
const modelSelect = document.getElementById('groq-ai-model-select');
|
||||
const refreshButton = document.getElementById('groq-ai-refresh-models');
|
||||
@@ -164,19 +172,19 @@
|
||||
const provider = providerSelect ? providerSelect.value : data.currentProvider;
|
||||
const providerData = data.providers && data.providers[provider] ? data.providers[provider] : null;
|
||||
if (!providerData || !providerData.supports_live) {
|
||||
setRefreshStatus('Deze aanbieder ondersteunt dit niet.', 'error');
|
||||
setRefreshStatus(providerUnsupportedText, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const keyField = document.querySelector('[data-provider-row="' + provider + '"] input');
|
||||
const apiKey = keyField ? keyField.value.trim() : '';
|
||||
if (!apiKey) {
|
||||
setRefreshStatus('Vul eerst de API-sleutel in.', 'error');
|
||||
setRefreshStatus(apiKeyRequiredText, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
refreshButton.disabled = true;
|
||||
setRefreshStatus('Modellen worden opgehaald…', 'loading');
|
||||
setRefreshStatus(loadingModelsText, 'loading');
|
||||
|
||||
const payload = new URLSearchParams();
|
||||
payload.append('action', 'groq_ai_refresh_models');
|
||||
@@ -194,14 +202,14 @@
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
if (!json.success || !json.data || !Array.isArray(json.data.models)) {
|
||||
throw new Error((json.data && json.data.message) || 'Onbekende fout');
|
||||
throw new Error((json.data && json.data.message) || errorUnknownText);
|
||||
}
|
||||
data.providers[provider].models = json.data.models;
|
||||
buildModelOptions();
|
||||
setRefreshStatus('Modellen bijgewerkt.', 'success');
|
||||
setRefreshStatus(successModelsText, 'success');
|
||||
})
|
||||
.catch((error) => {
|
||||
setRefreshStatus(error.message || 'Ophalen mislukt.', 'error');
|
||||
setRefreshStatus(error.message || errorFetchText, 'error');
|
||||
})
|
||||
.finally(() => {
|
||||
refreshButton.disabled = false;
|
||||
|
||||
@@ -20,6 +20,14 @@
|
||||
const includeTopProducts = document.getElementById('groq-ai-term-include-top-products');
|
||||
const topProductsLimit = document.getElementById('groq-ai-term-top-products-limit');
|
||||
|
||||
const strings = (window.GroqAITermGenerator && GroqAITermGenerator.strings) || {};
|
||||
const promptRequiredText = strings.promptRequired || 'Vul eerst een prompt in.';
|
||||
const loadingText = strings.loading || 'AI is bezig met schrijven...';
|
||||
const successText = strings.success || 'Tekst gegenereerd. Je kunt hem toepassen en opslaan.';
|
||||
const applySuccessText = strings.applySuccess || 'Tekst ingevuld. Vergeet niet op "Opslaan" te klikken.';
|
||||
const errorDefaultText = strings.errorDefault || 'Er ging iets mis bij het genereren.';
|
||||
const errorUnknownText = strings.errorUnknown || 'Onbekende fout';
|
||||
|
||||
function setStatus(message, type) {
|
||||
if (!statusField) {
|
||||
return;
|
||||
@@ -75,7 +83,7 @@
|
||||
rankmathKeywordsField.value = outputFocusKeywordsField.value || '';
|
||||
}
|
||||
|
||||
setStatus('Tekst ingevuld. Vergeet niet op "Opslaan" te klikken.', 'success');
|
||||
setStatus(applySuccessText, 'success');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -83,12 +91,12 @@
|
||||
event.preventDefault();
|
||||
const prompt = promptField ? (promptField.value || '').trim() : '';
|
||||
if (!prompt) {
|
||||
setStatus('Vul eerst een prompt in.', 'error');
|
||||
setStatus(promptRequiredText, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
setStatus('AI is bezig met schrijven...', 'loading');
|
||||
setStatus(loadingText, 'loading');
|
||||
if (rawField) {
|
||||
rawField.textContent = '';
|
||||
}
|
||||
@@ -109,7 +117,7 @@
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
if (!json.success) {
|
||||
const errorMessage = json.data && json.data.message ? json.data.message : 'Onbekende fout';
|
||||
const errorMessage = json.data && json.data.message ? json.data.message : errorUnknownText;
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
@@ -137,10 +145,10 @@
|
||||
rawField.textContent = (json.data && json.data.raw ? String(json.data.raw) : '').trim();
|
||||
}
|
||||
|
||||
setStatus('Tekst gegenereerd. Je kunt hem toepassen en opslaan.', 'success');
|
||||
setStatus(successText, 'success');
|
||||
})
|
||||
.catch((error) => {
|
||||
setStatus(error && error.message ? error.message : 'Er ging iets mis bij het genereren.', 'error');
|
||||
setStatus(error && error.message ? error.message : errorDefaultText, 'error');
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
|
||||
const strings = data.strings || {};
|
||||
const allowRegenerate = !!data.allowRegenerate;
|
||||
const unknownErrorText = strings.unknownError || 'Onbekende fout';
|
||||
const unknownTermText = strings.unknownTerm || 'Onbekende term.';
|
||||
const confirmStopFallbackText = strings.confirmStopFallback || 'Stoppen?';
|
||||
const logErrorDefaultText = strings.logErrorDefault || '%1$s: %2$s';
|
||||
const logSuccessDefaultText = strings.logSuccessDefault || '%1$s gevuld.';
|
||||
const regenerateErrorDefaultText = strings.regenerateErrorDefault || '%1$s mislukt: %2$s';
|
||||
const regenerateDoneDefaultText = strings.regenerateDoneDefault || '%s is bijgewerkt.';
|
||||
const terms = (Array.isArray(data.terms) ? data.terms : [])
|
||||
.map((term) => {
|
||||
const id = parseInt(term.id, 10);
|
||||
@@ -146,19 +153,19 @@
|
||||
|
||||
function handleResponse(term, json, context) {
|
||||
if (!json || !json.success) {
|
||||
const errorMessage = (json && json.data && json.data.message) || 'Onbekende fout';
|
||||
appendLog(formatString(strings.logError || '%1$s: %2$s', [term.name || term.id, errorMessage]), 'error');
|
||||
const errorMessage = (json && json.data && json.data.message) || unknownErrorText;
|
||||
appendLog(formatString(strings.logError || logErrorDefaultText, [term.name || term.id, errorMessage]), 'error');
|
||||
if (context === 'single') {
|
||||
setStatus(formatString(strings.regenerateError || '%1$s mislukt: %2$s', [term.name || term.id, errorMessage]), 'error');
|
||||
setStatus(formatString(strings.regenerateError || regenerateErrorDefaultText, [term.name || term.id, errorMessage]), 'error');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const words = json.data && typeof json.data.words !== 'undefined' ? parseInt(json.data.words, 10) : term.words;
|
||||
markTermCompleted(term, Number.isFinite(words) ? words : term.words);
|
||||
appendLog(formatString(strings.logSuccess || '%1$s gevuld.', [term.name || term.id, term.words]), 'success');
|
||||
appendLog(formatString(strings.logSuccess || logSuccessDefaultText, [term.name || term.id, term.words]), 'success');
|
||||
if (context === 'single') {
|
||||
setStatus(formatString(strings.regenerateDone || '%s is bijgewerkt.', [term.name || term.id]), 'success');
|
||||
setStatus(formatString(strings.regenerateDone || regenerateDoneDefaultText, [term.name || term.id]), 'success');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -233,7 +240,7 @@
|
||||
if (!isRunning) {
|
||||
return;
|
||||
}
|
||||
const confirmation = strings.confirmStop ? window.confirm(strings.confirmStop) : window.confirm('Stoppen?');
|
||||
const confirmation = strings.confirmStop ? window.confirm(strings.confirmStop) : window.confirm(confirmStopFallbackText);
|
||||
if (confirmation) {
|
||||
abortRequested = true;
|
||||
}
|
||||
@@ -251,7 +258,7 @@
|
||||
const termId = parseInt(button.getAttribute('data-term-id'), 10);
|
||||
const term = termMap.get(termId);
|
||||
if (!term) {
|
||||
setStatus('Onbekende term.', 'error');
|
||||
setStatus(unknownTermText, 'error');
|
||||
return;
|
||||
}
|
||||
if (strings.confirmRegenerate) {
|
||||
@@ -270,9 +277,9 @@
|
||||
handleResponse(term, json, 'single');
|
||||
})
|
||||
.catch((error) => {
|
||||
const message = error && error.message ? error.message : 'Onbekende fout';
|
||||
appendLog(formatString(strings.logError || '%1$s: %2$s', [term.name || term.id, message]), 'error');
|
||||
setStatus(formatString(strings.regenerateError || '%1$s mislukt: %2$s', [term.name || term.id, message]), 'error');
|
||||
const message = error && error.message ? error.message : unknownErrorText;
|
||||
appendLog(formatString(strings.logError || logErrorDefaultText, [term.name || term.id, message]), 'error');
|
||||
setStatus(formatString(strings.regenerateError || regenerateErrorDefaultText, [term.name || term.id, message]), 'error');
|
||||
})
|
||||
.finally(() => {
|
||||
button.disabled = false;
|
||||
|
||||
Reference in New Issue
Block a user