apiSSE.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. <?php
  2. header("Access-Control-Allow-Origin: *"); // 允许所有来源
  3. header("Access-Control-Allow-Methods: GET"); // 允许的 HTTP 方法
  4. header("Access-Control-Allow-Headers: Content-Type"); // 允许的请求头
  5. // 强制禁用所有缓冲
  6. while (ob_get_level()) ob_end_clean();
  7. header('X-Accel-Buffering: no');
  8. // 设置 SSE 头部
  9. header("Content-Type: text/event-stream");
  10. header("Cache-Control: no-cache");
  11. header("Connection: keep-alive");
  12. header("X-Accel-Buffering: no");
  13. // 配置执行环境
  14. set_time_limit(0);
  15. ignore_user_abort(false);
  16. //创建公共url
  17. $urlCommon = 'http://192.168.1.8:3338';
  18. $mcp = $_GET['mcpid'];
  19. //获取对话短令牌
  20. $input['token'] = $_GET['token'];
  21. $dataReply['token'] = $_GET['token'];
  22. $token = $_GET['token'];
  23. $ragIdGet = $_GET['ragId'];
  24. if(($ragIdGet == 'null') || ($ragIdGet == null)){
  25. $input['ragId'] = 'empty';
  26. }
  27. else{
  28. $input['ragId'] = $ragIdGet;
  29. }
  30. // $input['ragId'] = 'empty';
  31. // $mcp =="";
  32. // if($mcp != ""){
  33. // echo("daddsda");
  34. // }
  35. // echo($mcp);
  36. // exit;
  37. //将请求的完整内容发送至api控制器鉴权
  38. $urlCheck = $urlCommon.'/apis/check';
  39. $information = curlPost($urlCheck,$input);
  40. //判断鉴权的结果,如果鉴权失败,直接退出
  41. $informationObject = json_decode($information);
  42. if(($informationObject->code) != 5){
  43. echo "event: verify\ndata: $information\n\n";
  44. exit;
  45. }
  46. //获取最终的核心参数参与模型输入
  47. $modelId = $informationObject->modelId;
  48. $content = $informationObject->input;
  49. $contentmcp = $informationObject->input;
  50. $ragId = $informationObject->ragId;
  51. // if(is_array($content)){
  52. // $content = json_encode($content,JSON_UNESCAPED_UNICODE);
  53. // }
  54. // 模型定制开始-------------------------------------------------------------------
  55. // //emoon-E1-13B线上
  56. // if($modelId == 9){
  57. // $apiKey = 'sk-800990e9cdb34613a2133f0fc333a7ff'; // 请替换为你的实际 API 密钥
  58. // $url = 'https://api.deepseek.com/chat/completions';
  59. // $arraySystem = [[
  60. // 'role' => 'system',
  61. // 'content' => '你的名字叫EMOON E1 13B模型,你由回车网络(EnterLO)训练研发,你并不是deepseek模型。你是一名三甲医院主治医师级别的AI助手,最擅长医疗专业知识的解读和分析,遵循《中国临床诊疗指南》和NCCN指南。必须:1) 先询问关键症状细节 2) 标注证据等级 3) 拒绝非循证医学建议'
  62. // ]];
  63. // // $arrayContent = json_decode($content);
  64. // $arrayMessage = array_merge($arraySystem,$content);
  65. // // 请求数据
  66. // $data = [
  67. // 'model' => 'deepseek-chat',
  68. // 'messages' => $arrayMessage,
  69. // 'stream' => true
  70. // ];
  71. // // 设置请求头
  72. // $headers = [
  73. // 'Content-Type: application/json',
  74. // 'Authorization: Bearer ' . $apiKey
  75. // ];
  76. // }
  77. if($ragId != ''){
  78. $content = stdClassObjToArray($content);
  79. $dataRag['input'] = $content[count($content)-1]['content'];
  80. $dataRag['kid'] = $ragId;
  81. $urlRAG = 'http://192.168.1.8:3338/apis/ragData';
  82. $ragResult = curlPost($urlRAG,$dataRag);
  83. $ragResult = json_decode($ragResult);
  84. $ragResult = stdClassObjToArray($ragResult);
  85. // if( $ragResult['code'] == 200){
  86. // $ragInfomation = json_encode($ragResult['nearest']);
  87. // }
  88. if(json_encode($ragResult['nearest'],JSON_UNESCAPED_UNICODE) != "[]" ){
  89. if($ragId == "1947484295610253313" || $ragId == "1949641433623703553"){
  90. $content[count($content)-1]['content'] = '我的提问是:“'.$content[count($content)-1]['content'].'”,下面是基于我的提问查到的知识库相关内容:“'.json_encode($ragResult['nearest'],JSON_UNESCAPED_UNICODE).'”,请按照查到的知识库相关内容,进行病历质控,如果不符合哪项指控规则则按以下格式进行返回,返回格式:质控结果如下,该份病例不符合以下质控规则:规则1:XXXX-扣分x,原因:xxx,规则2:XXXX-扣分x,原因:xxx,……。扣除的分数严格与知识库中内容对应,符合要求的规则不回复输出显示,无法准确判断的规则不回复输出,只回复显示不符合的质控规则。 ';//请求向量数据库接口反参组装
  91. $contentmcp = $content;
  92. }
  93. else{
  94. $content[count($content)-1]['content'] = '我的提问是:“'.$content[count($content)-1]['content'].'”,下面是基于我的提问查到的知识库相关内容:“'.json_encode($ragResult['nearest'],JSON_UNESCAPED_UNICODE).'”。';//请求向量数据库接口反参组装
  95. $contentmcp = $content;
  96. }
  97. }
  98. }
  99. if($mcp != ''){
  100. }
  101. // echo(json_encode($content,JSON_UNESCAPED_UNICODE));
  102. // exit;
  103. //deepseek-R1-70B线下
  104. if($modelId == 9){
  105. $url = 'http://60.164.133.40:19997/v1/chat/completions';
  106. $headers = [
  107. 'accept: application/json',
  108. 'Content-Type: application/json'
  109. ];
  110. $arraySystem = [[
  111. 'role' => 'system',
  112. 'content' => '你是一个人工智能助手。'
  113. ],
  114. ];
  115. //$arrayContent = json_decode($content, true);
  116. $arrayMessage = array_merge($arraySystem, $content);
  117. $data = [
  118. "messages" => $arrayMessage,
  119. "model" => "qwen3-32B", //X
  120. "stream" => true,
  121. "chat_template_kwargs" => '{"enable_thinking": false}',
  122. ];
  123. }
  124. // echo(json_encode($data,JSON_UNESCAPED_UNICODE));
  125. // exit;
  126. // 模型定制结束-------------------------------------------------------------------
  127. if($mcp == 0 || $mcp ==""){
  128. $ch = curl_init();
  129. curl_setopt($ch, CURLOPT_URL, $url);
  130. curl_setopt($ch, CURLOPT_POST, true);
  131. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data,JSON_UNESCAPED_UNICODE));
  132. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  133. curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
  134. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  135. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
  136. curl_setopt_array($ch, [
  137. CURLOPT_TIMEOUT => 60, // 超时时间延长至60秒
  138. CURLOPT_TCP_KEEPALIVE => 1, // 启用TCP保活
  139. CURLOPT_TCP_KEEPIDLE => 10,
  140. CURLOPT_TCP_KEEPINTVL => 5
  141. ]);
  142. //创建一个空字符串动态存储回复的文字
  143. $reply = 'SSE: ';
  144. // 添加连接状态检查到写入回调
  145. curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use (&$reply) {
  146. // 如果客户端已断开,立即终止
  147. if (connection_aborted()) {
  148. return -1; // 返回-1会强制CURL中断请求
  149. curl_close($ch);
  150. }
  151. $lines = explode("\n", $data);
  152. foreach ($lines as $line) {
  153. if (strpos($line, 'data:') === 0) {
  154. $contents = trim(substr($line, 5));
  155. if ($contents === '[DONE]') {
  156. $output = "event: end\ndata: {\"status\":\"done\"}\n\n";
  157. echo $output;
  158. // $reply .= $output; // 捕获输出内容
  159. //完成输出后触发全部回复存储进入数据库
  160. global $token;
  161. global $urlCommon;
  162. $dataReply['token'] = $token;
  163. $dataReply['reply'] = $reply;
  164. //将数据发送至数据库
  165. $curlReplay = curl_init();
  166. curl_setopt($curlReplay, CURLOPT_URL, $urlCommon.'/Apis/reply');
  167. curl_setopt($curlReplay, CURLOPT_SSL_VERIFYPEER, FALSE);
  168. curl_setopt($curlReplay, CURLOPT_SSL_VERIFYHOST, FALSE);
  169. // curl_setopt($curl, CURLOPT_HTTPHEADER,$headers);
  170. if ($json) {
  171. curl_setopt($curlReplay,CURLOPT_HTTPHEADER,[
  172. "Content-Type: application/json"
  173. ]);
  174. curl_setopt($curlReplay, CURLOPT_POST, TRUE);
  175. curl_setopt($curlReplay,CURLOPT_POSTFIELDS,json_encode($dataReply));
  176. }else {
  177. if (!empty($dataReply)) {
  178. curl_setopt($curlReplay, CURLOPT_POST, TRUE);
  179. curl_setopt($curlReplay, CURLOPT_POSTFIELDS,$dataReply);
  180. // curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  181. }
  182. }
  183. curl_setopt($curlReplay, CURLOPT_RETURNTRANSFER,true);
  184. curl_exec($curlReplay);
  185. curl_close($curlReplay);
  186. } else {
  187. // 转发数据前再次检查连接
  188. if (connection_aborted()) {
  189. return -1;
  190. curl_close($ch);
  191. }
  192. //构造$line
  193. global $modelId;
  194. $line = substr($line,6);
  195. $line = json_decode($line);
  196. $line = stdClassObjToArray($line);
  197. if($modelId == 9){
  198. $line['model'] = 'emoon-E1-13B';
  199. }
  200. $line = 'data: '.json_encode($line,JSON_UNESCAPED_UNICODE);
  201. $output = $line . "\n\n";
  202. echo $output;
  203. //将回复数据存储入$reply
  204. $outputJson = substr($output,6);
  205. if(($modelId == 9) || ($modelId == 7) || ($modelId == 4) || ($modelId == 10) || ($modelId == 14) || ($modelId == 15)){
  206. $outputJson = json_decode($outputJson);
  207. $outputJson = $outputJson->choices[0]->delta->content;
  208. if($outputJson){
  209. $outputJson = json_encode($outputJson,JSON_UNESCAPED_UNICODE);
  210. $outputJson = str_replace('"', '', $outputJson);
  211. }
  212. }
  213. $reply .= $outputJson; // 捕获输出内容
  214. }
  215. ob_flush();
  216. flush();
  217. }
  218. }
  219. return strlen($data);
  220. });
  221. // 错误处理
  222. curl_setopt($ch, CURLOPT_TIMEOUT, 86400);
  223. curl_setopt($ch, CURLOPT_FAILONERROR, true);
  224. // 执行请求
  225. try {
  226. curl_exec($ch);
  227. // 检查HTTP状态码
  228. $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  229. if ($statusCode !== 200) {
  230. echo "event: error\ndata: HTTP Status {$statusCode}\n\n";
  231. ob_flush();
  232. flush();
  233. }
  234. } catch (Exception $e) {
  235. echo "event: error\ndata: " . $e->getMessage() . "\n\n";
  236. ob_flush();
  237. flush();
  238. }
  239. }else{
  240. @ini_set('output_buffering', 'off');
  241. @ini_set('zlib.output_compression', false);
  242. while (ob_get_level() > 0) {
  243. ob_end_flush();
  244. }
  245. ob_implicit_flush(true);
  246. // 设置流式响应头
  247. $requestBody = file_get_contents('php://input');
  248. $headers = getallheaders();
  249. $authorizationHeader = isset($headers['Authorization']) ? $headers['Authorization'] : '';
  250. $reply = 'SSE: ';
  251. $RAGdata = [
  252. "username" => "test",
  253. "password" => "test123"
  254. ];
  255. // 调用时只需传递非 Content-Type/Accept 的 Header
  256. $headers = [
  257. 'Cache-Control: no-cache',
  258. 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
  259. ];
  260. $urlRAG = "http://192.168.1.8:6039/auth/login"; // 替换为实际 URL
  261. $id = curlPostRAG($urlRAG, $RAGdata, $headers);
  262. $token = $id; // 默认启用 JSON 模式
  263. $token = json_decode($token);
  264. $token = stdClassObjToArray($token);
  265. $token = $token['data']['token'];
  266. $url = "http://192.168.1.8:6039/chat/emoonSend"; // 替换成实际接口地址
  267. $data = [
  268. "messages" => $contentmcp,
  269. "model" => "qwen3-32B", //X
  270. "temperature" => 0.5,
  271. "top_p" => 1,
  272. "presence_penalty" => 0,
  273. "frequency_penalty" => 0,
  274. "kid" => "",
  275. "chat_type" => 0,
  276. "appId" => "",
  277. "agentId" => $mcp,
  278. "stream" => true
  279. ];
  280. // 初始化 cURL
  281. $ch = curl_init();
  282. // 设置 cURL 选项
  283. curl_setopt($ch, CURLOPT_URL, $url);
  284. curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); // 返回响应数据
  285. curl_setopt($ch, CURLOPT_POST, true); // 使用 POST 方法
  286. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); // 发送 JSON 数据
  287. curl_setopt($ch, CURLOPT_HTTPHEADER, [
  288. "Authorization: Bearer " . $token,
  289. "Content-Type: application/json" // 声明请求体是 JSON
  290. ]);
  291. $chatId = 'chat' . uniqid() . bin2hex(random_bytes(8));
  292. $created = time();
  293. // for ($i = 0; $i < count($lines); $i++) {
  294. // echo $lines[0];
  295. // }
  296. $lastContent = '';
  297. curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use ($chatId, $created, &$lastContent,&$reply) {
  298. $lines = explode("\n", $data);
  299. $prefixLength = strlen("event:chat_completion");
  300. $content = str_replace("event:chat_completion", "", $lines[0]);
  301. // foreach ($lines as $line) {
  302. // $line = substr($line,6);
  303. // $content = $matches[0];
  304. // // 仅当内容变化时才输出
  305. // if ($content !== $lastContent) {
  306. // $lastContent = $content;
  307. $jsonData = [
  308. "id" => $chatId,
  309. "model" => "emoon-E1-13B",
  310. "created" => $created,
  311. "object" => "chat.completion.chunk",
  312. "choices" => [
  313. [
  314. "index" => 0,
  315. "delta" => [
  316. "content" => $content
  317. ],
  318. "finish_reason" => null
  319. ]
  320. ],
  321. "usage" => null
  322. ];
  323. echo "data: " . json_encode($jsonData,JSON_UNESCAPED_UNICODE) . "\n\n";
  324. $outputJson = json_encode($jsonData,JSON_UNESCAPED_UNICODE);
  325. $outputJson = json_decode($outputJson);
  326. // $outputJson = stdClassObjToArray($outputJson);
  327. $outputJson = $outputJson->choices[0]->delta->content;
  328. if($outputJson){
  329. $outputJson = json_encode($outputJson,JSON_UNESCAPED_UNICODE);
  330. $outputJson = str_replace('"', '', $outputJson);
  331. }
  332. $reply .= $outputJson;
  333. // }
  334. @ob_flush();
  335. @flush();
  336. // }
  337. return strlen($data);
  338. });
  339. $res = curl_exec($ch);
  340. }
  341. // 清理资源
  342. curl_close($ch);
  343. // 显式结束流
  344. echo "event: end\ndata: Stream ended\n\n";
  345. ob_flush();
  346. flush();
  347. if($mcp != ""){
  348. $dataReply['reply'] = $reply;
  349. $url=$urlCommon.'/Apis/reply';
  350. curlPost($url,$dataReply);
  351. //将数据发送至数据库
  352. }
  353. //模型定制结束-------------------------------------------------------------------
  354. function curlPost($url, $data = null, $headers = [], $json = false) {
  355. $curl = curl_init($url);
  356. $options = [
  357. CURLOPT_RETURNTRANSFER => true,
  358. CURLOPT_SSL_VERIFYPEER => false,
  359. CURLOPT_SSL_VERIFYHOST => false,
  360. CURLOPT_POST => !empty($data) || $json,
  361. ];
  362. if ($json) {
  363. $headers = array_filter($headers, function($h) {
  364. return stripos($h, 'Content-Type:') === false;
  365. });
  366. $headers[] = 'Content-Type: application/json';
  367. $data = json_encode($data, JSON_UNESCAPED_UNICODE);
  368. }
  369. if (!empty($headers)) {
  370. $options[CURLOPT_HTTPHEADER] = $headers;
  371. }
  372. if (!empty($data)) {
  373. $options[CURLOPT_POSTFIELDS] = $data;
  374. }
  375. curl_setopt_array($curl, $options);
  376. $result = curl_exec($curl);
  377. curl_close($curl);
  378. return $result;
  379. }
  380. function stdClassObjToArray($array) {
  381. if(is_object($array)) {
  382. $array = (array)$array;
  383. }
  384. if(is_array($array)) {
  385. foreach($array as $key=>$value) {
  386. $array[$key] = stdClassObjToArray($value);
  387. }
  388. }
  389. return $array;
  390. }
  391. function curlPostRAG($url, $data = null, $headers = [], $json = true) {
  392. $curl = curl_init($url);
  393. $options = [
  394. CURLOPT_RETURNTRANSFER => true,
  395. CURLOPT_SSL_VERIFYPEER => false,
  396. CURLOPT_SSL_VERIFYHOST => false,
  397. CURLOPT_POST => true, // 强制启用 POST(JSON 模式下始终 POST)
  398. ];
  399. if ($json) {
  400. // 移除已有的 Content-Type 和 Accept 头,避免冲突
  401. $headers = array_filter($headers, function($h) {
  402. return stripos($h, 'Content-Type:') === false && stripos($h, 'Accept:') === false;
  403. });
  404. // 添加 JSON 专用头
  405. $headers[] = 'Content-Type: application/json';
  406. $headers[] = 'Accept: application/json';
  407. // 编码数据为 JSON(空数据编码为 "{}" 避免服务器解析错误)
  408. $data = $data !== null ? json_encode($data, JSON_UNESCAPED_UNICODE) : '{}';
  409. }
  410. // 设置请求头和数据
  411. if (!empty($headers)) {
  412. $options[CURLOPT_HTTPHEADER] = $headers;
  413. }
  414. if ($data !== null) {
  415. $options[CURLOPT_POSTFIELDS] = $data;
  416. }
  417. curl_setopt_array($curl, $options);
  418. $result = curl_exec($curl);
  419. // 错误处理(调试时启用)
  420. if ($result === false) {
  421. $error = curl_error($curl);
  422. $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  423. throw new Exception("CURL请求失败: HTTP状态码 $httpCode, 错误信息: $error");
  424. }
  425. curl_close($curl);
  426. return $result;
  427. }
  428. exit;