Refactor Agent View

This commit is contained in:
gpt-engineer-app[bot]
2025-10-17 16:31:41 +00:00
parent 9d925d1ae3
commit b0a1cfdab5
4 changed files with 504 additions and 355 deletions
-195
View File
@@ -1,195 +0,0 @@
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { Input } from "@/components/ui/input";
import { Download, Send, Sparkles } from "lucide-react";
import { LegalOpinion } from "./AgentView";
import { ScrollArea } from "@/components/ui/scroll-area";
import { useToast } from "@/hooks/use-toast";
interface AgentChatProps {
selectedOpinion: LegalOpinion | null;
isCreatingNew: boolean;
onOpinionCreated: (opinion: LegalOpinion) => void;
}
export const AgentChat = ({
selectedOpinion,
isCreatingNew,
onOpinionCreated,
}: AgentChatProps) => {
const [title, setTitle] = useState("");
const [instructions, setInstructions] = useState("");
const [category, setCategory] = useState("");
const [generatedContent, setGeneratedContent] = useState("");
const [isGenerating, setIsGenerating] = useState(false);
const { toast } = useToast();
const handleGenerate = async () => {
if (!instructions.trim()) {
toast({
title: "Instruções necessárias",
description: "Por favor, forneça instruções para gerar o parecer.",
variant: "destructive",
});
return;
}
setIsGenerating(true);
// Simulação de chamada à IA - aqui você integraria com a API real
setTimeout(() => {
const mockContent = `PARECER JURÍDICO
TÍTULO: ${title || "Parecer Jurídico"}
${instructions}
ANÁLISE:
Este parecer foi gerado com base nas instruções fornecidas. A análise considera os seguintes aspectos legais:
1. Fundamentação Legal
2. Precedentes Judiciais
3. Doutrina Aplicável
4. Conclusão e Recomendações
CONCLUSÃO:
Com base na análise realizada, conclui-se que...
___________________________
Parecer gerado em ${new Date().toLocaleDateString('pt-BR')}`;
setGeneratedContent(mockContent);
setIsGenerating(false);
if (isCreatingNew) {
const newOpinion: LegalOpinion = {
id: Date.now().toString(),
title: title || "Novo Parecer",
content: mockContent,
createdAt: new Date(),
category: category || undefined,
};
onOpinionCreated(newOpinion);
}
toast({
title: "Parecer gerado com sucesso!",
description: "O parecer está pronto para download.",
});
}, 2000);
};
const handleDownloadDocx = () => {
// Aqui você implementaria a geração real do DOCX
// Por enquanto, vamos criar um arquivo de texto
const content = generatedContent || selectedOpinion?.content || "";
const blob = new Blob([content], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${title || selectedOpinion?.title || 'parecer'}.txt`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
toast({
title: "Download iniciado",
description: "O parecer está sendo baixado.",
});
};
const displayContent = generatedContent || selectedOpinion?.content;
return (
<div className="flex flex-col h-full bg-background">
<div className="p-6 border-b border-border">
<h2 className="text-2xl font-bold text-foreground">
{selectedOpinion ? selectedOpinion.title : "Novo Parecer Jurídico"}
</h2>
{selectedOpinion && (
<p className="text-sm text-muted-foreground mt-1">
Criado em {new Date(selectedOpinion.createdAt).toLocaleDateString('pt-BR')}
</p>
)}
</div>
<div className="flex-1 overflow-hidden">
<div className="h-full p-6 space-y-4">
{(isCreatingNew || !selectedOpinion) && (
<>
<div className="space-y-2">
<label className="text-sm font-medium text-foreground">Título do Parecer</label>
<Input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Ex: Análise sobre Contrato de Prestação de Serviços"
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-foreground">Categoria</label>
<Input
value={category}
onChange={(e) => setCategory(e.target.value)}
placeholder="Ex: Direito Civil, Trabalhista, etc."
/>
</div>
</>
)}
<div className="space-y-2">
<label className="text-sm font-medium text-foreground">
{selectedOpinion ? "Instruções para novo modelo" : "Instruções para gerar o parecer"}
</label>
<Textarea
value={instructions}
onChange={(e) => setInstructions(e.target.value)}
placeholder="Descreva os detalhes, contexto e aspectos legais que devem ser considerados no parecer..."
className="min-h-[120px]"
/>
</div>
<Button
onClick={handleGenerate}
disabled={isGenerating}
className="w-full gap-2"
>
{isGenerating ? (
<>Gerando parecer...</>
) : (
<>
<Sparkles className="w-4 h-4" />
{selectedOpinion ? "Gerar Novo Modelo com IA" : "Gerar Parecer com IA"}
</>
)}
</Button>
{displayContent && (
<div className="space-y-2">
<div className="flex items-center justify-between">
<label className="text-sm font-medium text-foreground">Parecer Gerado</label>
<Button
onClick={handleDownloadDocx}
variant="outline"
size="sm"
className="gap-2"
>
<Download className="w-4 h-4" />
Baixar DOCX
</Button>
</div>
<ScrollArea className="h-[300px] rounded-md border border-border p-4">
<pre className="whitespace-pre-wrap font-sans text-sm text-foreground">
{displayContent}
</pre>
</ScrollArea>
</div>
)}
</div>
</div>
</div>
);
};
-121
View File
@@ -1,121 +0,0 @@
import { Plus, Search, Trash2, Eye } from "lucide-react";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { LegalOpinion } from "./AgentView";
import { Input } from "@/components/ui/input";
import { useState } from "react";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
interface AgentSidebarProps {
opinions: LegalOpinion[];
onCreateNew: () => void;
onSelectOpinion: (opinion: LegalOpinion) => void;
onDeleteOpinion: (id: string) => void;
onSearch: () => void;
selectedOpinionId?: string;
}
export const AgentSidebar = ({
opinions,
onCreateNew,
onSelectOpinion,
onDeleteOpinion,
onSearch,
selectedOpinionId,
}: AgentSidebarProps) => {
const [searchTerm, setSearchTerm] = useState("");
const filteredOpinions = opinions.filter(op =>
op.title.toLowerCase().includes(searchTerm.toLowerCase())
);
return (
<div className="w-80 border-r border-border bg-sidebar flex flex-col h-full">
<div className="p-4 border-b border-border space-y-3">
<h2 className="text-xl font-bold text-sidebar-foreground">Agente de Parecer</h2>
<Button onClick={onCreateNew} className="w-full gap-2">
<Plus className="w-4 h-4" />
Novo Parecer
</Button>
<Button onClick={onSearch} variant="outline" className="w-full gap-2">
<Search className="w-4 h-4" />
Pesquisar Base de Pareceres
</Button>
<Input
placeholder="Buscar pareceres..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full"
/>
</div>
<ScrollArea className="flex-1">
<div className="p-2">
<Table>
<TableHeader>
<TableRow>
<TableHead>Título</TableHead>
<TableHead className="w-[120px]">Data</TableHead>
<TableHead className="w-[100px] text-center">Ações</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredOpinions.map((opinion) => (
<TableRow
key={opinion.id}
className={selectedOpinionId === opinion.id ? "bg-sidebar-accent" : ""}
>
<TableCell className="font-medium">
<div>
<p className="truncate">{opinion.title}</p>
{opinion.category && (
<p className="text-xs text-muted-foreground mt-1">{opinion.category}</p>
)}
</div>
</TableCell>
<TableCell className="text-sm text-muted-foreground">
{new Date(opinion.createdAt).toLocaleDateString('pt-BR')}
</TableCell>
<TableCell>
<div className="flex items-center justify-center gap-1">
<Button
variant="ghost"
size="icon"
className="h-8 w-8"
onClick={() => onSelectOpinion(opinion)}
title="Visualizar"
>
<Eye className="w-4 h-4" />
</Button>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 text-destructive hover:text-destructive"
onClick={() => onDeleteOpinion(opinion.id)}
title="Excluir"
>
<Trash2 className="w-4 h-4" />
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
{filteredOpinions.length === 0 && (
<div className="text-center text-muted-foreground py-8">
<p className="text-sm">Nenhum parecer encontrado</p>
</div>
)}
</div>
</ScrollArea>
</div>
);
};
+258 -38
View File
@@ -1,6 +1,23 @@
import { useState } from "react";
import { AgentSidebar } from "./AgentSidebar";
import { AgentChat } from "./AgentChat";
import { Plus, Search, Eye, Trash2, ArrowUpDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { OpinionDialog } from "./OpinionDialog";
import { AgentSearch } from "./AgentSearch";
export interface LegalOpinion {
@@ -11,64 +28,267 @@ export interface LegalOpinion {
category?: string;
}
type SortField = "title" | "createdAt" | "category";
type SortOrder = "asc" | "desc";
export const AgentView = () => {
const [opinions, setOpinions] = useState<LegalOpinion[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(10);
const [sortField, setSortField] = useState<SortField>("createdAt");
const [sortOrder, setSortOrder] = useState<SortOrder>("desc");
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [selectedOpinion, setSelectedOpinion] = useState<LegalOpinion | null>(null);
const [isCreatingNew, setIsCreatingNew] = useState(false);
const [showSearch, setShowSearch] = useState(false);
const handleCreateNew = () => {
setIsCreatingNew(true);
setSelectedOpinion(null);
setShowSearch(false);
const handleSort = (field: SortField) => {
if (sortField === field) {
setSortOrder(sortOrder === "asc" ? "desc" : "asc");
} else {
setSortField(field);
setSortOrder("asc");
}
};
const handleSelectOpinion = (opinion: LegalOpinion) => {
setSelectedOpinion(opinion);
setIsCreatingNew(false);
setShowSearch(false);
};
const filteredOpinions = opinions.filter(
(op) =>
op.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
op.category?.toLowerCase().includes(searchTerm.toLowerCase())
);
const handleSearch = () => {
setShowSearch(true);
setIsCreatingNew(false);
setSelectedOpinion(null);
};
const sortedOpinions = [...filteredOpinions].sort((a, b) => {
const multiplier = sortOrder === "asc" ? 1 : -1;
if (sortField === "createdAt") {
return multiplier * (new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
}
const aValue = a[sortField] || "";
const bValue = b[sortField] || "";
return multiplier * aValue.toString().localeCompare(bValue.toString());
});
const totalPages = Math.ceil(sortedOpinions.length / itemsPerPage);
const startIndex = (currentPage - 1) * itemsPerPage;
const paginatedOpinions = sortedOpinions.slice(startIndex, startIndex + itemsPerPage);
const handleOpinionCreated = (newOpinion: LegalOpinion) => {
setOpinions([newOpinion, ...opinions]);
setSelectedOpinion(newOpinion);
setIsCreatingNew(false);
setIsDialogOpen(false);
setSelectedOpinion(null);
};
const handleDeleteOpinion = (id: string) => {
setOpinions(opinions.filter(op => op.id !== id));
if (selectedOpinion?.id === id) {
setSelectedOpinion(null);
}
};
const handleViewOpinion = (opinion: LegalOpinion) => {
setSelectedOpinion(opinion);
setIsDialogOpen(true);
};
const handleNewOpinion = () => {
setSelectedOpinion(null);
setIsDialogOpen(true);
};
const handleSelectFromSearch = (opinion: LegalOpinion) => {
setSelectedOpinion(opinion);
setShowSearch(false);
setIsDialogOpen(true);
};
if (showSearch) {
return (
<div className="flex h-full">
<AgentSidebar
opinions={opinions}
onCreateNew={handleCreateNew}
onSelectOpinion={handleSelectOpinion}
onDeleteOpinion={handleDeleteOpinion}
onSearch={handleSearch}
selectedOpinionId={selectedOpinion?.id}
<div className="flex flex-col h-full">
<div className="p-6 border-b border-border">
<Button variant="outline" onClick={() => setShowSearch(false)}>
Voltar para Pareceres
</Button>
</div>
<AgentSearch onSelectOpinion={handleSelectFromSearch} />
</div>
);
}
return (
<div className="flex flex-col h-full bg-background">
<div className="p-6 border-b border-border">
<div className="flex items-center justify-between mb-4">
<h1 className="text-3xl font-bold text-foreground">Agente de Parecer Jurídico</h1>
<div className="flex gap-2">
<Button onClick={() => setShowSearch(true)} variant="outline" className="gap-2">
<Search className="w-4 h-4" />
Pesquisar Base de Pareceres
</Button>
<Button onClick={handleNewOpinion} className="gap-2">
<Plus className="w-4 h-4" />
Novo Parecer
</Button>
</div>
</div>
<div className="flex items-center gap-4">
<Input
placeholder="Buscar pareceres..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="max-w-sm"
/>
<div className="flex-1">
{showSearch ? (
<AgentSearch onSelectOpinion={handleSelectOpinion} />
<div className="flex items-center gap-2">
<span className="text-sm text-muted-foreground">Itens por página:</span>
<Select
value={itemsPerPage.toString()}
onValueChange={(value) => {
setItemsPerPage(Number(value));
setCurrentPage(1);
}}
>
<SelectTrigger className="w-20">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="5">5</SelectItem>
<SelectItem value="10">10</SelectItem>
<SelectItem value="20">20</SelectItem>
<SelectItem value="50">50</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</div>
<div className="flex-1 overflow-auto p-6">
<div className="border rounded-lg">
<Table>
<TableHeader>
<TableRow>
<TableHead>
<Button
variant="ghost"
onClick={() => handleSort("title")}
className="flex items-center gap-1 font-semibold"
>
Título
<ArrowUpDown className="w-4 h-4" />
</Button>
</TableHead>
<TableHead>
<Button
variant="ghost"
onClick={() => handleSort("category")}
className="flex items-center gap-1 font-semibold"
>
Categoria
<ArrowUpDown className="w-4 h-4" />
</Button>
</TableHead>
<TableHead>
<Button
variant="ghost"
onClick={() => handleSort("createdAt")}
className="flex items-center gap-1 font-semibold"
>
Data de Criação
<ArrowUpDown className="w-4 h-4" />
</Button>
</TableHead>
<TableHead className="text-center">Ações</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{paginatedOpinions.length === 0 ? (
<TableRow>
<TableCell colSpan={4} className="text-center py-12 text-muted-foreground">
{searchTerm
? "Nenhum parecer encontrado"
: "Nenhum parecer criado ainda. Clique em 'Novo Parecer' para começar."}
</TableCell>
</TableRow>
) : (
<AgentChat
selectedOpinion={selectedOpinion}
isCreatingNew={isCreatingNew}
onOpinionCreated={handleOpinionCreated}
/>
paginatedOpinions.map((opinion) => (
<TableRow key={opinion.id}>
<TableCell className="font-medium">{opinion.title}</TableCell>
<TableCell>{opinion.category || "-"}</TableCell>
<TableCell>
{new Date(opinion.createdAt).toLocaleDateString("pt-BR")}
</TableCell>
<TableCell>
<div className="flex items-center justify-center gap-2">
<Button
variant="ghost"
size="icon"
onClick={() => handleViewOpinion(opinion)}
title="Visualizar"
>
<Eye className="w-4 h-4" />
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => handleDeleteOpinion(opinion.id)}
className="text-destructive hover:text-destructive"
title="Excluir"
>
<Trash2 className="w-4 h-4" />
</Button>
</div>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</div>
{totalPages > 1 && (
<div className="flex items-center justify-between mt-4">
<p className="text-sm text-muted-foreground">
Mostrando {startIndex + 1} a {Math.min(startIndex + itemsPerPage, sortedOpinions.length)} de{" "}
{sortedOpinions.length} pareceres
</p>
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
disabled={currentPage === 1}
>
Anterior
</Button>
<div className="flex items-center gap-1">
{Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => (
<Button
key={page}
variant={currentPage === page ? "default" : "outline"}
size="sm"
onClick={() => setCurrentPage(page)}
className="w-10"
>
{page}
</Button>
))}
</div>
<Button
variant="outline"
size="sm"
onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
disabled={currentPage === totalPages}
>
Próxima
</Button>
</div>
</div>
)}
</div>
<OpinionDialog
open={isDialogOpen}
onOpenChange={setIsDialogOpen}
selectedOpinion={selectedOpinion}
onOpinionCreated={handleOpinionCreated}
/>
</div>
);
};
+245
View File
@@ -0,0 +1,245 @@
import { useState, useEffect } from "react";
import { Download, Sparkles } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Label } from "@/components/ui/label";
import { ScrollArea } from "@/components/ui/scroll-area";
import { useToast } from "@/hooks/use-toast";
import { LegalOpinion } from "./AgentView";
interface OpinionDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
selectedOpinion: LegalOpinion | null;
onOpinionCreated: (opinion: LegalOpinion) => void;
}
export const OpinionDialog = ({
open,
onOpenChange,
selectedOpinion,
onOpinionCreated,
}: OpinionDialogProps) => {
const [title, setTitle] = useState("");
const [category, setCategory] = useState("");
const [instructions, setInstructions] = useState("");
const [generatedContent, setGeneratedContent] = useState("");
const [isGenerating, setIsGenerating] = useState(false);
const { toast } = useToast();
useEffect(() => {
if (selectedOpinion) {
setTitle(selectedOpinion.title);
setCategory(selectedOpinion.category || "");
setGeneratedContent(selectedOpinion.content);
setInstructions("");
} else {
setTitle("");
setCategory("");
setInstructions("");
setGeneratedContent("");
}
}, [selectedOpinion]);
const handleGenerate = async () => {
if (!instructions.trim()) {
toast({
title: "Instruções necessárias",
description: "Por favor, forneça instruções para gerar o parecer.",
variant: "destructive",
});
return;
}
if (!title.trim()) {
toast({
title: "Título necessário",
description: "Por favor, forneça um título para o parecer.",
variant: "destructive",
});
return;
}
setIsGenerating(true);
// Simulação de chamada à IA - aqui você integraria com a API real
setTimeout(() => {
const mockContent = `PARECER JURÍDICO
TÍTULO: ${title}
CATEGORIA: ${category || "Não especificada"}
${instructions}
ANÁLISE:
Este parecer foi gerado com base nas instruções fornecidas. A análise considera os seguintes aspectos legais:
1. Fundamentação Legal
- Análise da legislação aplicável ao caso
- Interpretação dos dispositivos legais pertinentes
2. Precedentes Judiciais
- Jurisprudência dos tribunais superiores
- Decisões relevantes em casos semelhantes
3. Doutrina Aplicável
- Posicionamento dos principais autores
- Análise crítica da literatura jurídica
4. Conclusão e Recomendações
- Síntese dos pontos fundamentais
- Orientações práticas para o caso
CONCLUSÃO:
Com base na análise realizada, considerando a legislação vigente, a jurisprudência consolidada e a doutrina majoritária, conclui-se que os fundamentos apresentados nas instruções são juridicamente sustentáveis.
Recomenda-se:
- Acompanhamento da evolução legislativa
- Monitoramento de novas decisões judiciais
- Revisão periódica do presente parecer
___________________________
Parecer gerado em ${new Date().toLocaleDateString("pt-BR")}
Profissional responsável: IA Jurídica HGTX Codex`;
setGeneratedContent(mockContent);
setIsGenerating(false);
const newOpinion: LegalOpinion = {
id: selectedOpinion?.id || Date.now().toString(),
title: title,
content: mockContent,
createdAt: new Date(),
category: category || undefined,
};
onOpinionCreated(newOpinion);
toast({
title: "Parecer gerado com sucesso!",
description: "O parecer está pronto para download.",
});
}, 2000);
};
const handleDownloadDocx = () => {
const content = generatedContent;
const blob = new Blob([content], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `${title || "parecer"}.txt`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
toast({
title: "Download iniciado",
description: "O parecer está sendo baixado.",
});
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-4xl max-h-[90vh]">
<DialogHeader>
<DialogTitle>
{selectedOpinion ? "Gerar Novo Modelo do Parecer" : "Novo Parecer Jurídico"}
</DialogTitle>
<DialogDescription>
{selectedOpinion
? "Forneça instruções para gerar um novo modelo baseado neste parecer"
: "Preencha os dados e instruções para gerar um novo parecer com IA"}
</DialogDescription>
</DialogHeader>
<ScrollArea className="max-h-[calc(90vh-120px)] pr-4">
<div className="space-y-4 py-4">
<div className="space-y-2">
<Label htmlFor="title">Título do Parecer *</Label>
<Input
id="title"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Ex: Análise sobre Contrato de Prestação de Serviços"
disabled={!!selectedOpinion}
/>
</div>
<div className="space-y-2">
<Label htmlFor="category">Categoria</Label>
<Input
id="category"
value={category}
onChange={(e) => setCategory(e.target.value)}
placeholder="Ex: Direito Civil, Trabalhista, etc."
disabled={!!selectedOpinion}
/>
</div>
<div className="space-y-2">
<Label htmlFor="instructions">
Instruções para gerar o parecer *
</Label>
<Textarea
id="instructions"
value={instructions}
onChange={(e) => setInstructions(e.target.value)}
placeholder="Descreva os detalhes, contexto e aspectos legais que devem ser considerados no parecer..."
className="min-h-[150px]"
/>
</div>
<Button
onClick={handleGenerate}
disabled={isGenerating}
className="w-full gap-2"
>
{isGenerating ? (
<>Gerando parecer...</>
) : (
<>
<Sparkles className="w-4 h-4" />
Gerar Parecer com IA
</>
)}
</Button>
{generatedContent && (
<div className="space-y-2 pt-4 border-t">
<div className="flex items-center justify-between">
<Label>Parecer Gerado</Label>
<Button
onClick={handleDownloadDocx}
variant="outline"
size="sm"
className="gap-2"
>
<Download className="w-4 h-4" />
Baixar DOCX
</Button>
</div>
<ScrollArea className="h-[300px] rounded-md border p-4">
<pre className="whitespace-pre-wrap font-sans text-sm">
{generatedContent}
</pre>
</ScrollArea>
</div>
)}
</div>
</ScrollArea>
</DialogContent>
</Dialog>
);
};