'/chat/completions', 'deepseek-reasoner' => '/chat/completions', 'analysis' => '/v1/image_analysis', 'getToken' => '/api/v0/users/login', 'upload' => '/v1/upload', ]; public function __construct() { set_time_limit(0); $this->apiUrl = ConfigService::make()->getConfigByCode('dk_base_url'); $this->apiKey = ConfigService::make()->getConfigByCode('dk_api_key'); $this->apiName = ConfigService::make()->getConfigByCode('dk_api_name'); $this->chatUrl = ConfigService::make()->getConfigByCode('dk_chat_api_url'); $this->account = ConfigService::make()->getConfigByCode('dk_chat_account'); $this->password = ConfigService::make()->getConfigByCode('dk_chat_password'); } /** * 静态入口 * @return static|null */ public static function make() { if (!self::$instance) { self::$instance = new static(); } return self::$instance; } /** * AI 分析接口 * @param $params * @param string $model * @return array|false|mixed */ public function apiRequest($params, $model='deepseek-chat') { if(empty($this->apiUrl) || empty($this->apiKey) || empty($this->apiName)){ $this->error = 'AI接口参数未配置'; return false; } $headers = [ 'Content-Type: application/json', 'Accept: application/json', 'Authorization: Bearer ' . $this->apiKey ]; $answer = isset($params['answer'])? $params['answer'] : ''; $correct = isset($params['correct'])? $params['correct'] : ''; $score = isset($params['score'])? $params['score'] : 0; $type = isset($params['type'])? $params['type'] : 1; // 1-模式1,2-模式2 if($type==1){ $content = '你是一个答题高手,请分析两个答案的相似度给出评分,并尝试按 JSON:{"score": 8,"submit_answer":"this is submit answer","analysis":"this is analysis result"}返回'; $message = "请分析正确答案【{$correct}】和提交的答案【{$answer}】的相似度,按总分{$score}以及答题过程和答案匹配度综合给出评分?"; }else if($type==2){ $content = '你是一个答题高手,请分析两个答案的相似度给出评分,并尝试按 JSON:{"score": 8,"submit_answer":"this is submit answer","analysis":"this is analysis result"}返回'; $message = "请分析正确答案【{$correct}】和图片中提交的答案【{$answer}】的相似度,按总分{$score}以及答题过程和答案匹配度综合给出评分?"; }else if($type==3){ $content = '你是一个答题高手,请分析两个答案的相似度给出评分,并尝试按 JSON:{"score": 8,"submit_answer":"this is submit answer","analysis":"this is analysis result"}返回'; $message = "请分析图片中正确答案【{$correct}】和提交的答案【{$answer}】的相似度,按总分{$score}以及答题过程和答案匹配度综合给出评分?"; }else if($type==4){ $content = '你是一个答题高手,请分析两个答案的相似度给出评分,并尝试按 JSON:{"score": 8,"submit_answer":"this is submit answer","analysis":"this is analysis result"}返回'; $message = "请分析图片中正确答案【{$correct}】和图片中提交的答案【{$answer}】的相似度,按总分{$score}以及答题过程和答案匹配度综合给出评分?"; }else{ $content = '你是一个答题高手,请给描述中问题的答案评分,并尝试按 JSON:{"score": 8,"submit_answer":"this is submit answer","analysis":"this is analysis result"}返回'; $message = "请给题目【{$correct}】总分{$score}的答案【{$answer}】评分?"; } $format = 'json_object'; $data = [ 'model'=> $model, 'messages'=> [ [ 'role' => 'system', 'content' => $content ], [ 'role' => 'user', 'content' => $message ], ], 'stream' => false, //false 非流 true//流返回,需要前端追加和保持长连接 'response_format'=>[ 'type'=> $format //返回格式(text,json_object) ], "max_tokens"=>4096, //最大返回token数 ]; $url = $this->apiUrl.$this->apiUrls[$model]; $this->saveLog("caches:dkApi:{$model}:request_1_".date('YmdHis'), ['url'=>$url,'data'=>$data],1); $result = aiRequest($url, json_encode($data), 120, $headers); $result = $result? json_decode(trim($result),true) : []; if(empty($result)){ $this->error = '答案验证失败'; return false; } $this->saveLog("caches:dkApi:{$model}:request_2_".date('YmdHis'), ['url'=>$url,'data'=>$data,'result'=>$result],1); $choices = isset($result['choices'])? $result['choices'] : []; $choiceData = isset($choices[0]['message'])? $choices[0]['message'] : []; $choiceContent = isset($choiceData['content'])? $choiceData['content'] : ''; $content = $choiceContent? str_replace('\n','', $choiceContent) : ''; $content = $content? preg_replace("/^```json/",'', $content) : ''; $content = $content? rtrim($content,'```') : ''; $content = $content? json_decode($content, true) : []; return $content; } public function getChatToken() { if(empty($this->chatUrl) || empty($this->account) || empty($this->password)){ $this->error = 'AI图片接口参数未配置'; return false; } $cacheKey = "caches:dkApi:token_{$this->account}:".md5($this->password); $data = RedisService::get($cacheKey); if($data){ return $data; } $data = [ 'area_code'=>'+86', 'os'=>'web', 'email'=>'', 'device_id'=>'', 'mobile'=> $this->account, 'password'=> $this->password, ]; dump($data); $url = $this->chatUrl.$this->apiUrls['getToken']; dump($url); $result = httpRequest($url, json_encode($data,256),'post','',5); dump($result); } /** * 上传文件到DeepSeek */ public function getImageData($imageUrl) { $uploadUrl = $this->apiUrl.$this->apiUrls['uploadFile']; $filePath = ATTACHMENT_PATH.get_image_path($imageUrl); if (!file_exists($filePath)) { return false; } $mimeType = mime_content_type($filePath); $fileName = basename($filePath); // 准备文件数据 $fileData = [ 'file' => new \CURLFile($filePath, $mimeType, $fileName), 'purpose' => 'vision' // 或者 'assistants',根据用途 ]; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $uploadUrl, CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $fileData, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $this->apiKey ], CURLOPT_TIMEOUT => 30 ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); dump($response); curl_close($ch); if ($httpCode === 200) { $result = json_decode($response, true); return $result['id'] ?? false; } return false; } /** * 上传图片 * @param $image * @return false */ public function analyzeImageByFile($fileIds, $prompt='请分析读取这张图片内容') { if(empty($this->apiUrl) || empty($this->apiKey) || empty($this->apiName)){ $this->error = 'AI接口参数未配置'; return false; } $headers = [ 'Content-Type: application/json', 'Accept: application/json', 'Authorization: Bearer ' . $this->apiKey ]; // $filePath = ATTACHMENT_PATH.get_image_path($imageUrl); // $imageData = base64_encode(file_get_contents($filePath)); // $mineType = mime_content_type($filePath); $data = [ 'model'=> 'deepseek-reasoner', 'messages'=> [ [ 'role' => 'user', 'content' => $prompt, 'file_ids'=> ['file-bc202f5a-0894-478c-b22c-c79c9f8b8298'] ] ], // 'stream' => false, //false 非流 true//流返回,需要前端追加和保持长连接 // 'response_format'=>[ // 'type'=> 'text' //返回格式(text,json_object) // ], "max_tokens"=>2048, //最大返回token数 ]; $model = 'deepseek-reasoner'; $url = $this->apiUrl.$this->apiUrls[$model]; $this->saveLog("caches:dkApi:{$model}:request_1_".date('YmdHis'), ['url'=>$url,'data'=>$data]); $result = aiRequest($url, json_encode($data), 60, $headers); dump($result); var_dump($result); } /** * 上传Base64图片 * @param $image * @return false */ public function analyzeImageByBase64($imageUrl, $prompt='请分析读取这张图片内容') { if(empty($this->apiUrl) || empty($this->apiKey) || empty($this->apiName)){ $this->error = 'AI接口参数未配置'; return false; } $headers = [ 'Content-Type: application/json', 'Accept: application/json', 'Authorization: Bearer ' . $this->apiKey ]; $filePath = ATTACHMENT_PATH.get_image_path($imageUrl); $imageData = base64_encode(file_get_contents($filePath)); $mineType = mime_content_type($filePath); $data = [ 'purpose'=>'vision', 'file'=> $imageData, 'filename'=> basename($filePath), 'mine_type'=> $mineType ]; $model = 'uploadFile'; $url = $this->apiUrl.$this->apiUrls['uploadFile']; $this->saveLog("caches:dkApi:{$model}:request_1_".date('YmdHis'), ['url'=>$url,'data'=>$data]); $result = aiRequest($url, json_encode($data), 60, $headers); dump($result); var_dump($result); } /** * 上传图片 * @param $image * @return false */ public function analyzeImage($imageUrl) { if(empty($this->apiUrl) || empty($this->apiKey) || empty($this->apiName)){ $this->error = 'AI接口参数未配置'; return false; } $headers = [ "Content-Type:multipart/form-data", 'Accept: application/json', 'Authorization: Bearer ' . $this->apiKey ]; $filePath = ATTACHMENT_PATH.get_image_path($imageUrl); $mimeType = mime_content_type($filePath); $fileName = basename($filePath); // 准备文件数据 $data = [ 'image'=> new \CURLFile($filePath, $mimeType, $fileName), ]; $url = $this->apiUrl.$this->apiUrls['upload']; $this->saveLog("caches:dkApi:analysis:request_1_".date('YmdHis'), ['url'=>$url,'data'=>$data]); $result = aiRequest($url, $data, 60, $headers); dump($result); var_dump($result); } /** * 生成图片 * @param $image * @return false */ public function makeImage($prompt) { if(empty($this->apiUrl) || empty($this->apiKey) || empty($this->apiName)){ $this->error = 'AI接口参数未配置'; return false; } $headers = [ 'Content-Type: application/json', 'Accept: application/json', 'Authorization: Bearer ' . $this->apiKey ]; $url = $this->apiUrl.$this->apiUrls['deepseek-chat']; $data = [ 'prompt'=> $prompt, 'model'=>'deepseek-image', 'size'=> '1024x1024', ]; $result = aiRequest($url, json_encode($data), 10, $headers); var_dump($result); } /** * 获取题目内容 * @param $imageUrl * @return false */ public function getImageTopicData($imageUrl) { if(empty($imageUrl)){ return false; } $cacheKey = "caches:orcData:".md5($imageUrl); $data = RedisService::get($cacheKey); if($data){ return $data; } // 图片获取数据 if(preg_match("/(images|temp)/", $imageUrl)){ $path = get_image_path($imageUrl); try { $ocr = new TesseractOCR(ATTACHMENT_PATH.$path); $data = $ocr->lang('chi_sim','eng') ->psm(6) ->run(5); } catch (\Exception $exception){ $data = ''; } $data = $data?str_replace("\n",'\n', $data):''; if($data){ RedisService::set($cacheKey, $data, 3600); } return $data; } return $imageUrl; } /** * 保存缓存日志 * @param $cacheKey * @param $message * @param $expireTime */ public function saveLog($cacheKey, $message, $expireTime=0, $open=false) { if(env('APP_DEBUG',true) || $open){ RedisService::set($cacheKey, $message, $this->expireTime); } } }