- Streaming AI endpoint at /campanha/api/ai-chat with DeepSeek V4 Flash - 8 tools: calculate, getMunicipalityVotes, getTopDeputies, getDobradinhas, getMunicipalityOverview, getLeaderships, getOrganizations, searchEntities - In-memory rate limiter (50 msgs / 15 min per user) - Desktop: resizable right sidebar via react-resizable-panels - Mobile: full-screen Drawer opened by FAB (2/3 size of quick-actions FAB) - Markdown rendering with react-markdown + remark-gfm (tables, bold, lists) - Session-bound context (clean slate each open) - Auth via existing campaign-token cookie, tools respect user RBAC - Architecture doc: docs/plans/ai-chat-sollinha.md - E2E tests: campaignAiChat.e2e.spec.ts (mocked endpoint)
26 lines
682 B
TypeScript
26 lines
682 B
TypeScript
'use client'
|
|
|
|
import { Bot } from 'lucide-react'
|
|
|
|
import { Button } from '@/components/ui/button'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
import { useAISidebar } from '@/components/campaign/shell/ai/CampaignAISidebarContext'
|
|
|
|
export const CampaignAIHeaderButton = ({ className }: { className?: string }) => {
|
|
const ctx = useAISidebar()
|
|
|
|
return (
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon"
|
|
className={cn('size-11 hidden shrink-0 md:inline-flex', className)}
|
|
aria-label="Sollinha — Assistente virtual"
|
|
title="Sollinha — Assistente virtual"
|
|
onClick={() => ctx?.toggle()}
|
|
>
|
|
<Bot className="size-5" />
|
|
</Button>
|
|
)
|
|
}
|