Files
Mark Gregory 5dbb04e3ad AI provider management
* OpenAI-compatible provider adapter
* OpenAI support
* LM Studio support
* Ollama OpenAI-compatible support
* Encrypted API-key storage
* Default provider and model selection
* Provider connection testing
* Reusable prompt library
* Prompt variables and templates
* Prompt version field
* AI execution history
* Token-usage storage
* Duration and failure tracking
* Manual knowledge sources
* Knowledge-source chunking
* Knowledge indexing status
* Authenticated AI REST endpoint
* AI administration dashboard
* AI permissions
* Module registration and boot test
2026-07-24 13:01:56 +01:00

22 lines
3.9 KiB
PHP

<x-layouts.app :title="__('AI Platform')">
<div class="space-y-6">
<div><flux:heading size="xl">AI Platform</flux:heading><flux:text>Configure hosted or local models, reusable prompts, execution history and knowledge sources.</flux:text></div>
@if(session('status'))<flux:callout variant="success">{{ session('status') }}</flux:callout>@endif
@if(session('error'))<flux:callout variant="danger">{{ session('error') }}</flux:callout>@endif
<div class="grid gap-4 md:grid-cols-4">
<flux:card><flux:text>Providers</flux:text><flux:heading size="xl">{{ $providers->count() }}</flux:heading></flux:card>
<flux:card><flux:text>Prompts</flux:text><flux:heading size="xl">{{ $prompts->total() }}</flux:heading></flux:card>
<flux:card><flux:text>Executions</flux:text><flux:heading size="xl">{{ \Modules\AI\Models\AIExecution::count() }}</flux:heading></flux:card>
<flux:card><flux:text>Knowledge sources</flux:text><flux:heading size="xl">{{ \Modules\AI\Models\AIKnowledgeSource::count() }}</flux:heading></flux:card>
</div>
<div class="grid gap-6 xl:grid-cols-2">
<flux:card class="space-y-4"><flux:heading>Provider</flux:heading><form method="POST" action="{{ route('administration.ai.providers.store') }}" class="space-y-3">@csrf
<flux:input name="name" label="Name" required/><flux:select name="driver" label="Driver"><option value="openai_compatible">OpenAI compatible</option><option value="openai">OpenAI</option><option value="lm_studio">LM Studio</option><option value="ollama">Ollama</option></flux:select>
<flux:input name="base_url" label="Base URL" placeholder="http://127.0.0.1:1234/v1"/><flux:input name="api_key" type="password" label="API key"/><flux:input name="default_model" label="Default model" required/><flux:checkbox name="is_default" value="1" label="Default provider"/><flux:button type="submit" variant="primary">Add provider</flux:button></form>
<div class="divide-y">@foreach($providers as $provider)<div class="flex items-center justify-between py-3"><div><strong>{{ $provider->name }}</strong><div class="text-sm opacity-70">{{ $provider->driver }} · {{ $provider->default_model }}</div></div><form method="POST" action="{{ route('administration.ai.providers.test',$provider) }}">@csrf<flux:button size="sm">Test</flux:button></form></div>@endforeach</div></flux:card>
<flux:card class="space-y-4"><flux:heading>Reusable prompt</flux:heading><form method="POST" action="{{ route('administration.ai.prompts.store') }}" class="space-y-3">@csrf
<flux:input name="name" label="Name" required/><flux:input name="slug" label="Slug"/><flux:input name="purpose" label="Purpose" placeholder="summarisation"/><flux:textarea name="system_prompt" label="System prompt"/><flux:textarea name="user_template" label="User template" placeholder="Summarise: [input]" required/><flux:button type="submit" variant="primary">Add prompt</flux:button></form></flux:card>
<flux:card class="space-y-4"><flux:heading>Knowledge source</flux:heading><form method="POST" action="{{ route('administration.ai.knowledge.store') }}" class="space-y-3">@csrf<flux:input name="name" label="Name" required/><flux:textarea name="content" label="Content" rows="10" required/><flux:button type="submit" variant="primary">Index source</flux:button></form><div class="divide-y">@foreach($sources as $source)<div class="py-2"><strong>{{ $source->name }}</strong><div class="text-sm opacity-70">{{ $source->status }} · {{ $source->chunk_count }} chunks</div></div>@endforeach</div></flux:card>
<flux:card class="space-y-4"><flux:heading>Recent executions</flux:heading><div class="divide-y">@forelse($executions as $execution)<div class="py-3"><div class="flex justify-between"><strong>{{ $execution->purpose ?: 'Prompt execution' }}</strong><span>{{ $execution->status }}</span></div><div class="text-sm opacity-70">{{ $execution->model }} · {{ $execution->duration_ms }} ms · {{ $execution->created_at?->diffForHumans() }}</div></div>@empty<flux:text>No executions yet.</flux:text>@endforelse</div></flux:card>
</div></div></x-layouts.app>