group(function () { Route::get('/health', [AiServicesIntegrationController::class, 'health']); Route::post('/test/admet', [AiServicesIntegrationController::class, 'testAdmet']); Route::post('/test/chemical-search', [AiServicesIntegrationController::class, 'testChemicalSearch']); Route::get('/test/drug-repurposing', [AiServicesIntegrationController::class, 'testDrugRepurposing']); }); } // ==================== AWARDS ==================== Route::get('/awards', [AwardController::class, 'index']); Route::get('/awards/{id}', [AwardController::class, 'show']); Route::get('/awards/{id}/scientists', [AwardController::class, 'getScientistsByAward']); // ==================== SCIENTISTS ==================== Route::get('/scientists', [ScientistController::class, 'index']); Route::get('/scientists/{id}', [ScientistController::class, 'show']); Route::get('/scientists/{id}/awards', [ScientistController::class, 'getAwardsByScientist']); // ==================== USER ==================== // ==================== USERS & AUTHENTICATION ==================== Route::prefix('user')->group(function () { Route::post('register', [AuthController::class, 'register']); Route::post('login', [AuthController::class, 'login']); // email verification Route::post('/verify-email', [EmailVerificationController::class, 'verify']); Route::post('/resend-verification', [EmailVerificationController::class, 'resend']); // password reset Route::post('forgot-password', [PasswordResetController::class, 'sendForgotPasswordOtp']); Route::post('reset-password', [PasswordResetController::class, 'resetPassword']); Route::post('/resend-reset-password-otp', [PasswordResetController::class, 'resendResetPasswordOtp']); // login google Route::post('auth/google', [AuthController::class, 'handleGoogleCallback']); // profile and logout routes Route::middleware('auth:sanctum')->group(function () { Route::get('profile', [UserController::class, 'profile']); Route::post('update-profile', [UserController::class, 'updateProfile']); Route::post('logout', [AuthController::class, 'logout']); }); }); // ====================NEWS==================== Route::middleware('auth:sanctum')->group(function () { Route::get('/news', [NewsController::class, 'index']); Route::get('/news/refresh', [NewsController::class, 'refresh']); Route::get('/news/categories', [NewsController::class, 'getCategories']); Route::post('/news/{articleId}/share', [NewsController::class, 'shareArticle']); Route::post('/news/{articleId}/save', [NewsController::class, 'saveArticle']); Route::get('/news/saved', [NewsController::class, 'getSavedArticles']); Route::delete('/news/saved/{savedArticleId}', [NewsController::class, 'unsaveArticle']); }); // ====================DOCKING==================== Route::middleware('auth:sanctum')->prefix('docking')->group(function () { Route::get('history', [DockingController::class, 'history']); Route::post('submit', [DockingController::class, 'submit']); Route::get('{id}', [DockingController::class, 'status']); }); Route::get('docking/download/{id}', [DockingController::class, 'download']); // ====================CONVERT SMILES==================== Route::middleware('auth:sanctum')->prefix('convert-smiles')->group(function () { Route::get('history', [ConvertSmilesController::class, 'history']); Route::post('convert', [ConvertSmilesController::class, 'convert']); Route::get('download/{id}', [ConvertSmilesController::class, 'download']); }); // ==================== DRUG REPURPOSING / SCREENING ==================== Route::prefix('drug-repurposing')->middleware('auth:sanctum')->group(function () { Route::get('targets/history', [ScreeningController::class, 'historyTargets']); Route::post('targets', [ScreeningController::class, 'targets']); Route::get('targets/{id}', [ScreeningController::class, 'statusTargets'])->whereNumber('id'); Route::get('screen/history', [ScreeningController::class, 'historyScreening']); Route::get('screen/{id}', [ScreeningController::class, 'statusScreening'])->whereNumber('id'); Route::post('screen', [ScreeningController::class, 'screen']); }); // ==================== CHEMICAL SEARCH ==================== Route::middleware('auth:sanctum')->prefix('chemical-search')->group(function () { Route::post('/', [ChemicalSearchController::class, 'store']); Route::post('/full-rag', [ChemicalSearchController::class, 'fullRag']); }); // ==================== MD SIMULATION ==================== Route::get('/md-simulation/health', [MdSimulationController::class, 'health']); Route::middleware('auth:sanctum')->prefix('md-simulation')->group(function () { Route::post('/process', [MdSimulationController::class, 'process']); Route::get('/history', [MdSimulationController::class, 'history']); Route::get('/status/{remoteJobId}', [MdSimulationController::class, 'status']); Route::post('/analyze/{remoteJobId}', [MdSimulationController::class, 'analyze']); Route::get('/download/{remoteJobId}', [MdSimulationController::class, 'download']); Route::get('/download-analysis/{remoteJobId}', [MdSimulationController::class, 'downloadAnalysis']); }); // ==================== AI Agent ==================== Route::get('chemistry/health', [ChemistryController::class, 'health']); Route::middleware('auth:sanctum')->group(function () { Route::prefix('chemistry')->group(function () { // Threads Route::post('thread', [ChemistryController::class, 'createThread']); Route::get('threads', [ChemistryController::class, 'listThreads']); Route::post('/thread-messages', [ChemistryController::class, 'threadMessages']); // Chat Route::post('chat', [ChemistryController::class, 'chat']); // Analysis Route::post('analyze/smiles', [ChemistryController::class, 'analyzeSmiles']); Route::post('analyze/compare', [ChemistryController::class, 'compare']); Route::post('analyze/docking', [ChemistryController::class, 'docking']); // CSV Batch Route::post('csv/upload', [ChemistryController::class, 'uploadCsv']); Route::get('csv/status/{job_id}', [ChemistryController::class, 'csvStatus']); Route::get('csv/results/{job_id}', [ChemistryController::class, 'csvResults']); Route::get('csv/jobs', [ChemistryController::class, 'listJobs']); Route::delete('csv/jobs/{job_id}', [ChemistryController::class, 'deleteJob']); // User History Route::get('history', [ChemistryController::class, 'userHistory']); }); }); // ==================== ADMET PREDICTION ==================== Route::middleware('auth:sanctum')->post('/admet/predict', [AdmetController::class, 'predict']); // ==================== AI-GENERATION ==================== Route::middleware('auth:sanctum')->prefix('ai')->group(function () { Route::prefix('generation')->group(function () { Route::post('/run', [GenerationController::class, 'run']); Route::get('/history', [GenerationController::class, 'history']); Route::middleware('job.owner')->group(function () { Route::get('/status/{job_id}', [GenerationController::class, 'status']); Route::get('/jobs/{job_id}/results', [GenerationController::class, 'results']); Route::post('/jobs/{job_id}/cancel', [GenerationController::class, 'cancel']); }); }); // ========== Files ========== Route::middleware('job.owner')->get('/files/{job_id}/{filename}', [GenerationController::class, 'downloadFile']); // ========== Ligands Export ========== Route::post('/ligands/export', [LigandsController::class, 'exportLigands']); }); // ==================== STRIPE ==================== Route::post('/stripe/webhook', [StripeWebhookController::class, 'handleWebhook']); Route::middleware('auth:sanctum')->group(function () { Route::get('/plans', [SubscriptionController::class, 'plans']); Route::prefix('subscription')->group(function () { Route::post('/checkout', [SubscriptionController::class, 'checkout']); Route::get('/status', [SubscriptionController::class, 'status']); Route::post('/swap', [SubscriptionController::class, 'swap']); Route::post('/cancel', [SubscriptionController::class, 'cancel']); Route::post('/resume', [SubscriptionController::class, 'resume']); Route::get('/invoices', [SubscriptionController::class, 'invoices']); Route::get('/billing-portal', [SubscriptionController::class, 'billingPortal']); }); }); // cloudinary file upload test route Route::post('/upload-file', function (Request $request) { $request->validate([ 'file' => 'required|file', ]); try { $file = $request->file('file'); $originalName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME); $extension = $file->getClientOriginalExtension(); $cloudinary = new Cloudinary([ 'cloud' => [ 'cloud_name' => env('CLOUDINARY_CLOUD_NAME'), 'api_key' => env('CLOUDINARY_API_KEY'), 'api_secret' => env('CLOUDINARY_API_SECRET'), ], 'url' => ['secure' => true], ]); $result = $cloudinary->uploadApi()->upload( $file->getRealPath(), [ 'resource_type' => 'raw', 'public_id' => $originalName, 'filename_override' => $originalName . '.' . $extension, ] ); return response()->json([ 'url' => $result['secure_url'], ]); } catch (\Exception $e) { return response()->json([ 'error' => $e->getMessage(), ], 500); } });