KunWeb/zciyphp/openai.php
2025-05-16 01:00:48 +08:00

221 lines
8.6 KiB
PHP

<?php
/* =================================================================================
* License: GPL-2.0 license
* Author: 众产® https://ciy.cn/code
* Version: 0.1.0
====================================================================================*/
/*
$openai = new openai(''); //初始化
$openai->newsystem(''); //定义系统角色,新对话
$openai->completion(''); //发起对话
*/
namespace ciy;
class openai {
public $id; //扩展数据1
public $obj; //扩展数据2
private $aicfg = array();
public $messages = array();
private $tt = -999; //0 2
private $tp = -999; //0 2
private $fp = -999; //-2 2
private $pp = -999; //-2 2
private $debug = false;
public function __construct($ai) {
if (is_array($ai))
$this->aicfg = $ai;
}
public function debug($debug = true) {
$this->debug = $debug;
}
public function setparam($spstr) {
$sp = getstrparam($spstr, ',');
if (isset($sp['tt']))
$this->tt = (float)$sp['tt'];
if (isset($sp['tp']))
$this->tp = (float)$sp['tp'];
if (isset($sp['fp']))
$this->fp = (float)$sp['fp'];
if (isset($sp['pp']))
$this->pp = (float)$sp['pp'];
}
public function newsystem($msg = null) {
$this->messages = array();
if (!empty($msg))
$this->messages[] = array('role' => 'system', 'content' => $msg);
}
public function completion($prompt, $isjson = false, $funcdatarows = null, $toolcb = null) {
$this->messages[] = array('role' => 'user', 'content' => $prompt);
$tools = null;
if (is_array($funcdatarows)) {
$tools = array();
foreach ($funcdatarows as $funcdatarow) {
$fparam = array();
$paramjson = $funcdatarow['paramjson'];
if ($paramjson[0] == '{')
$fparam = json_decode($paramjson, true);
else {
$fparam = array();
$fparam['type'] = 'object';
$fparam['properties'] = array();
$fparam['required'] = array();
$paramjsons = getstrparam($paramjson, "\n");
foreach ($paramjsons as $key => $val) {
$require = false;
if ($key[0] == '*') {
$key = substr($key, 1);
$require = true;
}
$fparam['properties'][$key] = array();
$fparam['properties'][$key]['type'] = 'string';
$fparam['properties'][$key]['description'] = $val;
if ($require)
$fparam['required'][] = $key;
}
}
$tool = array();
$tool['type'] = 'function';
$tool['function'] = array();
$tool['function']['name'] = 'F' . $funcdatarow['id'];
$tool['function']['description'] = $funcdatarow['descs'];
$tool['function']['parameters'] = $fparam;
$tools[] = $tool;
}
}
while (true) {
$data = array();
$data['model'] = $this->aicfg['model'];
$data['messages'] = $this->messages;
if ($tools)
$data['tools'] = $tools;
if ($this->aicfg['maxtoken'] > 0)
$data['max_tokens'] = $this->aicfg['maxtoken'];
if ($this->fp > -999)
$data['frequency_penalty'] = $this->fp;
if ($this->pp > -999)
$data['presence_penalty'] = $this->pp;
if ($this->tt > -999)
$data['temperature'] = $this->tt;
if ($this->tp > -999)
$data['top_p'] = $this->tp;
if ($isjson)
$data['response_format'] = array('type' => 'json_object');
if ($this->debug) {
savelogfile('openai', $this->aicfg['baseurl']);
savelogfile('openai', json_encode($data, JSON_UNESCAPED_UNICODE));
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->aicfg['baseurl'] . '/chat/completions');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->aicfg['aikey']
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$response = curl_exec($ch);
if ($this->debug) {
savelogfile('openai', '--------------------------------');
savelogfile('openai', $response);
savelogfile('openai', '');
}
curl_close($ch);
if ($response === false) {
curl_close($ch);
return 'ERR: ' . curl_error($ch) . ' (' . curl_errno($ch) . ')';
}
$json = json_decode($response, true);
if (isset($json['error_msg']))
return 'ERR: ' . $json['error_msg'];
if (isset($json['error']))
return 'ERR: ' . $json['error']['message'];
if (!isset($json['choices']))
return 'ERR: no choices.' . $response;
$finish = $json['choices'][0]['finish_reason'];
$message = $json['choices'][0]['message'];
$this->messages[] = $message;
if ($finish == 'tool_calls') {
foreach ($message['tool_calls'] as $tool_call) {
$result = $toolcb($tool_call['function']);
if (!is_string($result))
$result = json_encode($result, JSON_UNESCAPED_UNICODE);
else if (substr($result, 0, 3) == 'ERR')
return $result;
$this->messages[] = array(
"tool_call_id" => $tool_call['id'],
"role" => "tool",
"name" => $tool_call['function']['name'],
"content" => $result
);
}
continue;
}
if (!$isjson) {
$message['finish_reason'] = $finish;
return $message;
}
$content = $message['content'];
$ind = strpos($content, '```json');
if ($ind !== false) {
$ind2 = strpos($content, '```', $ind + 7);
if ($ind2 !== false)
$content = substr($content, $ind + 7, $ind2 - $ind - 7);
}
$json = json_decode($content, true);
if ($json === null)
return 'ERR: json decode error.' . $content;
return $json;
}
}
public function chat($messages, $cb) {
$this->messages = $messages;
$data = [
'model' => $this->aicfg['model'],
'messages' => $this->messages,
'stream' => true,
];
if ($this->aicfg['maxtoken'] > 0)
$data['max_tokens'] = $this->aicfg['maxtoken'];
if ($this->fp > -999)
$data['frequency_penalty'] = $this->fp;
if ($this->pp > -999)
$data['presence_penalty'] = $this->pp;
if ($this->tt > -999)
$data['temperature'] = $this->tt;
if ($this->tp > -999)
$data['top_p'] = $this->tp;
if ($this->debug) {
savelogfile('openai', $this->aicfg['baseurl']);
savelogfile('openai', json_encode($data, JSON_UNESCAPED_UNICODE));
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->aicfg['baseurl'] . '/chat/completions');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->aicfg['aikey']
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $data) use ($cb) {
if ($this->debug) {
savelogfile('openai', substr($data, 6, -2));
}
$cb($data);
return strlen($data);
});
curl_exec($ch);
if (curl_errno($ch))
return '错误: ' . curl_error($ch);
curl_close($ch);
return true;
}
}