Created
September 21, 2025 18:20
-
-
Save eduPHP/50c3c9e8a7fc31f83027bb3088c1cd0a to your computer and use it in GitHub Desktop.
Samples for Mixtape Co
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace App\DTO; | |
| use App\DTO\Contracts\AIInputOptions as AIInputOptionsInterface; | |
| use App\Models\Optimization; | |
| use Illuminate\Support\Collection; | |
| class AIInputOptions implements AIInputOptionsInterface | |
| { | |
| public Collection $settings; | |
| public function __construct( | |
| public string $resume = "", | |
| public bool $makeGrammaticalCorrections = false, | |
| public bool $changeProfessionalSummary = false, | |
| public bool $generateCoverLetter = false, | |
| public bool $changeTargetRole = false, | |
| public bool $mentionRelocationAvailability = false, | |
| public string $roleName = '', | |
| public string $roleDescription = '', | |
| public ?string $roleLocation = '', | |
| public string $roleCompany = '', | |
| public array $metadata = [], | |
| Collection $options = null, | |
| ) { | |
| $this->settings = $options ?? collect(); | |
| } | |
| public static function fromOptimization(Optimization $optimization): static | |
| { | |
| $content = $optimization->resume->detected_content; | |
| return new static( | |
| resume: $content, | |
| makeGrammaticalCorrections: $optimization->make_grammatical_corrections, | |
| changeProfessionalSummary: $optimization->change_professional_summary, | |
| generateCoverLetter: $optimization->generate_cover_letter, | |
| changeTargetRole: $optimization->change_target_role, | |
| mentionRelocationAvailability: $optimization->mention_relocation_availability, | |
| roleName: $optimization->role_name, | |
| roleDescription: $optimization->role_description, | |
| roleLocation: $optimization->role_location, | |
| roleCompany: $optimization->role_company, | |
| metadata: [ | |
| 'optimization_id' => $optimization->id, | |
| ], | |
| options: $optimization->user->ai_settings, | |
| ); | |
| } | |
| public function system(): array | |
| { | |
| $config = [ | |
| // Role + tone | |
| 'You are a job seeker matching your resume to job postings. Answer ONLY in JSON. Be direct: no softening. | |
| If the resume has bad compatibility bad, say so. If there is no chance of getting the job, state it directly.', | |
| // Resume context | |
| "The following is your resume and single source of truth:\n\n{$this->resume}", | |
| // Resume formatting rules | |
| 'Resume formatting rules: | |
| - Contact info → <p class="contact-info">text | text | text</p> | |
| - Section titles → <h2 class="section-title">Section Title</h2><div>Content</div> | |
| - Name → <h1 class="name">Full Name</h1><h3 class="job-title">Job Title</h3> | |
| - Experience → <h3 class="exp-title">Title</h3><p class="exp-period">place and period</p><ul>Description</ul>', | |
| // Resume improvement instructions | |
| $this->changeProfessionalSummary | |
| ? "Replace the Professional Summary with a role-specific one, emphasizing your strengths (keep the title)." | |
| : false, | |
| $this->changeTargetRole | |
| ? "Replace the Target Role (below the name) with: {$this->roleName}." | |
| : false, | |
| $this->mentionRelocationAvailability | |
| ? "At the bottom (class=\"footer\"), add: | |
| 'Available for remote work or relocation to {$this->roleLocation} through visa sponsorship'" | |
| : false, | |
| $this->mentionRelocationAvailability | |
| ? "If the company does not sponsor visas, include this fact in the 'findings' output list as a missing_requirement." | |
| : false, | |
| $this->makeGrammaticalCorrections | |
| ? "Correct grammar across the resume." | |
| : false, | |
| // Scoring logic | |
| "When compatibility_score < {$this->settings['compatibilityScoreLevels']['medium']}, | |
| provide short-term and long-term improvement plans.", | |
| // API enforcement | |
| 'Always reply ONLY with a valid JSON object that matches the schema. | |
| Do not add explanations, prefaces, or comments outside JSON.', | |
| $this->settings['instructions'] ?? false, | |
| ]; | |
| return array_filter($config); | |
| } | |
| public function user(): array | |
| { | |
| return [ | |
| "Optimize your resume for the {$this->roleLocation} market. | |
| - Reorganize sections to match {$this->roleLocation}'s best practices. | |
| - Improve content for higher selection rate. | |
| - Keep the title intact. | |
| - Role description is: {$this->roleDescription} | |
| - Translate the output resume to its language!", | |
| ]; | |
| } | |
| public function schema(): array | |
| { | |
| return [ | |
| "name" => "candidate_evaluation", | |
| "schema" => [ | |
| "type" => "object", | |
| "additionalProperties" => false, | |
| "properties" => [ | |
| "resume" => [ | |
| "type" => "string", | |
| "description" => "HTML resume, body content only, with basic styling", | |
| ], | |
| "compatibility_score" => [ | |
| "type" => "integer", | |
| "description" => "REALISTIC 0-100 score", | |
| ], | |
| "top_choice" => [ | |
| "type" => "string", | |
| "maxLength" => 400, | |
| "description" => "If compatibility_score >= {$this->settings['compatibilityScoreLevels']['top']}, first-person pitch explaining why this is a top choice. Otherwise empty string.", | |
| ], | |
| "professional_summary" => [ | |
| "type" => "string", | |
| "description" => "Same professional summary included in the resume", | |
| ], | |
| "language" => [ | |
| "type" => "string", | |
| "description" => "Language of the role description i.e. 'en_US, pt_BR, etc.'", | |
| ], | |
| "cover_letter" => [ | |
| "type" => "array", | |
| "description" => $this->generateCoverLetter | |
| ? "Return 3 paragraphs with casual phrasing, no intro or signature." | |
| : "Empty array.", | |
| "items" => ["type" => "string"], | |
| ], | |
| "findings" => [ | |
| "type" => "array", | |
| "description" => "Consolidated evaluation items: strong alignments (at least 2), moderate gaps, missing requirements, or issues.", | |
| "items" => [ | |
| "type" => "object", | |
| "additionalProperties" => false, | |
| "properties" => [ | |
| "group" => [ | |
| "type" => "string", | |
| "enum" => ["strong_alignment", "moderate_gap", "missing_requirement", "issue"], | |
| "description" => "Classification of the finding.", | |
| ], | |
| "title" => ["type" => "string"], | |
| "description" => ["type" => "string"], | |
| ], | |
| "required" => ["group", "title", "description"], | |
| ], | |
| ], | |
| "reasoning" => [ | |
| "type" => "string", | |
| "description" => "Would you recommend this candidate? How can they improve their resume to match the job description?", | |
| ], | |
| ], | |
| "required" => [ | |
| "resume", | |
| "compatibility_score", | |
| "professional_summary", | |
| "language", | |
| "cover_letter", | |
| "findings", | |
| "reasoning", | |
| "top_choice", | |
| ], | |
| ], | |
| ]; | |
| } | |
| public function metadata(): array | |
| { | |
| return $this->metadata; | |
| } | |
| public function getTextPrompt(): string | |
| { | |
| $prompt = ""; | |
| collect($this->system())->each(function ($line) use (&$prompt) { | |
| $prompt .= "# System:\n$line\n\n"; | |
| }); | |
| collect($this->user())->each(function ($line) use (&$prompt) { | |
| $prompt .= "# User:\n$line\n\n"; | |
| }); | |
| return $prompt; | |
| } | |
| public function toArray(): array | |
| { | |
| return [ | |
| 'system' => $this->system(), | |
| 'user' => $this->user(), | |
| 'metadata' => $this->metadata(), | |
| ]; | |
| } | |
| public function __toString(): string | |
| { | |
| return $this->getTextPrompt(); | |
| } | |
| public function model(): string | |
| { | |
| return $this->settings['model'] ?? config('openai.model'); | |
| } | |
| public function idempotencyKey(): string | |
| { | |
| return $this->model() . '-response-' . sha1($this->__toString()); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <x-layout> | |
| <x-slot:breadcrumbs> | |
| <x-breadcrumbs.appointments.appointments-breadcrumbs :$for/> | |
| </x-slot:breadcrumbs> | |
| <x-card.wrapper stack> | |
| <x-card> | |
| <x-title>{{ __('Daily Calendar (By Zone & Assignees)') }}</x-title> | |
| <x-card.row class="mx-0 mb-2"> | |
| <x-card.column class="md:w-1/2"> | |
| <livewire:calendars.partials.zone-filter :wire:key="'zone-filter-'.time()" :$for/> | |
| </x-card.column> | |
| <x-card.column class="md:w-1/2"> | |
| <livewire:calendars.partials.grid-results :wire:key="'result-filter-'.time()" /> | |
| </x-card.column> | |
| </x-card.row> | |
| <livewire:calendars.user-view :wire:key="'by-user-scheduler-'.time()" cy="calendars-user-view" :$for /> | |
| </x-card> | |
| </x-card.wrapper> | |
| </x-layout> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace Modules\OpenAI; | |
| use App\DTO\Contracts\AIInputOptions; | |
| use App\DTO\Contracts\AIAgentPrompter; | |
| use App\DTO\Contracts\AIResponseDTO; | |
| use App\Exceptions\RequestException; | |
| use Illuminate\Support\Arr; | |
| use Illuminate\Support\Facades\Http; | |
| class OpenAIPrompter implements AIAgentPrompter | |
| { | |
| public function handle(AIInputOptions $options): AIResponseDTO | |
| { | |
| $incrementUsage = ! cache()->has($options->idempotencyKey()); | |
| /** @var array $content */ | |
| $content = cache()->remember($options->idempotencyKey(), now()->addDay(), function () use ($options) { | |
| $response = Http::withToken(config('openai.openai_api_key')) | |
| ->withOptions(['timeout' => 300]) | |
| ->post(config('openai.endpoint'), [ | |
| 'model' => $options->model(), | |
| 'store' => true, | |
| 'metadata' => $options->metadata(), | |
| 'input' => [ | |
| ...array_map(fn($instruction) => ['role' => 'system', 'content' => $instruction], $options->system()), | |
| ...array_map(fn($instruction) => ['role' => 'user', 'content' => $instruction], $options->user()), | |
| ], | |
| ...$this->getSchemaSettings($options) | |
| ]); | |
| if ($response->successful() === false) { | |
| throw new RequestException($response->json('error.message'), $response->getStatusCode()); | |
| } | |
| return $response->json(); | |
| }); | |
| \Log::debug('OpenAI Response', [$options->idempotencyKey() => $content]); | |
| return new OpenAiResponse( | |
| ...$this->cleanup($content['output']), | |
| usage: $incrementUsage ? $content['usage']['total_tokens'] : 0, | |
| id: $content['id'], | |
| model: $content['model'], | |
| ); | |
| } | |
| private function cleanup(array $outputs): array | |
| { | |
| $response = Arr::first($outputs, function ($output) { | |
| return $output['type'] === 'message'; | |
| }); | |
| return json_decode($response['content'][0]['text'], true); | |
| } | |
| private function getSchemaSettings(AIInputOptions $options): array | |
| { | |
| $textFormat = ['gpt-4.1', 'gpt-4o-mini']; | |
| if (in_array(config('openai.model'), $textFormat)) { | |
| return [ | |
| 'text' => [ | |
| 'format' => [ | |
| 'type' => 'json_schema', | |
| ...$options->schema(), | |
| ], | |
| ], | |
| ]; | |
| } | |
| return [ | |
| 'response_format' => [ | |
| 'type' => 'json_schema', | |
| 'json_schema' => $options->schema(), | |
| ] | |
| ]; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment