first commit
This commit is contained in:
257
docs/08-ia.md
Normal file
257
docs/08-ia.md
Normal file
@@ -0,0 +1,257 @@
|
||||
# 8. Integração de Inteligência Artificial
|
||||
|
||||
## 8.1 Casos de Uso de IA
|
||||
|
||||
| Funcionalidade | Descrição | Modelo |
|
||||
|---|---|---|
|
||||
| **Match Inteligente** | Sugere os 3 animais mais compatíveis com o perfil do utilizador | Claude Sonnet (API) |
|
||||
| **Assistente de Suporte** | Responde a dúvidas sobre adopção e doação em chat em tempo real | Claude Sonnet (streaming) |
|
||||
| **Geração de Descrições** | Gera descrições cativantes para animais sem texto fornecido pelo canil | Claude Haiku (API) |
|
||||
| **Análise de Necessidades** | Identifica padrões nas necessidades dos canis e sugere campanhas | Claude Sonnet (API) |
|
||||
| **Moderação de Conteúdo** | Verifica fotos e textos submetidos pelos canis antes de publicar | Claude Sonnet Vision |
|
||||
|
||||
---
|
||||
|
||||
## 8.2 Arquitectura do Agente de Match
|
||||
|
||||
O sistema de match inteligente funciona em dois passos:
|
||||
|
||||
1. **Recolha de contexto:** combina o perfil do utilizador com o inventário actualizado de animais disponíveis
|
||||
2. **Inferência:** passa o contexto ao Claude com um system prompt especializado e recebe sugestões fundamentadas
|
||||
|
||||
### Estrutura do Contexto
|
||||
|
||||
```typescript
|
||||
// lib/ai/match.ts
|
||||
|
||||
interface MatchContext {
|
||||
user: {
|
||||
district: string;
|
||||
age: number;
|
||||
preferences: {
|
||||
species?: 'dog' | 'cat' | 'other';
|
||||
preferredSize?: 'small' | 'medium' | 'large';
|
||||
experience: 'first_time' | 'experienced' | 'expert';
|
||||
livingSpace: 'apartment' | 'house_no_garden' | 'house_with_garden';
|
||||
activityLevel: 'low' | 'moderate' | 'high';
|
||||
hasChildren?: boolean;
|
||||
hasOtherPets?: boolean;
|
||||
};
|
||||
history: {
|
||||
viewedAnimalIds: string[];
|
||||
pastAdoptions: number;
|
||||
};
|
||||
};
|
||||
availableAnimals: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
species: string;
|
||||
breed: string | null;
|
||||
ageMonths: number;
|
||||
sex: string;
|
||||
sterilized: boolean;
|
||||
district: string;
|
||||
shelterName: string;
|
||||
urgent: boolean;
|
||||
description: string | null;
|
||||
}>;
|
||||
}
|
||||
```
|
||||
|
||||
### System Prompt do Agente de Match
|
||||
|
||||
```typescript
|
||||
// lib/ai/prompts.ts
|
||||
|
||||
export const MATCH_SYSTEM_PROMPT = `
|
||||
És um especialista em adopção responsável de animais da plataforma PawLink,
|
||||
em Portugal. O teu papel é ajudar utilizadores a encontrar o animal de estimação
|
||||
mais compatível com o seu estilo de vida.
|
||||
|
||||
INSTRUÇÕES:
|
||||
- Analisa o perfil do utilizador e a lista de animais disponíveis
|
||||
- Sugere exactamente 3 animais, ordenados por compatibilidade (do mais ao menos compatível)
|
||||
- Para cada animal, explica em 2-3 frases porque é uma boa correspondência
|
||||
- Considera sempre: espaço disponível, nível de actividade, experiência, localidade
|
||||
- Animais com flag "urgent: true" devem receber peso extra na pontuação
|
||||
- Não inventes características — usa apenas os dados fornecidos
|
||||
- Se não houver animais adequados, diz-o honestamente e explica porquê
|
||||
|
||||
FORMATO DA RESPOSTA (JSON):
|
||||
{
|
||||
"matches": [
|
||||
{
|
||||
"animalId": "string",
|
||||
"compatibilityScore": 95,
|
||||
"reason": "string — 2-3 frases em português"
|
||||
}
|
||||
],
|
||||
"generalAdvice": "string — conselho geral opcional (máximo 1 frase)"
|
||||
}
|
||||
|
||||
Responde APENAS com JSON válido, sem texto adicional.
|
||||
`;
|
||||
```
|
||||
|
||||
### Implementação da Chamada à API
|
||||
|
||||
```typescript
|
||||
// lib/ai/match.ts
|
||||
import Anthropic from '@anthropic-ai/sdk';
|
||||
|
||||
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
||||
|
||||
export async function getAnimalMatches(context: MatchContext) {
|
||||
const response = await anthropic.messages.create({
|
||||
model: 'claude-sonnet-4-20250514',
|
||||
max_tokens: 1024,
|
||||
system: MATCH_SYSTEM_PROMPT,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: `Perfil do utilizador e animais disponíveis:\n${JSON.stringify(context, null, 2)}`
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const text = response.content[0].type === 'text' ? response.content[0].text : '';
|
||||
|
||||
try {
|
||||
return JSON.parse(text) as { matches: MatchResult[]; generalAdvice?: string };
|
||||
} catch {
|
||||
console.error('Erro ao fazer parse da resposta de match:', text);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8.3 Assistente de Suporte (Chatbot)
|
||||
|
||||
O assistente responde em tempo real usando **streaming** para melhor experiência do utilizador. É implementado com o Vercel AI SDK.
|
||||
|
||||
### System Prompt do Suporte
|
||||
|
||||
```typescript
|
||||
export const SUPPORT_SYSTEM_PROMPT = `
|
||||
És o assistente virtual da PawLink, uma plataforma portuguesa de adopção de
|
||||
animais e doação a canis. Chamas-te Paws.
|
||||
|
||||
PAPEL:
|
||||
- Ajudar utilizadores a navegar na plataforma e responder a dúvidas sobre
|
||||
adopção e doação de animais
|
||||
- Fornecer informação geral sobre cuidados com animais de estimação
|
||||
- Orientar utilizadores que estejam a considerar adoptar pela primeira vez
|
||||
|
||||
LIMITAÇÕES:
|
||||
- Não tens acesso a informação em tempo real sobre animais específicos ou
|
||||
disponibilidade actual (sugere usar os filtros da plataforma)
|
||||
- Não podes processar pagamentos ou fazer reservas directamente
|
||||
- Para questões técnicas graves, sugere contacto via email: suporte@pawlink.pt
|
||||
|
||||
TOM:
|
||||
- Caloroso, encorajador e amigável
|
||||
- Profissional mas acessível
|
||||
- Nunca condescendente
|
||||
|
||||
LÍNGUA: Responde sempre em português de Portugal (pt-PT).
|
||||
`;
|
||||
```
|
||||
|
||||
### Endpoint de Streaming
|
||||
|
||||
```typescript
|
||||
// app/api/chat/route.ts
|
||||
import { streamText } from 'ai';
|
||||
import { anthropic } from '@ai-sdk/anthropic';
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { messages } = await req.json();
|
||||
|
||||
const result = await streamText({
|
||||
model: anthropic('claude-sonnet-4-20250514'),
|
||||
system: SUPPORT_SYSTEM_PROMPT,
|
||||
messages,
|
||||
maxTokens: 500, // respostas concisas no chat
|
||||
});
|
||||
|
||||
return result.toDataStreamResponse();
|
||||
}
|
||||
```
|
||||
|
||||
### Componente de Chat no Frontend
|
||||
|
||||
```typescript
|
||||
// components/chat/SupportChat.tsx
|
||||
'use client';
|
||||
import { useChat } from 'ai/react';
|
||||
|
||||
export function SupportChat() {
|
||||
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
|
||||
api: '/api/chat',
|
||||
initialMessages: [{
|
||||
id: 'welcome',
|
||||
role: 'assistant',
|
||||
content: 'Olá! Sou o Paws, o assistente da PawLink. Como posso ajudar-te hoje? 🐾'
|
||||
}]
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="chat-container">
|
||||
{messages.map(msg => (
|
||||
<div key={msg.id} className={`message ${msg.role}`}>
|
||||
{msg.content}
|
||||
</div>
|
||||
))}
|
||||
<form onSubmit={handleSubmit}>
|
||||
<input value={input} onChange={handleInputChange} placeholder="Escreve a tua mensagem..." />
|
||||
<button type="submit" disabled={isLoading}>Enviar</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8.4 Geração de Descrições de Animais
|
||||
|
||||
Quando um canil regista um animal sem fornecer descrição, o sistema gera automaticamente uma descrição cativante:
|
||||
|
||||
```typescript
|
||||
export async function generateAnimalDescription(animal: {
|
||||
name: string;
|
||||
species: string;
|
||||
breed: string | null;
|
||||
ageMonths: number;
|
||||
sex: string;
|
||||
sterilized: boolean;
|
||||
}) {
|
||||
const response = await anthropic.messages.create({
|
||||
model: 'claude-haiku-4-5', // Haiku é suficiente e mais económico para esta tarefa
|
||||
max_tokens: 200,
|
||||
messages: [{
|
||||
role: 'user',
|
||||
content: `Escreve uma descrição curta e cativante (máximo 3 frases) para este animal
|
||||
disponível para adopção numa plataforma portuguesa.
|
||||
Dados: ${JSON.stringify(animal)}
|
||||
Escreve em português de Portugal, com tom caloroso e encorajador.
|
||||
Não inventes factos específicos, usa apenas os dados fornecidos.`
|
||||
}]
|
||||
});
|
||||
|
||||
return response.content[0].type === 'text' ? response.content[0].text : null;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8.5 Boas Práticas e Limites
|
||||
|
||||
- **Rate limiting:** chamadas à IA limitadas a 20 por utilizador por hora para controlo de custos
|
||||
- **Cache de resultados:** respostas de match são cacheadas 30 minutos no Redis (o inventário não muda ao segundo)
|
||||
- **Fallback gracioso:** se a API da Anthropic falhar, a plataforma funciona normalmente sem funcionalidades de IA
|
||||
- **Transparência:** o utilizador é informado quando está a interagir com IA
|
||||
- **Sem decisões críticas:** a IA sugere mas nunca decide automaticamente — o utilizador tem sempre controlo
|
||||
- **Monitorização de custos:** dashboard no Anthropic Console para acompanhar utilização e custos
|
||||
Reference in New Issue
Block a user