This commit is contained in:
johnnyq
2026-08-06 19:18:34 -04:00
parent 942fe41b18
commit 605c7811e4
12 changed files with 309 additions and 134 deletions

View File

@@ -0,0 +1,18 @@
<?php
/*
* ITFlow - Database update to version 2.6.7 (from 2.6.6)
* Included by admin/database_updates.php - do not access directly
*/
defined('FROM_DB_UPDATER') || die("Direct file access is not allowed");
// The AI endpoints used to send a hardcoded temperature (0.5, or 0.3 for ticket
// summaries). Newer OpenAI models accept nothing but their own default and reject
// the request outright, which surfaced as "Failed to get a response from the AI API".
//
// Temperature is now per-model and optional: NULL means don't send the parameter
// at all, which is the setting that works on every provider. Existing rows get
// NULL so they stop sending it.
mysqli_query($mysqli, "ALTER TABLE `ai_models` ADD COLUMN IF NOT EXISTS `ai_model_temperature` decimal(3,2) DEFAULT NULL AFTER `ai_model_use_case`");

View File

@@ -62,6 +62,17 @@ ob_start();
</div>
</div>
<div class="form-group">
<label>Temperature</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-thermometer-half"></i></span>
</div>
<input type="number" class="form-control" name="temperature" step="0.1" min="0" max="2" value="" placeholder="Provider default">
</div>
<small class="form-text text-muted">Optional. Leave blank to let the provider use its default - some newer models reject every other value.</small>
</div>
<div class="form-group">
<textarea class="form-control" rows="8" name="prompt" placeholder="Enter a model prompt:"></textarea>
</div>

View File

@@ -4,13 +4,14 @@ require_once '../../includes/modal_header.php';
$model_id = intval($_GET['id']);
$sql = mysqli_query($mysqli, "SELECT ai_model_ai_provider_id, ai_model_id, ai_model_name, ai_model_prompt, ai_model_use_case FROM ai_models WHERE ai_model_id = $model_id LIMIT 1");
$sql = mysqli_query($mysqli, "SELECT ai_model_ai_provider_id, ai_model_id, ai_model_name, ai_model_prompt, ai_model_use_case, ai_model_temperature FROM ai_models WHERE ai_model_id = $model_id LIMIT 1");
$row = mysqli_fetch_assoc($sql);
$ai_model_ai_provider_id = intval($row['ai_model_ai_provider_id']);
$model_id = intval($row['ai_model_id']);
$model_name = escapeHtml($row['ai_model_name']);
$use_case = escapeHtml($row['ai_model_use_case']);
$temperature = escapeHtml($row['ai_model_temperature']);
$prompt = escapeHtml($row['ai_model_prompt']);
// Generate the HTML form content using output buffering.
@@ -74,6 +75,16 @@ ob_start();
</div>
</div>
<div class="form-group">
<label>Temperature</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-thermometer-half"></i></span>
</div>
<input type="number" class="form-control" name="temperature" step="0.1" min="0" max="2" value="<?= $temperature ?>" placeholder="Provider default">
</div>
<small class="form-text text-muted">Optional. Leave blank to let the provider use its default - some newer models reject every other value.</small>
</div>
<div class="form-group">
<textarea class="form-control" rows="8" name="prompt" placeholder="Enter a model prompt:"><?= $prompt ?></textarea>
</div>

View File

@@ -10,7 +10,11 @@ require_once __DIR__ . "/../includes/check_login.php";
// Only allow running post files via inclusion (prevents people/bots poking them directly)
define('FROM_POST_HANDLER', true);
// Load all admin module POST logic
// Load all admin module POST logic.
// *_model.php is a RESERVED suffix: those files are not handlers, they are inline
// field-parsing fragments that read $_POST at include time, so the glob must not
// pull them in. A handler named *_model.php is silently never loaded - name entity
// handlers around it (admin/post/ai_models.php, not ai_model.php).
if (!empty($session_is_admin)) {
foreach (glob(__DIR__ . "/post/*.php") as $admin_module) {
if (!str_ends_with($admin_module, '_model.php')) {
@@ -22,3 +26,11 @@ if (!empty($session_is_admin)) {
// Logout is shared between portals
require_once __DIR__ . "/../post/logout.php";
require_once __DIR__ . "/../post/misc.php";
// Every handler above exits or redirects, so getting here means no handler claimed
// the request - a blank page and no trace of why. Log it; the usual cause is a
// handler file that never loaded.
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$unhandled = implode(', ', array_slice(array_keys($_POST), 0, 10));
logApp('Request', 'warning', "Unhandled POST to admin/post.php - no handler matched. Fields: $unhandled");
}

View File

@@ -1,7 +1,7 @@
<?php
/*
* ITFlow - GET/POST request handler for AI Models ('ai_model')
* ITFlow - GET/POST request handler for AI Models ('ai_models')
*/
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
@@ -15,9 +15,17 @@ if (isset($_POST['add_ai_model'])) {
$prompt = escapeSql($_POST['prompt']);
$use_case = escapeSql($_POST['use_case']);
mysqli_query($mysqli,"INSERT INTO ai_models SET ai_model_name = '$model', ai_model_prompt = '$prompt', ai_model_use_case = '$use_case', ai_model_ai_provider_id = $provider_id");
// Blank means "send no temperature at all" - the only setting that works on every
// provider. Anything else rides as a numeric literal, so no quoting.
$temperature = ($_POST['temperature'] ?? '') === '' ? 'NULL' : floatval($_POST['temperature']);
$ai_model_id = mysqli_insert_id($mysqli);
mysqli_query($mysqli,"INSERT INTO ai_models SET ai_model_name = '$model', ai_model_prompt = '$prompt', ai_model_use_case = '$use_case', ai_model_temperature = $temperature, ai_model_ai_provider_id = $provider_id");
if (!mysqli_affected_rows($mysqli)) {
logApp('AI', 'error', 'Failed to create AI Model ' . $model . ': ' . mysqli_error($mysqli));
flashAlert("AI Model <strong>$model</strong> could not be created - see Admin > App Logs", 'error');
redirect();
}
logAudit("AI Model", "Create", "$session_name created AI Model $model");
@@ -36,7 +44,11 @@ if (isset($_POST['edit_ai_model'])) {
$prompt = escapeSql($_POST['prompt']);
$use_case = escapeSql($_POST['use_case']);
mysqli_query($mysqli,"UPDATE ai_models SET ai_model_name = '$model', ai_model_prompt = '$prompt', ai_model_use_case = '$use_case' WHERE ai_model_id = $model_id");
// Blank means "send no temperature at all" - the only setting that works on every
// provider. Anything else rides as a numeric literal, so no quoting.
$temperature = ($_POST['temperature'] ?? '') === '' ? 'NULL' : floatval($_POST['temperature']);
mysqli_query($mysqli,"UPDATE ai_models SET ai_model_name = '$model', ai_model_prompt = '$prompt', ai_model_use_case = '$use_case', ai_model_temperature = $temperature WHERE ai_model_id = $model_id");
logAudit("AI Model", "Edit", "$session_name edited AI Model $model");