style updates
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AI\Services;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Modules\AI\Contracts\AIManager as AIManagerContract;
|
||||
use Modules\AI\Contracts\AIProviderDriver;
|
||||
@@ -7,36 +9,57 @@ use Modules\AI\Drivers\OpenAICompatibleDriver;
|
||||
use Modules\AI\Models\AIExecution;
|
||||
use Modules\AI\Models\AIPrompt;
|
||||
use Modules\AI\Models\AIProvider;
|
||||
|
||||
final class AIManager implements AIManagerContract
|
||||
{
|
||||
public function execute(AIPrompt|string $prompt,array $variables=[],array $options=[]): AIExecution
|
||||
public function execute(AIPrompt|string $prompt, array $variables = [], array $options = []): AIExecution
|
||||
{
|
||||
$promptModel=is_string($prompt)?AIPrompt::where('slug',$prompt)->where('is_active',true)->firstOrFail():$prompt;
|
||||
$provider=$this->provider($options['provider_id']??null); $input=$promptModel->render($variables);
|
||||
$execution=AIExecution::create(['execution_id'=>(string)Str::uuid(),'ai_provider_id'=>$provider->id,'ai_prompt_id'=>$promptModel->id,'user_id'=>auth()->id(),'model'=>$options['model']??$provider->default_model,'purpose'=>$promptModel->purpose,'input'=>$input,'context'=>$variables,'status'=>'running']);
|
||||
$started=microtime(true);
|
||||
$promptModel = is_string($prompt) ? AIPrompt::where('slug', $prompt)->where('is_active', true)->firstOrFail() : $prompt;
|
||||
$provider = $this->provider($options['provider_id'] ?? null);
|
||||
$input = $promptModel->render($variables);
|
||||
$execution = AIExecution::create(['execution_id' => (string) Str::uuid(), 'ai_provider_id' => $provider->id, 'ai_prompt_id' => $promptModel->id, 'user_id' => auth()->id(), 'model' => $options['model'] ?? $provider->default_model, 'purpose' => $promptModel->purpose, 'input' => $input, 'context' => $variables, 'status' => 'running']);
|
||||
$started = microtime(true);
|
||||
try {
|
||||
$messages=[]; if (filled($promptModel->system_prompt)) $messages[]=['role'=>'system','content'=>$promptModel->system_prompt];
|
||||
$messages[]=['role'=>'user','content'=>$input]; $result=$this->driver($provider)->generate($provider,$messages,$options);
|
||||
$execution->update(['output'=>$result['text'],'usage'=>$result['usage'],'status'=>'completed','duration_ms'=>(int)((microtime(true)-$started)*1000),'completed_at'=>now()]);
|
||||
$messages = [];
|
||||
if (filled($promptModel->system_prompt)) {
|
||||
$messages[] = ['role' => 'system', 'content' => $promptModel->system_prompt];
|
||||
}
|
||||
$messages[] = ['role' => 'user', 'content' => $input];
|
||||
$result = $this->driver($provider)->generate($provider, $messages, $options);
|
||||
$execution->update(['output' => $result['text'], 'usage' => $result['usage'], 'status' => 'completed', 'duration_ms' => (int) ((microtime(true) - $started) * 1000), 'completed_at' => now()]);
|
||||
} catch (\Throwable $e) {
|
||||
report($e); $execution->update(['status'=>'failed','error'=>$e->getMessage(),'duration_ms'=>(int)((microtime(true)-$started)*1000),'completed_at'=>now()]);
|
||||
report($e);
|
||||
$execution->update(['status' => 'failed', 'error' => $e->getMessage(), 'duration_ms' => (int) ((microtime(true) - $started) * 1000), 'completed_at' => now()]);
|
||||
}
|
||||
|
||||
return $execution->refresh();
|
||||
}
|
||||
|
||||
public function testProvider(int $providerId): array
|
||||
{
|
||||
$provider=AIProvider::findOrFail($providerId);
|
||||
try { $result=$this->driver($provider)->test($provider); $provider->update(['last_tested_at'=>now(),'last_test_status'=>'passed','last_test_message'=>$result['message']]); return $result; }
|
||||
catch (\Throwable $e) { $provider->update(['last_tested_at'=>now(),'last_test_status'=>'failed','last_test_message'=>$e->getMessage()]); return ['ok'=>false,'message'=>$e->getMessage()]; }
|
||||
$provider = AIProvider::findOrFail($providerId);
|
||||
try {
|
||||
$result = $this->driver($provider)->test($provider);
|
||||
$provider->update(['last_tested_at' => now(), 'last_test_status' => 'passed', 'last_test_message' => $result['message']]);
|
||||
|
||||
return $result;
|
||||
} catch (\Throwable $e) {
|
||||
$provider->update(['last_tested_at' => now(), 'last_test_status' => 'failed', 'last_test_message' => $e->getMessage()]);
|
||||
|
||||
return ['ok' => false, 'message' => $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
||||
private function provider(?int $id): AIProvider
|
||||
{
|
||||
return AIProvider::query()->when($id,fn($q)=>$q->whereKey($id))->when(!$id,fn($q)=>$q->where('is_default',true))->where('is_active',true)->first()
|
||||
?? AIProvider::where('is_active',true)->firstOrFail();
|
||||
return AIProvider::query()->when($id, fn ($q) => $q->whereKey($id))->when(! $id, fn ($q) => $q->where('is_default', true))->where('is_active', true)->first()
|
||||
?? AIProvider::where('is_active', true)->firstOrFail();
|
||||
}
|
||||
|
||||
private function driver(AIProvider $provider): AIProviderDriver
|
||||
{
|
||||
return match($provider->driver) { 'openai_compatible','openai','lm_studio','ollama'=>app(OpenAICompatibleDriver::class), default=>throw new \InvalidArgumentException("Unsupported AI driver [{$provider->driver}].") };
|
||||
return match ($provider->driver) {
|
||||
'openai_compatible','openai','lm_studio','ollama' => app(OpenAICompatibleDriver::class), default => throw new \InvalidArgumentException("Unsupported AI driver [{$provider->driver}].")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AI\Services;
|
||||
|
||||
use Modules\AI\Models\AIKnowledgeSource;
|
||||
|
||||
final class KnowledgeIndexer
|
||||
{
|
||||
public function index(AIKnowledgeSource $source,int $chunkSize=1800): AIKnowledgeSource
|
||||
public function index(AIKnowledgeSource $source, int $chunkSize = 1800): AIKnowledgeSource
|
||||
{
|
||||
$content=trim((string)$source->content); $source->chunks()->delete();
|
||||
$chunks=$content===''?[]:$this->split($content,max(500,$chunkSize));
|
||||
foreach($chunks as $position=>$chunk) $source->chunks()->create(['position'=>$position+1,'content'=>$chunk]);
|
||||
$source->update(['checksum'=>hash('sha256',$content),'status'=>'indexed','chunk_count'=>count($chunks),'indexed_at'=>now()]);
|
||||
$content = trim((string) $source->content);
|
||||
$source->chunks()->delete();
|
||||
$chunks = $content === '' ? [] : $this->split($content, max(500, $chunkSize));
|
||||
foreach ($chunks as $position => $chunk) {
|
||||
$source->chunks()->create(['position' => $position + 1, 'content' => $chunk]);
|
||||
}
|
||||
$source->update(['checksum' => hash('sha256', $content), 'status' => 'indexed', 'chunk_count' => count($chunks), 'indexed_at' => now()]);
|
||||
|
||||
return $source->refresh();
|
||||
}
|
||||
private function split(string $content,int $size): array
|
||||
|
||||
private function split(string $content, int $size): array
|
||||
{
|
||||
$paragraphs=preg_split('/\R{2,}/',$content) ?: [$content]; $chunks=[]; $buffer='';
|
||||
foreach($paragraphs as $paragraph){ if(strlen($buffer)+strlen($paragraph)+2>$size && $buffer!==''){ $chunks[]=trim($buffer); $buffer=''; } $buffer.=$paragraph."\n\n"; }
|
||||
if(trim($buffer)!=='') $chunks[]=trim($buffer); return $chunks;
|
||||
$paragraphs = preg_split('/\R{2,}/', $content) ?: [$content];
|
||||
$chunks = [];
|
||||
$buffer = '';
|
||||
foreach ($paragraphs as $paragraph) {
|
||||
if (strlen($buffer) + strlen($paragraph) + 2 > $size && $buffer !== '') {
|
||||
$chunks[] = trim($buffer);
|
||||
$buffer = '';
|
||||
} $buffer .= $paragraph."\n\n";
|
||||
}
|
||||
if (trim($buffer) !== '') {
|
||||
$chunks[] = trim($buffer);
|
||||
}
|
||||
|
||||
return $chunks;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user