DeepSeekService.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. <?php
  2. namespace App\Services;
  3. use thiagoalessio\TesseractOCR\TesseractOCR;
  4. /**
  5. * DeepSeek服务管理-服务类
  6. * @author laravel开发员
  7. * @since 2020/11/11
  8. * @package App\Services
  9. */
  10. class DeepSeekService extends BaseService
  11. {
  12. // 静态对象
  13. protected static $instance = null;
  14. protected $debug = true;
  15. protected $expireTime = 7200; // 缓存日志时长
  16. protected $apiKey = '';
  17. protected $apiName = '';
  18. protected $apiurl = '';
  19. protected $chaturl = 'https://chat.deepseek.com/api';
  20. // 接口地址
  21. protected $apiUrls = [
  22. // 授权登录
  23. 'deepseek-chat' => '/chat/completions',
  24. 'deepseek-reasoner' => '/chat/completions',
  25. 'upload' => '/v1/upload',
  26. 'generations' => '/v1/images/generations',
  27. 'generate' => '/v1/text/generate',
  28. 'upload_file' => '/v0/file/upload_file',
  29. ];
  30. public function __construct()
  31. {
  32. set_time_limit(0);
  33. $this->apiUrl = ConfigService::make()->getConfigByCode('dk_base_url');
  34. $this->apiKey = ConfigService::make()->getConfigByCode('dk_api_key');
  35. $this->apiName = ConfigService::make()->getConfigByCode('dk_api_name');
  36. }
  37. /**
  38. * 静态入口
  39. * @return static|null
  40. */
  41. public static function make()
  42. {
  43. if (!self::$instance) {
  44. self::$instance = new static();
  45. }
  46. return self::$instance;
  47. }
  48. /**
  49. * AI 分析接口
  50. * @param $params
  51. * @param string $model
  52. * @return array|false|mixed
  53. */
  54. public function apiRequest($params, $model='deepseek-chat')
  55. {
  56. if(empty($this->apiUrl) || empty($this->apiKey) || empty($this->apiName)){
  57. $this->error = 'AI接口参数未配置';
  58. return false;
  59. }
  60. $headers = [
  61. 'Content-Type: application/json',
  62. 'Accept: application/json',
  63. 'Authorization: Bearer ' . $this->apiKey
  64. ];
  65. $answer = isset($params['answer'])? $params['answer'] : '';
  66. $topic = isset($params['topic'])? $params['topic'] : '';
  67. $score = isset($params['score'])? $params['score'] : 0;
  68. $type = isset($params['type'])? $params['type'] : 1; // 1-文本,2-图片
  69. $content = '你是一个答题高手,请给描述中问题的答案评分,并尝试按 JSON:{"score": 8,"topic":"this is topic content","analysis":"this is topic analysis"}返回';
  70. $message = "请给题目【{$topic}】总分{$score}的答案【{$answer}】评分?";
  71. $format = 'json_object';
  72. if($type == 2){
  73. $content = '你是一个识图专家,请读取图中中英文数字或符号内容,并尝试按 JSON:{"content":"this is photo content"}';
  74. // $format = 'text';
  75. // $content = '你是一个答题高手,请给描述中问题的答案评分,并尝试按 JSON:{"score": 8,"topic":"this is topic content","answer":"this is answer content","analysis":"this is topic analysis"}返回';
  76. preg_match("/\.(jpg|jpeg|png)/", $answer, $extData);
  77. $ext = isset($extData[0])? $extData[0] : 'jpg';
  78. $ext = $ext=='png'? 'png' : 'jpeg';
  79. $filePath = ATTACHMENT_PATH.get_image_path($answer);
  80. $image = file_get_contents($filePath);
  81. $base64 = base64_encode($image);
  82. $base64 = "data:image/{$ext};base64,{$base64}";
  83. $message = "请读取图片【{$base64}】内容?";
  84. // $message = "请给总分为{$score}的题目【{$topic}】针对图片内【{$base64}】答案评分?";
  85. }
  86. $data = [
  87. 'model'=> $model,
  88. 'messages'=> [
  89. [
  90. 'role' => 'system',
  91. 'content' => $content
  92. ],
  93. [
  94. 'role' => 'user',
  95. 'content' => $message
  96. ],
  97. ],
  98. 'stream' => false, //false 非流 true//流返回,需要前端追加和保持长连接
  99. 'response_format'=>[
  100. 'type'=> $format //返回格式(text,json_object)
  101. ],
  102. "max_tokens"=>2048, //最大返回token数
  103. ];
  104. $url = $this->apiUrl.$this->apiUrls[$model];
  105. $this->saveLog("caches:dkApi:{$model}:request_1_".date('YmdHis'), ['url'=>$url,'data'=>$data]);
  106. $result = aiRequest($url, json_encode($data), 60, $headers);
  107. dump($result);
  108. $result = $result? json_decode(trim($result),true) : [];
  109. if(empty($result)){
  110. $this->error = '答案验证失败';
  111. return false;
  112. }
  113. $this->saveLog("caches:dkApi:{$model}:request_2_".date('YmdHis'), ['url'=>$url,'data'=>$data,'result'=>$result]);
  114. $choices = isset($result['choices'])? $result['choices'] : [];
  115. $choiceData = isset($choices[0]['message'])? $choices[0]['message'] : [];
  116. $choiceContent = isset($choiceData['content'])? $choiceData['content'] : '';
  117. $content = $choiceContent? str_replace('\n','', $choiceContent) : '';
  118. $content = $content? preg_replace("/^```json/",'', $content) : '';
  119. $content = $content? rtrim($content,'```') : '';
  120. $content = $content? json_decode($content, true) : [];
  121. return $content;
  122. }
  123. /**
  124. * 上传图片
  125. * @param $image
  126. * @return false
  127. */
  128. public function upload($image)
  129. {
  130. if(empty($this->apiUrl) || empty($this->apiKey) || empty($this->apiName)){
  131. $this->error = 'AI接口参数未配置';
  132. return false;
  133. }
  134. $headers = [
  135. 'Content-Type: application/json',
  136. // 'Accept: application/json',
  137. 'Authorization: Bearer ' . $this->apiKey
  138. ];
  139. $filePath = ATTACHMENT_PATH.get_image_path($image);
  140. dump($filePath);
  141. // $url = $this->apiUrl.$this->apiUrls['generate'];
  142. $url = $this->chaturl.$this->apiUrls['upload_file'];
  143. var_dump(basename($image));
  144. // $file = fopen($url, 'rb');
  145. $filePath = ATTACHMENT_PATH.get_image_path($filePath);
  146. $image = file_get_contents($filePath);
  147. $base64 = base64_encode($image);
  148. $base64 = "data:image/jpeg;base64,{$base64}";
  149. // $file = new \CURLFile(realpath($filePath), 'application/octet-stream', basename($image));
  150. $data = ['image' => $base64];
  151. // $data = [
  152. // "prompt"=> "解释量子计算的基本原理",
  153. // "max_tokens"=> 200,
  154. // "temperature"=>0.7
  155. // ];
  156. $data = [
  157. 'files'=> $data
  158. ];
  159. var_dump($url);
  160. var_dump($data);
  161. $result = aiRequest($url, '', 10, $headers);
  162. var_dump($result);
  163. }
  164. /**
  165. * 生成图片
  166. * @param $image
  167. * @return false
  168. */
  169. public function makeImage($prompt)
  170. {
  171. if(empty($this->apiUrl) || empty($this->apiKey) || empty($this->apiName)){
  172. $this->error = 'AI接口参数未配置';
  173. return false;
  174. }
  175. $headers = [
  176. 'Content-Type: application/json',
  177. 'Accept: application/json',
  178. 'Authorization: Bearer ' . $this->apiKey
  179. ];
  180. $url = $this->apiUrl.$this->apiUrls['deepseek-chat'];
  181. $data = [
  182. 'prompt'=> $prompt,
  183. 'model'=>'deepseek-image',
  184. 'size'=> '1024x1024',
  185. ];
  186. $result = aiRequest($url, json_encode($data), 10, $headers);
  187. var_dump($result);
  188. }
  189. /**
  190. * 获取题目内容
  191. * @param $imageUrl
  192. * @return false
  193. */
  194. public function getImageTopicData($imageUrl)
  195. {
  196. if(empty($imageUrl)){
  197. return false;
  198. }
  199. // 图片获取数据
  200. if(preg_match("/(images|temp)/", $imageUrl)){
  201. $path = get_image_path($imageUrl);
  202. // foreach((new TesseractOCR())->availableLanguages() as $lang) echo $lang;
  203. $ocr = new TesseractOCR(ATTACHMENT_PATH.$path);
  204. $data = $ocr->lang('chi_sim','eng','chi_tra')
  205. ->allowlist(range('a', 'z'), range('A', 'Z'), range(0, 9), '-_@')
  206. ->run(30);
  207. var_dump($data);
  208. return $data;
  209. }
  210. return $imageUrl;
  211. }
  212. /**
  213. * 保存缓存日志
  214. * @param $cacheKey
  215. * @param $message
  216. * @param $expireTime
  217. */
  218. public function saveLog($cacheKey, $message, $expireTime=0, $open=false)
  219. {
  220. if(env('APP_DEBUG') || $open){
  221. RedisService::set($cacheKey, $message, $expireTime||$this->expireTime);
  222. }
  223. }
  224. }