212 lines
6.8 KiB
PHP
212 lines
6.8 KiB
PHP
<?php
|
|
|
|
class GeminiJob extends Job {
|
|
|
|
public static function jobs() { return 1; }
|
|
|
|
public $docid;
|
|
public $move=false;
|
|
|
|
public function __construct($docid, $source="unknown") {
|
|
parent::__construct($source);
|
|
$this->docid = $docid;
|
|
}
|
|
|
|
public function run() {
|
|
|
|
$pdf = false;
|
|
|
|
$subs = [
|
|
"Installation and Operating Information",
|
|
"Installation and Configuration",
|
|
"Installing and Getting Started",
|
|
"Installation/Operator's Manual",
|
|
"Installation/Operator's Guide",
|
|
"Programmer's Reference Guide",
|
|
"Field Maintenance Print Set",
|
|
"Illustrated Parts Breakdown",
|
|
"Installation/Owner's Guide",
|
|
"Installation Information",
|
|
"Installation/User Guide",
|
|
"User Documentation Kit",
|
|
"Programmer Information",
|
|
"Technical Description",
|
|
"Operator Information",
|
|
"Configuration Guide",
|
|
"Upgrade Information",
|
|
"Installation Manual",
|
|
"Service Information",
|
|
"Installation Guide",
|
|
"Programming Manual",
|
|
"Maintenance Manual",
|
|
"Maintenance Guide",
|
|
"Technical Summary",
|
|
"Operator's Guide",
|
|
"System Reference",
|
|
"User Information",
|
|
"Technical Manual",
|
|
"Language Manual",
|
|
"Service Manual",
|
|
"Service Guide",
|
|
"Read Me First",
|
|
"Owner's Guide",
|
|
"Release Notes",
|
|
"Options Guide",
|
|
"Users' Manual",
|
|
"User's Manual",
|
|
"HiTest Notes",
|
|
"User's Guide",
|
|
"Design Guide",
|
|
"User Manual",
|
|
"User Guide",
|
|
|
|
];
|
|
|
|
$doc = new Document($this->docid);
|
|
|
|
$minsize = 999999999999999;
|
|
|
|
foreach ($doc->revisions as $r) {
|
|
$p = new PDF($r->path() . "/doc.pdf");
|
|
if ($p->size() < $minsize) {
|
|
$minsize = $p->size();
|
|
$rev = $r;
|
|
$pdf = $p;
|
|
}
|
|
}
|
|
|
|
if (!$pdf) {
|
|
$this->fail("No files to upload");
|
|
return;
|
|
}
|
|
|
|
$prods = [];
|
|
$db = DB::getInstance();
|
|
$q = $db->query("select id, full_path from product");
|
|
while ($r = $db->nextRecord($q)) {
|
|
$prods[] = $r->id . "," . $r->full_path;
|
|
}
|
|
|
|
if ($doc->is_incoming()) {
|
|
$this->move = true;
|
|
}
|
|
|
|
file_put_contents("/tmp/category-list.csv", implode("\n", $prods) . "\n");
|
|
|
|
$this->status("Processing document with Gemini");
|
|
try {
|
|
$gemini = new Gemini();
|
|
// $gemini->verbose = true;
|
|
|
|
$p = new GeminiParameter("title", "object", "The title of the document (note: none of these parts should include the order number)", true);
|
|
$p->add_child("main_title", "string", "The primary portion of the title, properly recapitalized to fit English grammar", true);
|
|
$p->add_child("subtitle", "string", "Any portion of the title that could be used as a subtitle, such as 'user guide' or 'maintenance guide' etc. Remove this from the main title. Should not be the order number.");
|
|
$p->add_child("subsubtitle", "string", "Any part of the title that could be extra information such as version number or language. Should not be the order number.");
|
|
$gemini->add_parameter($p);
|
|
|
|
$p = new GeminiParameter("category", "integer", "The category the document best fits in from the provided list of categories in the file category-list.csv", true);
|
|
$gemini->add_parameter($p);
|
|
|
|
$gemini->add_parameter(new GeminiParameter("order_number", "string", "The document order number, often in the format XX-YYYYY-ZZ where YYYYY is based on the product code and ZZ is the type of document. Never more than 15 characters long."));
|
|
$gemini->add_parameter(new GeminiParameter("overview", "string", "A brief one-line overview of the document content in plain text format", true));
|
|
$gemini->add_parameter(new GeminiParameter("summary", "string", "A longer summary of the document content in markdown format", true));
|
|
$gemini->upload_callback([$this, "uploadcb"]);
|
|
$gemini->process_callback([$this, "processcb"]);
|
|
|
|
$gemini->attach($pdf->basename(), $pdf);
|
|
$gemini->attach("category-list.csv", new File("/tmp/category-list.csv"));
|
|
|
|
$lines = $gemini->geminiOverview();
|
|
} catch (Exception $e) {
|
|
$this->status($e->getMessage());
|
|
if ($e->getMessage() == "The request timed out. Please try again.") {
|
|
$this->retry("timeout");
|
|
} else if ($e->getMessage() == "HTTP Error 0 requesting AI assistance") {
|
|
$this->retry("error 0");
|
|
} else if (str_starts_with($e->getMessage(), "You exceeded your current quota, please check your plan and billing details.")) {
|
|
$this->retries++;
|
|
if ($this->retries < 5) {
|
|
$this->retry("quota exceeded");
|
|
} else {
|
|
$this->fail("Too many retries");
|
|
}
|
|
} else if ($e->getMessage() == "This model is currently experiencing high demand. Spikes in demand are usually temporary. Please try again later.") {
|
|
$this->retry("overload");
|
|
} else {
|
|
$this->fail();
|
|
}
|
|
return;
|
|
}
|
|
|
|
$data = json_decode($lines, true);
|
|
|
|
if (!$data) {
|
|
$this->fail("No response from AI");
|
|
return;
|
|
}
|
|
|
|
// Reload document since this took a while
|
|
$doc = new Document($this->docid);
|
|
|
|
if (array_key_exists("title", $data)) {
|
|
$doc->subtitle = "";
|
|
$doc->subsubtitle = "";
|
|
if (array_key_exists("main_title", $data["title"])) { $doc->title = $data['title']['main_title']; }
|
|
if (array_key_exists("subtitle", $data["title"])) { $doc->subtitle = $data['title']['subtitle']; }
|
|
if (array_key_exists("subsubtitle", $data["title"])) { $doc->subsubtitle = $data['title']['subsubtitle']; }
|
|
if ($doc->subtitle != "") {
|
|
$doc->title = str_replace(" " . $doc->subtitle, "", $doc->title);
|
|
}
|
|
}
|
|
if (array_key_exists("order_number", $data)) { $doc->internal_id = substr($data['order_number'], 0, 20); }
|
|
if (array_key_exists("summary", $data)) { $doc->overview = $data['summary']; }
|
|
if (array_key_exists("overview", $data)) { $doc->oneliner = $data['overview']; }
|
|
|
|
|
|
|
|
$doc->save();
|
|
|
|
if (array_key_exists("category", $data)) {
|
|
$cat = $data['category'];
|
|
$q = $db->query("select * from product where id=:id", ["id" => $cat]);
|
|
if ($r = $db->nextRecord($q)) {
|
|
if ($this->move) {
|
|
$q = $db->query("delete from docproduct where document=:id", ["id" => $doc->id]);
|
|
}
|
|
$edp = DocProduct::find([
|
|
["product", "=", $r->id],
|
|
["document", "=", $doc->id]
|
|
])->first();
|
|
|
|
if (!$edp) {
|
|
$dp = new DocProduct;
|
|
$dp->document = $doc->id;
|
|
$dp->product = $r->id;
|
|
$dp->save();
|
|
}
|
|
} else {
|
|
print("--- Incorrect category suggested: " . $cat . "\n");
|
|
}
|
|
}
|
|
|
|
$this->status("Finished");
|
|
$this->finish();
|
|
return;
|
|
}
|
|
|
|
|
|
public function uploadcb($percent) {
|
|
$this->status("Uploading: " . $percent . "% complete");
|
|
}
|
|
|
|
public function processcb($message) {
|
|
$this->status($message);
|
|
}
|
|
|
|
function cleanup($txt) {
|
|
$txt = str_replace("Ø", "0", $txt);
|
|
$txt = str_replace(".", " ", $txt);
|
|
return $txt;
|
|
}
|
|
}
|