-
Notifications
You must be signed in to change notification settings - Fork 0
Adding a Custom AI Provider
If your model is behind an API that is not OpenAI-shaped, you can add a provider. It is a small class and two registrations.
Before you start: if the API is OpenAI-shaped, you do not need this. Point the OpenAI-compatible provider at your endpoint instead.
A provider does one thing: turn your configuration into a single HTTP call and hand back the raw assistant text. That is the whole job.
It does not build the prompt, parse the model's JSON, validate fields, or sanitise anything. All of that belongs to AI_FQ_Question_Generator, and duplicating it in a provider is how the two drift apart.
interface AI_FQ_Provider_Interface {
public function generate_question();
}Return either a normalised question array or a WP_Error. Never a raw string, never false or null.
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class AI_FQ_Example_Provider implements AI_FQ_Provider_Interface {
public function generate_question() {
$endpoint = trim( get_option( 'ai_fq_example_endpoint', '' ) );
$api_key = defined( 'AI_FQ_EXAMPLE_KEY' )
? trim( AI_FQ_EXAMPLE_KEY )
: trim( get_option( 'ai_fq_example_key', '' ) );
$model = trim( get_option( 'ai_fq_example_model', '' ) );
if ( ! wp_http_validate_url( $endpoint ) || empty( $api_key ) || empty( $model ) ) {
return new WP_Error(
'ai_fq_example_config',
__( 'The Example configuration is invalid.', 'ai-fun-questions' )
);
}
// Start from the shared body; change only what your API needs.
$body = AI_FQ_Question_Generator::request_body( $model );
$response = wp_remote_post(
$endpoint,
array(
'timeout' => 30,
'redirection' => 2,
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
),
'body' => wp_json_encode( $body ),
)
);
if ( is_wp_error( $response ) ) {
return self::public_error();
}
$code = wp_remote_retrieve_response_code( $response );
$data = json_decode( wp_remote_retrieve_body( $response ), true );
// Adjust this path to your API's response shape.
$content = $data['choices'][0]['message']['content'] ?? '';
if ( $code < 200 || $code >= 300 || '' === $content ) {
return self::public_error();
}
return AI_FQ_Question_Generator::normalize_response( $content );
}
private static function public_error() {
return new WP_Error(
'ai_fq_provider_error',
__( 'The AI service is temporarily unavailable. Please try again.', 'ai-fun-questions' )
);
}
}Save it as includes/providers/class-example.php.
1. Load the file in ai-fun-questions.php, after the interface — the implements clause fatals at parse time otherwise:
require_once AI_FQ_PATH . 'includes/providers/class-example.php';2. Add a case to AI_FQ_Question_Generator::get_provider():
case 'example':
return new AI_FQ_Example_Provider();Note the switch has a default returning the Ollama provider, so an unregistered name silently becomes Ollama rather than erroring. If you register a provider and it behaves like Ollama, check your spelling.
To make it selectable in the admin, add an entry to AI_FQ_Admin::providers() and a settings panel alongside the existing ones.
Return the generator's result verbatim, including its WP_Errors. Do not inspect or rewrite them.
Never return the upstream error to the caller. Provider messages can contain your endpoint or credential. Return the generic error and, if you want detail, log it behind WP_DEBUG.
Read secrets from a constant first, option second. That is what keeps keys out of the database.
Set timeout and redirection. 30 and 2, matching the others.
Treat success as 2xx and non-empty content in one condition. A 200 with an empty body is a failure, not an empty question.
Get the response path right. This is the most common bug when copying an existing provider — OpenAI-compatible and Hugging Face read choices[0].message.content, Ollama reads message.content. Copy a file, forget to change this, and every call silently returns the generic error.
There is no test button. Select your provider, save, and load a page with the shortcode. If it fails, check the browser's Network tab for the REST response code — see Could Not Generate a Question.
Run php -l over any file you change; the repository's docs/testing.md has the full checklist.
Getting started
- Home
- What AI Fun Questions Does
- Installing the Plugin
- The Settings Screen
- Adding the Widget to Your Site
Provider setup
Running it
- Keeping API Keys Out of the Database
- Rate Limits Explained
- Running Behind Cloudflare or a CDN
- What It Costs to Run
Troubleshooting
- Error Messages Reference
- Please Wait Before Requesting Another Question
- Could Not Generate a Question
Privacy and security
Extending