123 lines
4.0 KiB
PHP
123 lines
4.0 KiB
PHP
<?php
|
|||
|
|
|
||
|
|
namespace App\Console\Commands;
|
||
|
|
|
||
|
|
use App\Models\Job;
|
||
|
|
use App\Models\Tag;
|
||
|
|
use Illuminate\Console\Attributes\Description;
|
||
|
|
use Illuminate\Console\Attributes\Signature;
|
||
|
|
use Illuminate\Console\Command;
|
||
|
|
use Illuminate\Support\Facades\Http;
|
||
|
|
use Illuminate\Support\Facades\Log;
|
||
|
|
|
||
|
|
#[Signature('jobs:curate {--batch=50}')]
|
||
|
|
#[Description('Curate jobs by fetching tags from an external API')]
|
||
|
|
class CurateJobs extends Command
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* Execute the console command.
|
||
|
|
*/
|
||
|
|
public function handle(): int
|
||
|
|
{
|
||
|
|
$batchSize = (int) $this->option('batch');
|
||
|
|
//$apiUrl = $this->option('api-url');
|
||
|
|
$apiUrl = 'https://loki.c0rrup7.net';
|
||
|
|
|
||
|
|
if (empty($apiUrl)) {
|
||
|
|
$this->error('API URL is required. Use --api-url option to provide the endpoint.');
|
||
|
|
return self::FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->info('Starting job curation...');
|
||
|
|
$this->newLine();
|
||
|
|
|
||
|
|
// Fetch uncurated jobs
|
||
|
|
$uncuratedJobs = Job::uncurated()
|
||
|
|
->limit($batchSize)
|
||
|
|
->get();
|
||
|
|
|
||
|
|
if ($uncuratedJobs->isEmpty()) {
|
||
|
|
$this->info('No uncurated jobs found.');
|
||
|
|
return self::SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->info("Found {$uncuratedJobs->count()} uncurated jobs.");
|
||
|
|
$this->newLine();
|
||
|
|
|
||
|
|
$curatedCount = 0;
|
||
|
|
$failedCount = 0;
|
||
|
|
|
||
|
|
$progressBar = $this->output->createProgressBar($uncuratedJobs->count());
|
||
|
|
$progressBar->start();
|
||
|
|
|
||
|
|
foreach ($uncuratedJobs as $job) {
|
||
|
|
try {
|
||
|
|
$body = 'This is the content of a job ad, you need to read it and extract the relevant tags from it. Respond only with the tags in JSON format, NO OTHER TEXT BEFOR OR AFTER THE JSON.';
|
||
|
|
$body .= 'Title: '. htmlentities($job->title);
|
||
|
|
$body .= 'Description: '. htmlentities($job->description);
|
||
|
|
|
||
|
|
// Make POST request to API with job name and description
|
||
|
|
$response = Http::timeout(130)
|
||
|
|
->withHeaders([
|
||
|
|
'Accept' => 'application/json',
|
||
|
|
'X-Api-Key' => '1620539ff09a897a7281a8b626c145e5',
|
||
|
|
])
|
||
|
|
->post($apiUrl, [
|
||
|
|
'service' => 'ollama',
|
||
|
|
'model' => 'llama3',
|
||
|
|
'stream' => false,
|
||
|
|
'prompt' => $body,
|
||
|
|
]);
|
||
|
|
|
||
|
|
if ($response->successful()) {
|
||
|
|
$tags = $response->json();
|
||
|
|
|
||
|
|
if (is_array($tags) && !empty($tags)) {
|
||
|
|
$tagIds = [];
|
||
|
|
|
||
|
|
foreach ($tags as $tagName) {
|
||
|
|
// Find or create tag
|
||
|
|
$tag = Tag::firstOrCreate(
|
||
|
|
['name' => $tagName]
|
||
|
|
);
|
||
|
|
|
||
|
|
$tagIds[] = $tag->id;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Sync tags with the job
|
||
|
|
$job->tags()->sync($tagIds);
|
||
|
|
|
||
|
|
// Mark job as curated
|
||
|
|
$job->update(['is_curated' => true]);
|
||
|
|
|
||
|
|
$curatedCount++;
|
||
|
|
} else {
|
||
|
|
// Mark as curated even if no tags returned
|
||
|
|
$job->update(['is_curated' => true]);
|
||
|
|
$curatedCount++;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
$failedCount++;
|
||
|
|
Log::warning("Failed to curate job #{$job->id}: API returned {$response->status()}");
|
||
|
|
}
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
$failedCount++;
|
||
|
|
Log::error("Error curating job #{$job->id}: {$e->getMessage()}");
|
||
|
|
}
|
||
|
|
|
||
|
|
$progressBar->advance();
|
||
|
|
}
|
||
|
|
|
||
|
|
$progressBar->finish();
|
||
|
|
$this->newLine(2);
|
||
|
|
|
||
|
|
$this->info("Successfully curated {$curatedCount} jobs.");
|
||
|
|
|
||
|
|
if ($failedCount > 0) {
|
||
|
|
$this->warn("Failed to curate {$failedCount} jobs. Check logs for details.");
|
||
|
|
}
|
||
|
|
|
||
|
|
return self::SUCCESS;
|
||
|
|
}
|
||
|
|
}
|