Pipeline Automatizado para Aquisição e Transformação de Fotografias de Fauna via Python e LongCat-Image-Edit

Fundamentos da Arquitetura Automatizada

A geração contínua de materiais visuais padronizados para comércio eletrônico, plataformas educacionais ou redes sociais impõe gargalos operacionais quando realizada manualmente. Ferramentas tradicionais de manipcação gráfica exigem conhecimento técnico aprofundado e não escalam linearmente com a demanda. A combinação de scripts de extração de dados web com modelos de inteligência artificial generativa resolve essa limitação ao permitir a ingestão massiva de arquivos brutos e a aplicação programática de transformações visuais.

O ecossistema descrito aqui utiliza coletores web leves para obter imagens de repositórios públicos, enviando-as posteriormente para o motor LongCat-Image-Edit através de chamadas REST. A ferramenta de inferência compreende instruções em linguagem natural, permitindo a substituição de planos de fundo, ajuste de iluminação e adição de elementos semânticos em poucos segundos. Todo o ciclo opera de forma assíncrona e autônoma.

Provisionamento de Ambientes

Implantação do Motor de Inferência

A execução da solução requer um host com suporte a CUDA, mínimo de 8 GB de RAM e aproximadamente 50 GB de armazenamento livre. A distribuição mais estável utiliza contêineres Docker, garantindo isolamento de dependências e compatibilidade entre sistemas operacionais.

# Recuperação da imagem oficial
docker pull registry.cn-hangzhou.aliyuncs.com/csdn_ai/longcat-image-edit:latest

# Inicialização com mapeamento de volumes e GPU
docker run -d \
  --nome-processador-fauna \
  -p 8080:8080 \
  -v $(pwd)/originais:/workspace/input \
  -v $(pwd)/processados:/workspace/output \
  --gpus all \
  registry.cn-hangzhou.aliyuncs.com/csdn_ai/longcat-image-edit:latest

Após a ativação, o serviço responde em http://localhost:8080. O painel exposto permite testes manuais, mas o fluxo produtivo prioriza a interface programática.

Configuração do Interpretador Python

Recomenda-se um ambiente virtual isolado para evitar conflitos de versões de pacotes. As dependências necessárias focam em requisições HTTP síncronas, parsing HTML e manipulação matricial básica.

python -m venv venv-fauna
source venv-fauna/bin/activate
pip install requests beautifulsoup4 lxml pillow opencv-python tqdm

Extração de Dados de Imagem

Plataformas como Pexels e Pixabay disponibliizam acervos sob licença CC0, estruturados semanticamente. O coletor deve priorizar endpoints que exponham URLs diretas nos atributos srcset ou data-src, aplicando politicas de throttling para respeitar os limites de requisições do servidro alvo.

Implementação do Coletor

# modulo_coletor.py
import os, time, logging
import requests
from urllib.parse import urljoin
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path

logging.basicConfig(level=logging.INFO, format='%(asctime)s | %(levelname)s | %(message)s')
logger = logging.getLogger(__name__)

class HarvestorImagensFauna:
    def __init__(self, dominio_base, pasta_destino, max_solicitacoes=4):
        self.alvo = dominio_base
        self.caminho = Path(pasta_destino)
        self.caminho.mkdir(parents=True, exist_ok=True)
        self.limite_threads = max_solicitacoes
        self.sessao_http = requests.Session()
        self.sessao_http.headers.update({
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0',
            'Accept-Language': 'pt-BR,pt;q=0.9,en;q=0.8'
        })

    def _extrair_links_pagina(self, termo_busca, paginas_varredura=2):
        urls_coletadas = []
        for p in range(1, paginas_varredura + 1):
            alvo_req = f"{self.alvo}/search/{termo_busca}?page={p}"
            logger.info(f"Escaneando {alvo_req}")
            try:
                resp = self.sessao_http.get(alvo_req, timeout=15)
                resp.raise_for_status()
                doc = BeautifulSoup(resp.content, "lxml")
                elementos = doc.find_all('img', attrs={'srcset': True})
                for el in elementos:
                    if 'srcset' in el.attrs:
                        candidatas = [u.split()[0] for u in el['srcset'].split(',') if u.strip()]
                        if candidatas:
                            urls_coletadas.append(urljoin(self.alvo, candidatas[-1]))
                time.sleep(1.5 + (p * 0.8))
            except Exception as falha:
                logger.warning(f"Ignorando página {p} devido a: {falha}")
        return list(dict.fromkeys(urls_coletadas))

    def _baixar_arquivo(self, url_origem, indice):
        caminho_final = self.caminho / f"registro_{indice:05d}.jpg"
        if caminho_final.exists():
            return str(caminho_final)
        try:
            fluxo = self.sessao_http.get(url_origem, stream=True, timeout=20)
            fluxo.raise_for_status()
            with open(caminho_final, 'wb') as f:
                for bloco in fluxo.iter_content(chunk_size=8192):
                    f.write(bloco)
            logger.info(f"Armazenado: {caminho_final.name}")
            return str(caminho_final)
        except Exception as erro:
            logger.error(f"Falha ao recuperar {url_origem[:45]}... -> {erro}")
            return None

    def processar_lote(self, termos_pesquisa, limite_total=90):
        pool = []
        for termo in termos_pesquisa:
            pool.extend(self._extrair_links_pagina(termo, paginas_varredura=3))
            time.sleep(2)
        
        pool_filtrado = list(dict.fromkeys(pool))[:limite_total]
        logger.info(f"URLs únicas validadas: {len(pool_filtrado)}")
        
        registros = []
        with ThreadPoolExecutor(max_workers=self.limite_threads) as executor:
            mapeamento = {executor.submit(self._baixar_arquivo, u, i+1): u for i, u in enumerate(pool_filtrado)}
            for futuro in as_completed(mapeamento):
                res = futuro.result()
                if res:
                    registros.append(res)
        
        logger.info(f"Finalizado. {len(registros)} itens salvos localmente.")
        return registros

Integração com Motor de Inferência

A camada de transformação interage com o serviço exposto na porta 8080. A API aceita formulários multipart contendo o arquivo de origem, parâmetros de controle de geração (como força de modificação e escala de direcionamento) e a instrução textual.

Cliente REST para Automação

# modulo_editor.py
import json, time, shutil
import requests
from pathlib import Path

class MotorTransformacaoVisual:
    def __init__(self, endereco_api="http://127.0.0.1:8080"):
        self.endpoint = f"{endereco_api.rstrip('/')}/api/edit"

    def executar_instrucao(self, entrada_arquivo, texto_comando, forca=0.7, escala_cfg=7.0):
        try:
            with open(entrada_arquivo, "rb") as f:
                payload = {"prompt": texto_comando, "strength": forca, "guidance_scale": escala_cfg}
                arquivos = {"image": f}
                resposta = requests.post(self.endpoint, files=arquivos, data=payload, timeout=140)
            
            if resposta.status_code != 200:
                raise ConnectionError(f"Código {resposta.status_code} retornado pelo servidor")
                
            resultado_json = resposta.json()
            if not resultado_json.get("success"):
                raise ValueError(resultado_json.get("error", "Falha desconhecida na inferência"))
            
            dir_saida = Path(entrada_arquivo).parent / "temp_processados"
            dir_saida.mkdir(exist_ok=True)
            caminho_saida = dir_saida / f"tmp_{Path(entrada_arquivo).stem}.png"
            with open(caminho_saida, "wb") as out:
                out.write(resultado_json["image_data"])
            return str(caminho_saida)
        except Exception as e:
            print(f"Erro no processamento de {entrada_arquivo}: {e}")
            return None

    def lote_autonomo(self, pasta_entrada, pasta_saida, logica_prompt):
        origem = Path(pasta_entrada)
        destino = Path(pasta_saida)
        destino.mkdir(parents=True, exist_ok=True)
        padroes = ("*.jpg", "*.jpeg", "*.png", "*.webp")
        alvos = [f for ext in padroes for f in origem.glob(ext)]

        sucesso_contador = 0
        for idx, arquivo in enumerate(alvos, 1):
            comando = logica_prompt(arquivo.name) if callable(logica_prompt) else logica_prompt
            print(f"[{idx}/{len(alvos)}] Aplicando diretriz em {arquivo.name}")
            tmp = self.executar_instrucao(str(arquivo), comando)
            if tmp:
                final = destino / f"{idx:04d}_{arquivo.stem}.png"
                shutil.move(tmp, str(final))
                sucesso_contador += 1
            time.sleep(0.9)
        print(f"\nProcessamento em lote finalizado: {sucesso_contador} arquivos exportados.")
        return sucesso_contador

Orquestração Unificada do Fluxo

# orquestrador_principal.py
from pathlib import Path
from modulo_coletor import HarvestorImagensFauna
from modulo_editor import MotorTransformacaoVisual

def iniciar_pipeline_completo():
    raiz_projeto = Path("./projeto_fauna_automacao")
    pasta_bruta = raiz_projeto / "coleta_bruta"
    pasta_lapidada = raiz_projeto / "exportacao_final"
    for p in (pasta_bruta, pasta_lapidada): p.mkdir(parents=True, exist_ok=True)

    print("--- Estágio 1: Aquisição de Ativos ---")
    coletor = HarvestorImagensFauna(
        dominio_base="https://pixabay.com",
        pasta_destino=str(pasta_bruta),
        max_solicitacoes=3
    )
    arquivos_obtidos = coletor.processar_lote(
        termos_pesquisa=["golden_retriever", "siames_cat", "french_bulldog", "parrot"],
        limite_total=60
    )

    if not arquivos_obtidos:
        print("Fluxo interrompido: nenhum ativo recuperado.")
        return

    print("\n--- Estágio 2: Inferência Neural ---")
    editor = MotorTransformacaoVisual()

    def diretriz_contextual(nome_arquivo):
        identificadores = ["cat", "gato", "feline"]
        if any(tag in nome_arquivo for tag in identificadores):
            return "Adicionar óculos redondos e gravata borboleta, plano de fundo cinza claro e uniforme"
        elif "dog" in nome_arquivo or "bulldog" in nome_arquivo:
            return "Inserir cachecol vermelho, piso de madeira clara, iluminação lateral suave"
        return "Isolamento do sujeito, fundo branco puro #FFFFFF, nitidez otimizada para e-commerce"

    editor.lote_autonomo(
        pasta_entrada=str(pasta_bruta),
        pasta_saida=str(pasta_lapidada),
        logica_prompt=diretriz_contextual
    )
    print("\nPipeline executado com sucesso.")

if __name__ == "__main__":
    iniciar_pipeline_completo()

Otimizações de Pré-processamento

A qualidade da saída generativa é diretamente proporcional à clareza da entrada. Filtros computacionais aplicados antes da chamada da API podem remover ruídos de compressão e realçar estruturas anatômicas.

def refinar_matriz_visual(caminho_imagem):
    import cv2
    import numpy as np
    buffer = cv2.imread(caminho_imagem)
    if buffer is None: return
    
    matriz_agucamento = np.array([[-1, -1, -1], [-1, 9.5, -1], [-1, -1, -1]])
    destaque = cv2.filter2D(buffer, -1, matriz_agucamento)
    
    lab = cv2.cvtColor(destaque, cv2.COLOR_BGR2LAB)
    l, a, b = cv2.split(lab)
    
    adaptador = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
    l_corrigido = adaptador.apply(l)
    resultado = cv2.merge((l_corrigido, a, b))
    
    cv2.imwrite(caminho_imagem, cv2.cvtColor(resultado, cv2.COLOR_LAB2BGR))

Estratégias de Escalabilidade e Conformidade

Ao processar centenas de arquivos simultaneamente, a gestão de recursos de vídeo torna-se crítica. A flag --shm-size=2g no Docker previne falhas de memória compartilhada, enquanto filas assíncronas (Redis ou SQLite) garantem que picos de solicitação não sobrecarreguem a GPU. Configurações de produção robustas tipicamente empregam aceleradores com 24GB de VRAM, 16 núcleos lógicos e armazenamento NVMe para IOPS elevados.

Aspectos legais exigem atenção contínua: acervos CC0 permitem uso comercial, mas a redistribuição de imagens modificadas que contenham marcas registradas ou rostos identificáveis sem autorização viola direitos autorais. A prática recomendada restringe a coleta a domínios públicos verificados e aplica metadados de procedência aos arquivos gerados, documentando o processo de derivação para auditoria futura.

Tags: python-requests BeautifulSoup4 opencv-python docker-gpu longcat-image-edit

Publicado em 9-5 12:46