Files
dayMaker_lp/documentação/03_AI_VISION_LAYER.md
2026-05-13 15:59:02 +01:00

5.0 KiB

👁️ Camada de Visão por IA

Objetivo

Usar IA de visão computacional para identificar automaticamente o que está na foto tirada pelo utilizador, sugerindo:

  • Nome do item
  • Categoria
  • Tags relevantes

Isto reduz o esforço do utilizador ao mínimo.


Serviço escolhido: Google Vision API

Porquê Google Vision?

  • Fácil integração com Firebase (mesmo ecosistema Google)
  • Excelente deteção de objetos do quotidiano
  • Labels em múltiplos idiomas
  • Tier gratuito generoso (1.000 unidades/mês)
  • Documentação extensa

Funcionalidades usadas no MVP

Feature Uso
LABEL_DETECTION Identificar o objeto (ex: "T-shirt", "Laptop")
OBJECT_LOCALIZATION Confirmar que existe um objeto na foto

No MVP não usamos OCR, Safe Search ou outras features avançadas.


Integração técnica

Chamada à API (exemplo React Native)

// services/visionApi.js

const VISION_API_KEY = process.env.GOOGLE_VISION_API_KEY;
const VISION_API_URL = `https://vision.googleapis.com/v1/images:annotate?key=${VISION_API_KEY}`;

export async function analyzeImage(base64Image) {
  const requestBody = {
    requests: [
      {
        image: { content: base64Image },
        features: [
          { type: 'LABEL_DETECTION', maxResults: 10 },
          { type: 'OBJECT_LOCALIZATION', maxResults: 5 }
        ]
      }
    ]
  };

  const response = await fetch(VISION_API_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(requestBody)
  });

  const data = await response.json();
  return parseVisionResponse(data);
}

Parsing da resposta

// services/visionApi.js (continuação)

export function parseVisionResponse(data) {
  const labels = data.responses[0]?.labelAnnotations || [];
  const objects = data.responses[0]?.localizedObjectAnnotations || [];

  // Extrair labels com score > 0.7
  const highConfidenceLabels = labels
    .filter(l => l.score > 0.7)
    .map(l => l.description.toLowerCase());

  // Mapear para categoria da app
  const category = mapLabelsToCategory(highConfidenceLabels);

  // Sugerir nome baseado no objeto mais confiante
  const suggestedName = objects[0]?.name || labels[0]?.description || 'Item';

  return {
    suggestedName,
    category,
    tags: highConfidenceLabels.slice(0, 5),
    rawLabels: highConfidenceLabels
  };
}

Mapeamento de Labels → Categorias

// constants/categoryMapping.js

export const LABEL_TO_CATEGORY = {
  // Roupa
  't-shirt': 'clothing',
  'shirt': 'clothing',
  'dress': 'clothing',
  'jacket': 'clothing',
  'coat': 'clothing',
  'jeans': 'clothing',
  'trousers': 'clothing',
  'sweater': 'clothing',
  'clothing': 'clothing',
  'fashion': 'clothing',

  // Eletrónica
  'laptop': 'electronics',
  'computer': 'electronics',
  'smartphone': 'electronics',
  'tablet': 'electronics',
  'headphones': 'electronics',
  'camera': 'electronics',
  'charger': 'electronics',
  'cable': 'electronics',
  'electronics': 'electronics',

  // Calçado
  'shoe': 'footwear',
  'boot': 'footwear',
  'sneaker': 'footwear',
  'sandal': 'footwear',
  'footwear': 'footwear',

  // Acessórios
  'bag': 'accessories',
  'backpack': 'accessories',
  'watch': 'accessories',
  'sunglasses': 'accessories',
  'hat': 'accessories',
  'belt': 'accessories',

  // Documentos
  'passport': 'documents',
  'document': 'documents',
  'book': 'documents',
  'notebook': 'documents',
};

export function mapLabelsToCategory(labels) {
  for (const label of labels) {
    if (LABEL_TO_CATEGORY[label]) {
      return LABEL_TO_CATEGORY[label];
    }
  }
  return 'other'; // fallback
}

Fluxo de UX ao adicionar item

1. Utilizador tira foto
2. App mostra loading ("A analisar item...")
3. Google Vision responde com labels
4. App mostra:
   - Nome sugerido (editável)
   - Categoria sugerida (editável)
   - Tags sugeridas (checkboxes, editáveis)
5. Utilizador confirma ou ajusta
6. Item guardado

O utilizador tem sempre controlo final. A IA apenas sugere.


Tratamento de erros

Erro Comportamento
API indisponível Mostrar formulário manual, sem sugestões
Foto sem objeto reconhecível Mostrar sugestão "Outro" e pedir nome manual
Score muito baixo (< 0.5) Ignorar label, não sugerir
Timeout Retry 1x, depois formulário manual

Evolução futura desta camada

  • Fase 2: Treinar modelo custom com os dados dos utilizadores
  • Fase 3: Identificar marcas e modelos específicos
  • Fase 3: Reconhecimento de cor dominante para filtros de outfit

Notas para o agente IA

  • A chave da API (GOOGLE_VISION_API_KEY) nunca deve aparecer em código client-side em produção — usar Firebase Cloud Functions como proxy
  • No MVP, a chamada pode ser feita diretamente do cliente para simplicidade
  • Nunca guardar rawLabels como name sem confirmação do utilizador
  • O mapeamento de labels é iterativo — quando encontrar labels não mapeadas, adicionar ao ficheiro categoryMapping.js