EmbeddingService.php 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. <?php
  2. namespace App\Services;
  3. use Illuminate\Support\Facades\Http;
  4. class EmbeddingService
  5. {
  6. protected string $modelId;
  7. protected string $apiUrl = '';
  8. protected int $maxRetries = 3;
  9. /**
  10. * 创建服务实例,初始化 OpenAI API Key
  11. *
  12. * @return void
  13. */
  14. public function __construct(AIModelService $aiModels)
  15. {
  16. $models = $aiModels->getSysModels('embedding');
  17. $this->modelId = $models[0]['uid'];
  18. $this->apiUrl = config('mint.ai.proxy').'/api/openai';
  19. }
  20. public function generate($text)
  21. {
  22. return $this->callOpenAI($text);
  23. }
  24. /**
  25. * 调用 OpenAI GPT 模型生成embedding
  26. *
  27. * {
  28. "object": "list",
  29. "data": [
  30. {
  31. "object": "embedding",
  32. "index": 0,
  33. "embedding": [
  34. -0.012345,
  35. 0.021876,
  36. 0.004231,
  37. -0.037654,
  38. 0.016482,
  39. -0.001273,
  40. 0.029871,
  41. -0.015630
  42. // ... 共1536个浮点数
  43. ]
  44. }
  45. ],
  46. "model": "text-embedding-3-small",
  47. "usage": {
  48. "prompt_tokens": 16,
  49. "total_tokens": 16
  50. }
  51. }
  52. *
  53. * 带有重试机制和指数退避。
  54. * 在 429 或 500+ 错误时重试,最大重试次数为 maxRetries。
  55. * 其他错误直接返回空字符串。
  56. *
  57. * @param string $text 输入文本
  58. * @param int $maxTokens 每次请求允许的最大 tokens 数
  59. * @return string 模型返回的摘要文本
  60. */
  61. protected function callOpenAI(string $text): string
  62. {
  63. $attempt = 0;
  64. $delay = 1;
  65. $payload = [
  66. 'model' => $this->modelId,
  67. 'input' => $text,
  68. ];
  69. while ($attempt < $this->maxRetries) {
  70. try {
  71. $response = Http::timeout(100)
  72. ->withHeaders([
  73. 'Authorization' => 'Bearer ',
  74. 'Content-Type' => 'application/json',
  75. ])->post($this->apiUrl, [
  76. 'model_id' => $this->modelId,
  77. 'payload' => $payload,
  78. ]);
  79. if ($response->successful()) {
  80. $data = $response->json();
  81. if (isset($data['data']['embedding'])) {
  82. return $data['data']['embedding'];
  83. } else {
  84. return false;
  85. }
  86. }
  87. if (in_array($response->status(), [429, 500, 502, 503, 504])) {
  88. throw new \Exception('Temporary server error: '.$response->status());
  89. }
  90. return false;
  91. } catch (\Exception $e) {
  92. $attempt++;
  93. if ($attempt >= $this->maxRetries) {
  94. return false;
  95. }
  96. sleep($delay);
  97. $delay *= 10;
  98. }
  99. }
  100. return false;
  101. }
  102. }