/home/edulekha/crm.edulekha.com/modules/openai/controllers/Finetuning.php
<?php

use app\services\ai\AiProviderRegistry;
use Perfexcrm\Openai\OpenAiProvider;

defined('BASEPATH') or exit('No direct script access allowed');

class Finetuning extends AdminController
{
    /**
     * Display the fine-tuning management page
     */
    public function index()
    {
        if (staff_cant('view', 'settings')) {
            access_denied('OpenAI Settings');
        }

        /** @var OpenAiProvider */
        $provider = AiProviderRegistry::getProvider('openai');

        // Get fine-tuned models
        $fineTunedModels = $provider->getFineTunedModels();

        $currentFineTunedModel = get_option('openai_fine_tuned_model');
        $useFineTuning         = get_option('openai_use_fine_tuning') == '1';
        $finetuningBaseModel   = get_option('openai_fine_tuning_base_model') ?: OpenAiProvider::defaultFineTuningModel();
        $ourFineTunedModel     = get_option('openai_our_fine_tuned_model');
        $lastJobId             = get_option('openai_fine_tuning_last_job_id');
        $lastJob               = [];

        if ($lastJobId) {
            try {
                $lastJob = $provider->retrieveFineTuningJob($lastJobId);

                if (! empty($lastJob['model']) && (empty($ourFineTunedModel) || $ourFineTunedModel !== $lastJob['model'])) {
                    update_option('openai_our_fine_tuned_model', $lastJob['model']);
                    $ourFineTunedModel = $lastJob['model'];
                }
            } catch (Exception $e) {
                // Handle exception if the job is not found or any other error occurs
                log_message('error', 'Error retrieving fine-tuning job: ' . $e->getMessage());
            }
        }

        // Count knowledge base articles
        $this->db->where('active', 1);
        $this->db->where('staff_article', 0);
        $articleCount = $this->db->count_all_results(db_prefix() . 'knowledge_base');

        $this->load->view('openai/finetuning/manage', [
            'title'                          => _l('openai_fine_tuning'),
            'fine_tuned_models'              => $fineTunedModels,
            'current_fine_tuned_model'       => $currentFineTunedModel,
            'our_fine_tuned_model'           => $ourFineTunedModel,
            'use_fine_tuning'                => $useFineTuning,
            'last_job_id'                    => $lastJobId,
            'last_job'                       => $lastJob,
            'article_count'                  => $articleCount,
            'predefined_replies_count'       => $predefinedRepliesCount = $this->db->count_all_results(db_prefix() . 'tickets_predefined_replies'),
            'fine_tuning_base_model'         => $finetuningBaseModel,
            'fine_tuning_models'             => OpenAiProvider::getFineTuningModels(),
            'meets_fine_tuning_requirements' => $meetsRequirements = $articleCount >= 10 || $predefinedRepliesCount >= 10,
            'can_fine_tune'                  => $meetsRequirements && (is_null($lastJob['status'] ?? null) || in_array($lastJob['status'], ['succeeded', 'failed', 'cancelled'])),
        ]);
    }

    public function set_base_model()
    {
        if (staff_cant('edit', 'settings')) {
            access_denied('OpenAI Settings');
        }

        $data = $this->input->post();

        update_option('openai_fine_tuning_base_model', $data['model']);

        echo json_encode([
            'success' => true,
            'message' => _l('settings_updated'),
        ]);
    }

    /**
     * Start a new fine-tuning job
     */
    public function start_job()
    {
        if (staff_cant('edit', 'settings')) {
            access_denied('OpenAI Settings');
        }

        $this->load->library('openai/fine_tuner');
        $result = $this->fine_tuner->startFineTuning();

        echo json_encode($result);
    }

    /**
     * Check the status of a fine-tuning job
     */
    public function check_status()
    {
        if (staff_cant('edit', 'settings')) {
            access_denied('OpenAI Settings');
        }

        $jobId = $this->input->post('job_id');

        $this->load->library('openai/fine_tuner');
        $result = $this->fine_tuner->checkFineTuningStatus($jobId);

        echo json_encode($result);
    }

    /**
     * Toggle the use of fine-tuning
     */
    public function toggle_use()
    {
        if (staff_cant('edit', 'settings')) {
            access_denied('OpenAI Settings');
        }

        $useFineTuning = $this->input->post('use_fine_tuning') === 'true';
        update_option('openai_use_fine_tuning', $useFineTuning ? '1' : '0');

        echo json_encode([
            'success' => true,
            'message' => $useFineTuning ? _l('fine_tuning_enabled') : _l('fine_tuning_disabled'),
        ]);
    }

    /**
     * Set the active fine-tuned model
     */
    public function set_model()
    {
        if (staff_cant('edit', 'settings')) {
            access_denied('OpenAI Settings');
        }

        $modelId = $this->input->post('model_id');
        update_option('openai_fine_tuned_model', $modelId);

        update_option('openai_use_fine_tuning', '1');

        echo json_encode([
            'success' => true,
            'message' => _l('fine_tuned_model_set'),
        ]);
    }

    /**
     * Delete a fine-tuned model
     */
    public function delete_model()
    {
        if (staff_cant('edit', 'settings')) {
            access_denied('OpenAI Settings');
        }

        $modelId = $this->input->post('model_id');

        /** @var OpenAiProvider */
        $provider = AiProviderRegistry::getProvider('openai');
        $result   = $provider->deleteFineTunedModel($modelId);

        echo json_encode([
            'success' => $result,
            'message' => $result ? _l('fine_tuned_model_deleted') : _l('fine_tuned_model_delete_failed'),
        ]);
    }
}