Os sistemas de recomendação estão por toda parte. Da Netflix e Spotify à Amazon. Mas e se você quisesse criar um mecanismo de recomendação visible? Um que olha para a imagem, não apenas o título ou as tags? Neste artigo, você criará um sistema de recomendação de moda masculina. Ele usará incorporações de imagem e o banco de dados de vetores QDRANT. Você irá de dados de imagem bruta para recomendações visuais em tempo actual.
Objetivo de aprendizagem
- Como as incorporações de imagem representam conteúdo visible
- Como usar o FastEmbbed para geração vetorial
- Como armazenar e pesquisar vetores usando o QDRANT
- Como construir um mecanismo de recomendação orientado a suggestions
- Como criar uma interface de interface do simples
Caso de uso: recomendações visuais para camisetas e polos
Think about um usuário clica em uma camisa polo elegante. Em vez de usar tags de produto, seu sistema de recomendação de moda recomendará camisetas e polos que parecem semelhantes. Ele usa a própria imagem para tomar essa decisão.
Vamos explorar como.
Etapa 1: Compreendendo incorporações de imagem
O que são incorporações de imagem?
Um incorporação de imagem é um vetor. É uma lista de números. Esses números representam os principais recursos da imagem. Duas imagens semelhantes têm incorporações que estão juntas no espaço vetorial. Isso permite que o sistema mede a similaridade visible.
Por exemplo, duas camisetas diferentes podem parecer diferentes em pixels. Mas suas incorporações estarão próximas se tiverem cores, padrões e texturas semelhantes. Essa é uma capacidade essential para um sistema de recomendação de moda.

Como as incorporações são geradas?
A maioria dos modelos de incorporação usa aprendizado profundo. CNNs (redes neurais convolucionais) extraem padrões visuais. Esses padrões se tornam parte do vetor.
No nosso caso, usamos o Fastembed. O modelo de incorporação usado aqui é: QDRANT/UNICOM-VIT-B-32
from fastembed import ImageEmbedding
from typing import Record
from dotenv import load_dotenv
import os
load_dotenv()
mannequin = ImageEmbedding(os.getenv("IMAGE_EMBEDDING_MODEL"))
def compute_image_embedding(image_paths: Record(str)) -> checklist(float):
return checklist(mannequin.embed(image_paths))
Esta função leva uma lista de caminhos de imagem. Retorna vetores que capturam a essência dessas imagens.
Etapa 2: Obtendo o conjunto de dados
Usamos um conjunto de dados de cerca de 2000 imagens de moda masculina. Você pode encontrá -lo em Kaggle. Aqui está como carregamos o conjunto de dados:
import shutil, os, kagglehub
from dotenv import load_dotenv
load_dotenv()
kaggle_repo = os.getenv("KAGGLE_REPO")
path = kagglehub.dataset_download(kaggle_repo)
target_folder = os.getenv("DATA_PATH")
def getData():
if not os.path.exists(target_folder):
shutil.copytree(path, target_folder)
Este script verifica se a pasta de destino existe. Caso contrário, copia as imagens lá.
Etapa 3: Armazene e pesquise vetores com QDRANT
Depois de incorporar, precisamos armazená -los e pesquisar. É aqui que QDRANT vem. É um banco de dados vetorial rápido e escalável.
Aqui está como se conectar ao banco de dados de vetores QDrant:
from qdrant_client import QdrantClient
shopper = QdrantClient(
url=os.getenv("QDRANT_URL"),
api_key=os.getenv("QDRANT_API_KEY"),
)
That is the right way to insert the photographs paired with its embedding to a Qdrant assortment:
class VectorStore:
def __init__(self, embed_batch: int = 64, upload_batch: int = 32, parallel_uploads: int = 3):
# ... (initializer code omitted for brevity) ...
def insert_images(self, image_paths: Record(str)):
def chunked(iterable, dimension):
for i in vary(0, len(iterable), dimension):
yield iterable(i:i + dimension)
for batch in chunked(image_paths, self.embed_batch):
embeddings = compute_image_embedding(batch) # Batch embed
factors = (
fashions.PointStruct(id=str(uuid.uuid4()), vector=emb, payload={"image_path": img})
for emb, img in zip(embeddings, batch)
)
# Batch add every sub-batch
self.shopper.upload_points(
collection_name=self.collection_name,
factors=factors,
batch_size=self.upload_batch,
parallel=self.parallel_uploads,
max_retries=3,
wait=True
)
Esse código leva uma lista de caminhos de arquivo de imagem, transforma -os em incorporação em lotes e carrega essas incorporações para uma coleção QDRANT. Primeiro verifica se a coleção existe. Em seguida, ele processa as imagens em paralelo usando threads para acelerar as coisas. Cada imagem recebe um ID exclusivo e é envolvido em um “ponto” com sua incorporação e caminho. Esses pontos são então enviados para QDRANT em pedaços.
Pesquise imagens semelhantes
def search_similar(query_image_path: str, restrict: int = 5):
emb_list = compute_image_embedding((query_image_path))
hits = shopper.search(
collection_name="fashion_images",
query_vector=emb_list(0),
restrict=restrict
)
return ({"id": h.id, "image_path": h.payload.get("image_path")} for h in hits)
Você dá uma imagem de consulta. O sistema retorna imagens visualmente semelhantes usando métricas de similaridade de cosseno.
Etapa 4: Crie o mecanismo de recomendação com suggestions
Agora vamos um passo adiante. E se o usuário gostar de algumas imagens e não gosta de outras? O sistema de recomendação de moda pode aprender com isso?
Sim. O QDRANT nos permite dar suggestions positivo e negativo. Em seguida, retorna resultados melhores e mais personalizados.
class RecommendationEngine:
def get_recommendations(self, liked_images:Record(str), disliked_images:Record(str), restrict=10):
beneficial = shopper.advocate(
collection_name="fashion_images",
constructive=liked_images,
unfavourable=disliked_images,
restrict=restrict
)
return ({"id": hit.id, "image_path": hit.payload.get("image_path")} for hit in beneficial)
Aqui estão as entradas desta função:
- gostei_images: uma lista de IDs de imagem que representam itens que o usuário gostou.
- Não gostei_Images: Uma lista de IDs de imagem que representam itens que o usuário não gostava.
- LIMITE (OPCIONAL): Um número inteiro especificando o número máximo de recomendações a serem retornadas (padrão para 10).
Isso retornará roupas recomendadas usando a similaridade do vetor de incorporação apresentada anteriormente.
Isso permite que seu sistema se adapte. Aprende as preferências do usuário rapidamente.
Etapa 5: Construa uma interface do usuário com simplidade
Usamos o streamlit para criar a interface. É simples, rápido e escrito em Python.


Os usuários podem:
- Navegue roupas
- Gostar ou não gostar de itens
- Veja novas recomendações melhores
Aqui está o código do streamlit:
import streamlit as st
from PIL import Picture
import os
from src.advice.engine import RecommendationEngine
from src.vector_database.vectorstore import VectorStore
from src.knowledge.get_data import getData
# -------------- Config --------------
st.set_page_config(page_title="🧥 Males's Vogue Recommender", format="vast")
IMAGES_PER_PAGE = 12
# -------------- Guarantee Dataset Exists (as soon as) --------------
@st.cache_resource
def initialize_data():
getData()
return VectorStore(), RecommendationEngine()
vector_store, recommendation_engine = initialize_data()
# -------------- Session State Defaults --------------
session_defaults = {
"favored": {},
"disliked": {},
"current_page": 0,
"recommended_images": vector_store.factors,
"vector_store": vector_store,
"recommendation_engine": recommendation_engine,
}
for key, worth in session_defaults.objects():
if key not in st.session_state:
st.session_state(key) = worth
# -------------- Sidebar Data --------------
with st.sidebar:
st.title("🧥 Males's Vogue Recommender")
st.markdown("""
**Uncover trend types that fit your style.**
Like 👍 or dislike 👎 outfits and obtain AI-powered suggestions tailor-made to you.
""")
st.markdown("### 📦 Dataset")
st.markdown("""
- Supply: (Kaggle – virat164/fashion-database)(https://www.kaggle.com/datasets/virat164/fashion-database)
- ~2,000 trend photographs
""")
st.markdown("### 🧠 How It Works")
st.markdown("""
1. Photos are embedded into vector house
2. You present preferences by way of Like/Dislike
3. Qdrant finds visually comparable photographs
4. Outcomes are up to date in real-time
""")
st.markdown("### ⚙️ Applied sciences")
st.markdown("""
- **Streamlit** UI
- **Qdrant** vector DB
- **Python** backend
- **PIL** for picture dealing with
- **Kaggle API** for knowledge
""")
st.markdown("---")
# -------------- Core Logic Capabilities --------------
def get_recommendations(liked_ids, disliked_ids):
return st.session_state.recommendation_engine.get_recommendations(
liked_images=liked_ids,
disliked_images=disliked_ids,
restrict=3 * IMAGES_PER_PAGE
)
def refresh_recommendations():
liked_ids = checklist(st.session_state.favored.keys())
disliked_ids = checklist(st.session_state.disliked.keys())
st.session_state.recommended_images = get_recommendations(liked_ids, disliked_ids)
# -------------- Show: Chosen Preferences --------------
def display_selected_images():
if not st.session_state.favored and never st.session_state.disliked:
return
st.markdown("### 🧍 Your Picks")
cols = st.columns(6)
photographs = st.session_state.vector_store.factors
for i, (img_id, standing) in enumerate(
checklist(st.session_state.favored.objects()) + checklist(st.session_state.disliked.objects())
):
img_path = subsequent((img("image_path") for img in photographs if img("id") == img_id), None)
if img_path and os.path.exists(img_path):
with cols(i % 6):
st.picture(img_path, use_container_width=True, caption=f"{img_id} ({standing})")
col1, col2 = st.columns(2)
if col1.button("❌ Take away", key=f"remove_{img_id}"):
if standing == "favored":
del st.session_state.favored(img_id)
else:
del st.session_state.disliked(img_id)
refresh_recommendations()
st.rerun()
if col2.button("🔁 Change", key=f"switch_{img_id}"):
if standing == "favored":
del st.session_state.favored(img_id)
st.session_state.disliked(img_id) = "disliked"
else:
del st.session_state.disliked(img_id)
st.session_state.favored(img_id) = "favored"
refresh_recommendations()
st.rerun()
# -------------- Show: Advisable Gallery --------------
def display_gallery():
st.markdown("### 🧠 Good Recommendations")
web page = st.session_state.current_page
start_idx = web page * IMAGES_PER_PAGE
end_idx = start_idx + IMAGES_PER_PAGE
current_images = st.session_state.recommended_images(start_idx:end_idx)
cols = st.columns(4)
for idx, img in enumerate(current_images):
with cols(idx % 4):
if os.path.exists(img("image_path")):
st.picture(img("image_path"), use_container_width=True)
else:
st.warning("Picture not discovered")
col1, col2 = st.columns(2)
if col1.button("👍 Like", key=f"like_{img('id')}"):
st.session_state.favored(img("id")) = "favored"
refresh_recommendations()
st.rerun()
if col2.button("👎 Dislike", key=f"dislike_{img('id')}"):
st.session_state.disliked(img("id")) = "disliked"
refresh_recommendations()
st.rerun()
# Pagination
col1, _, col3 = st.columns((1, 2, 1))
with col1:
if st.button("⬅️ Earlier") and web page > 0:
st.session_state.current_page -= 1
st.rerun()
with col3:
if st.button("➡️ Subsequent") and end_idx < len(st.session_state.recommended_images):
st.session_state.current_page += 1
st.rerun()
# -------------- Most important Render Pipeline --------------
st.title("🧥 Males's Vogue Recommender")
display_selected_images()
st.divider()
display_gallery()
This UI closes the loop. It turns a operate right into a usable product.
Conclusão
Você acabou de criar um sistema completo de recomendação de moda. Ele vê imagens, entende recursos visuais e faz sugestões inteligentes.
Usando o Fastembed, o QDRANT e o Streamlit, agora você tem um poderoso sistema de recomendação. Funciona para camisetas, polos e roupas masculinas, mas pode ser adaptado a outras recomendações baseadas na imagem.
Perguntas frequentes
Não exatamente. Os números nas incorporações capturam recursos semânticos como formas, cores e texturas – não valores de pixels brutos. Isso ajuda o sistema a entender o significado por trás da imagem e não apenas os dados do Pixel.
Não. Ele aproveita a similaridade vetorial (como a similaridade de cosseno) no espaço de incorporação para encontrar itens visualmente semelhantes sem precisar treinar um modelo tradicional do zero.
Sim, você pode. Os modelos de incorporação de imagem de treinamento ou de ajuste fino geralmente envolvem estruturas como Tensorflow ou Pytorch e um conjunto de dados rotulado. Isso permite personalizar incorporações para necessidades específicas.
Sim, se você usar um modelo multimodal que mapeie as imagens e o texto no mesmo espaço vetorial. Dessa forma, você pode pesquisar imagens com consultas de texto ou vice -versa.
Fastembed é uma ótima opção para incorporações rápidas e eficientes. Mas existem muitas alternativas, incluindo modelos do OpenAI, Google ou Groq. A escolha depende do seu caso de uso e das necessidades de desempenho.
Absolutamente. As alternativas populares incluem Pinecone, Weaviate, Milvus e Vespa. Cada um possui recursos exclusivos, então escolha o que melhor se ajusta aos requisitos do seu projeto.
Não. Enquanto ambos usam pesquisas vetoriais, o RAG integra a recuperação à geração de idiomas para tarefas como a resposta das perguntas. Aqui, o foco está puramente nas recomendações de similaridade visible.
Faça login para continuar lendo e desfrutar de conteúdo com curado especialista.