File size: 3,629 Bytes
907b200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<?php

namespace App\Services;

use App\Models\ChemicalSearchJob;
use App\Models\ChemicalCompound;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class ChemicalSearchService
{
    public function search(string $smiles, int $topK, int $userId): array
    {
        return $this->callAiService($smiles, $topK, $userId, '/search/retrieval-only', false);
    }

    public function fullRag(string $smiles, int $topK, int $userId): array
    {
        return $this->callAiService($smiles, $topK, $userId, '/search/full-rag', true);
    }

    private function callAiService(
        string $smiles,
        int $topK,
        int $userId,
        string $endpoint,
        bool $includeReason
    ): array {
        $url = config('services.chemical_ai.url') . $endpoint;
        $startTime = microtime(true);

        try {
            $response = Http::withOptions([
                'verify' => false,
            ])->timeout(120)->post($url, [
                'smiles' => $smiles,
                'top_k' => $topK,
            ]);

            if (!$response->successful()) {
                throw new \Exception("AI Service error: " . $response->status());
            }

            $data = $response->json();
            $searchTimeMs = round((microtime(true) - $startTime) * 1000, 2);

            $compounds = [];
            foreach ($data['results'] ?? [] as $index => $result) {
                $compounds[] = [
                    'rank' => $index + 1,
                    'smiles' => $result['smiles'],
                    'name' => $result['name'] ?? null,
                    'cid' => $result['cid'] ?? null,
                    'similarity' => isset($result['similarity_score'])
                        ? round((float)$result['similarity_score'], 4)
                        : null,
                    'explanation' => $includeReason ? ($result['explanation'] ?? null) : null,
                    'image_url' => $result['image'] ?? null,
                ];
            }

            // Optional: Save to DB for history (بدون job status)
            $job = ChemicalSearchJob::create([
                'user_id' => $userId,
                'query_smiles' => $smiles,
                'top_k' => $topK,
                'status' => 'completed',
                'results' => $data['results'] ?? [],
                'image_urls' => array_column($data['results'] ?? [], 'image'),
                'metadata' => [
                    'total_results' => count($data['results'] ?? []),
                    'search_time_ms' => $searchTimeMs,
                    'similarity_metric' => 'Tanimoto',
                    'fingerprint' => 'Morgan (2048, radius=2)',
                    'source' => $includeReason ? 'full_rag' : 'retrieval',
                ],
                'started_at' => now(),
                'completed_at' => now(),
            ]);

            // Save compounds if you still want DB records
            foreach ($compounds as $compoundData) {
                ChemicalCompound::create([
                    'job_id' => $job->id,
                    ...$compoundData,
                ]);
            }

            return [
                'success' => true,
                'compounds' => $compounds,
                'metadata' => $job->metadata,
            ];
        } catch (\Exception $e) {
            Log::error('Chemical Search Failed', [
                'smiles' => $smiles,
                'error' => $e->getMessage(),
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage(),
            ];
        }
    }
}