Add Google and Groq AI providers, enhance provider manager, and implement conversation and logging services

- Introduced `Groq_AI_Provider_Google` and `Groq_AI_Provider_Groq` classes for handling AI interactions with Google and Groq respectively.
- Enhanced `Groq_AI_Provider_Manager` to register and manage multiple AI providers.
- Implemented `Groq_AI_Conversation_Manager` for managing conversation IDs and context hashes.
- Added `Groq_AI_Generation_Logger` for logging AI generation events and managing log tables.
- Developed `Groq_AI_Prompt_Builder` for constructing prompts and processing AI responses.
- Established `Groq_AI_Settings_Manager` for managing plugin settings, including context fields and module configurations.
This commit is contained in:
Roberto Guagliardo
2025-12-05 23:58:15 +01:00
commit 5171f93a93
26 changed files with 4040 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
<?php
abstract class Groq_AI_Abstract_OpenAI_Provider implements Groq_AI_Provider_Interface {
public function get_available_models() {
return [];
}
public function supports_response_format() {
return true;
}
public function supports_live_models() {
return true;
}
public function fetch_live_models( $api_key ) {
$endpoint = $this->get_models_endpoint();
if ( empty( $endpoint ) ) {
return new WP_Error( 'groq_ai_models_endpoint_missing', __( 'Geen model-endpoint beschikbaar voor deze aanbieder.', 'groq-ai-product-text' ) );
}
$response = wp_remote_get(
$endpoint,
[
'headers' => [
'Authorization' => 'Bearer ' . $api_key,
'Content-Type' => 'application/json',
],
'timeout' => 20,
]
);
if ( is_wp_error( $response ) ) {
return $response;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( isset( $body['error']['message'] ) ) {
return new WP_Error( 'groq_ai_provider_error', (string) $body['error']['message'] );
}
if ( empty( $body['data'] ) || ! is_array( $body['data'] ) ) {
return new WP_Error( 'groq_ai_empty_response', __( 'Geen modeldata ontvangen.', 'groq-ai-product-text' ) );
}
$models = [];
foreach ( $body['data'] as $model ) {
if ( ! empty( $model['id'] ) ) {
$models[] = sanitize_text_field( $model['id'] );
}
}
if ( empty( $models ) ) {
return new WP_Error( 'groq_ai_empty_response', __( 'Geen modeldata ontvangen.', 'groq-ai-product-text' ) );
}
return $models;
}
public function generate_content( array $args ) {
$settings = isset( $args['settings'] ) ? (array) $args['settings'] : [];
$prompt = isset( $args['prompt'] ) ? $args['prompt'] : '';
$system_prompt = isset( $args['system_prompt'] ) ? $args['system_prompt'] : '';
$model = ! empty( $args['model'] ) ? $args['model'] : $this->get_default_model();
$api_key = $this->get_api_key( $settings );
if ( empty( $api_key ) ) {
return new WP_Error( 'groq_ai_missing_api_key', sprintf( __( 'Stel eerst de API-sleutel voor %s in.', 'groq-ai-product-text' ), $this->get_label() ) );
}
$messages = [
[
'role' => 'system',
'content' => $system_prompt,
],
[
'role' => 'user',
'content' => $prompt,
],
];
$request_body = [
'model' => $model,
'messages' => $messages,
'temperature' => isset( $args['temperature'] ) ? (float) $args['temperature'] : 0.7,
'max_tokens' => 1024,
];
if ( ! empty( $args['response_format'] ) ) {
$request_body['response_format'] = $args['response_format'];
}
$response = wp_remote_post(
$this->get_endpoint(),
[
'headers' => [
'Authorization' => 'Bearer ' . $api_key,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode( $request_body ),
'timeout' => isset( $args['timeout'] ) ? (int) $args['timeout'] : 60,
]
);
if ( is_wp_error( $response ) ) {
return $response;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( isset( $body['error']['message'] ) ) {
return new WP_Error( 'groq_ai_provider_error', (string) $body['error']['message'] );
}
if ( empty( $body['choices'][0]['message']['content'] ) ) {
return new WP_Error(
'groq_ai_empty_response',
sprintf( __( 'Geen antwoord ontvangen van %s.', 'groq-ai-product-text' ), $this->get_label() )
);
}
$content = trim( $body['choices'][0]['message']['content'] );
$usage = isset( $body['usage'] ) && is_array( $body['usage'] ) ? $body['usage'] : [];
return [
'content' => $content,
'usage' => $usage,
'raw_response' => $body,
];
}
abstract protected function get_endpoint();
abstract protected function get_models_endpoint();
protected function get_api_key( $settings ) {
$field = $this->get_option_key();
return isset( $settings[ $field ] ) ? $settings[ $field ] : '';
}
}

View File

@@ -0,0 +1,158 @@
<?php
class Groq_AI_Provider_Google implements Groq_AI_Provider_Interface {
public function get_key() {
return 'google';
}
public function get_label() {
return __( 'Google AI (Gemini)', 'groq-ai-product-text' );
}
public function get_default_model() {
return 'gemini-1.5-flash';
}
public function get_available_models() {
return [
'gemini-1.5-flash',
'gemini-1.5-pro',
'gemini-pro',
];
}
public function get_option_key() {
return 'google_api_key';
}
public function supports_live_models() {
return true;
}
public function supports_response_format() {
return false;
}
public function fetch_live_models( $api_key ) {
$endpoint = add_query_arg(
[ 'key' => $api_key, 'pageSize' => 100 ],
'https://generativelanguage.googleapis.com/v1beta/models'
);
$response = wp_remote_get(
$endpoint,
[
'timeout' => 20,
]
);
if ( is_wp_error( $response ) ) {
return $response;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( isset( $body['error']['message'] ) ) {
return new WP_Error( 'groq_ai_provider_error', (string) $body['error']['message'] );
}
if ( empty( $body['models'] ) || ! is_array( $body['models'] ) ) {
return new WP_Error( 'groq_ai_empty_response', __( 'Geen modeldata ontvangen.', 'groq-ai-product-text' ) );
}
$models = [];
foreach ( $body['models'] as $model ) {
if ( ! empty( $model['name'] ) ) {
$parts = explode( '/', $model['name'] );
$models[] = sanitize_text_field( end( $parts ) );
}
}
if ( empty( $models ) ) {
return new WP_Error( 'groq_ai_empty_response', __( 'Geen modeldata ontvangen.', 'groq-ai-product-text' ) );
}
return $models;
}
public function generate_content( array $args ) {
$settings = isset( $args['settings'] ) ? (array) $args['settings'] : [];
$prompt = isset( $args['prompt'] ) ? $args['prompt'] : '';
$system_prompt = isset( $args['system_prompt'] ) ? $args['system_prompt'] : '';
$model = ! empty( $args['model'] ) ? $args['model'] : $this->get_default_model();
$api_key = isset( $settings[ $this->get_option_key() ] ) ? $settings[ $this->get_option_key() ] : '';
if ( empty( $api_key ) ) {
return new WP_Error( 'groq_ai_missing_api_key', sprintf( __( 'Stel eerst de API-sleutel voor %s in.', 'groq-ai-product-text' ), $this->get_label() ) );
}
$endpoint = add_query_arg(
'key',
$api_key,
sprintf( 'https://generativelanguage.googleapis.com/v1beta/models/%s:generateContent', rawurlencode( $model ) )
);
$payload = [
'contents' => [
[
'role' => 'user',
'parts' => [
[
'text' => $system_prompt . "\n\n" . $prompt,
],
],
],
],
'generationConfig' => [
'temperature' => isset( $args['temperature'] ) ? (float) $args['temperature'] : 0.7,
'maxOutputTokens' => 1024,
],
];
$response = wp_remote_post(
$endpoint,
[
'headers' => [
'Content-Type' => 'application/json',
],
'body' => wp_json_encode( $payload ),
'timeout' => isset( $args['timeout'] ) ? (int) $args['timeout'] : 60,
]
);
if ( is_wp_error( $response ) ) {
return $response;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( isset( $body['error']['message'] ) ) {
return new WP_Error( 'groq_ai_provider_error', (string) $body['error']['message'] );
}
if ( empty( $body['candidates'][0]['content']['parts'] ) ) {
return new WP_Error(
'groq_ai_empty_response',
sprintf( __( 'Geen antwoord ontvangen van %s.', 'groq-ai-product-text' ), $this->get_label() )
);
}
$parts = $body['candidates'][0]['content']['parts'];
$texts = [];
foreach ( $parts as $part ) {
if ( isset( $part['text'] ) ) {
$texts[] = $part['text'];
}
}
$content = trim( implode( "\n\n", array_filter( $texts ) ) );
$usage = isset( $body['usageMetadata'] ) && is_array( $body['usageMetadata'] ) ? $body['usageMetadata'] : [];
return [
'content' => $content,
'usage' => $usage,
'raw_response' => $body,
];
}
}

View File

@@ -0,0 +1,36 @@
<?php
class Groq_AI_Provider_Groq extends Groq_AI_Abstract_OpenAI_Provider {
public function get_key() {
return 'groq';
}
public function get_label() {
return __( 'Groq', 'groq-ai-product-text' );
}
public function get_default_model() {
return 'llama3-70b-8192';
}
public function get_available_models() {
return [
'llama3-70b-8192',
'llama3-8b-8192',
'mixtral-8x7b-32768',
'gemma-7b-it',
];
}
public function get_option_key() {
return 'groq_api_key';
}
protected function get_endpoint() {
return 'https://api.groq.com/openai/v1/chat/completions';
}
protected function get_models_endpoint() {
return 'https://api.groq.com/openai/v1/models';
}
}

View File

@@ -0,0 +1,24 @@
<?php
class Groq_AI_Provider_Manager {
/** @var Groq_AI_Provider_Interface[] */
private $providers = [];
public function __construct() {
$this->register_provider( new Groq_AI_Provider_Groq() );
$this->register_provider( new Groq_AI_Provider_OpenAI() );
$this->register_provider( new Groq_AI_Provider_Google() );
}
public function register_provider( Groq_AI_Provider_Interface $provider ) {
$this->providers[ $provider->get_key() ] = $provider;
}
public function get_providers() {
return $this->providers;
}
public function get_provider( $key ) {
return isset( $this->providers[ $key ] ) ? $this->providers[ $key ] : null;
}
}

View File

@@ -0,0 +1,36 @@
<?php
class Groq_AI_Provider_OpenAI extends Groq_AI_Abstract_OpenAI_Provider {
public function get_key() {
return 'openai';
}
public function get_label() {
return __( 'OpenAI', 'groq-ai-product-text' );
}
public function get_default_model() {
return 'gpt-4o-mini';
}
public function get_available_models() {
return [
'gpt-4o',
'gpt-4o-mini',
'gpt-4.1-mini',
'gpt-3.5-turbo',
];
}
public function get_option_key() {
return 'openai_api_key';
}
protected function get_endpoint() {
return 'https://api.openai.com/v1/chat/completions';
}
protected function get_models_endpoint() {
return 'https://api.openai.com/v1/models';
}
}