Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the basic structure for src/ #1

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"php": "^8.2",
"league/commonmark": "^2.4",
"orhanerday/open-ai": "^5.0",
"vlucas/phpdotenv": "^5.6"
"vlucas/phpdotenv": "^5.6",
"ext-curl": "*"
},
"autoload": {
"psr-4": {
Expand Down
61 changes: 40 additions & 21 deletions examples/core_example1/index.php
Original file line number Diff line number Diff line change
@@ -1,40 +1,59 @@
<?php

declare(strict_types=1);
require_once ('../../vendor/autoload.php');

$prompt = 'What is life';
use Jjr\RobustChat\Client;
use Jjr\RobustChat\Configuration;
use Jjr\RobustChat\Providers\OpenAIServiceProvider;
use Jjr\RobustChat\Utils\OpenAI\CustomCurlClient;
use Orhanerday\OpenAi\OpenAi;

require_once ('../../vendor/autoload.php');

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__.'/../../');
$dotenv->load();

// Set the API configuration for the AI service provider
$configuration = new Configuration($_ENV['OPEN_AI_KEY'], $_ENV['OPEN_AI_KEY_FOR_ORGANIZATION']);

/** See https://github.com/orhanerday/open-ai
* Note: This client is different than https://github.com/openai-php/client
*/
// init the API client (consider the dependency injection)
$apiClient = new OpenAi($configuration->getApiKey());
$apiClient = new CustomCurlClient(configuration: $configuration);

$open_ai = new Orhanerday\OpenAi\OpenAi($_ENV['OPEN_AI_KEY']); // <-- INPUT
$open_ai->setORG($_ENV['OPEN_AI_KEY_FOR_ORGANIZATION']); // <-- INPUT
// Create an instance of the AI service provider
$provider = new OpenAIServiceProvider($configuration, $apiClient);

// Create a client instance with the AI service provider
$client = new Client($provider);

$prompt = 'What is life';

// Prepare the messages for the AI service
$messages = [
...[], //<-- Following the pattern below, you would put previous messages here
...[], // <-- Following the pattern below, you would put previous messages here
[
'role' => 'user', // Ai_AbstractBase::SNUM_ROLE_user
'content' => $prompt // <-- INPUT. This is the question we are asking open AI
'role' => 'user', // Ai_AbstractBase::SNUM_ROLE_user
'content' => $prompt, // <-- INPUT. This is the question we are asking open AI
]];

$opts = [
'messages' => $messages,
'temperature' => 0.9,
"max_tokens" => 150,
"frequency_penalty" => 0,
"presence_penalty" => 0.6,
"stream" => false,
'model' => 'gpt-3.5-turbo',// This is the openAi model we want it to use
// Set options for the AI service request
$options = [
'messages' => $messages,
'temperature' => 0.9,
'max_tokens' => 150,
'frequency_penalty' => 0,
'presence_penalty' => 0.6,
'stream' => false,
'model' => 'gpt-3.5-turbo', // This is the openAi model we want it to use
];
$response_asJson = $open_ai->chat($opts);
$response = json_decode($response_asJson);

// Generate a response from the AI service
$response = $client->generateResponse($prompt, $options);

// Extract the answer from the response
$answer = $response->getRawResponseData()->choices[0]->message->content;

$answer = $response->choices[0]->message->content;
// Print the prompt and answer
print <<<html
Prompt: $prompt
<br>
Expand Down
81 changes: 81 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

declare(strict_types=1);

namespace Jjr\RobustChat;

use Jjr\RobustChat\Contracts\ServiceProviderInterface;
use Jjr\RobustChat\DTO\Response\Response;

/**
* Client class for interacting with AI service providers.
*/
class Client
{
/**
* The AI service provider instance.
*
* @var \Jjr\RobustChat\Contracts\ServiceProviderInterface
*/
protected ServiceProviderInterface $provider;

/**
* Client constructor.
*
* @param \Jjr\RobustChat\Contracts\ServiceProviderInterface $provider The AI service provider instance.
*/
public function __construct(ServiceProviderInterface $provider)
{
$this->provider = $provider;
}

/**
* Set the AI service provider instance.
*
* @param \Jjr\RobustChat\Contracts\ServiceProviderInterface $provider The AI service provider instance.
* @return void
*/
public function setProvider(ServiceProviderInterface $provider): void
{
$this->provider = $provider;
}

/**
* Generate a response using the AI service provider.
*
* @param string $input The input text or data for generating the response.
* @param array $options Additional options for the request.
* @return \Jjr\RobustChat\DTO\Response\Response The generated response.
* @throws \Jjr\RobustChat\Exceptions\AIException If an error occurs during the request.
*/
public function generateResponse(string $input, array $options = []): Response
{
return $this->provider->generateResponse($input, $options);
}

/**
* Classify text using the AI service provider.
*
* @param string $text The text to classify.
* @param array $options Additional options for the request.
* @return \Jjr\RobustChat\DTO\Response\Response The classification result.
* @throws \Jjr\RobustChat\Exceptions\AIException If an error occurs during the request.
*/
public function classifyText(string $text, array $options = []): Response
{
return $this->provider->classifyText($text, $options);
}

/**
* Get a completion for the given prompt using the AI service provider.
*
* @param string $prompt The prompt for which to generate a completion.
* @param array $options Additional options for the request.
* @return \Jjr\RobustChat\DTO\Response\Response The generated completion.
* @throws \Jjr\RobustChat\Exceptions\AIException If an error occurs during the request.
*/
public function getCompletion(string $prompt, array $options = []): Response
{
return $this->provider->getCompletion($prompt, $options);
}
}
38 changes: 38 additions & 0 deletions src/Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace Jjr\RobustChat;

/**
* Configuration class for the AI service provider.
*/
readonly class Configuration
{
public function __construct(
protected ?string $apiKey = null,
protected ?string $apiKeyForOrganization = null,
)
{
}

/**
* Get the API key for organization for the AI service provider.
*
* @return string|null The API key.
*/
public function getApiKeyForOrganization(): ?string
{
return $this->apiKeyForOrganization;
}

/**
* Get the API key for the AI service provider.
*
* @return string|null The API key.
*/
public function getApiKey(): ?string
{
return $this->apiKey;
}
}
43 changes: 43 additions & 0 deletions src/Contracts/ServiceProviderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace Jjr\RobustChat\Contracts;

use Jjr\RobustChat\DTO\Response\Response;

/**
* Interface defining methods for interacting with AI service providers.
*/
interface ServiceProviderInterface
{
/**
* Generate a response from the AI service provider.
*
* @param string $input The input text or data for generating the response.
* @param array $options Additional options for the request (e.g., parameters for the AI model).
* @return \Jjr\RobustChat\DTO\Response\Response The generated response from the AI service.
* @throws \Jjr\RobustChat\Exceptions\AIException If an error occurs during the request.
*/
public function generateResponse(string $input, array $options = []): Response;

/**
* Classify text using the AI service provider.
*
* @param string $text The text to classify.
* @param array $options Additional options for the request (e.g., parameters for the classification model).
* @return Response The classification result.
* @throws \Jjr\RobustChat\Exceptions\AIException If an error occurs during the request.
*/
public function classifyText(string $text, array $options = []): Response;

/**
* Get a completion for the given prompt using the AI service provider.
*
* @param string $prompt The prompt for which to generate a completion.
* @param array $options Additional options for the request (e.g., parameters for the AI model).
* @return Response The generated completion.
* @throws \Jjr\RobustChat\Exceptions\AIException If an error occurs during the request.
*/
public function getCompletion(string $prompt, array $options = []): Response;
}
9 changes: 9 additions & 0 deletions src/DTO/Response/OpenAIResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace Jjr\RobustChat\DTO\Response;

class OpenAIResponse extends Response
{
}
20 changes: 20 additions & 0 deletions src/DTO/Response/Response.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Jjr\RobustChat\DTO\Response;

class Response
{
public function __construct(protected readonly ?object $rawResponseData = null)
{
}

/**
* @return object|null
*/
public function getRawResponseData(): ?object
{
return $this->rawResponseData;
}
}
33 changes: 33 additions & 0 deletions src/Exceptions/AIException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Jjr\RobustChat\Exceptions;

use Exception;

/**
* Exception class for AI service provider errors.
*/
class AIException extends Exception
{
/**
* AIException constructor.
*
* @inheritdoc
*/
public function __construct($message = "", $code = 0, Exception $previous = null)
{
parent::__construct($message, $code, $previous);
}

/**
* Get a string representation of the exception.
*
* @inheritdoc
*/
public function __toString(): string
{
return __CLASS__ . ": [$this->code]: $this->message\n";
}
}
12 changes: 12 additions & 0 deletions src/Exceptions/OpenAIException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Jjr\RobustChat\Exceptions;

/**
* Exception class for OpenAI service errors.
*/
class OpenAIException extends AIException
{
}
33 changes: 33 additions & 0 deletions src/Providers/AbstractServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Jjr\RobustChat\Providers;

use Jjr\RobustChat\Configuration;
use Jjr\RobustChat\Contracts\ServiceProviderInterface;
use Jjr\RobustChat\DTO\Response\Response;

/**
* Abstract class implementing common functionality for AI service providers.
*/
abstract class AbstractServiceProvider implements ServiceProviderInterface
{
/**
* AbstractServiceProvider constructor.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aghorianducalis In general, I'd like avoid a comment like this because it is clear from the function __construct about it's main role.
Just add a comment when it clarifies what is happening, or is a note to other devs about the state of the code

*
* @param Configuration $configuration The API configuration for the AI service provider.
*/
public function __construct(
protected readonly Configuration $configuration,
protected $apiClient
)
{
}

abstract public function generateResponse(string $input, array $options = []): Response;

abstract public function classifyText(string $text, array $options = []): Response;

abstract public function getCompletion(string $prompt, array $options = []): Response;
}
Loading