Deepseek.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <?php
  2. namespace app\api\controller;
  3. use app\common\controller\Api;
  4. use Symfony\Component\HttpFoundation\StreamedResponse;
  5. use think\Db;
  6. use app\common\library\Deepseek as DeepseekAI;
  7. /**
  8. * AI
  9. */
  10. class Deepseek extends Api
  11. {
  12. protected $noNeedLogin = ['*'];
  13. protected $noNeedRight = ['*'];
  14. public function index()
  15. {
  16. $params = input();
  17. $chat = new DeepseekAI();
  18. $response = $chat->completions($params['messages'],$params['model'],$params['type']);
  19. // dump($response);
  20. return new StreamedResponse(function() use ($response) {
  21. $body = $response->getBody();
  22. while (!$body->eof()) {
  23. echo $body->read(1024); // 每次读取 1024 字节
  24. ob_flush();
  25. flush();
  26. }
  27. }, 200, [
  28. 'Content-Type' => 'application/json', // 根据实际情况设置响应头
  29. ]);
  30. }
  31. public function mockDeepSeekStream()
  32. {
  33. // 这是模拟的文本片段 - 实际应替换为真实的API调用
  34. $textChunks = [
  35. "你好!这是 DeepSeek 的流式文本响应。\n\n",
  36. "我正在逐块返回文本内容。\n",
  37. "这种方式可以实现实时输出效果。\n",
  38. "这种方式可以实现实时输出效果。\n",
  39. "最后一块内容。\n"
  40. ];
  41. // 逐块输出文本
  42. foreach ($textChunks as $chunk) {
  43. echo $chunk;
  44. ob_flush(); // 刷新PHP输出缓冲区
  45. flush(); // 刷新系统缓冲区
  46. sleep(1); // 暂停0.3秒模拟网络延迟
  47. }
  48. }
  49. public function deepseek(){
  50. $config = config('deepseek');
  51. $apiKey = $config['key']; //
  52. $url = 'https://api.deepseek.com/chat/completions';
  53. $params = input();
  54. $data = [
  55. 'model' => $params['model'],
  56. 'messages' => $params['messages'],
  57. // "frequency_penalty" => 0,
  58. "max_tokens" => 2048,
  59. /*"presence_penalty" => 0,
  60. "response_format" => [
  61. "type" => $params['type']
  62. ],
  63. "stop" => null,*/
  64. "stream" => true,
  65. /*"stream_options" => null,
  66. "temperature" => 1,
  67. "top_p" => 1,
  68. "tools" => null,
  69. "tool_choice" => "none",
  70. "logprobs" => false,
  71. "top_logprobs" => null*/
  72. ];
  73. // 初始化cURL会话
  74. $ch = curl_init($url);
  75. // 设置cURL选项
  76. curl_setopt_array($ch, [
  77. CURLOPT_RETURNTRANSFER => true,
  78. CURLOPT_SSL_VERIFYPEER => false,
  79. CURLOPT_POST => true,
  80. CURLOPT_POSTFIELDS => json_encode($data),
  81. CURLOPT_HTTPHEADER => [
  82. 'Content-Type: application/json',
  83. 'Authorization: Bearer ' . $apiKey,
  84. 'Accept: text/event-stream' // 重要:声明接受事件流
  85. ],
  86. CURLOPT_WRITEFUNCTION => function($ch, $data) {
  87. // 实时处理流数据
  88. $lines = explode("\n", $data);
  89. foreach ($lines as $line) {
  90. if (strpos($line, 'data: ') === 0) {
  91. $jsonStr = substr($line, 6); // 移除"data: "前缀
  92. // 跳过结束标记
  93. if (trim($jsonStr) === '[DONE]') {
  94. continue;
  95. }
  96. // 解析JSON数据
  97. $eventData = json_decode($jsonStr, true);
  98. if (isset($eventData['choices'][0]['delta']['content'])) {
  99. $content = $eventData['choices'][0]['delta']['content'];
  100. // 输出内容并立即刷新缓冲区
  101. echo $content;
  102. ob_flush();
  103. flush();
  104. }
  105. }
  106. }
  107. return strlen($data); // 返回已处理数据长度
  108. }
  109. ]);
  110. // 执行请求
  111. $response = curl_exec($ch);
  112. // 错误处理
  113. if (curl_errno($ch)) {
  114. echo 'Error: ' . curl_error($ch);
  115. }
  116. // 关闭连接
  117. curl_close($ch);
  118. // 创建cURL句柄
  119. /* $ch = curl_init();
  120. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
  121. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  122. curl_setopt($ch, CURLOPT_URL, $url);
  123. curl_setopt($ch, CURLOPT_POST, true);
  124. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  125. curl_setopt($ch, CURLOPT_HTTPHEADER, [
  126. 'Content-Type: application/json',
  127. 'Authorization: Bearer ' . $apiKey,
  128. 'Accept: text/event-stream' // 重要:声明接受事件流
  129. ]);
  130. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 直接输出
  131. curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $chunk) {
  132. // 直接输出接收到的数据块
  133. echo $chunk;
  134. // ob_flush();
  135. // flush();
  136. return strlen($chunk); // 必须返回写入的字节数
  137. });
  138. // 执行请求
  139. curl_exec($ch);
  140. // 检查错误
  141. if (curl_errno($ch)) {
  142. // 错误处理
  143. echo "\n\n[ERROR] API请求失败: " . curl_error($ch);
  144. }
  145. curl_close($ch);*/
  146. }
  147. }