Using OpenAI to create a Q&A in Laravel/PHP with embedding

OpenAI isn't just for python!

It took me a while to thoroughly do an embedded OpenAI with PHP/Laravel. Most of the examples are in Python or Js. For the future devs ahead, here's what I learned.

I wanted to integrate our internal knowledge base and create a chat app our team could use to find an answer quickly (this part won't include the actual chat part but the code to start it).

You can start with the Laravel wrapper openai-php/laravel and follow those instructions on setting up your OpenAI API key. If you're not using Laravel, you can use the agnostic library openai-php/client

We'll use the OpenAI model to embed our array into text-embedding-ada-002 to get the vertices of an input array of information, compare it to an input, and then use the completion with text-davinci-003 to output the data. We will compare it with a fundamental cosine similarity in PHP. You should know this should be done on a database level rather than within PHP for a faster and more cost-effective way.

Here are a few questions about the top ten php functions:

vagrant@homestead:~/Code/monitorbase.com$ php artisan temp:open

 What is your question?:
 > get the length of a string

the ada match: strlen(): Returns the length of a string
Make it humanish:  To get the length of a string in PHP, you can use the strlen() function. For example,
        $string = "Hello World";
        echo strlen($string);
        // Outputs 11
vagrant@homestead:~/Code/monitorbase.com$ php artisan temp:open

 What is your question?:
 > how od I know how many records are in an arry?

the ada match: count(): Counts the number of elements in an array or an object
Make it humanish:  You can use the count() function in PHP to determine how many records are in an array. For example, if you have an array, $records, with 10 records, you can use count($records) to get the number of records.

Here's the complete code; I'll explain fully in Part 2.

<?php

namespace App\Console\Commands\Utils;

use Illuminate\Console\Command;
use OpenAI\Laravel\Facades\OpenAI;

class OpenAiExampleOne extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'temp:open';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Example of OpenAI emmbeded in Laravel';

    /**
     * Execute the console command.
     *
     * @return void
     */
    public function handle()
    {
        // The data that we want to train the model on
        // This is what we would insert into the database to be able to
        // run the question on without having to pay for the tokens
        $prompts = $this->getPrompts();

        // Send the prompts to the OpenAI API to get the embeddings
        $inputs = $this->getInputs($prompts);

        // Ask the user a question
        $userQuestion = $this->ask('What is your question?');

        // Get the embedding for the question
        $question = OpenAi::embeddings()->create([
            'model' => 'text-embedding-ada-002',
            'input' => [
                $userQuestion,
            ]
        ]);

        // Take the question and compare it to the prompts
        $answer = $this->getAnswer($prompts, $inputs, $question);
        // Output the answer
        $this->info('the ada match: ' . $prompts[$answer['index']]);
        // Get a prompt to send to the davanci model
        $davanci = "Rewrite the question and give the answer with an example in PHP from the context
        Contect: {$prompts[$answer['index']]}
        Question: {$userQuestion}
        Answer:";
        // Send the prompt to the davanci model
        $result = OpenAI::completions()->create([
            'model' => 'text-davinci-003',
            'prompt' => $davanci,
            'temperature' => 0.9,
            'max_tokens' => 200,
        ]);
        // Output the result
        $this->info("Make it humanish: {$result['choices'][0]['text']}");
    }

    public function getAnswer($prompts, $inputs, $question)
    {
        // loops throuogh all the inputs and compare on a cosine similarity to the question and output the correct answer
        $results = [];
        for ($i = 0; $i < count($inputs->embeddings); $i++) {
            $similarity = $this->cosineSimilarity($inputs->embeddings[$i]->embedding, $question->embeddings[0]->embedding);
            // store the simliarty and index in an array and sort by the similarity
            $results[] = [
                'similarity' => $similarity,
                'index' => $i,
                'input' => $prompts[$i],
            ];
        }
        usort($results, function ($a, $b) {
            return $a['similarity'] <=> $b['similarity'];
        });

        return end($results);
    }

    public function cosineSimilarity($u, $v)
    {
        $dotProduct = 0;
        $uLength = 0;
        $vLength = 0;
        for ($i = 0; $i < count($u); $i++) {
            $dotProduct += $u[$i] * $v[$i];
            $uLength += $u[$i] * $u[$i];
            $vLength += $v[$i] * $v[$i];
        }
        $uLength = sqrt($uLength);
        $vLength = sqrt($vLength);
        return $dotProduct / ($uLength * $vLength);
    }

    public function getInputs($prompts)
    {
        return OpenAi::embeddings()->create([
            'model' => 'text-embedding-ada-002',
            'input' => $prompts,
        ]);
    }

    public function getPrompts()
    {
        return [
            'echo(): Outputs one or more strings',
            'print(): Outputs a string',
            'strlen(): Returns the length of a string',
            'count(): Counts the number of elements in an array or an object',
            'array(): Creates an array',
            'in_array(): Checks if a value exists in an array',
            'is_array(): Checks if a variable is an array',
            'sort(): Sorts an array',
            'strtolower(): Converts a string to lowercase',
            'strtoupper(): Converts a string to uppercase'
        ];
    }
}

Did you find this article valuable?

Support Guy Warner by becoming a sponsor. Any amount is appreciated!