169 lines
6.1 KiB
TypeScript
169 lines
6.1 KiB
TypeScript
/**
|
||
* ChatbotConfigSection Component
|
||
*
|
||
* Displays chatbot-specific configuration fields (connector, system prompt)
|
||
* Only shown when featureCode is "chatbot"
|
||
*/
|
||
|
||
import React, { useEffect } from 'react';
|
||
import { TextField } from '../../components/UiComponents/TextField';
|
||
import { useBilling } from '../../hooks/useBilling';
|
||
import styles from './Admin.module.css';
|
||
|
||
import { useLanguage } from '../../providers/language/LanguageContext';
|
||
|
||
const PROVIDER_LABELS: Record<string, string> = {
|
||
anthropic: 'Anthropic (Claude)',
|
||
openai: 'OpenAI (GPT)',
|
||
perplexity: 'Perplexity',
|
||
tavily: 'Tavily (Web Search)',
|
||
privatellm: 'Private LLM',
|
||
internal: 'Internal',
|
||
};
|
||
|
||
export interface ChatbotConfig {
|
||
connector: string;
|
||
systemPrompt: string;
|
||
}
|
||
|
||
export interface ChatbotConfigSectionProps {
|
||
connectors: string[]; // Array of selected connector types (database connectors only)
|
||
systemPrompt: string;
|
||
enableWebResearch: boolean; // Enable Tavily web research
|
||
allowedProviders: string[]; // Selected LLM providers (empty = all allowed)
|
||
onConnectorsChange: (connectors: string[]) => void;
|
||
onSystemPromptChange: (prompt: string) => void;
|
||
onEnableWebResearchChange: (enabled: boolean) => void;
|
||
onAllowedProvidersChange: (providers: string[]) => void;
|
||
}
|
||
|
||
export const ChatbotConfigSection: React.FC<ChatbotConfigSectionProps> = ({ connectors,
|
||
systemPrompt,
|
||
enableWebResearch,
|
||
allowedProviders,
|
||
onConnectorsChange,
|
||
onSystemPromptChange,
|
||
onEnableWebResearchChange,
|
||
onAllowedProvidersChange,
|
||
}) => {
|
||
const { t } = useLanguage();
|
||
const { allowedProviders: availableProviders, loadAllowedProviders, loading: providersLoading } = useBilling();
|
||
|
||
useEffect(() => {
|
||
if (availableProviders.length === 0 && !providersLoading) {
|
||
loadAllowedProviders();
|
||
}
|
||
}, []);
|
||
|
||
const availableConnectors = [
|
||
{ id: 'preprocessor', label: t('Althaus Preprocessor'), value: 'preprocessor' }
|
||
];
|
||
|
||
const handleConnectorToggle = (connectorValue: string) => {
|
||
if (connectors.includes(connectorValue)) {
|
||
onConnectorsChange(connectors.filter(c => c !== connectorValue));
|
||
} else {
|
||
onConnectorsChange([...connectors, connectorValue]);
|
||
}
|
||
};
|
||
|
||
const handleProviderToggle = (provider: string) => {
|
||
if (allowedProviders.includes(provider)) {
|
||
onAllowedProvidersChange(allowedProviders.filter(p => p !== provider));
|
||
} else {
|
||
onAllowedProvidersChange([...allowedProviders, provider]);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className={styles.chatbotConfigSection}>
|
||
<div className={styles.configField}>
|
||
<label className={styles.configLabel}>{t('Connector')}:</label>
|
||
<div className={styles.multiselectContainer}>
|
||
{availableConnectors.map(connector => {
|
||
const isSelected = connectors.includes(connector.value);
|
||
return (
|
||
<label key={connector.id} className={styles.multiselectOption}>
|
||
<input
|
||
type="checkbox"
|
||
checked={isSelected}
|
||
onChange={() => handleConnectorToggle(connector.value)}
|
||
className={styles.multiselectCheckbox}
|
||
/>
|
||
<span className={styles.multiselectLabel}>{connector.label}</span>
|
||
</label>
|
||
);
|
||
})}
|
||
</div>
|
||
{connectors.length === 0 && (
|
||
<p style={{ fontSize: '0.75rem', color: 'var(--text-secondary)', marginTop: '0.5rem' }}>
|
||
{t('Ohne Connector werden keine SQL-Abfragen unterstützt.')}
|
||
</p>
|
||
)}
|
||
</div>
|
||
|
||
<div className={styles.configField}>
|
||
<label className={styles.configLabel} style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
|
||
<input
|
||
type="checkbox"
|
||
checked={enableWebResearch}
|
||
onChange={(e) => onEnableWebResearchChange(e.target.checked)}
|
||
className={styles.multiselectCheckbox}
|
||
/>
|
||
<span>{t('Web Research aktivieren (Tavily)')}</span>
|
||
</label>
|
||
<p className={styles.configHelpText}>
|
||
{t('Wenn aktiviert, führt der Chatbot zusätzlich Web-Recherchen mit Tavily durch, um aktuelle Informationen aus dem Internet zu finden.')}
|
||
</p>
|
||
</div>
|
||
|
||
<div className={styles.configField}>
|
||
<label className={styles.configLabel}>{t('LLM-Anbieter')}:</label>
|
||
<div className={styles.multiselectContainer}>
|
||
{providersLoading ? (
|
||
<span style={{ fontSize: '0.85rem', color: 'var(--text-secondary)' }}>{t('Anbieter laden')}</span>
|
||
) : (
|
||
availableProviders.map(provider => (
|
||
<label key={provider} className={styles.multiselectOption}>
|
||
<input
|
||
type="checkbox"
|
||
checked={allowedProviders.includes(provider)}
|
||
onChange={() => handleProviderToggle(provider)}
|
||
className={styles.multiselectCheckbox}
|
||
/>
|
||
<span className={styles.multiselectLabel}>
|
||
{PROVIDER_LABELS[provider] || provider}
|
||
</span>
|
||
</label>
|
||
))
|
||
)}
|
||
</div>
|
||
{allowedProviders.length === 0 && !providersLoading && (
|
||
<p style={{ fontSize: '0.75rem', color: 'var(--text-secondary)', marginTop: '0.5rem' }}>
|
||
{t('Keine Einschränkung – alle verfügbaren Anbieter werden verwendet.')}
|
||
</p>
|
||
)}
|
||
</div>
|
||
|
||
<div className={styles.configField}>
|
||
<label className={styles.configLabel}>
|
||
{t('System Prompt')}: <span style={{ color: 'var(--error-color)' }}>*</span>
|
||
</label>
|
||
<TextField
|
||
type="text"
|
||
value={systemPrompt}
|
||
onChange={onSystemPromptChange}
|
||
placeholder={t('Benutzerdefinierter Systemprompt für den Chatbot')}
|
||
className={styles.configTextArea}
|
||
size="md"
|
||
rows={6}
|
||
required={true}
|
||
/>
|
||
<p className={styles.configHelpText}>
|
||
{t('Dieser Prompt wird für Analyse und Antwort-Generierung verwendet (erforderlich).')}{' '}
|
||
{t('Platzhalter')}: {'{userPrompt}'}, {'{context}'}, {'{db_results_part}'}, {'{web_results_part}'}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|