Spaces:
Sleeping
Sleeping
| """Vector memory backed by ChromaDB + sentence-transformers. | |
| Stores high-scoring outputs embedded by their brief, and retrieves the most | |
| similar past winners as few-shot examples. Only entries >= RETRIEVAL_SCORE_FLOOR | |
| (3.5/5) are kept or returned. | |
| """ | |
| import os | |
| # sentence-transformers pulls in `transformers`, which will try to import a | |
| # TensorFlow/Keras backend if one is present. We only use the PyTorch path, so | |
| # disable the TF backend before anything imports transformers. (Avoids the | |
| # "Keras 3 is not supported" import error in envs that have TF/Keras 3.) | |
| os.environ.setdefault("USE_TF", "0") | |
| os.environ.setdefault("USE_TORCH", "1") | |
| os.environ.setdefault("TRANSFORMERS_NO_ADVISORY_WARNINGS", "1") | |
| import json | |
| import uuid | |
| from typing import Any | |
| import chromadb | |
| from chromadb.utils import embedding_functions | |
| CHROMA_DIR = os.getenv("CHROMA_DIR", "./chroma_db") | |
| COLLECTION_NAME = "ad_copy_memory" | |
| EMBED_MODEL = "all-MiniLM-L6-v2" | |
| # Minimum weighted score for an entry to live in / be retrieved from memory. | |
| RETRIEVAL_SCORE_FLOOR = 3.5 | |
| def _brief_to_text(brief: dict[str, Any]) -> str: | |
| """Flatten a brand brief into a single string used for embedding.""" | |
| parts = [ | |
| brief.get("brand", ""), | |
| brief.get("product", ""), | |
| brief.get("audience", ""), | |
| brief.get("tone", ""), | |
| brief.get("goal", ""), | |
| ] | |
| return " | ".join(str(p) for p in parts if p) | |
| class Memory: | |
| """Vector memory of high-scoring ad copy, keyed by brief similarity.""" | |
| def __init__(self, persist_dir: str = CHROMA_DIR): | |
| self._client = chromadb.PersistentClient(path=persist_dir) | |
| # sentence-transformers embedding function, computed locally. | |
| self._embed_fn = embedding_functions.SentenceTransformerEmbeddingFunction( | |
| model_name=EMBED_MODEL | |
| ) | |
| self._collection = self._client.get_or_create_collection( | |
| name=COLLECTION_NAME, | |
| embedding_function=self._embed_fn, | |
| metadata={"hnsw:space": "cosine"}, | |
| ) | |
| def add( | |
| self, | |
| brief: dict[str, Any], | |
| variant_type: str, | |
| output: str, | |
| score: float, | |
| prompt_version: str, | |
| timestamp: str, | |
| ) -> bool: | |
| """Store one high-scoring output. Returns False if below the floor.""" | |
| if score < RETRIEVAL_SCORE_FLOOR: | |
| return False | |
| self._collection.add( | |
| ids=[str(uuid.uuid4())], | |
| documents=[output], | |
| metadatas=[ | |
| { | |
| "brief": json.dumps(brief), | |
| "variant_type": variant_type, | |
| "score": float(score), | |
| "prompt_version": prompt_version, | |
| "timestamp": timestamp, | |
| } | |
| ], | |
| ) | |
| return True | |
| def retrieve(self, brief: dict[str, Any], k: int = 3) -> list[dict[str, Any]]: | |
| """Return up to k most similar past entries with score >= the floor. | |
| Results are ordered by vector similarity to the incoming brief. | |
| """ | |
| count = self._collection.count() | |
| if count == 0: | |
| return [] | |
| results = self._collection.query( | |
| query_texts=[_brief_to_text(brief)], | |
| # Over-fetch so the score filter still leaves us close to k. | |
| n_results=min(max(k * 3, k), count), | |
| where={"score": {"$gte": RETRIEVAL_SCORE_FLOOR}}, | |
| ) | |
| docs = results.get("documents", [[]])[0] | |
| metas = results.get("metadatas", [[]])[0] | |
| examples: list[dict[str, Any]] = [] | |
| for doc, meta in zip(docs, metas): | |
| examples.append( | |
| { | |
| "brief": json.loads(meta.get("brief", "{}")), | |
| "variant_type": meta.get("variant_type", "output"), | |
| "output": doc, | |
| "score": meta.get("score", 0.0), | |
| "prompt_version": meta.get("prompt_version", ""), | |
| } | |
| ) | |
| if len(examples) >= k: | |
| break | |
| return examples | |
| def count(self) -> int: | |
| return self._collection.count() | |