-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
79c8413
commit 65178ca
Showing
37 changed files
with
803 additions
and
90 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,16 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/** | ||
* This file is part of Hyperf. | ||
* | ||
* @link https://www.hyperf.io | ||
* @document https://hyperf.wiki | ||
* @contact [email protected] | ||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE | ||
*/ | ||
|
||
use Hyperf\Odin\Apis\AzureOpenAI\AzureOpenAI; | ||
use Hyperf\Odin\Apis\AzureOpenAI\AzureOpenAIConfig; | ||
use Hyperf\Odin\Apis\AzureOpenAI\Client as AzureOpenAIClient; | ||
|
@@ -8,7 +19,7 @@ | |
use Hyperf\Odin\Apis\OpenAI\OpenAIConfig; | ||
use Hyperf\Odin\Message\SystemMessage; | ||
use Hyperf\Odin\Message\UserMessage; | ||
use function Hyperf\Support\env as env; | ||
use function Hyperf\Support\env; | ||
|
||
! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1)); | ||
|
||
|
@@ -18,34 +29,33 @@ | |
|
||
class LLM | ||
{ | ||
|
||
public string $model = 'gpt-3.5-turbo'; | ||
|
||
public function chat(array $messages, float $temperature = 0.9,): string | ||
public function chat(array $messages, float $temperature = 0.9): string | ||
{ | ||
$client = $this->getAzureOpenAIClient(); | ||
$client->setDebug(false); | ||
return $client->chat($messages, $this->model, $temperature, 3000); | ||
} | ||
|
||
function getOpenAIClient(): OpenAIClient | ||
public function getOpenAIClient(): OpenAIClient | ||
{ | ||
$openAI = new OpenAI(); | ||
$config = new OpenAIConfig(env('OPENAI_API_KEY_FOR_TEST'),); | ||
$config = new OpenAIConfig(env('OPENAI_API_KEY')); | ||
return $openAI->getClient($config); | ||
} | ||
|
||
function getAzureOpenAIClient(): AzureOpenAIClient | ||
public function getAzureOpenAIClient(): AzureOpenAIClient | ||
{ | ||
$openAI = new AzureOpenAI(); | ||
$config = new AzureOpenAIConfig(apiKey: env('AZURE_OPENAI_API_KEY_FOR_TEST'), baseUrl: env('AZURE_OPENAI_HOST'), apiVersion: env('AZURE_OPENAI_API_VERSION'), deploymentName: env('AZURE_OPENAI_DEPLOYMENT_NAME'),); | ||
$config = new AzureOpenAIConfig(apiKey: env('AZURE_OPENAI_API_KEY'), baseUrl: env('AZURE_OPENAI_API_BASE'), apiVersion: env('AZURE_OPENAI_API_VERSION'), deploymentName: env('AZURE_OPENAI_DEPLOYMENT_NAME')); | ||
return $openAI->getClient($config); | ||
} | ||
} | ||
|
||
function chat(string $message): string | ||
{ | ||
$prefixPrompt = <<<PROMPT | ||
$prefixPrompt = <<<'PROMPT' | ||
You are a code generator for a low-code platform. The project uses Hyperf 3.0 framework for code implementation. You need to analyze the process in detail and generate complete and runnable code. The result must be returned according to the required format. | ||
PROMPT; | ||
|
||
|
@@ -58,13 +68,13 @@ function chat(string $message): string | |
return $result; | ||
} | ||
|
||
$userMessage = "我需要设计一个访客管理系统,需要创建一个表单用于满足访客申请的表单,需要收集访客的姓名、手机号码、身份证号码、来访时间、来访的团队名称等基础信息,如果访客有开车过来,还需要提供车牌"; | ||
$userMessage = '我需要设计一个访客管理系统,需要创建一个表单用于满足访客申请的表单,需要收集访客的姓名、手机号码、身份证号码、来访时间、来访的团队名称等基础信息,如果访客有开车过来,还需要提供车牌'; | ||
|
||
/** | ||
* Code structure generation | ||
* Code structure generation. | ||
*/ | ||
$analyse = <<<PROMPT | ||
User Demand:$userMessage | ||
User Demand:{$userMessage} | ||
Requirements: Analyze user needs and design code structure to meet the needs. Code structure should be simple, clear, and without redundancy. Use full namespace for class calls. Code structure must comply with Hyperf 3.0 framework rules. No need to output code or extra line breaks, just output code structure according to format requirements. A request usually includes Controller, Service, Model, Repository, FormRequest. A class should have all methods. | ||
Format: | ||
[ | ||
|
@@ -91,7 +101,6 @@ function chat(string $message): string | |
Result: | ||
PROMPT; | ||
|
||
|
||
$result = chat($analyse); | ||
$structs = json_decode(trim($result), true); | ||
|
||
|
@@ -110,19 +119,18 @@ function chat(string $message): string | |
$paramsText .= "{$param['type']} {$param['name']}, "; | ||
} | ||
$paramsText = rtrim($paramsText, ', '); | ||
$text .= "- {$method['name']}($paramsText): {$method['return_type']} // {$method['desc']}" . PHP_EOL; | ||
$text .= "- {$method['name']}({$paramsText}): {$method['return_type']} // {$method['desc']}" . PHP_EOL; | ||
} | ||
$promptStructs[] = $text; | ||
} | ||
$promptStruct = implode(PHP_EOL, $promptStructs); | ||
|
||
|
||
/** | ||
* Data structure generation | ||
* Data structure generation. | ||
*/ | ||
$dataStruct = ''; | ||
$dataStructPrompt = <<<PROMPT | ||
User requirements: $userMessage | ||
User requirements: {$userMessage} | ||
Requirements: Generate the data structure that meets the user requirements. The data structure should be simple, clear, and without redundancy. Data structure is the key structure to realize user requirements. No extra line breaks, just output data structure according to format requirements. | ||
Format: | ||
DataModelName: | ||
|
@@ -133,7 +141,7 @@ function chat(string $message): string | |
$dataStruct = chat($dataStructPrompt); | ||
|
||
/** | ||
* Code generation | ||
* Code generation. | ||
*/ | ||
$outputDir = BASE_PATH . '/output'; | ||
$codeContext = ''; | ||
|
@@ -142,11 +150,11 @@ function chat(string $message): string | |
continue; | ||
} | ||
$generate = <<<PROMPT | ||
User requirements: $userMessage | ||
User requirements: {$userMessage} | ||
data structure: | ||
$dataStruct | ||
{$dataStruct} | ||
code structure: | ||
$promptStruct | ||
{$promptStruct} | ||
Requirements: Generate runnable detailed PHP code for `{$struct['class']}` class based on code structure and user requirements. Only output code for `{$struct['class']}` class, code structure must comply with Hyperf 3.0 framework rules. Use Camel case for class names, class properties, and method names. Use Snake case for array keys. Implement strong typing. The code implementation must be runnable specific code and must implementation all logic, cannot be omitted, and cannot only have comments, strictly follow the return type. No need for explanations or Note or extra line breaks, just output the code, make sure the code is runnable. | ||
Result: | ||
PROMPT; | ||
|
@@ -167,5 +175,3 @@ function chat(string $message): string | |
$codeContext .= '// Class: ' . $struct['path'] . PHP_EOL; | ||
$codeContext .= $code . PHP_EOL; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
<?php | ||
|
||
use Hyperf\Odin\Apis\AzureOpenAI\AzureOpenAI; | ||
use Hyperf\Odin\Apis\AzureOpenAI\AzureOpenAIConfig; | ||
use Hyperf\Odin\Apis\AzureOpenAI\Client as AzureOpenAIClient; | ||
use Hyperf\Odin\Apis\OpenAI\Client as OpenAIClient; | ||
use Hyperf\Odin\Apis\OpenAI\OpenAI; | ||
use Hyperf\Odin\Apis\OpenAI\OpenAIConfig; | ||
use Hyperf\Odin\Apis\OpenAI\Response\ChatCompletionChoice; | ||
use Hyperf\Odin\Interpreter\CodeRunner; | ||
use Hyperf\Odin\Memory\AbstractMemory; | ||
use Hyperf\Odin\Memory\MessageHistory; | ||
use Hyperf\Odin\Message\AssistantMessage; | ||
use Hyperf\Odin\Message\SystemMessage; | ||
use Hyperf\Odin\Message\UserMessage; | ||
use Hyperf\Odin\Prompt\InterpreterPromptTemplate; | ||
use function Hyperf\Support\env as env; | ||
|
||
! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1)); | ||
|
||
require_once dirname(dirname(__FILE__)) . '/vendor/autoload.php'; | ||
|
||
\Hyperf\Di\ClassLoader::init(); | ||
|
||
class LLM | ||
{ | ||
|
||
public string $model = 'gpt-3.5-turbo'; | ||
protected int $times = 0; | ||
|
||
public function chat(array $messages, float $temperature = 0.9, array $functions = []): string | ||
{ | ||
$client = $this->getAzureOpenAIClient(); | ||
$client->setDebug(false); | ||
$response = $client->chat($messages, $this->model, $temperature, 3000, [], $functions); | ||
$choice = $response->getChoices()[0]; | ||
try { | ||
if ($choice instanceof ChatCompletionChoice && $choice->isFinishedByFunctionCall()) { | ||
$message = $choice->getMessage(); | ||
if ($message instanceof AssistantMessage) { | ||
echo 'AI: ' . $message->getContent() . PHP_EOL; | ||
$functionCall = $message->getFunctionCall(); | ||
$functionName = $functionCall['name']; | ||
$functionParameters = json_decode($functionCall['arguments'], true); | ||
$functionCallResult = match ($functionName) { | ||
'run_code' => function () use ($functions, $temperature, $messages, $functionParameters) { | ||
if ($this->times > 3) { | ||
return 'No result'; | ||
} | ||
if (! isset($functionParameters['language']) || ! isset($functionParameters['code'])) { | ||
$this->times++; | ||
echo '[DEBUG] Invalid function parameters' . PHP_EOL; | ||
return $this->chat($messages, $temperature, $functions); | ||
} | ||
|
||
$language = $functionParameters['language']; | ||
$code = $functionParameters['code']; | ||
return (new CodeRunner())->runCode($language, $code); | ||
}, | ||
}; | ||
$result = $functionCallResult(); | ||
if (! $result) { | ||
$result = 'No result'; | ||
} | ||
$response = $result; | ||
} | ||
} | ||
} catch (\Throwable $e) { | ||
echo $e->getMessage() . PHP_EOL; | ||
} | ||
return $response; | ||
} | ||
|
||
function getOpenAIClient(): OpenAIClient | ||
{ | ||
$openAI = new OpenAI(); | ||
$config = new OpenAIConfig(env('OPENAI_API_KEY'),); | ||
return $openAI->getClient($config); | ||
} | ||
|
||
function getAzureOpenAIClient(): AzureOpenAIClient | ||
{ | ||
$openAI = new AzureOpenAI(); | ||
$config = new AzureOpenAIConfig(apiKey: env('AZURE_OPENAI_API_KEY'), baseUrl: env('AZURE_OPENAI_API_BASE'), apiVersion: env('AZURE_OPENAI_API_VERSION'), deploymentName: env('AZURE_OPENAI_DEPLOYMENT_NAME'),); | ||
return $openAI->getClient($config); | ||
} | ||
} | ||
|
||
function chat(string $message, AbstractMemory $memory = null, string $conversationId = null): string | ||
{ | ||
$name = get_current_user(); | ||
$os = PHP_OS_FAMILY; | ||
$cwd = getcwd(); | ||
$functions = [ | ||
[ | ||
'name' => 'run_code', | ||
'description' => 'Executes code and returns the output.', | ||
'parameters' => [ | ||
'type' => 'object', | ||
'properties' => [ | ||
'language' => [ | ||
'type' => 'string', | ||
'description' => 'The programming language', | ||
'enum' => [ | ||
'php', | ||
'shell' | ||
] | ||
], | ||
'code' => [ | ||
'type' => 'string', | ||
'description' => 'The code to execute', | ||
], | ||
], | ||
'required' => [ | ||
'language', | ||
'code' | ||
], | ||
], | ||
] | ||
]; | ||
$llm = new LLM(); | ||
if ($memory) { | ||
$message = $memory->buildPrompt($message, $conversationId); | ||
} | ||
$messages = [ | ||
'system' => new SystemMessage((new InterpreterPromptTemplate())->buildSystemPrompt($name, $cwd, $os)), | ||
'user' => new UserMessage($message), | ||
]; | ||
var_dump($messages['user']->getContent()); | ||
$response = $llm->chat($messages, temperature: 0, functions: $functions); | ||
$memory?->addHumanMessage($message, $conversationId); | ||
$memory?->addAIMessage($response, $conversationId); | ||
return $response; | ||
} | ||
|
||
$conversionId = uniqid(); | ||
$memory = new MessageHistory(); | ||
while (true) { | ||
echo 'Human: '; | ||
$input = trim(fgets(STDIN, 1024)); | ||
$response = trim(chat($input, $memory, $conversionId)); | ||
echo 'AI: ' . $response . PHP_EOL; | ||
} |
Oops, something went wrong.