AiClientService.php 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. <?php
  2. namespace App\Services;
  3. use Illuminate\Support\Facades\Http;
  4. class AiClientService
  5. {
  6. public function callJson(string $prompt): array
  7. {
  8. $driver = config('ai.driver', 'deepseek');
  9. return match ($driver) {
  10. 'deepseek' => $this->callDeepSeek($prompt),
  11. 'openai' => $this->callOpenAi($prompt),
  12. default => throw new \RuntimeException("Unsupported AI driver: {$driver}"),
  13. };
  14. }
  15. private function callDeepSeek(string $prompt): array
  16. {
  17. $config = config('ai.deepseek', []);
  18. $apiKey = $config['api_key'] ?? env('DEEPSEEK_API_KEY');
  19. $baseUrl = rtrim($config['base_url'] ?? 'https://api.deepseek.com/v1', '/');
  20. $model = $config['model'] ?? 'deepseek-chat';
  21. $timeout = (int) ($config['timeout'] ?? 30);
  22. $response = Http::withHeaders([
  23. 'Authorization' => "Bearer {$apiKey}",
  24. 'Content-Type' => 'application/json',
  25. ])->timeout($timeout)->post($baseUrl . '/chat/completions', [
  26. 'model' => $model,
  27. 'messages' => [
  28. ['role' => 'user', 'content' => $prompt],
  29. ],
  30. 'temperature' => 0.1,
  31. ]);
  32. if (!$response->successful()) {
  33. throw new \RuntimeException('DeepSeek API error: ' . $response->body());
  34. }
  35. $content = $response->json('choices.0.message.content');
  36. return $this->parseJsonResponse($content);
  37. }
  38. private function callOpenAi(string $prompt): array
  39. {
  40. $config = config('ai.openai', []);
  41. $apiKey = $config['api_key'] ?? env('OPENAI_API_KEY');
  42. $baseUrl = rtrim($config['base_url'] ?? 'https://api.openai.com/v1', '/');
  43. $model = $config['model'] ?? 'gpt-3.5-turbo';
  44. $timeout = (int) ($config['timeout'] ?? 30);
  45. $response = Http::withHeaders([
  46. 'Authorization' => "Bearer {$apiKey}",
  47. 'Content-Type' => 'application/json',
  48. ])->timeout($timeout)->post($baseUrl . '/chat/completions', [
  49. 'model' => $model,
  50. 'messages' => [
  51. ['role' => 'user', 'content' => $prompt],
  52. ],
  53. 'temperature' => 0.1,
  54. ]);
  55. if (!$response->successful()) {
  56. throw new \RuntimeException('OpenAI API error: ' . $response->body());
  57. }
  58. $content = $response->json('choices.0.message.content');
  59. return $this->parseJsonResponse($content);
  60. }
  61. private function parseJsonResponse(?string $content): array
  62. {
  63. if (!$content) {
  64. return [];
  65. }
  66. $content = trim($content);
  67. $content = preg_replace('/```(?:json)?/i', '', $content);
  68. $content = str_replace('```', '', $content);
  69. $content = trim($content);
  70. $data = json_decode($content, true);
  71. if (json_last_error() !== JSON_ERROR_NONE) {
  72. $start = strpos($content, '{');
  73. $end = strrpos($content, '}');
  74. if ($start !== false && $end !== false && $end > $start) {
  75. $slice = substr($content, $start, $end - $start + 1);
  76. $data = json_decode($slice, true);
  77. }
  78. }
  79. return is_array($data) ? $data : [];
  80. }
  81. }