Módulo 6: Embedding Operations

Mini-Proyecto: Semantic Explorer Tool

Descripción

Construirás una herramienta que permite explorar embeddings mediante operations: analogías, interpolation, clustering, y outlier detection. CLI interactivo para experimentar.


semantic_explorer.py

import numpy as np
from openai import OpenAI
from sklearn.cluster import KMeans
import os

class SemanticExplorer:
    """Herramienta de exploración semántica"""
    
    def __init__(self):
        self.client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
        self.embeddings_cache = {}
    
    def get_embedding(self, text):
        """Get/cache embedding"""
        if text in self.embeddings_cache:
            return self.embeddings_cache[text]
        
        emb = np.array(self.client.embeddings.create(
            model="text-embedding-3-small",
            input=text
        ).data[0].embedding)
        
        self.embeddings_cache[text] = emb
        return emb
    
    def analogy(self, a, b, c):
        """A is to B as C is to ?"""
        emb_a = self.get_embedding(a)
        emb_b = self.get_embedding(b)
        emb_c = self.get_embedding(c)
        
        result = emb_b - emb_a + emb_c
        return result
    
    def interpolate(self, text_a, text_b, alpha=0.5):
        """Interpolate entre 2 textos"""
        emb_a = self.get_embedding(text_a)
        emb_b = self.get_embedding(text_b)
        
        return alpha * emb_a + (1 - alpha) * emb_b
    
    def cluster(self, texts, n_clusters=3):
        """Cluster texts"""
        embeddings = np.array([self.get_embedding(t) for t in texts])
        
        kmeans = KMeans(n_clusters=n_clusters, random_state=42)
        labels = kmeans.fit_predict(embeddings)
        
        # Agrupar por cluster
        clusters = {}
        for i, label in enumerate(labels):
            if label not in clusters:
                clusters[label] = []
            clusters[label].append(texts[i])
        
        return clusters
    
    def find_nearest(self, target_emb, candidates, k=3):
        """Encontrar k candidatos más cercanos"""
        candidate_embs = [self.get_embedding(c) for c in candidates]
        
        similarities = []
        for i, cand_emb in enumerate(candidate_embs):
            sim = np.dot(target_emb, cand_emb) / (
                np.linalg.norm(target_emb) * np.linalg.norm(cand_emb)
            )
            similarities.append((candidates[i], sim))
        
        # Sort por similarity
        similarities.sort(key=lambda x: x[1], reverse=True)
        
        return similarities[:k]

def main():
    """CLI interactivo"""
    explorer = SemanticExplorer()
    
    print("=== Semantic Explorer Tool ===\n")
    print("Commands:")
    print("  analogy <A> <B> <C> [candidates...]")
    print("  interpolate <A> <B> [alpha]")
    print("  cluster <text1> <text2> ... [n_clusters]")
    print("  quit\n")
    
    while True:
        cmd = input("> ").strip()
        
        if cmd == "quit":
            break
        
        parts = cmd.split()
        
        if parts[0] == "analogy" and len(parts) >= 7:
            a, b, c = parts[1], parts[2], parts[3]
            candidates = parts[4:]
            
            result_emb = explorer.analogy(a, b, c)
            nearest = explorer.find_nearest(result_emb, candidates)
            
            print(f"\n'{a}' is to '{b}' as '{c}' is to:")
            for word, sim in nearest:
                print(f"  {word}: {sim:.4f}")
            print()
        
        elif parts[0] == "interpolate" and len(parts) >= 3:
            text_a, text_b = parts[1], parts[2]
            alpha = float(parts[3]) if len(parts) > 3 else 0.5
            
            result_emb = explorer.interpolate(text_a, text_b, alpha)
            
            # Buscar concepto más cercano
            candidates = ["neutral", "mixed", "balanced", "hybrid", "blend"]
            nearest = explorer.find_nearest(result_emb, candidates, k=1)
            
            print(f"\nInterpolation ({alpha:.1f} × '{text_a}' + {1-alpha:.1f} × '{text_b}'):")
            print(f"  Closest concept: {nearest[0][0]} ({nearest[0][1]:.4f})")
            print()
        
        elif parts[0] == "cluster" and len(parts) >= 4:
            texts = parts[1:-1] if parts[-1].isdigit() else parts[1:]
            n_clusters = int(parts[-1]) if parts[-1].isdigit() else 2
            
            clusters = explorer.cluster(texts, n_clusters)
            
            print(f"\nClusters ({n_clusters}):")
            for label, items in clusters.items():
                print(f"  Cluster {label}: {', '.join(items)}")
            print()

if __name__ == "__main__":
    main()

Ejemplo de uso

$ python semantic_explorer.py

=== Semantic Explorer Tool ===

Commands:
  analogy <A> <B> <C> [candidates...]
  interpolate <A> <B> [alpha]
  cluster <text1> <text2> ... [n_clusters]
  quit

> analogy king man woman queen princess prince

'king' is to 'man' as 'woman' is to:
  queen: 0.9234
  princess: 0.8567
  prince: 0.7823

> interpolate happy sad 0.5

Interpolation (0.5 × 'happy' + 0.5 × 'sad'):
  Closest concept: neutral (0.8456)

> cluster Python JavaScript Go Rust HTML CSS 2

Clusters (2):
  Cluster 0: Python, JavaScript, Go, Rust
  Cluster 1: HTML, CSS

Resumen del Módulo 6

Qué implementaste:

  • ✅ Arithmetic operations (analogías)
  • ✅ Interpolation (blending)
  • ✅ Composition (averaging, weighted)
  • ✅ Dimensionality reduction (PCA, UMAP)
  • ✅ Clustering (K-means)
  • ✅ Outlier detection
  • ✅ Semantic Explorer Tool

Líneas: ~400 (production tool)


Siguiente módulo

Módulo 7: Production Patterns

Aprenderás:

  • Caching strategies
  • Monitoring & logging
  • Error handling
  • Scaling patterns
  • Cost optimization
  • Fault tolerance

Módulo 6 completadoEmbedding Operations: álgebra semántica avanzada