<?php
namespace App\Helper;
use App\Entity\AiCount;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpKernel\Exception\HttpException;
class AiHelper
{
private $apiKey;
private $apiKeyMistral;
public $entityManager;
public function __construct(ParameterBagInterface $params, EntityManagerInterface $entityManager = null)
{
$this->apiKey = $params->get('gemini_api_key');
$this->apiKeyMistral = 'dFkwpcRnE237t2oKIFbHcTBNRnQg9NNc';
$this->entityManager = $entityManager;
}
public function generateContent(string $prompt, bool $jsonOutput = false)
{
// 1. Check Model Name (Ensure 2.0 is available, otherwise switch to 1.5)
$url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-lite-latest:generateContent?key=" . $this->apiKey;
$data = [
'contents' => [['parts' => [['text' => $prompt]]]]
];
if ($jsonOutput) {
$data['generationConfig'] = [
'response_mime_type' => 'application/json'
];
}
$options = [
'http' => [
'header' => "Content-Type: application/json\r\n",
'method' => 'POST',
'content' => json_encode($data),
'ignore_errors' => true // 2. Allow reading the error body from Google
]
];
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
// 3. Robust Error Handling
if ($result === false) {
// Handle connection failure
return 'Error: Could not connect to AI service.';
}
$decodedResult = json_decode($result, true);
// Check if Google returned an error structure
if (isset($decodedResult['error'])) {
// Log this error or return it to understand why it fails
return 'API Error: ' . ($decodedResult['error']['message'] ?? 'Unknown error');
}
// 4. Fix Database Logic: Normalize date to Midnight (00:00:00)
// This ensures we only have ONE row per day
$countDate = new \DateTime('today midnight');
$existingAiCount = $this->entityManager->getRepository(AiCount::class)
->findOneBy(['countDate' => $countDate]);
if ($existingAiCount) {
$existingAiCount->setCounter($existingAiCount->getCounter() + 1);
} else {
$aiCount = new AiCount();
$aiCount->setCountDate($countDate);
$aiCount->setCounter(1);
$this->entityManager->persist($aiCount);
}
// 5. Optimization: Move cleanup to a CRON job ideally.
// If keeping it here, do it randomly (1 in 100 calls) to save performance
if (rand(1, 100) === 1) {
$this->cleanupOldCounts();
}
$this->entityManager->flush();
return $decodedResult['candidates'][0]['content']['parts'][0]['text'] ?? 'No response generated';
}
public function generateContentMistral(string $prompt, $model = 'mistral-small-latest', bool $jsonOutput = false): string
{
$url = "https://api.mistral.ai/v1/chat/completions";
$data = [
// 'model' => $model, // mistral-large-latest / mistral-small-latest
'model' => 'mistral-tiny-latest', // mistral-large-latest / mistral-small-latest
'messages' => [['role' => 'user', 'content' => $prompt]]
];
if ($jsonOutput) {
$data['response_format'] = ['type' => 'json_object'];
}
$options = [
'http' => [
'header' => "Content-Type: application/json\r\n" .
"Authorization: Bearer " . $this->apiKeyMistral . "\r\n",
'method' => 'POST',
'content' => json_encode($data)
]
];
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
$decoded = json_decode($result, true);
$countDate = new \DateTime('today midnight');
$existingAiCount = $this->entityManager->getRepository(AiCount::class)
->findOneBy(['countDate' => $countDate]);
if ($existingAiCount) {
$existingAiCount->setCounter($existingAiCount->getCounter() + 1);
} else {
$aiCount = new AiCount();
$aiCount->setCountDate($countDate);
$aiCount->setCounter(1);
$this->entityManager->persist($aiCount);
}
$this->entityManager->flush();
return $decoded['choices'][0]['message']['content'] ?? '';
}
private function cleanupOldCounts()
{
$threeMonthsAgo = (new \DateTime())->modify('-3 months');
// Use DELETE query instead of loading entities (Much faster)
$this->entityManager->createQueryBuilder()
->delete(AiCount::class, 'a')
->where('a.countDate < :threeMonthsAgo')
->setParameter('threeMonthsAgo', $threeMonthsAgo)
->getQuery()
->execute();
}
public function justCorrect(string $text)
{
return $this->generateContent('Corriger ce texte sans en changer le sens ni la mise en forme ni balise html : "'.$text.'" Ne retourner que le texte corrigé et rien d\'autre. Conserver la mise en forme HTML.');
}
}