ailixir-api / app /Services /ChemicalSearchService.php
AILIXIR Bot
Auto-sync: 201d269f287526269b8ffded5f450ff36b46c740
907b200
Raw
History Blame Contribute Delete
3.63 kB
<?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(),
];
}
}
}