Google Gemini: API
Odborník na umělou inteligenci, vynikající PHP programátor a úžadný člověk David Grudl před časem zveřejnil sneak peek pluginu do Admineru, který dovoluje sestavovat SQL dotazy pomocí AI. Navázal tak na svůj SQL Wizard. Plugin ale nikdy nepublikoval, tak si možná část lidí myslela, že to je fake. Řekl jsem si, jak by asi bylo složité to doopravdy udělat, a ukázalo se, že úplně triviální! Použil jsem Google Gemini a z jednoduchosti jeho nasazení jsem byl velmi mile překvapen. Nemusíte chodit do žádné Google Cloud Console (která je neuvěřitelně nepřehledná), ale prostě přímo v AI Studiu vygenerujete klíč a hned vidíte URL, na kterém ho můžete použít. Implementace v PHP je pak už jednoduchá:
<?php /** Položení dotazu Google Gemini * @param string Dotaz v přirozeném jazyce * @param string Klíč získáte na https://aistudio.google.com/apikey * @param string Dostupné modely: https://ai.google.dev/gemini-api/docs/models#available-models * @return string Odpověď umělé inteligence * @copyright Jakub Vrána, https://php.vrana.cz/ */ function gemini($prompt, $apiKey, $model = "gemini-2.0-flash") { $context = stream_context_create(array("http" => array( "method" => "POST", "header" => array("User-Agent: PHP", "Content-Type: application/json"), "content" => '{"contents": [{"parts":[{"text": ' . json_encode($prompt) . '}]}]}', ))); $response = json_decode(file_get_contents("https://generativelanguage.googleapis.com/v1beta/models/$model:generateContent?key=$apiKey", false, $context)); return $response->candidates[0]->content->parts[0]->text; } ?>
V pluginu pak dotazu od uživatele předřadím schéma databáze a přidám nějakou omáčku, aby to vracelo skutečně jen SQL dotaz, který pak prostě zobrazím. Funguje to naprosto neskutečně:
Poradí si to dokonce i s češtinou, umí to vytvářet i INSERT
, přidávat indexy a já nevím, co ještě:
Plugin vyžaduje Adminer 5.1.0, kam jsem přidal hook pro zobrazení promptu na tom správném místě, jinak si to žádnou změnu nevyžádalo.
Diskuse
Tomáš:
Pěkné, díky moc za updaty. Zjistil jsem, že při zapnutém pluginu CodeMirror se nevrací text do editoru SQL dotazu. Upravil jsem si takto.codemirror.php:
var cmt = cm;
sql-gemini.php:
cmt.setValue(req.responseText);
cmt.refresh();
Jakub Vrána
:
Díky, opravil jsem.


Jenda:
Co potřebuji upravit, abych tuhle featuru přidal do Editoru v read only režimu?Jenda:
Do homepage() jsem pridal form, v headers() zpracovam gemini dotaz s tim ze ma delat jen selecty a ukladam sql do tridni promenne, a v homepage pred formularem zase vypisuju data z get_rows(). Skoncim pokud v odpovedi prijde delete/truncate/alter/insert...
Jakub Vrána
:
Super! Zveřejníš to? Já původně zvažoval dát tam tlačítko I'm feeling lucky, který by dotazy rovnou prováděl.


Jenda:
zatim to mam nějak takto:<?php
function homepage() {
if ($this->gem) {
if ($this->containsForbiddenWords($this->gem)) {
echo "Chyba dotazu";
} else {
echo $this->renderTable(Adminer\get_rows($this->gem));
}
}
echo "<form action='' method='post' enctype='multipart/form-data' id='form'><p><textarea name='gemini' rows='5' cols='50' title='AI prompt'>" . Adminer\h($_POST["gemini"]) . "</textarea>
<p><input type='submit' value='Hledej s AI'></p></form>\n";
return true;
}
function headers() {
if ($_POST["gemini"] && !isset($_POST["query"])) {
$prompt = "You are a data analyst. I have a " . Adminer\get_driver(Adminer\DRIVER) . " database with this structure:\n\n";
foreach (Adminer\tables_list() as $table => $type) {
$prompt .= Adminer\create_sql($table, false, "CREATE") . ";\n\n";
}
$prompt .= "Only use SELECT statements. Do not use any commands that modify the database structure or data, such as INSERT, UPDATE, DELETE, TRUNCATE, or ALTER. Prefer returning more columns. Dont return any comments. Your task is to generate SQL query to retrieve data from the database for reporting purposes. Add column names into first row, if doing aggregation better use union all to display column names in first row. \n\n";
$prompt .= "Give me one SQL SELECT query and nothing else for following question:\n\n$_POST[gemini]\n\n";
//~ echo $prompt; exit;
$context = stream_context_create(array("http" => array(
"method" => "POST",
"header" => array("User-Agent: AdminerSqlGemini", "Content-Type: application/json"),
"content" => '{"contents": [{"parts":[{"text": ' . json_encode($prompt) . '}]}]}',
)));
$response = json_decode(file_get_contents("https://generativelanguage.googleapis.com/v1beta/models/".$this->model.":generateContent?key=".$this->apiKey, false, $context));
$text = $response->candidates[0]->content->parts[0]->text;
$in_code = false;
$this->gem = "";
foreach (preg_split('~(^|\n)```(sql)?(\n|$)~', $text) as $part) {
$part = trim($part);
if ($part) {
$this->gem.= ($in_code ? $part : "/*\n$part\n*/") . "\n\n";
}
$in_code = !$in_code;
}
}
}
?>
Někdy poplete sql a do prvního řádku v selectu vloží konstanty názvů sloupcu místo hodnot.. je to mírně experimentální. Ani netuším, jestli to je správně použití homepage() a header()... zhodnotte
Jakub Vrána
:
Asi by to mohlo být v homepage() celé. Žádné hlavičky to zdá se neposílá, tak to být v headers() nemusí.
Jinak super!


Vložit komentář

