💻 Примеры: запросы, эмбеддинги, поиск

← К оглавлению урока

⚡ Эмбеддинг текста

# embed.py
import numpy as np
r = client.models.embed_content(
    model="text-embedding-004", contents="Я люблю программирование.")
vector = np.array(r.embeddings[0].values)  # вектор длиной 768

Пример 1. Задержка между запросами (как в лекции)

Небольшая пауза перед запросом помогает не упираться в rate limit.

# ai4_1.py
import time, os
from google import genai
from dotenv import load_dotenv

load_dotenv()
client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))

def get_gemini_response(prompt):
    time.sleep(0.3)                      # небольшая задержка перед запросом
    response = client.models.generate_content(
        model="gemini-2.0-flash", contents=[prompt])
    return response.text

print(get_gemini_response("What are rate limits?"))

Пример 2. Таймаут запроса (как в лекции)

Клиент с таймаутом 10 секунд: если сервер не ответит — получим ошибку, а не вечное ожидание.

# ai4_2.py
import time, os
from google import genai
from google.genai import types
from dotenv import load_dotenv

load_dotenv()
timeout_seconds = 10
client = genai.Client(
    api_key=os.getenv("GEMINI_API_KEY"),
    http_options=types.HttpOptions(timeout=timeout_seconds * 1000),  # в миллисекундах
)

def get_gemini_response(prompt):
    time.sleep(0.3)
    try:
        r = client.models.generate_content(
            model="gemini-2.0-flash", contents=[prompt])
        return r.text
    except Exception as e:               # таймаут, сеть, лимиты
        return f"Произошла ошибка: {e}"

print(get_gemini_response("What is a request timeout?"))

Пример 3. Автоповтор с tenacity (как в лекции)

До 3 попыток с экспоненциальной задержкой (2 → 4 → 8 с).

# ai4_3.py
import time, os
from tenacity import retry, stop_after_attempt, wait_exponential
from google import genai
from google.genai import types
from dotenv import load_dotenv

load_dotenv()
client = genai.Client(
    api_key=os.getenv("GEMINI_API_KEY"),
    http_options=types.HttpOptions(timeout=10000),
)

# stop_after_attempt(3) — максимум 3 попытки
# wait_exponential(min=2, max=10) — пауза 2 → 4 → 8 с (не больше 10)
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
def get_gemini_response(prompt):
    time.sleep(0.3)
    r = client.models.generate_content(
        model="gemini-2.0-flash", contents=[prompt])
    return r.text

print(get_gemini_response("What is a request timeout?"))

Пример 4. Получение эмбеддингов (как в лекции)

# ai4_4.py
import os
import numpy as np
from google import genai
from dotenv import load_dotenv

load_dotenv()
client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))

def get_embedding(text):
    response = client.models.embed_content(
        model="text-embedding-004", contents=text)
    return np.array(response.embeddings[0].values)   # вектор как numpy-массив

v1 = get_embedding("Я люблю программирование.")
v2 = get_embedding("Кодинг – это моё хобби.")
print("Размерность вектора:", v1.shape)              # (768,)

Пример 5. Семантический поиск через FAISS (как в лекции)

Индексируем набор текстов, затем по запросу «Питание кошек» находим близкие по смыслу.

# ai4_5.py
import os
import faiss
import numpy as np
from google import genai
from dotenv import load_dotenv

load_dotenv()
client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))

def get_embedding(text):
    r = client.models.embed_content(model="text-embedding-004", contents=text)
    return np.array(r.embeddings[0].values)

texts = [
    "Кошки любят рыбу и мясо",
    "Основной рацион кошек — это белок",
    "Чем кормить котёнка?",
    "Собака играет в парке",
    "Спелый ананас полон витаминов",
]

# 1. Эмбеддинги всех текстов
embeddings = np.array([get_embedding(t) for t in texts])

# 2. FAISS-индекс по L2-расстоянию
dimension = embeddings.shape[1]          # длина вектора (768)
index = faiss.IndexFlatL2(dimension)
index.add(embeddings)

# 3. Поиск k ближайших к запросу
def semantic_search(query, k=2):
    q = get_embedding(query).reshape(1, -1)
    D, I = index.search(q, k)            # D — расстояния, I — индексы
    return [texts[i] for i in I[0]]

print(semantic_search("Питание кошек", k=3))
# → отзывы про рацион/корм кошек, хотя слова «питание» в них нет
⚠️ IndexFlatL2 сравнивает по евклидову расстоянию. Для эмбеддингов корректнее косинусная близость (нормализация + IndexFlatIP) — см. Старый vs Новый.

Пример 6. Косинусное сходство без API (практика)

Как «похожесть» считается математически — на простом TF-IDF, без обращения к модели. Важно: это поиск по символам/словам (поверхностный), не по смыслу — сравните с эмбеддингами.

# compare_vectors.py
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

def similarity(word1, word2):
    # char_wb — символьные n-граммы: лучше для коротких русских слов
    vectorizer = TfidfVectorizer(analyzer="char_wb", ngram_range=(2, 4))
    vectors = vectorizer.fit_transform([word1.lower(), word2.lower()])
    return float(cosine_similarity(vectors[0], vectors[1])[0][0])

print(f"собака ↔ кошка: {similarity('собака', 'кошка'):.4f}")
print(f"мышь ↔ крыса:  {similarity('мышь', 'крыса'):.4f}")