AI Assistant — multi-provider chat (Claude / GPT / Gemini)
Schema: - ai_chats: company_id, user_id, title, provider; index pe activitate - ai_messages: role (system/user/assistant), content, meta JSON (tokens, latency, model) Service AiAssistantService (multi-provider): - ask($chat, $message): persistă mesajul user, build system prompt cu context tenant (statistici clienți/mașini/cereri/datorii), apelează API-ul providerului, persistă răspunsul cu meta (tokens, latency) - callClaude: api.anthropic.com/v1/messages cu claude-sonnet-4-5 - callOpenAI: api.openai.com/v1/chat/completions cu gpt-4o-mini - callGemini: generativelanguage.googleapis.com cu gemini-1.5-flash - Try/catch pe toate; eroare devine mesaj asistent fără să crape System prompt include: - Numele și orașul companiei - Statistici curente (clienți, mașini, cereri noi, fișe active, datorii) - Limita stricta: NU inventează date Custom Filament Page /app/ai-assistant (group Analiză): - Sidebar stâng: listă conversații (last 20), buton 'Nouă' + delete cu confirm - Main: bubble chat (user dreapta albastru, asistent stânga gri) - Meta jos pe răspuns: provider · latency · tokens - Empty state friendly cu instrucțiuni configurare - Loading indicator (3 dots animate) când AI răspunde - Auto-scroll la mesaj nou - Enter trimite, Shift+Enter newline - Auto-titlu chat din primul mesaj user (60 chars) Settings page extins cu secțiune 'Asistent AI': - Provider implicit (claude/gpt/gemini) - 3 chei API (password fields, revealable) - Key-urile salvate în companies.settings.ai (per tenant, izolat)
This commit is contained in:
@@ -50,6 +50,10 @@ class Settings extends Page
|
||||
'notify_payment' => $notify['payment'] ?? true,
|
||||
'notify_appointment' => $notify['appointment'] ?? true,
|
||||
'notify_reminder' => $notify['reminder'] ?? true,
|
||||
'ai_default_provider' => $settings['ai']['default_provider'] ?? 'claude',
|
||||
'ai_claude_key' => $settings['ai']['claude_key'] ?? null,
|
||||
'ai_gpt_key' => $settings['ai']['gpt_key'] ?? null,
|
||||
'ai_gemini_key' => $settings['ai']['gemini_key'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -120,6 +124,18 @@ class Settings extends Page
|
||||
Forms\Components\Toggle::make('notify_appointment')->label('Programare confirmată')->default(true),
|
||||
Forms\Components\Toggle::make('notify_reminder')->label('Reminder ITP / revizie')->default(true),
|
||||
]),
|
||||
Schemas\Components\Section::make('Asistent AI')
|
||||
->description('Adaugă chei API ca să activezi asistentul. Cheile rămân la voi — nu sunt partajate.')
|
||||
->columns(2)
|
||||
->schema([
|
||||
Forms\Components\Select::make('ai_default_provider')
|
||||
->label('Provider implicit')
|
||||
->options(['claude' => 'Claude (Anthropic)', 'gpt' => 'ChatGPT (OpenAI)', 'gemini' => 'Gemini (Google)'])
|
||||
->default('claude'),
|
||||
Forms\Components\TextInput::make('ai_claude_key')->label('Claude API Key')->password()->revealable()->placeholder('sk-ant-...'),
|
||||
Forms\Components\TextInput::make('ai_gpt_key')->label('OpenAI API Key')->password()->revealable()->placeholder('sk-proj-...'),
|
||||
Forms\Components\TextInput::make('ai_gemini_key')->label('Gemini API Key')->password()->revealable(),
|
||||
]),
|
||||
])
|
||||
->statePath('data');
|
||||
}
|
||||
@@ -151,6 +167,12 @@ class Settings extends Page
|
||||
'appointment' => (bool) ($data['notify_appointment'] ?? true),
|
||||
'reminder' => (bool) ($data['notify_reminder'] ?? true),
|
||||
],
|
||||
'ai' => [
|
||||
'default_provider' => $data['ai_default_provider'] ?? 'claude',
|
||||
'claude_key' => $data['ai_claude_key'] ?? null,
|
||||
'gpt_key' => $data['ai_gpt_key'] ?? null,
|
||||
'gemini_key' => $data['ai_gemini_key'] ?? null,
|
||||
],
|
||||
]),
|
||||
]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user