import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Box, Typography, TextField, Button, FormControlLabel, Checkbox, IconButton, Grid, Card, CircularProgress, Container, CardContent, Tabs, Tab, FormControl, Select, MenuItem, InputLabel } from '@mui/material'; import { ArrowBack, PlayCircleOutline, Article, Code, Description, SmartToy } from '@mui/icons-material'; import { useGlobalInfoStore, useCacheInvalidation } from '../../../context/globalInfo'; import { canCreateBrowserInState, getActiveBrowserId, stopRecording } from '../../../api/recording'; import { createScrapeRobot, createLLMRobot, createAndRunRecording } from "../../../api/storage"; import { AuthContext } from '../../../context/auth'; import { GenericModal } from '../../ui/GenericModal'; interface TabPanelProps { children?: React.ReactNode; index: number; value: number; } function TabPanel(props: TabPanelProps) { const { children, value, index, ...other } = props; return ( ); } const RobotCreate: React.FC = () => { const { t } = useTranslation(); const navigate = useNavigate(); const { setBrowserId, setRecordingUrl, notify, setRecordingId, setRerenderRobots } = useGlobalInfoStore(); const [tabValue, setTabValue] = useState(0); const [url, setUrl] = useState(''); const [scrapeRobotName, setScrapeRobotName] = useState(''); const [extractRobotName, setExtractRobotName] = useState(''); const [needsLogin, setNeedsLogin] = useState(false); const [isLoading, setIsLoading] = useState(false); const [isWarningModalOpen, setWarningModalOpen] = useState(false); const [activeBrowserId, setActiveBrowserId] = useState(''); const [outputFormats, setOutputFormats] = useState([]); const [generationMode, setGenerationMode] = useState<'agent' | 'recorder' | null>(null); // AI Extract tab state const [aiPrompt, setAiPrompt] = useState(''); const [llmProvider, setLlmProvider] = useState<'anthropic' | 'openai' | 'ollama'>('ollama'); const [llmModel, setLlmModel] = useState(''); const [llmApiKey, setLlmApiKey] = useState(''); const [llmBaseUrl, setLlmBaseUrl] = useState(''); const [aiRobotName, setAiRobotName] = useState(''); const { state } = React.useContext(AuthContext); const { user } = state; const { addOptimisticRobot, removeOptimisticRobot, invalidateRecordings, invalidateRuns, addOptimisticRun } = useCacheInvalidation(); const handleTabChange = (event: React.SyntheticEvent, newValue: number) => { setTabValue(newValue); }; const handleStartRecording = async () => { if (!url.trim()) { notify('error', 'Please enter a valid URL'); return; } setIsLoading(true); try { const canCreateRecording = await canCreateBrowserInState("recording"); if (!canCreateRecording) { const activeBrowser = await getActiveBrowserId(); if (activeBrowser) { setActiveBrowserId(activeBrowser); setWarningModalOpen(true); } else { notify('warning', t('recordingtable.notifications.browser_limit_warning')); } setIsLoading(false); return; } setBrowserId('new-recording'); setRecordingUrl(url); window.sessionStorage.setItem('browserId', 'new-recording'); window.sessionStorage.setItem('recordingUrl', url); window.sessionStorage.setItem('initialUrl', url); window.sessionStorage.setItem('needsLogin', needsLogin.toString()); const sessionId = Date.now().toString(); window.sessionStorage.setItem('recordingSessionId', sessionId); window.open(`/recording-setup?session=${sessionId}`, '_blank'); window.sessionStorage.setItem('nextTabIsRecording', 'true'); // Reset loading state immediately after opening new tab setIsLoading(false); navigate('/robots'); } catch (error) { console.error('Error starting recording:', error); notify('error', 'Failed to start recording. Please try again.'); setIsLoading(false); } }; const handleDiscardAndCreate = async () => { if (activeBrowserId) { await stopRecording(activeBrowserId); notify('warning', t('browser_recording.notifications.terminated')); } setWarningModalOpen(false); setIsLoading(false); // Continue with the original Recording logic setBrowserId('new-recording'); setRecordingUrl(url); window.sessionStorage.setItem('browserId', 'new-recording'); window.sessionStorage.setItem('recordingUrl', url); window.sessionStorage.setItem('initialUrl', url); window.sessionStorage.setItem('needsLogin', needsLogin.toString()); const sessionId = Date.now().toString(); window.sessionStorage.setItem('recordingSessionId', sessionId); window.open(`/recording-setup?session=${sessionId}`, '_blank'); window.sessionStorage.setItem('nextTabIsRecording', 'true'); navigate('/robots'); }; return ( navigate('/robots')} sx={{ ml: -1, mr: 1, color: theme => theme.palette.text.primary, backgroundColor: 'transparent !important', '&:hover': { backgroundColor: 'transparent !important', }, '&:active': { backgroundColor: 'transparent !important', }, '&:focus': { backgroundColor: 'transparent !important', }, '&:focus-visible': { backgroundColor: 'transparent !important', }, }} disableRipple aria-label="Go back" > Create New Robot Maxun Logo Extract structured data from websites using AI or record your own extraction workflow. setUrl(e.target.value)} label="Website URL" /> Generation Mode setGenerationMode('recorder')} sx={{ flex: 1, cursor: 'pointer', border: '2px solid', borderColor: generationMode === 'recorder' ? '#ff00c3' : 'divider', transition: 'all 0.2s', '&:hover': { borderColor: '#ff00c3', } }} > Record yourself You control the browser setGenerationMode('agent')} sx={{ flex: 1, cursor: 'pointer', border: '2px solid', borderColor: generationMode === 'agent' ? '#ff00c3' : 'divider', transition: 'all 0.2s', '&:hover': { borderColor: '#ff00c3', } }} > AI Powered AI will take care of everything {generationMode === 'agent' && ( setExtractRobotName(e.target.value)} label="Robot Name" /> setAiPrompt(e.target.value)} label="Extraction Prompt" /> LLM Provider Model {/* API Key for non-Ollama providers */} {llmProvider !== 'ollama' && ( setLlmApiKey(e.target.value)} label="API Key (Optional if set in .env)" /> )} {llmProvider === 'ollama' && ( setLlmBaseUrl(e.target.value)} label="Ollama Base URL (Optional)" /> )} )} {generationMode === 'recorder' && ( )} Maxun Logo Turn websites into LLM-ready Markdown, clean HTML, or screenshots for AI apps. setScrapeRobotName(e.target.value)} sx={{ mb: 2 }} label="Robot Name" /> setUrl(e.target.value)} label="Website URL" sx={{ mb: 2 }} /> Output Formats * { setWarningModalOpen(false); setIsLoading(false); }} modalStyle={modalStyle}>
{t('recordingtable.warning_modal.title')} {t('recordingtable.warning_modal.message')}
); }; export default RobotCreate; const modalStyle = { top: '50%', left: '50%', transform: 'translate(-50%, -50%)', width: '30%', backgroundColor: 'background.paper', p: 4, height: 'fit-content', display: 'block', padding: '20px', };