Para o projeto funcionar, precisei fazer varias modificações
bloco 3 libs
# Importações necessárias
import os
from langchain_classic.chains import ConversationalRetrievalChain
from langchain_classic.memory import ConversationBufferWindowMemory
from langchain_community.vectorstores import Chroma
from langchain_google_genai import GoogleGenerativeAIEmbeddings, ChatGoogleGenerativeAI
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import CharacterTextSplitter
from langchain_core.documents import Document
import google.generativeai as genai
import warnings
warnings.filterwarnings('ignore')
no bloco 4 Secrets
import os
from google.colab import userdata
os.environ["GOOGLE_API_KEY"] = userdata.get('GEMINI_API_KEY_TEMP')
GOOGLE_API_KEY = os.environ["GOOGLE_API_KEY"]
print("✅ Google API Key configurada!")
bloco 6
import time
import random
from langchain_core.embeddings import Embeddings
class ResilientGoogleEmbeddings(Embeddings):
"""Wrapper com retry + cache em memória para o Gemini Embeddings."""
def __init__(self, base_embeddings, max_attempts=6, initial_delay=2.0):
self.base_embeddings = base_embeddings
self.max_attempts = max_attempts
self.initial_delay = initial_delay
self._query_cache = {}
self._documents_cache = {}
def _run_with_retry(self, operation, description):
last_error = None
for attempt in range(1, self.max_attempts + 1):
try:
return operation()
except Exception as e:
last_error = e
if attempt == self.max_attempts:
break
# Backoff exponencial + pequeno jitter para evitar novas
# colisões/requisições em sequência na API do Google.
delay = self.initial_delay * (2 ** (attempt - 1))
delay += random.uniform(0, 0.75)
print(
f"⚠️ Gemini Embeddings falhou ({description}) - "
f"tentativa {attempt}/{self.max_attempts}. "
f"Nova tentativa em {delay:.1f}s..."
)
time.sleep(delay)
raise RuntimeError(
f"Gemini Embeddings não respondeu após {self.max_attempts} tentativas. "
f"Erro original: {last_error}"
) from last_error
def embed_query(self, text):
text = str(text).strip()
if not text:
raise ValueError("Não é possível gerar embedding para uma pergunta vazia.")
if text in self._query_cache:
return self._query_cache[text]
result = self._run_with_retry(
lambda: self.base_embeddings.embed_query(text),
"embed_query"
)
self._query_cache[text] = result
return result
def embed_documents(self, texts):
texts = [str(text).strip() for text in texts]
if not texts:
return []
missing = [text for text in texts if text not in self._documents_cache]
if missing:
result = self._run_with_retry(
lambda: self.base_embeddings.embed_documents(missing),
f"embed_documents ({len(missing)} textos)"
)
for text, vector in zip(missing, result):
self._documents_cache[text] = vector
return [self._documents_cache[text] for text in texts]
def __getattr__(self, name):
# Mantém acesso às configurações/atributos do embedder original.
return getattr(self.base_embeddings, name)
# Embedder oficial do Google Gemini.
# max_retries do componente Google trata algumas falhas internamente;
# o wrapper acima acrescenta uma camada adicional para falhas 500 transitórias.
_base_embeddings = GoogleGenerativeAIEmbeddings(
model="gemini-embedding-001",
google_api_key=GOOGLE_API_KEY,
max_retries=3,
)
embeddings = ResilientGoogleEmbeddings(
_base_embeddings,
max_attempts=6,
initial_delay=2.0,
)
# Cria/abre o mesmo banco Chroma sem duplicar os documentos quando
# a célula for executada novamente.
vectorstore = Chroma(
collection_name="ia_gemini",
embedding_function=embeddings,
persist_directory="./chroma_db_gemini",
)
# Só indexa os documentos na primeira execução.
if vectorstore._collection.count() == 0:
vectorstore.add_documents(docs)
print(f"✅ {len(docs)} documentos indexados no Chroma.")
else:
print(
f"✅ Chroma reutilizado: {vectorstore._collection.count()} "
"documentos já indexados."
)
print("✅ Gemini Embeddings configurado com retry + cache.")
bloco9
#omiti demais códigos só o que mudou aqui
time.sleep(1)
resultado = qa_chain.invoke({"question": pergunta})