My goal this morning was to see if I could tie in the OpenAI API for a project where I uploaded images to WordPress and it automatically extracted the text from the image. Since I’ve been using the OpenAI API previously and had a decent amount of success with text extraction, I went ahead and tried that.
API Connection
The way I tend to do things is to break them into pieces. My first goal was to see if I could easily get a PHP connection to the API. Keeping it outside WP for now and avoiding the image lets me make sure that part works before moving on. PHP also lets me avoid some of the issues I get confused about in javascript with the security of API keys. I may have things I don’t understand with PHP as well but at least I feel better.
<?php
$apiKey = 'ye-old-api-key-goes-here';
$ch = curl_init('https://api.openai.com/v1/chat/completions');
$data = [
'model' => 'gpt-4',
'messages' => [
['role' => 'system', 'content' => 'You are an assistant who keeps things brief and direct.'],
['role' => 'user', 'content' => 'What time is it?']
],
'temperature' => 0.7
];
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey,
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Request Error: ' . curl_error($ch);
} else {
$responseData = json_decode($response, true);
echo $responseData['choices'][0]['message']['content'];
}
curl_close($ch);
Now for the image
Not a whole lot of difference to connect in the image.
<?php
$apiKey = 'ye-old-api-key-goes-here';
$ch = curl_init('https://api.openai.com/v1/chat/completions');
$imagePath = 'example.jpeg'; // Local file path of the image - I could probably do it via URL as well but this felt more certain
// Read and base64-encode the image
$imageData = base64_encode(file_get_contents($imagePath));
$base64Url = 'data:image/jpeg;base64,' . $imageData;
$data = [
'model' => 'gpt-4o',
'messages' => [
[
"role" => "user",
"content" => [
[
"type" => "image_url",
"image_url" => [
"url" => $base64Url
]
],
[
"type" => "text",
"text" => "Extract the text from this image."
]
]
]
],
//'temperature' => 0.7
"max_tokens" => 900
];
// Initialize curl
$ch = curl_init('https://api.openai.com/v1/chat/completions');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
// Send request and get response
$response = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error: ' . curl_error($ch);
} else {
$responseData = json_decode($response, true);
echo $responseData['choices'][0]['message']['content'];
}
curl_close($ch);
Put it in WordPress
Now I need to get it tied into WordPress and set it to run in certain scenarios. For now, a plugin seemed most sensible and I opted to run it on image upload. add_attachment was the hook I used and it should run every time anything is attached.
This is the WP portion.
add_action('add_attachment', 'dlinq_openai_image_handler');
function dlinq_openai_image_handler($post_ID) {
$mime = get_post_mime_type($post_ID);
if (strpos($mime, 'image/') === 0) {
// Tis' an image
$imagePath = get_attached_file($post_ID);
$text = dlinq_openai_ai_text_extractor($imagePath);
update_post_meta($post_ID, '_wp_attachment_image_alt', $text);//write it to the alt text area
}
}
Now we tweak the OpenAI portion a tiny bit and make it accessible as a function.
function dlinq_openai_ai_text_extractor($imagePath){
$apiKey = 'ye-old-api-key-goes-here';
$ch = curl_init("https://api.openai.com/v1/chat/completions");
// Read and base64-encode the image
$imageData = base64_encode(file_get_contents($imagePath));
$base64Url = 'data:image/jpeg;base64,' . $imageData;
$data = [
"model" => "gpt-4o",
"messages" => [
//['role' => 'system', 'content' => 'You are a helpful assistant.'],
[
"role" => "user",
"content" => [
[
"type" => "image_url",
"image_url" => [
"url" => $base64Url
]
],
[
"type" => "text",
"text" => "Extract the text from this image."
]
]
]
],
//'temperature' => 0.7
"max_tokens" => 1500
];
// Initialize curl
$ch = curl_init("https://api.openai.com/v1/chat/completions");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
// Send request and get response
$response = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error: ' . curl_error($ch);
} else {
$responseData = json_decode($response, true);
return $responseData['choices'][0]['message']['content'];
}
curl_close($ch);
}
How’s it going?
I’ve run it a number of times now. It takes a little while to generate the text. Nothing crazy but it’s not instant. I’ve got a limit on the number of tokens (1500) that it can use at a time because I wasn’t sure how much this would cost. It’s looking like it’s pretty low. I’ve run 8 or so images with varying amounts of text through and the total cost today is 4 cents. I might try some other APIs. I really want to try Transkribus.
I also think it might be better to put the extracted text elsewhere to make it easier to verify it against the image. I can think of some nice workflows that would then give you the option to include it as alt text or do something else.
I’ve also been talking to Jim about his AI Madeness project and this type of integration could be crazy. I knew it’d be possible but I didn’t realize it’d be this easy. Now we could throw in some basic info into some ACF field in WP and generate a coverage post. That post could then trigger a set of personas to comment on the post and against each other. Throw in some randomization of who talks to who, etc. etc. and you’ve got a large amount of crazy stuff going on automatically that could also interact with actual commenters. It’s both inviting in the insanity and terrible in how it will be used by all the bad people.
I fucking love it! You’re a genius. I am sure am glad one of left nonprogrammustan!