FastMovieAI 二开基线 v1.0 (完整源码)

This commit is contained in:
李建琦
2026-08-26 18:41:02 +08:00
parent fad7690c0c
commit d54584f70d
888 changed files with 105571 additions and 1 deletions
@@ -0,0 +1,43 @@
<?php
namespace plugin\control\utils;
class LRUCache
{
private int $capacity;
private array $cache = [];
private array $order = [];
public function __construct($capacity = 2000)
{
$this->capacity = $capacity;
}
public function get($key)
{
if (!isset($this->cache[$key])) {
return null;
}
unset($this->order[$key]);
$this->order[$key] = true;
return $this->cache[$key];
}
public function set($key, $value)
{
if (isset($this->cache[$key])) {
$this->cache[$key] = $value;
unset($this->order[$key]);
$this->order[$key] = true;
return;
}
if (count($this->cache) >= $this->capacity) {
$oldestKey = array_key_first($this->order);
unset($this->cache[$oldestKey], $this->order[$oldestKey]);
}
$this->cache[$key] = $value;
$this->order[$key] = true;
}
}
@@ -0,0 +1,97 @@
<?php
namespace plugin\control\utils\yidevs;
use app\expose\helper\Config;
use GuzzleHttp\Client as GuzzleHttpClient;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\RequestException;
use plugin\control\utils\yidevs\stream\Client as StreamClient;
use plugin\control\utils\yidevs\Exception\InvalidResultException;
use plugin\control\utils\yidevs\Exception\InvalidTokenException;
use support\Log;
class Client
{
protected $token;
// protected $domain = 'https://api.yidevs.com';
protected $domain = 'http://110.42.56.227:36999';
protected $HttpClient;
protected $channels_uid;
public function __construct()
{
if ($domain = getenv('YIDEVS_DOMAIN')) {
$this->domain = $domain;
}
}
public function setChannelsUid(int $channels_uid)
{
$this->channels_uid = $channels_uid;
$config = new Config('yidevs', 'control', $channels_uid);
if (!$config->token) {
throw new InvalidTokenException('YIDEVS_TOKEN is not set for channels_uid: ' . $channels_uid);
}
$this->token = $config->token;
}
public function client()
{
$this->HttpClient = new GuzzleHttpClient([
'base_uri' => $this->domain,
'timeout' => 600,
'verify' => false,
'proxy' => false
]);
}
public function request(string $method, string $url, array $options = [])
{
try {
$this->client();
$response = $this->HttpClient->request($method, $url, array_merge([
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $this->token,
]
], $options));
$res = $response->getBody()->getContents();
} catch (ClientException | RequestException $e) {
Log::error($e->getMessage() . PHP_EOL . $e->getTraceAsString());
throw new \Exception($e->getMessage());
} catch (\Throwable $th) {
Log::error($th->getMessage() . PHP_EOL . $th->getTraceAsString());
throw new \Exception($th->getMessage());
}
return $res;
}
public function stream(string $url, array $data = [], ?callable $stream = null)
{
return new StreamClient($this->token, $this->domain . '/' . $url, $data, $stream);
}
public function get(string $url, array $query = [])
{
$res = $this->request('GET', $url, ['query' => $query]);
$result = json_decode($res, true);
if (!isset($result['code'])) {
throw new InvalidResultException($res);
}
if ($result['code'] != 200) {
throw new \Exception($result['msg']);
}
return $result['data'];
}
public function post(string $url, array $data = [], ?callable $stream = null)
{
if ($stream) {
return new StreamClient($this->token, $this->domain . '/' . $url, $data, $stream);
}
$res = $this->request('POST', $url, ['json' => $data]);
$result = json_decode($res, true);
if (!isset($result['code'])) {
throw new InvalidResultException($res);
}
if ($result['code'] != 200) {
throw new \Exception($result['msg']);
}
return $result['data'];
}
}
@@ -0,0 +1,7 @@
<?php
namespace plugin\control\utils\yidevs\Exception;
class HttpCurlException extends \Exception
{
}
@@ -0,0 +1,7 @@
<?php
namespace plugin\control\utils\yidevs\Exception;
class InvalidResultException extends \Exception
{
}
@@ -0,0 +1,7 @@
<?php
namespace plugin\control\utils\yidevs\Exception;
class InvalidTokenException extends \Exception
{
}
@@ -0,0 +1,17 @@
<?php
namespace plugin\control\utils\yidevs;
use plugin\control\utils\yidevs\trait\Audio;
use plugin\control\utils\yidevs\trait\AudioAssistant;
use plugin\control\utils\yidevs\trait\Chat;
use plugin\control\utils\yidevs\trait\ChatAssistant;
use plugin\control\utils\yidevs\trait\Draw;
use plugin\control\utils\yidevs\trait\DrawAssistant;
use plugin\control\utils\yidevs\trait\Video;
use plugin\control\utils\yidevs\trait\VideoAssistant;
class Yidevs
{
use Chat, ChatAssistant, Draw, DrawAssistant, Video, VideoAssistant, Audio, AudioAssistant;
}
@@ -0,0 +1,121 @@
<?php
namespace plugin\control\utils\yidevs\stream;
use plugin\control\utils\yidevs\Exception\HttpCurlException;
use support\Log;
class Client
{
protected $streamFunction;
public function __construct(string $token, string $url, array $data = [], ?callable $streamFunction = null)
{
try {
$this->streamFunction = $streamFunction;
$data['stream'] = true;
$curl_info = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 600,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
'Content-Type:application/json',
'Accept:application/json',
'Authorization:Bearer ' . $token,
],
CURLOPT_PROXY => false
];
$curl_info[CURLOPT_WRITEFUNCTION] = [$this, 'streamWriteFunction'];
$curl = curl_init();
curl_setopt_array($curl, $curl_info);
$response = curl_exec($curl);
// $info = curl_getinfo($curl);
$error = curl_error($curl);
curl_close($curl);
if (! $response) {
throw new HttpCurlException($error);
}
} catch (\Throwable $th) {
throw $th;
}
}
public function streamWriteFunction($ch, $data)
{
// data 必须是字符串
if (!is_string($data)) {
return strlen($data);
}
try {
// 用户处理
$this->parseResponse($data, function ($line) use ($ch) {
if (is_callable($this->streamFunction)) {
$line = ($this->streamFunction)($ch, $line);
}
if (is_string($line)) {
// 检查 DONE
if ($line === 'DONE') {
throw new \Exception('DONE');
}
} else {
if (isset($line['error'])) {
throw new \Exception('DONE');
}
}
});
} catch (\Throwable $th) {
if ($th->getMessage() !== 'DONE') {
Log::error($th->getMessage() . PHP_EOL . $th->getTraceAsString());
}
}
flush();
// 必须返回 exact byte count
return strlen($data);
}
public function parseResponse($data, callable $callback)
{
// 按换行分割,兼容 \n 和 \r\n
$lines = preg_split("/\r?\n/", $data);
foreach ($lines as $line) {
$line = trim($line);
if ($line === '') {
continue; // 跳过空行
}
// 必须以 data: 开头
if (strpos($line, 'data: ') === 0) {
// 截掉 data: 前缀
$json = trim(substr($line, 6));
} else {
$json = $line;
}
// SSE 结束标记:[DONE]
if ($json === '[DONE]') {
$callback('DONE');
continue;
}
try {
// 尝试解析 JSON
$payload = json_decode($json, true);
if (isset($payload['error'])) {
throw new \Exception("[{$payload['error']['code']}]" . $payload['error']['message']);
}
$line = $payload;
} catch (\Throwable $th) {
}
$callback($line);
}
}
}
@@ -0,0 +1,45 @@
<?php
namespace plugin\control\utils\yidevs\trait;
use plugin\control\utils\yidevs\Client;
trait Audio
{
/**
* 获取壹定开放平台大模型-音频-模型列表
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $data
* @return array
*/
public static function AudioModels(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->get('app/yimind/api/Audio/models', $data);
}
/**
* 调用壹定开放平台大模型-音频-生成
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $data
* @return array
*/
public static function AudioTTS(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->post('app/yimind/api/Audio/tts', $data);
}
public static function AudioVoiceClone(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->post('app/yimind/api/Audio/cloneVoice', $data);
}
public static function AudioVoiceList(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->get('app/yimind/api/Audio/voiceList', $data);
}
}
@@ -0,0 +1,33 @@
<?php
namespace plugin\control\utils\yidevs\trait;
use plugin\control\utils\yidevs\Client;
trait AudioAssistant
{
/**
* 获取壹定开放平台大模型-音频助手列表
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $query
* @return array
*/
public static function AudioAssistantlist(int $channels_uid, array $query = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->get('app/yimind/api/AudioAssistant/list', $query);
}
/**
* 调用壹定开放平台大模型-音频助手
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $data
* @return array
*/
public static function AudioAssistantTTS(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->post('app/yimind/api/AudioAssistant/tts', $data);
}
}
@@ -0,0 +1,37 @@
<?php
namespace plugin\control\utils\yidevs\trait;
use plugin\control\utils\yidevs\Client;
trait Chat
{
/**
* 获取壹定开放平台大模型-模型列表
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $query
* @return array
*/
public static function ChatModels(int $channels_uid, array $query = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->get('app/yimind/api/Chat/models', $query);
}
/**
* 调用壹定开放平台大模型-聊天-对话
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $data
* @param callable|null $stream
* @return mixed
*/
public static function ChatCompletions(int $channels_uid, array $data = [], ?callable $stream = null)
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
if ($stream) {
return $Client->stream('app/yimind/api/Chat/completions', $data, $stream);
}
return $Client->request('POST', 'app/yimind/api/Chat/completions', ['json' => $data]);
}
}
@@ -0,0 +1,33 @@
<?php
namespace plugin\control\utils\yidevs\trait;
use plugin\control\utils\yidevs\Client;
trait ChatAssistant
{
/**
* 获取壹定开放平台大模型-助手列表
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $query
* @return array
*/
public static function ChatAssistantlist(int $channels_uid, array $query = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->get('app/yimind/api/ChatAssistant/list', $query);
}
/**
* 调用壹定开放平台大模型-助手
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $data
* @return array
*/
public static function ChatAssistantCompletions(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->post('app/yimind/api/ChatAssistant/completions', $data);
}
}
@@ -0,0 +1,33 @@
<?php
namespace plugin\control\utils\yidevs\trait;
use plugin\control\utils\yidevs\Client;
trait Draw
{
/**
* 获取壹定开放平台大模型-绘图-模型列表
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $data
* @return array
*/
public static function DrawModels(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->get('app/yimind/api/Draw/models', $data);
}
/**
* 调用壹定开放平台大模型-绘图-生成
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $data
* @return array
*/
public static function DrawTIGI(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->post('app/yimind/api/Draw/tigi', $data);
}
}
@@ -0,0 +1,33 @@
<?php
namespace plugin\control\utils\yidevs\trait;
use plugin\control\utils\yidevs\Client;
trait DrawAssistant
{
/**
* 获取壹定开放平台大模型-绘图助手列表
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $query
* @return array
*/
public static function DrawAssistantlist(int $channels_uid, array $query = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->get('app/yimind/api/DrawAssistant/list', $query);
}
/**
* 调用壹定开放平台大模型-绘图助手
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $data
* @return array
*/
public static function DrawAssistantTIGI(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->post('app/yimind/api/DrawAssistant/tigi', $data);
}
}
@@ -0,0 +1,33 @@
<?php
namespace plugin\control\utils\yidevs\trait;
use plugin\control\utils\yidevs\Client;
trait Video
{
/**
* 获取壹定开放平台大模型-视频-模型列表
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $data
* @return array
*/
public static function VideoModels(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->get('app/yimind/api/Video/models', $data);
}
/**
* 调用壹定开放平台大模型-视频-生成
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $data
* @return array
*/
public static function VideoTITV(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->post('app/yimind/api/Video/titv', $data);
}
}
@@ -0,0 +1,33 @@
<?php
namespace plugin\control\utils\yidevs\trait;
use plugin\control\utils\yidevs\Client;
trait VideoAssistant
{
/**
* 获取壹定开放平台大模型-绘图助手列表
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $query
* @return array
*/
public static function VideoAssistantlist(int $channels_uid, array $query = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->get('app/yimind/api/VideoAssistant/list', $query);
}
/**
* 调用壹定开放平台大模型-绘图助手
* @param int $channels_uid 分站使用$request->uid,客户端使用$request->channels_uid
* @param array $data
* @return array
*/
public static function VideoAssistantTITV(int $channels_uid, array $data = [])
{
$Client = new Client();
$Client->setChannelsUid($channels_uid);
return $Client->post('app/yimind/api/VideoAssistant/titv', $data);
}
}