feat: add emoji-regex and remove-accents dependencies; enhance chat and setup pages
- Added `emoji-regex` and `remove-accents` packages to improve text processing capabilities. - Implemented automatic Ollama startup in the chat page for better user experience. - Enhanced setup page to include GPU selection based on hardware specifications. - Updated chat input to support real-time validation and improved user feedback. - Refactored message handling in chat to incorporate new processing features.
This commit is contained in:
1 parent
4275295e4f
commit
84ea2dec19
51 files changed
+7857
-573
No files matched your search
@@ -1,3 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -7,7 +10,12 @@ import {
|
||||
} from "@/components/ui/dialog"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Download } from "lucide-react"
|
||||
import { Progress } from "@/components/ui/progress"
|
||||
import { Download, Loader2, AlertCircle, CheckCircle2, Play } from "lucide-react"
|
||||
import { useOllamaDownload } from "@/hooks/use-ollama-download"
|
||||
import { useToast } from "@/hooks/use-toast"
|
||||
import { useOperatingSystem } from "@/hooks/use-operating-system"
|
||||
import type { OS } from "@/lib/download-utils"
|
||||
|
||||
interface InstallModalProps {
|
||||
open: boolean;
|
||||
@@ -15,6 +23,162 @@ interface InstallModalProps {
|
||||
}
|
||||
|
||||
export function InstallModal({ open, onCheckAgain }: InstallModalProps) {
|
||||
const { os: detectedOS } = useOperatingSystem();
|
||||
const [activeTab, setActiveTab] = useState<OS>('mac');
|
||||
const downloadState = useOllamaDownload();
|
||||
const { toast } = useToast();
|
||||
|
||||
// Detectar OS e definir aba ativa quando modal abrir
|
||||
useEffect(() => {
|
||||
if (open && detectedOS) {
|
||||
setActiveTab(detectedOS);
|
||||
}
|
||||
}, [open, detectedOS]);
|
||||
|
||||
// Resetar estado quando o modal abrir
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
downloadState.reset();
|
||||
// Verificar se já existe download para a tab ativa
|
||||
downloadState.checkExistingDownload(activeTab);
|
||||
} else {
|
||||
// Parar verificação automática quando modal fechar
|
||||
downloadState.stopAutoCheck();
|
||||
}
|
||||
}, [open, activeTab]);
|
||||
|
||||
// Verificar download existente ao mudar de tab
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
downloadState.checkExistingDownload(activeTab);
|
||||
}
|
||||
}, [activeTab, open]);
|
||||
|
||||
// Escutar evento de Ollama instalado
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
|
||||
const handleOllamaInstalled = () => {
|
||||
// Ollama foi encontrado, verificar novamente para atualizar o estado
|
||||
onCheckAgain();
|
||||
};
|
||||
|
||||
window.addEventListener('ollama-installed', handleOllamaInstalled);
|
||||
return () => {
|
||||
window.removeEventListener('ollama-installed', handleOllamaInstalled);
|
||||
};
|
||||
}, [open, onCheckAgain]);
|
||||
|
||||
// Mostrar toast quando houver erro
|
||||
useEffect(() => {
|
||||
if (downloadState.downloadError) {
|
||||
toast({
|
||||
title: 'Erro no download',
|
||||
description: downloadState.downloadError,
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
}, [downloadState.downloadError, toast]);
|
||||
|
||||
const handleDownload = async (os: OS) => {
|
||||
await downloadState.handleDownload(os);
|
||||
};
|
||||
|
||||
const handleInstall = async () => {
|
||||
try {
|
||||
await downloadState.handleInstall();
|
||||
toast({
|
||||
title: 'Instalador iniciado',
|
||||
description: 'O instalador foi aberto. Siga as instruções na tela.',
|
||||
});
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: 'Erro ao executar instalador',
|
||||
description: error instanceof Error ? error.message : 'Erro desconhecido',
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const DownloadButton = ({ os, label }: { os: OS; label: string }) => {
|
||||
const isActive = activeTab === os;
|
||||
const isDownloading = downloadState.isDownloading && isActive;
|
||||
const hasDownloaded = downloadState.filePath !== null && isActive;
|
||||
|
||||
if (hasDownloaded && !isDownloading) {
|
||||
return (
|
||||
<Button
|
||||
variant="default"
|
||||
className="w-full"
|
||||
onClick={handleInstall}
|
||||
>
|
||||
<Play className="mr-2 h-4 w-4" />
|
||||
Instalar Ollama
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
onClick={() => handleDownload(os)}
|
||||
disabled={isDownloading}
|
||||
>
|
||||
{isDownloading ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
{downloadState.downloadStatus || 'Baixando...'}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
{label}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
const DownloadProgress = ({ os }: { os: OS }) => {
|
||||
const isActive = activeTab === os;
|
||||
const isDownloading = downloadState.isDownloading && isActive;
|
||||
const hasDownloaded = downloadState.filePath !== null && isActive;
|
||||
|
||||
if (!isDownloading && !hasDownloaded) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
{isDownloading && (
|
||||
<>
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-muted-foreground">
|
||||
{downloadState.downloadStatus || 'Baixando...'}
|
||||
</span>
|
||||
<span className="font-medium">{downloadState.downloadProgress}%</span>
|
||||
</div>
|
||||
<Progress value={downloadState.downloadProgress} className="h-2" />
|
||||
</>
|
||||
)}
|
||||
{hasDownloaded && !isDownloading && (
|
||||
<div className="flex items-start gap-2 p-3 bg-green-50 dark:bg-green-950/20 rounded-md">
|
||||
<CheckCircle2 className="h-4 w-4 mt-0.5 text-green-600 dark:text-green-400" />
|
||||
<div className="text-sm flex-1">
|
||||
<p className="font-medium text-green-900 dark:text-green-100">
|
||||
Download concluído
|
||||
</p>
|
||||
<p className="text-green-700 dark:text-green-300">
|
||||
Clique em "Instalar Ollama" para iniciar a instalação.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open}>
|
||||
<DialogContent className="sm:max-w-[600px]">
|
||||
@@ -22,29 +186,41 @@ export function InstallModal({ open, onCheckAgain }: InstallModalProps) {
|
||||
<DialogTitle>Ollama não encontrado</DialogTitle>
|
||||
<DialogDescription>
|
||||
Para usar o OllaHub, você precisa ter o Ollama instalado no seu sistema.
|
||||
Siga os passos abaixo para o seu sistema operacional.
|
||||
Baixe e instale o Ollama usando os passos abaixo.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Tabs defaultValue="mac" className="w-full">
|
||||
<Tabs value={activeTab} onValueChange={(v) => setActiveTab(v as OS)} className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
<TabsTrigger value="mac">macOS</TabsTrigger>
|
||||
<TabsTrigger value="linux">Linux</TabsTrigger>
|
||||
<TabsTrigger value="windows">Windows</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="mac" className="space-y-4 py-4">
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-medium">1. Download e Instalação</h3>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<a href="https://ollama.com/download/Ollama-darwin.zip" target="_blank" rel="noopener noreferrer">
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
Baixar para macOS
|
||||
</a>
|
||||
</Button>
|
||||
<DownloadButton os="mac" label="Baixar para macOS" />
|
||||
<DownloadProgress os="mac" />
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Após instalar, abra o terminal e digite <code>ollama serve</code> se necessário.
|
||||
{downloadState.downloadError && activeTab === 'mac' && (
|
||||
<div className="flex items-start gap-2 p-3 bg-red-50 dark:bg-red-950/20 rounded-md">
|
||||
<AlertCircle className="h-4 w-4 mt-0.5 text-red-600 dark:text-red-400" />
|
||||
<div className="text-sm">
|
||||
<p className="font-medium text-red-900 dark:text-red-100">Erro no download</p>
|
||||
<p className="text-red-700 dark:text-red-300">
|
||||
{downloadState.downloadError}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-2 text-sm text-muted-foreground">
|
||||
<p>Após instalar, o Ollama será iniciado automaticamente. Se necessário, abra o terminal e digite <code className="bg-muted px-1 rounded">ollama serve</code>.</p>
|
||||
<p className="font-medium text-foreground">
|
||||
💡 Dica: Após concluir a instalação, você pode fechar qualquer janela de chat aberta pelo Ollama e continuar aqui no OllaHub.
|
||||
</p>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="linux" className="space-y-4 py-4">
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-medium">Instalação via Terminal</h3>
|
||||
@@ -52,35 +228,88 @@ export function InstallModal({ open, onCheckAgain }: InstallModalProps) {
|
||||
<code className="text-sm break-all">curl -fsSL https://ollama.com/install.sh | sh</code>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-medium">Ou baixar e instalar via interface</h3>
|
||||
<DownloadButton os="linux" label="Baixar Script de Instalação" />
|
||||
<DownloadProgress os="linux" />
|
||||
</div>
|
||||
{downloadState.downloadError && activeTab === 'linux' && (
|
||||
<div className="flex items-start gap-2 p-3 bg-red-50 dark:bg-red-950/20 rounded-md">
|
||||
<AlertCircle className="h-4 w-4 mt-0.5 text-red-600 dark:text-red-400" />
|
||||
<div className="text-sm">
|
||||
<p className="font-medium text-red-900 dark:text-red-100">Erro no download</p>
|
||||
<p className="text-red-700 dark:text-red-300">
|
||||
{downloadState.downloadError}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-medium">Comando Manual</h3>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Ou consulte <a href="https://ollama.com/download/linux" className="underline text-primary" target="_blank" rel="noopener noreferrer">ollama.com/download/linux</a> para instruções manuais.
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm font-medium text-foreground">
|
||||
💡 Dica: Após concluir a instalação, você pode fechar qualquer janela de chat aberta pelo Ollama e continuar aqui no OllaHub.
|
||||
</p>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="windows" className="space-y-4 py-4">
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-medium">1. Download do Instalador</h3>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<a href="https://ollama.com/download/OllamaSetup.exe" target="_blank" rel="noopener noreferrer">
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
Baixar para Windows
|
||||
</a>
|
||||
</Button>
|
||||
<DownloadButton os="windows" label="Baixar para Windows" />
|
||||
<DownloadProgress os="windows" />
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Execute o instalador baixado e siga as instruções na tela.
|
||||
{downloadState.downloadError && activeTab === 'windows' && (
|
||||
<div className="flex items-start gap-2 p-3 bg-red-50 dark:bg-red-950/20 rounded-md">
|
||||
<AlertCircle className="h-4 w-4 mt-0.5 text-red-600 dark:text-red-400" />
|
||||
<div className="text-sm">
|
||||
<p className="font-medium text-red-900 dark:text-red-100">Erro no download</p>
|
||||
<p className="text-red-700 dark:text-red-300">
|
||||
{downloadState.downloadError}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-2 text-sm text-muted-foreground">
|
||||
<p>Após clicar em "Instalar Ollama", o instalador será aberto. Siga as instruções na tela para completar a instalação.</p>
|
||||
<p className="font-medium text-foreground">
|
||||
💡 Dica: Após concluir a instalação, você pode fechar qualquer janela de chat aberta pelo Ollama e continuar aqui no OllaHub.
|
||||
</p>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
{/* Status de verificação automática */}
|
||||
{downloadState.isChecking && (
|
||||
<div className="flex items-start gap-2 p-3 bg-blue-50 dark:bg-blue-950/20 rounded-md mt-4">
|
||||
<Loader2 className="h-4 w-4 mt-0.5 text-blue-600 dark:text-blue-400 animate-spin" />
|
||||
<div className="text-sm flex-1">
|
||||
<p className="font-medium text-blue-900 dark:text-blue-100">
|
||||
Verificando instalação do Ollama...
|
||||
</p>
|
||||
<p className="text-blue-700 dark:text-blue-300">
|
||||
{downloadState.checkStatus || 'Aguardando instalação ser concluída...'}
|
||||
</p>
|
||||
<p className="text-xs text-blue-600 dark:text-blue-400 mt-1">
|
||||
Esta verificação continuará em segundo plano até encontrar o Ollama.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex justify-end gap-2 mt-4">
|
||||
<Button onClick={onCheckAgain}>
|
||||
Verificar Novamente
|
||||
<Button
|
||||
onClick={() => {
|
||||
// Chamar verificação completa (instalação + execução)
|
||||
onCheckAgain();
|
||||
}}
|
||||
>
|
||||
Verificar Novamente
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user