prepare($sql); $data_da = $anno . "-01-01"; $data_a = $anno . "-12-31"; $stmt->bindValue(':da', $data_da); $stmt->bindValue(':a', $data_a); $stmt->bindValue(':lim', $maxPerBatch, PDO::PARAM_INT); $stmt->execute(); $infortuni = $stmt->fetchAll(PDO::FETCH_ASSOC); if ($infortuni) { foreach ($infortuni as $inf) { $risultato = chiamaChatGPT_per_infortunio($inf); if ($risultato && isset($risultato['processo'])) { // aggiorno DB $upd = $pdo->prepare(" UPDATE infortuni_estesi SET processo = :processo, famiglia_rischio = :famiglia_rischio, dinamica_codificata = :dinamica_codificata, fattore_rischio_principale = :fattore_rischio_principale WHERE id = :id "); $upd->execute([ ':processo' => $risultato['processo'], ':famiglia_rischio' => $risultato['famiglia_rischio'], ':dinamica_codificata' => $risultato['dinamica_codificata'], ':fattore_rischio_principale' => $risultato['fattore_rischio_principale'], ':id' => $inf['id'] ]); $log[] = "Infortunio ID {$inf['id']} classificato come [{$risultato['processo']} / {$risultato['famiglia_rischio']}]"; } else { $log[] = "Infortunio ID {$inf['id']} – nessuna risposta valida dall'IA."; } } } else { $log[] = "Nessun infortunio da classificare per l'anno $anno."; } } // Conteggio quanti rimangono da classificare $stmt = $pdo->prepare(" SELECT COUNT(*) FROM infortuni_estesi WHERE data_infortunio BETWEEN :da AND :a AND (processo IS NULL OR processo = '') "); $stmt->execute([ ':da' => $anno . "-01-01", ':a' => $anno . "-12-31" ]); $daClassificare = (int)$stmt->fetchColumn(); /** * Funzione che chiama ChatGPT API per un singolo infortunio */ function chiamaChatGPT_per_infortunio(array $inf) { $prompt = build_prompt($inf); $apiKey = OPENAI_API_KEY; $url = "https://api.openai.com/v1/chat/completions"; $body = [ "model" => "gpt-4.1-mini", // o il modello che vuoi usare "messages" => [ [ "role" => "system", "content" => "Sei un assistente per la sicurezza sul lavoro. Data la descrizione di un infortunio in azienda di raccolta rifiuti, devi classificare il caso restituendo un JSON con le chiavi: processo, famiglia_rischio, dinamica_codificata, fattore_rischio_principale. Scrivi solo JSON valido." ], [ "role" => "user", "content" => $prompt ] ], "temperature" => 0.2 ]; $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . $apiKey ], CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($body), CURLOPT_TIMEOUT => 30 ]); $response = curl_exec($ch); if ($response === false) { return null; } $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($status < 200 || $status >= 300) { return null; } $data = json_decode($response, true); if (!isset($data['choices'][0]['message']['content'])) { return null; } $content = $data['choices'][0]['message']['content']; // Il modello risponde con JSON, lo decodifichiamo $json = json_decode($content, true); if (!$json) { // se per qualche motivo risponde testo normale, potresti fare parsing, // ma per ora torniamo null return null; } return [ 'processo' => $json['processo'] ?? null, 'famiglia_rischio' => $json['famiglia_rischio'] ?? null, 'dinamica_codificata' => $json['dinamica_codificata'] ?? null, 'fattore_rischio_principale' => $json['fattore_rischio_principale'] ?? null, ]; } function build_prompt(array $inf) { $txt = "Ti fornisco i dati di un infortunio in un'azienda che si occupa di raccolta e gestione rifiuti.\n"; $txt .= "Devi classificare il caso scegliendo:\n"; $txt .= "- processo tra: 'servizi esterni', 'centro raccolta', 'officina', 'sede aziendale', 'centro di trasferenza'\n"; $txt .= "- famiglia_rischio (esempi: scivolamento/inciampo, movimentazione manuale carichi, schiacciamento, incidente stradale/investimento, corpo estraneo nell'occhio, urto/schiacciamento, puntura/taglio, morso animale, ecc.)\n"; $txt .= "- dinamica_codificata (riassunto in 5–15 parole)\n"; $txt .= "- fattore_rischio_principale (es. meteo/ghiaccio, appoggio instabile, coordinamento squadra, organizzazione, DPI, traffico veicolare, ecc.).\n\n"; $txt .= "Dati caso:\n"; $txt .= "ID: {$inf['id']}\n"; $txt .= "Data: {$inf['data_infortunio']}\n"; $txt .= "Centro: {$inf['nome_centro']}\n"; $txt .= "Tipo evento: {$inf['tipo']}\n"; $txt .= "Gravità: {$inf['gravita']}\n"; $txt .= "Area: {$inf['area']}\n"; $txt .= "Mansione: {$inf['mansione']}\n"; $txt .= "Descrizione: {$inf['descrizione_evento']}\n\n"; $txt .= "Rispondi SOLO con un JSON come questo esempio:\n"; $txt .= "{\n"; $txt .= " \"processo\": \"servizi esterni\",\n"; $txt .= " \"famiglia_rischio\": \"scivolamento/inciampo\",\n"; $txt .= " \"dinamica_codificata\": \"Scende dal mezzo e distorce la caviglia\",\n"; $txt .= " \"fattore_rischio_principale\": \"appoggio instabile/discesa dal mezzo\"\n"; $txt .= "}\n"; return $txt; } ?>
Infortuni dell'anno da classificare:
Ad ogni clic verranno classificati al massimo infortuni (per contenere l’uso dell’API).