doc: update cookbook (#284)
* fix: sync-cookbook now supports new cookbook repo layout Cookbook repository changed structure: - Applications moved from root to applications/ subdirectory - Notebooks remain in notebooks/ directory (unchanged) Updated sync script to: - Look for apps in applications/* instead of root/* - Update GitHub URLs to include applications/ path - Add safety check if applications/ dir doesn't exist * doc: update cookbook * doc: update cookbook * doc: update cookbook
This commit is contained in:
parent
a24941f83b
commit
d5403a4b29
34 changed files with 6181 additions and 81 deletions
|
|
@ -4,14 +4,14 @@ Syncs content from the hindsight-cookbook repository.
|
||||||
|
|
||||||
- Clones the cookbook repo to a temp directory
|
- Clones the cookbook repo to a temp directory
|
||||||
- Converts notebooks/*.ipynb → docs/cookbook/recipes/*.md
|
- Converts notebooks/*.ipynb → docs/cookbook/recipes/*.md
|
||||||
- Converts app directories (with README.md) → docs/cookbook/applications/*.md
|
- Converts applications/*/ directories (with README.md) → docs/cookbook/applications/*.md
|
||||||
- Updates sidebars.ts with the new entries
|
- Updates sidebars.ts with the new entries
|
||||||
|
|
||||||
Usage: sync-cookbook (after installing hindsight-dev)
|
Usage: sync-cookbook (after installing hindsight-dev)
|
||||||
|
|
||||||
Conventions in cookbook repo:
|
Conventions in cookbook repo:
|
||||||
- notebooks/*.ipynb → Recipes (use cases, tutorials)
|
- notebooks/*.ipynb → Recipes (use cases, tutorials)
|
||||||
- Directories with README.md at root → Applications (complete apps)
|
- applications/*/ directories with README.md → Applications (complete apps)
|
||||||
- Notebook title extracted from first # heading in first markdown cell
|
- Notebook title extracted from first # heading in first markdown cell
|
||||||
- App title extracted from first # heading in README.md
|
- App title extracted from first # heading in README.md
|
||||||
"""
|
"""
|
||||||
|
|
@ -236,7 +236,13 @@ def process_applications(cookbook_dir: Path, apps_dir: Path) -> list[dict]:
|
||||||
"""Process application directories with README.md."""
|
"""Process application directories with README.md."""
|
||||||
apps = []
|
apps = []
|
||||||
|
|
||||||
for entry in sorted(cookbook_dir.iterdir()):
|
# Applications are now in the applications/ subdirectory
|
||||||
|
applications_dir = cookbook_dir / "applications"
|
||||||
|
if not applications_dir.exists():
|
||||||
|
print(" No applications directory found")
|
||||||
|
return apps
|
||||||
|
|
||||||
|
for entry in sorted(applications_dir.iterdir()):
|
||||||
if not entry.is_dir() or entry.name in IGNORE_DIRS:
|
if not entry.is_dir() or entry.name in IGNORE_DIRS:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -253,7 +259,7 @@ def process_applications(cookbook_dir: Path, apps_dir: Path) -> list[dict]:
|
||||||
readme_content = readme_path.read_text()
|
readme_content = readme_path.read_text()
|
||||||
|
|
||||||
# Create application page with frontmatter
|
# Create application page with frontmatter
|
||||||
app_url = f"https://github.com/vectorize-io/hindsight-cookbook/tree/main/{entry.name}"
|
app_url = f"https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/{entry.name}"
|
||||||
|
|
||||||
frontmatter = f"""---
|
frontmatter = f"""---
|
||||||
sidebar_position: {len(apps) + 1}
|
sidebar_position: {len(apps) + 1}
|
||||||
|
|
|
||||||
120
hindsight-docs/docs/cookbook/applications/chat-memory.md
Normal file
120
hindsight-docs/docs/cookbook/applications/chat-memory.md
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# Chat Memory App
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/chat-memory)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A demo chat application that uses Groq's `qwen/qwen3-32b` model with Hindsight for persistent per-user memory.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- 🧠 **Persistent Memory**: Each user gets their own memory bank that remembers conversations
|
||||||
|
- 🚀 **Fast AI**: Powered by Groq's high-speed inference
|
||||||
|
- 🎯 **Per-User Context**: Isolated memory per user with automatic context retrieval
|
||||||
|
- 💬 **Real-time Chat**: Instant responses with memory-augmented context
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### 1. Start Hindsight API
|
||||||
|
|
||||||
|
First, start the Hindsight API server using Docker:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export GROQ_API_KEY=your_groq_api_key_here
|
||||||
|
|
||||||
|
# Start Hindsight with Groq as the LLM provider
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_PROVIDER=groq \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$GROQ_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL="openai/gpt-oss-20b" \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
- **API**: http://localhost:8888
|
||||||
|
- **Control Plane UI**: http://localhost:9999
|
||||||
|
|
||||||
|
### 2. Configure Environment
|
||||||
|
|
||||||
|
Copy your Groq API key to the environment file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update .env.local with your Groq API key
|
||||||
|
echo "GROQ_API_KEY=your_groq_api_key_here" > .env.local
|
||||||
|
echo "HINDSIGHT_API_URL=http://localhost:8888" >> .env.local
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't have one, you can get a free Groq API key here: https://console.groq.com/home
|
||||||
|
|
||||||
|
### 3. Install Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Run the App
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open http://localhost:3000 in your browser.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. **User Identity**: Each browser session gets a unique user ID
|
||||||
|
2. **Memory Bank Creation**: First message creates a personal memory bank in Hindsight
|
||||||
|
3. **Context Retrieval**: Before responding, relevant memories are retrieved
|
||||||
|
4. **Memory Augmented Response**: Groq generates responses with memory context
|
||||||
|
5. **Conversation Storage**: Each conversation is stored for future context
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
User Message
|
||||||
|
↓
|
||||||
|
Next.js API Route (/api/chat)
|
||||||
|
↓
|
||||||
|
Hindsight.recall() → Get relevant memories
|
||||||
|
↓
|
||||||
|
Groq API → Generate response with memory context
|
||||||
|
↓
|
||||||
|
Hindsight.retain() → Store conversation
|
||||||
|
↓
|
||||||
|
Response to User
|
||||||
|
```
|
||||||
|
|
||||||
|
## Memory Bank Structure
|
||||||
|
|
||||||
|
Each user gets their own isolated memory bank with:
|
||||||
|
- **Name**: "Chat Memory for [userId]"
|
||||||
|
- **Background**: Conversational AI assistant context
|
||||||
|
- **Disposition**: Empathetic (4), Low Skepticism (2), Balanced Literalism (3)
|
||||||
|
|
||||||
|
## Try It Out
|
||||||
|
|
||||||
|
1. **First Conversation**: Tell the assistant about yourself
|
||||||
|
- "Hi! I'm a software engineer from San Francisco. I love Python and machine learning."
|
||||||
|
|
||||||
|
2. **Second Conversation**: Ask what it remembers
|
||||||
|
- "What do you know about me?"
|
||||||
|
- "What programming languages do I like?"
|
||||||
|
|
||||||
|
3. **Context Building**: Continue sharing preferences
|
||||||
|
- "I prefer VS Code over other editors"
|
||||||
|
- "I'm working on a React project"
|
||||||
|
|
||||||
|
4. **Memory Verification**: Visit the Hindsight Control Plane at http://localhost:9999 to see stored memories
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
- **Groq Model**: Uses `qwen/qwen3-32b` for fast, high-quality responses
|
||||||
|
- **Memory Storage**: Automatic conversation retention with context categorization
|
||||||
|
- **Memory Retrieval**: Semantic search with 2048 token budget for relevant context
|
||||||
145
hindsight-docs/docs/cookbook/applications/deliveryman-demo.md
Normal file
145
hindsight-docs/docs/cookbook/applications/deliveryman-demo.md
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
# Deliveryman Demo
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/deliveryman-demo)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A delivery agent simulation that demonstrates Hindsight's long-term memory capabilities. An AI agent navigates a multi-building office complex to deliver packages, learning employee locations and optimal paths over time through mental models.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Python 3.11+
|
||||||
|
- Node.js 18+
|
||||||
|
- [uv](https://docs.astral.sh/uv/) (Python package manager)
|
||||||
|
|
||||||
|
## Setup (Fresh Environment)
|
||||||
|
|
||||||
|
### 1. Clone Repositories
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone Hindsight (memory engine)
|
||||||
|
git clone https://github.com/anthropics/hindsight.git
|
||||||
|
|
||||||
|
# Clone the cookbook (contains this demo)
|
||||||
|
git clone https://github.com/anthropics/hindsight-cookbook.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Start Hindsight API
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd hindsight
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit `.env` with your LLM configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
HINDSIGHT_API_LLM_PROVIDER=groq
|
||||||
|
HINDSIGHT_API_LLM_API_KEY=<your-groq-api-key>
|
||||||
|
HINDSIGHT_API_LLM_MODEL=openai/gpt-oss-120b
|
||||||
|
HINDSIGHT_API_HOST=0.0.0.0
|
||||||
|
HINDSIGHT_API_PORT=8888
|
||||||
|
HINDSIGHT_API_ENABLE_OBSERVATIONS=true
|
||||||
|
|
||||||
|
# Retain extraction settings (improves employee/location extraction)
|
||||||
|
HINDSIGHT_API_RETAIN_EXTRACTION_MODE=custom
|
||||||
|
HINDSIGHT_API_RETAIN_CUSTOM_INSTRUCTIONS="Delivery agent. Remember employee locations, building layout, and optimal paths."
|
||||||
|
|
||||||
|
# Embedded database storage
|
||||||
|
PG0_DATA_DIR=/tmp/hindsight-data
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the API:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/dev/start-api.sh
|
||||||
|
# Runs on http://localhost:8888
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Start Hindsight Control Plane (Optional)
|
||||||
|
|
||||||
|
The control plane provides a web UI for inspecting memory banks, facts, and mental models.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd hindsight
|
||||||
|
./scripts/dev/start-control-plane.sh
|
||||||
|
# Runs on a dynamic port (check terminal output)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Start Demo Backend
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd hindsight-cookbook/deliveryman-demo/backend
|
||||||
|
|
||||||
|
# Create virtual environment and install dependencies
|
||||||
|
python -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Create `backend/.env`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
OPENAI_API_KEY=<your-openai-api-key>
|
||||||
|
GROQ_API_KEY=<your-groq-api-key>
|
||||||
|
HINDSIGHT_API_URL=http://localhost:8888
|
||||||
|
LLM_MODEL=openai/gpt-4o
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the backend:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./run.sh
|
||||||
|
# Or manually:
|
||||||
|
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --ws wsproto --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** The `--ws wsproto` flag is required for WebSocket support. Without it, connections will fail with error 1006.
|
||||||
|
|
||||||
|
### 5. Start Demo Frontend
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd hindsight-cookbook/deliveryman-demo/frontend
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
# Runs on http://localhost:5173
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Open the Demo
|
||||||
|
|
||||||
|
Navigate to http://localhost:5173 in your browser.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. The agent receives a delivery task (e.g., "Deliver Package #3954 to Victor Huang")
|
||||||
|
2. It navigates a multi-building complex with floors, elevators, and sky bridges
|
||||||
|
3. Along the way it encounters employees and learns their locations
|
||||||
|
4. After each delivery, the conversation is sent to Hindsight via the **retain** API
|
||||||
|
5. Hindsight extracts facts (employee locations, building layout) and builds **mental models**
|
||||||
|
6. On subsequent deliveries, the agent queries Hindsight to recall what it learned
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Browser (5173) → Frontend (React + Phaser)
|
||||||
|
↓ WebSocket
|
||||||
|
Backend (8000) → FastAPI + Delivery Agent
|
||||||
|
↓ HTTP
|
||||||
|
Hindsight API (8888) → Memory Engine + PostgreSQL
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
| Problem | Solution |
|
||||||
|
|---------|----------|
|
||||||
|
| WebSocket error 1006 | Restart backend with `--ws wsproto` flag |
|
||||||
|
| Mental models missing employees | Check `HINDSIGHT_API_RETAIN_EXTRACTION_MODE=custom` is set |
|
||||||
|
| Hindsight connection refused | Verify Hindsight API is running on port 8888 |
|
||||||
|
| Frontend shows "Disconnected" | Check backend is running on port 8000 |
|
||||||
|
|
@ -0,0 +1,206 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# Memory Approaches Comparison Demo
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/hindsight-litellm-demo)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
Interactive Streamlit app comparing three memory approaches for LLM applications:
|
||||||
|
|
||||||
|
1. **No Memory** - Each query is independent (baseline)
|
||||||
|
2. **Full Conversation History** - Pass entire conversation (truncated to simulate context limits)
|
||||||
|
3. **Hindsight Memory** - Intelligent semantic memory retrieval
|
||||||
|
|
||||||
|
This demo showcases how Hindsight's semantic memory outperforms traditional approaches, especially as conversations grow longer.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Set your OpenAI API key
|
||||||
|
export OPENAI_API_KEY=your-key
|
||||||
|
|
||||||
|
# 2. Start Hindsight server
|
||||||
|
docker run -d -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_PROVIDER=openai \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
|
||||||
|
# 3. Run the demo
|
||||||
|
./run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open http://localhost:8501 in your browser.
|
||||||
|
|
||||||
|
## What This Demo Shows
|
||||||
|
|
||||||
|
### The Problem with Traditional Approaches
|
||||||
|
|
||||||
|
| Approach | How it Works | Limitation |
|
||||||
|
|----------|--------------|------------|
|
||||||
|
| **No Memory** | Each query standalone | Forgets everything between messages |
|
||||||
|
| **Full History** | Pass all messages to LLM | Token limits cause truncation - loses early context |
|
||||||
|
| **Hindsight** | Semantic retrieval of relevant facts | Retrieves what's relevant regardless of when it was said |
|
||||||
|
|
||||||
|
### Key Insight
|
||||||
|
|
||||||
|
After 5-10 messages, watch the **Full Conversation History** column start losing early context due to truncation (artificially set to 4 messages to demonstrate this quickly). Meanwhile, **Hindsight Memory** can still recall facts from the beginning because it uses semantic retrieval rather than sequential history.
|
||||||
|
|
||||||
|
## Testing the Demo
|
||||||
|
|
||||||
|
1. **Introduce yourself**:
|
||||||
|
- "Hi, I'm Sarah, a data scientist at Netflix"
|
||||||
|
- "I prefer Python and love machine learning"
|
||||||
|
|
||||||
|
2. **Have several exchanges** about different topics
|
||||||
|
|
||||||
|
3. **Test recall**:
|
||||||
|
- "What programming language should I use?"
|
||||||
|
- "What do you know about me?"
|
||||||
|
|
||||||
|
Watch how the three columns respond differently as the conversation grows.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Side-by-side comparison** of all three approaches
|
||||||
|
- **Debug panels** showing what context each approach uses
|
||||||
|
- **Memory explorer** to search Hindsight memories directly
|
||||||
|
- **Configurable settings** for history truncation, max memories, etc.
|
||||||
|
- **Multi-provider support** via LiteLLM (OpenAI, Anthropic, Groq)
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Python 3.10+
|
||||||
|
- Hindsight server running (Docker recommended)
|
||||||
|
- At least one LLM API key (OpenAI recommended)
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### Using run.sh (Recommended)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set API key
|
||||||
|
export OPENAI_API_KEY=your-key
|
||||||
|
|
||||||
|
# Start Hindsight, then run:
|
||||||
|
./run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The script will check and install dependencies automatically.
|
||||||
|
|
||||||
|
### Manual Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
pip install streamlit litellm
|
||||||
|
|
||||||
|
# Install Hindsight packages
|
||||||
|
pip install hindsight-client hindsight-litellm
|
||||||
|
|
||||||
|
# Run the app
|
||||||
|
streamlit run app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Starting Hindsight Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_PROVIDER=openai \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
|
||||||
|
# Verify it's running
|
||||||
|
curl http://localhost:8888/health
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Sidebar Options
|
||||||
|
|
||||||
|
**Model Selection:**
|
||||||
|
- Provider: OpenAI, Anthropic, Groq
|
||||||
|
- Model: Various models per provider
|
||||||
|
- Custom model ID support
|
||||||
|
|
||||||
|
**Full History Config:**
|
||||||
|
- Max Messages to Keep (default: 4 to demonstrate truncation)
|
||||||
|
|
||||||
|
**Hindsight Config:**
|
||||||
|
- API URL (default: http://localhost:8888)
|
||||||
|
- Bank ID and Entity ID for memory isolation
|
||||||
|
- Max Memories to retrieve
|
||||||
|
- Recall Budget (low/mid/high)
|
||||||
|
|
||||||
|
**Generation Settings:**
|
||||||
|
- Temperature
|
||||||
|
- Max Tokens
|
||||||
|
- System Prompt
|
||||||
|
|
||||||
|
## Supported Models
|
||||||
|
|
||||||
|
### OpenAI
|
||||||
|
- gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-4, gpt-3.5-turbo
|
||||||
|
|
||||||
|
### Anthropic
|
||||||
|
- claude-3-5-sonnet-20241022, claude-3-5-haiku-20241022
|
||||||
|
- claude-3-opus-20240229, claude-3-sonnet-20240229
|
||||||
|
|
||||||
|
### Groq
|
||||||
|
- groq/llama-3.1-70b-versatile, groq/llama-3.1-8b-instant
|
||||||
|
- groq/mixtral-8x7b-32768
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Required
|
||||||
|
export OPENAI_API_KEY=sk-...
|
||||||
|
|
||||||
|
# Optional (for other providers)
|
||||||
|
export ANTHROPIC_API_KEY=sk-ant-...
|
||||||
|
export GROQ_API_KEY=gsk_...
|
||||||
|
|
||||||
|
# Optional
|
||||||
|
export HINDSIGHT_URL=http://localhost:8888
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Hindsight server not responding
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check if running
|
||||||
|
curl http://localhost:8888/health
|
||||||
|
|
||||||
|
# Start with Docker
|
||||||
|
docker run -d -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_PROVIDER=openai \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### hindsight-litellm not installed
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install hindsight-litellm
|
||||||
|
```
|
||||||
|
|
||||||
|
### API key errors
|
||||||
|
|
||||||
|
Make sure the appropriate API key is set:
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY=your-key
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [Hindsight](https://github.com/vectorize-io/hindsight) - Memory infrastructure for AI applications
|
||||||
|
- [hindsight-litellm](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/litellm) - LiteLLM integration package
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 4
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tool Learning Demo
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/hindsight-tool-learning-demo)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
An interactive Streamlit demo showing how Hindsight helps LLMs learn which tool to use when tool names are ambiguous.
|
||||||
|
|
||||||
|
## The Problem
|
||||||
|
|
||||||
|
When building AI agents with tool/function calling, tool names and descriptions aren't always clear. An LLM might randomly select between similarly-named tools, leading to incorrect behavior.
|
||||||
|
|
||||||
|
## The Scenario
|
||||||
|
|
||||||
|
This demo simulates a **customer service routing system** with two channels:
|
||||||
|
|
||||||
|
| Tool | Description (What the LLM sees) | Actual Purpose (Hidden) |
|
||||||
|
|------|--------------------------------|------------------------|
|
||||||
|
| `route_to_channel_alpha` | "Routes to channel Alpha for appropriate request types" | Financial issues (refunds, billing, payments) |
|
||||||
|
| `route_to_channel_omega` | "Routes to channel Omega for appropriate request types" | Technical issues (bugs, features, errors) |
|
||||||
|
|
||||||
|
The descriptions are **intentionally vague**! Without prior knowledge, the LLM must guess which channel handles what.
|
||||||
|
|
||||||
|
## The Solution: Learning with Hindsight
|
||||||
|
|
||||||
|
With Hindsight memory:
|
||||||
|
1. **Store routing feedback** about which channel handles which request type
|
||||||
|
2. **Retrieve learned knowledge** when making routing decisions
|
||||||
|
3. **Consistently route correctly** based on past experience
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
1. **Hindsight Server** running (Docker):
|
||||||
|
```bash
|
||||||
|
docker run -d -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_PROVIDER=openai \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **OpenAI API Key**:
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY=your-key-here
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run the Demo
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Or manually:
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
streamlit run app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to Use the Demo
|
||||||
|
|
||||||
|
### Step 1: Test Without Memory (Baseline)
|
||||||
|
|
||||||
|
1. Select a **Financial Request** (e.g., "I need a refund...")
|
||||||
|
2. Click **Route Request**
|
||||||
|
3. Observe: The "Without Hindsight" column may route incorrectly
|
||||||
|
|
||||||
|
### Step 2: Route First Customer and Learn
|
||||||
|
|
||||||
|
1. Route a customer → Both LLMs route simultaneously
|
||||||
|
2. Feedback is automatically stored to Hindsight
|
||||||
|
3. Wait ~5 seconds for Hindsight to index the memory
|
||||||
|
|
||||||
|
### Step 3: Test With Memory
|
||||||
|
|
||||||
|
1. Select another request (financial or technical)
|
||||||
|
2. Click **Route Request**
|
||||||
|
3. Observe: The "With Hindsight" column should now route correctly!
|
||||||
|
|
||||||
|
### Step 4: View Statistics
|
||||||
|
|
||||||
|
- See accuracy comparison between "Without Memory" vs "With Hindsight"
|
||||||
|
- Review test history to see the improvement over time
|
||||||
|
|
||||||
|
## Demo Features
|
||||||
|
|
||||||
|
- **Side-by-side comparison**: See routing results with and without memory
|
||||||
|
- **Pre-defined test requests**: Financial and technical scenarios
|
||||||
|
- **Custom requests**: Enter your own customer requests
|
||||||
|
- **Memory Explorer**: Query stored routing knowledge directly
|
||||||
|
- **Live statistics**: Track accuracy improvement
|
||||||
|
|
||||||
|
## Key Insight
|
||||||
|
|
||||||
|
> Even when tool names and descriptions don't reveal their purpose, Hindsight allows the LLM to **learn from experience** which tool to use for which type of request.
|
||||||
|
|
||||||
|
This is especially valuable for:
|
||||||
|
- Enterprise systems with legacy tool names
|
||||||
|
- Multi-tenant systems where tools have generic names
|
||||||
|
- Agents that need to learn organization-specific workflows
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
| Setting | Default | Description |
|
||||||
|
|---------|---------|-------------|
|
||||||
|
| Model | gpt-4o-mini | LLM model for routing decisions |
|
||||||
|
| Temperature (No Memory) | 0.7 | Randomness for baseline tests |
|
||||||
|
| Hindsight API URL | http://localhost:8888 | Hindsight server URL |
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `app.py` - Main Streamlit application
|
||||||
|
- `requirements.txt` - Python dependencies
|
||||||
|
- `run.sh` - Launch script with dependency checking
|
||||||
|
- `README.md` - This file
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 1
|
sidebar_position: 5
|
||||||
---
|
---
|
||||||
|
|
||||||
# OpenAI Agent + Hindsight Memory Integration
|
# OpenAI Agent + Hindsight Memory Integration
|
||||||
|
|
@ -7,7 +7,7 @@ sidebar_position: 1
|
||||||
|
|
||||||
:::info Complete Application
|
:::info Complete Application
|
||||||
This is a complete, runnable application demonstrating Hindsight integration.
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/openai-fitness-coach)
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/openai-fitness-coach)
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ This example showcases:
|
||||||
- **Function calling** to bridge them together
|
- **Function calling** to bridge them together
|
||||||
- **Streaming responses** for real-time interaction (enabled by default)
|
- **Streaming responses** for real-time interaction (enabled by default)
|
||||||
- **Bidirectional memory** - both user data AND coach observations stored
|
- **Bidirectional memory** - both user data AND coach observations stored
|
||||||
- **System-level post-processing** - automatic knowledge consolidation
|
- **System-level post-processing** - automatic opinion storage for reliability
|
||||||
- **Temporal-semantic memory** queries via function tools
|
- **Temporal-semantic memory** queries via function tools
|
||||||
- **Enhanced preference learning** - coach learns and respects user likes/dislikes
|
- **Enhanced preference learning** - coach learns and respects user likes/dislikes
|
||||||
- **Real-world integration pattern** for adding memory to AI agents
|
- **Real-world integration pattern** for adding memory to AI agents
|
||||||
|
|
@ -46,9 +46,9 @@ Hindsight API (returns workouts + preferences)
|
||||||
|
|
|
|
||||||
OpenAI Assistant (analyzes, gives advice)
|
OpenAI Assistant (analyzes, gives advice)
|
||||||
|
|
|
|
||||||
Function Call: store_memory(advice as experience)
|
Function Call: store_memory(advice as opinion)
|
||||||
|
|
|
|
||||||
Hindsight API (stores coach's advice, consolidates into observations)
|
Hindsight API (stores coach's observation)
|
||||||
|
|
|
|
||||||
Personalized Answer
|
Personalized Answer
|
||||||
```
|
```
|
||||||
|
|
@ -57,10 +57,10 @@ Personalized Answer
|
||||||
|
|
||||||
| Component | Standard Demo | OpenAI Integration |
|
| Component | Standard Demo | OpenAI Integration |
|
||||||
|-----------|---------------|-------------------|
|
|-----------|---------------|-------------------|
|
||||||
| **Conversation** | Hindsight `/reflect` endpoint | OpenAI Assistant API |
|
| **Conversation** | Hindsight `/think` endpoint | OpenAI Assistant API |
|
||||||
| **Memory** | Hindsight (built-in) | Hindsight (via function calling) |
|
| **Memory** | Hindsight (built-in) | Hindsight (via function calling) |
|
||||||
| **LLM** | Configured in Hindsight | OpenAI GPT-4 |
|
| **LLM** | Configured in Hindsight | OpenAI GPT-4 |
|
||||||
| **Knowledge Consolidation** | Automatic after retain | Automatic after retain |
|
| **Opinion Formation** | Automatic in `/think` | Explicit via `store_memory(type="opinion")` |
|
||||||
| **Best For** | Hindsight-native apps | Integrating memory into existing OpenAI agents |
|
| **Best For** | Hindsight-native apps | Integrating memory into existing OpenAI agents |
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
@ -126,7 +126,7 @@ retrieve_memories(query, fact_types, top_k)
|
||||||
search_workouts(after_date, before_date, workout_type)
|
search_workouts(after_date, before_date, workout_type)
|
||||||
get_nutrition_summary(after_date, before_date)
|
get_nutrition_summary(after_date, before_date)
|
||||||
get_user_goals()
|
get_user_goals()
|
||||||
get_coach_insights(about) # Retrieves observations
|
get_coach_opinions(about)
|
||||||
```
|
```
|
||||||
|
|
||||||
Each function makes API calls to Hindsight to fetch relevant memories.
|
Each function makes API calls to Hindsight to fetch relevant memories.
|
||||||
|
|
@ -191,8 +191,8 @@ The agent will automatically:
|
||||||
The OpenAI Agent can retrieve different memory types from Hindsight:
|
The OpenAI Agent can retrieve different memory types from Hindsight:
|
||||||
|
|
||||||
- **World Facts** (`fact_type: "world"`): Workouts, meals, activities
|
- **World Facts** (`fact_type: "world"`): Workouts, meals, activities
|
||||||
- **Experience Facts** (`fact_type: "experience"`): Goals, intentions, coach advice
|
- **Agent Facts** (`fact_type: "agent"`): Goals, intentions
|
||||||
- **Observations** (`fact_type: "observation"`): Consolidated knowledge about user patterns
|
- **Opinions** (`fact_type: "opinion"`): Coach's observations about patterns
|
||||||
|
|
||||||
## Customization
|
## Customization
|
||||||
|
|
||||||
|
|
@ -266,9 +266,9 @@ The key benefit: **Separation of concerns**
|
||||||
|
|
||||||
**Use Hindsight directly when:**
|
**Use Hindsight directly when:**
|
||||||
- You want a complete memory-first solution
|
- You want a complete memory-first solution
|
||||||
- You want automatic memory retrieval and observation consolidation
|
- You want automatic memory retrieval and opinion formation
|
||||||
- You want to use different LLM providers (not just OpenAI)
|
- You want to use different LLM providers (not just OpenAI)
|
||||||
- You want the `/reflect` endpoint's integrated approach
|
- You want the `/think` endpoint's integrated approach
|
||||||
|
|
||||||
## Learning Points
|
## Learning Points
|
||||||
|
|
||||||
|
|
|
||||||
371
hindsight-docs/docs/cookbook/applications/sanity-blog-memory.md
Normal file
371
hindsight-docs/docs/cookbook/applications/sanity-blog-memory.md
Normal file
|
|
@ -0,0 +1,371 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 6
|
||||||
|
---
|
||||||
|
|
||||||
|
# Sanity CMS Blog Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/sanity-blog-memory)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A Hindsight cookbook recipe demonstrating how to sync blog posts from **Sanity CMS** to Hindsight agent memory, enabling semantic search, temporal queries, and AI-powered content insights.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Blog Post Sync**: Automatically sync all blog posts from Sanity to Hindsight
|
||||||
|
- **Document-based Upsert**: Idempotent syncing with `document_id` - re-running sync updates existing content
|
||||||
|
- **Semantic Search**: Find related content using natural language queries
|
||||||
|
- **Temporal Queries**: Ask "What did I write in January 2025?"
|
||||||
|
- **Reflect for Insights**: Generate AI-powered analysis of your blog content
|
||||||
|
- **Related Content Discovery**: Power "Related Posts" features with semantic similarity
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ Sanity CMS │───────▶│ Sync Script │───────▶│ Hindsight │
|
||||||
|
│ (Content) │ GROQ │ (TypeScript) │ HTTP │ (Memory) │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ │
|
||||||
|
│ Your App │
|
||||||
|
│ - Recall │
|
||||||
|
│ - Reflect │
|
||||||
|
│ │
|
||||||
|
└─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Start Hindsight
|
||||||
|
|
||||||
|
Choose your preferred LLM provider:
|
||||||
|
|
||||||
|
**Option A: Using Docker Compose (Recommended)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set your API key
|
||||||
|
export OPENAI_API_KEY=sk-...
|
||||||
|
# OR
|
||||||
|
export GOOGLE_API_KEY=... # Gemini (free tier available)
|
||||||
|
# OR
|
||||||
|
export GROQ_API_KEY=... # Groq (free tier available)
|
||||||
|
|
||||||
|
# Start Hindsight
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option B: Using Docker directly**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY=sk-...
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
- **API**: http://localhost:8888
|
||||||
|
- **Control Plane UI**: http://localhost:9999
|
||||||
|
|
||||||
|
### 2. Configure Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy example config
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
# Edit with your values
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Required settings:
|
||||||
|
```bash
|
||||||
|
# Hindsight
|
||||||
|
HINDSIGHT_API_URL=http://localhost:8888
|
||||||
|
HINDSIGHT_BANK_ID=blog-memory
|
||||||
|
|
||||||
|
# Sanity CMS
|
||||||
|
SANITY_PROJECT_ID=your-project-id
|
||||||
|
SANITY_DATASET=production
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Install Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Sync Your Blog Posts
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run sync
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
```
|
||||||
|
=======================================
|
||||||
|
Sanity -> Hindsight Blog Sync
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Setting up memory bank...
|
||||||
|
Memory bank "blog-memory" ready
|
||||||
|
|
||||||
|
Fetching posts from Sanity CMS...
|
||||||
|
Found 10 posts to sync
|
||||||
|
|
||||||
|
Syncing posts to Hindsight...
|
||||||
|
[1/10] "Why I Chose Qwik"... done
|
||||||
|
[2/10] "Building AI Agents"... done
|
||||||
|
...
|
||||||
|
|
||||||
|
=======================================
|
||||||
|
Sync Complete
|
||||||
|
=======================================
|
||||||
|
Synced: 10 posts
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Query Your Content
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run query
|
||||||
|
```
|
||||||
|
|
||||||
|
## Query Examples
|
||||||
|
|
||||||
|
### Semantic Search
|
||||||
|
|
||||||
|
Find related content using natural language:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { recallMemory } from './hindsight-client.js';
|
||||||
|
|
||||||
|
// Find posts about AI agents
|
||||||
|
const result = await recallMemory('AI agents and automation', {
|
||||||
|
budget: 'mid',
|
||||||
|
maxTokens: 2048,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Found ${result.results.length} relevant posts`);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Temporal Queries
|
||||||
|
|
||||||
|
Ask about content from specific time periods:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Posts from January 2025
|
||||||
|
const result = await recallMemory('What did I write about in January 2025?', {
|
||||||
|
queryTimestamp: '2025-01-31T23:59:59Z',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reflect for Insights
|
||||||
|
|
||||||
|
Generate AI-powered analysis of your content:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { reflectOnMemory } from './hindsight-client.js';
|
||||||
|
|
||||||
|
// Analyze blog themes
|
||||||
|
const insights = await reflectOnMemory(
|
||||||
|
'What are the main themes of my blog? What topics do I write about most?',
|
||||||
|
{ budget: 'high' }
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(insights.text);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Related Content Discovery
|
||||||
|
|
||||||
|
Power your "Related Posts" feature:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Find posts similar to a specific article
|
||||||
|
const related = await recallMemory(
|
||||||
|
'Find posts related to "Why I Chose Qwik for My Personal Website"',
|
||||||
|
{ budget: 'mid' }
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Memory Structure
|
||||||
|
|
||||||
|
Each blog post is stored with rich metadata for optimal recall:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Blog Post: {title}
|
||||||
|
|
||||||
|
**Published:** {date}
|
||||||
|
**URL:** {base_url}/blog/{slug}
|
||||||
|
**Tags:** {tags}
|
||||||
|
**Reading Time:** {reading_time}
|
||||||
|
|
||||||
|
## Description
|
||||||
|
{description}
|
||||||
|
|
||||||
|
## Content
|
||||||
|
{full_content}
|
||||||
|
```
|
||||||
|
|
||||||
|
Key features:
|
||||||
|
- **document_id**: `post:{slug}` - Enables upsert on re-sync
|
||||||
|
- **context**: `blog-post` - Categorizes the memory type
|
||||||
|
- **timestamp**: Post publication date - Enables temporal queries
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
### 1. AI-Powered Blog Search
|
||||||
|
|
||||||
|
Replace keyword search with semantic understanding:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Old: keyword matching
|
||||||
|
const results = posts.filter(p => p.title.includes('React'));
|
||||||
|
|
||||||
|
// New: semantic understanding
|
||||||
|
const result = await recallMemory('frontend framework tutorials');
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Content Recommendation Engine
|
||||||
|
|
||||||
|
Generate personalized recommendations:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const recommendations = await reflectOnMemory(
|
||||||
|
'Based on a reader interested in "AI automation", recommend related posts'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Writing Assistant
|
||||||
|
|
||||||
|
Get topic suggestions based on your existing content:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const suggestions = await reflectOnMemory(
|
||||||
|
'What topics should I write about next? What gaps exist in my content?'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Content Analytics
|
||||||
|
|
||||||
|
Analyze your blog's evolution:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const analysis = await reflectOnMemory(
|
||||||
|
'How have my writing topics evolved over the past year?'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `HINDSIGHT_API_URL` | Hindsight API endpoint | `http://localhost:8888` |
|
||||||
|
| `HINDSIGHT_BANK_ID` | Memory bank identifier | `blog-memory` |
|
||||||
|
| `SANITY_PROJECT_ID` | Your Sanity project ID | (required) |
|
||||||
|
| `SANITY_DATASET` | Sanity dataset name | `production` |
|
||||||
|
| `SANITY_API_TOKEN` | Sanity API token (for private datasets) | (none) |
|
||||||
|
| `SANITY_API_VERSION` | Sanity API version | `2024-01-09` |
|
||||||
|
| `SITE_URL` | Your blog's base URL | `https://example.com` |
|
||||||
|
|
||||||
|
### Memory Bank Disposition
|
||||||
|
|
||||||
|
The memory bank is configured with disposition traits optimized for blog content:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
skepticism: 2, // Trusting - blog content is authoritative
|
||||||
|
literalism: 4, // Literal - exact content matters
|
||||||
|
empathy: 3, // Balanced
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extending for Other CMS Platforms
|
||||||
|
|
||||||
|
This pattern can be adapted for any CMS. The key components:
|
||||||
|
|
||||||
|
### 1. CMS Client
|
||||||
|
|
||||||
|
Replace `sanity-client.ts` with your CMS:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// contentful-client.ts
|
||||||
|
import { createClient } from 'contentful';
|
||||||
|
|
||||||
|
export async function getAllPosts(): Promise<BlogPost[]> {
|
||||||
|
const client = createClient({...});
|
||||||
|
const entries = await client.getEntries({ content_type: 'blogPost' });
|
||||||
|
return entries.items.map(transformPost);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Content Transformation
|
||||||
|
|
||||||
|
Ensure your content is formatted for semantic search:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function formatPostContent(post: BlogPost): string {
|
||||||
|
return `# ${post.title}
|
||||||
|
|
||||||
|
**Published:** ${post.date}
|
||||||
|
...
|
||||||
|
${post.content}`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Document ID Strategy
|
||||||
|
|
||||||
|
Use a consistent document ID for upsert behavior:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await retainBlogPost(content, {
|
||||||
|
documentId: `post:${post.slug}`, // Unique, stable identifier
|
||||||
|
timestamp: post.date,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "Connection refused" error
|
||||||
|
|
||||||
|
Make sure Hindsight is running:
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
curl http://localhost:8888/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### "No posts found" during sync
|
||||||
|
|
||||||
|
Check your Sanity configuration:
|
||||||
|
```bash
|
||||||
|
# Verify project ID
|
||||||
|
echo $SANITY_PROJECT_ID
|
||||||
|
|
||||||
|
# Test GROQ query
|
||||||
|
npx sanity query '*[_type == "post"][0..2]{title}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Slow recall/reflect responses
|
||||||
|
|
||||||
|
This is normal for the first query as Hindsight builds embeddings. Subsequent queries are faster. Use `budget: 'low'` for faster responses at the cost of recall quality.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [Hindsight Documentation](https://hindsight.vectorize.io/)
|
||||||
|
- [Hindsight GitHub](https://github.com/vectorize-io/hindsight)
|
||||||
|
- [Sanity CMS Documentation](https://www.sanity.io/docs)
|
||||||
|
- [Hindsight Cookbook](https://github.com/vectorize-io/hindsight-cookbook)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
276
hindsight-docs/docs/cookbook/applications/stancetracker.md
Normal file
276
hindsight-docs/docs/cookbook/applications/stancetracker.md
Normal file
|
|
@ -0,0 +1,276 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 7
|
||||||
|
---
|
||||||
|
|
||||||
|
# Stance Tracker
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/stancetracker)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
An AI-powered application that tracks political candidates' stances on issues over time using Hindsight memory system and web scraping.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Geographic Targeting**: Track stances by country, state/province, and city
|
||||||
|
- **Multi-Candidate Tracking**: Monitor multiple candidates simultaneously
|
||||||
|
- **Temporal Analysis**: Historical stance tracking with configurable time ranges
|
||||||
|
- **Automated Scraping**: Periodic content collection with configurable frequencies (hourly/daily/weekly)
|
||||||
|
- **Stance Change Detection**: Automatic detection and highlighting of position changes
|
||||||
|
- **Interactive Timeline**: Visual graph showing stance evolution with reference callouts
|
||||||
|
- **Source Attribution**: All stances linked to verified sources with excerpts
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Memory System (Hindsight Integration)
|
||||||
|
|
||||||
|
This app uses the Hindsight memory system from `github.com/vectorize-io/hindsight`:
|
||||||
|
|
||||||
|
1. **Banks**: Each scraper agent has its own memory bank
|
||||||
|
2. **Retain**: Stores candidate statements and web scraping results
|
||||||
|
3. **Recall**: Semantic search to retrieve relevant memories
|
||||||
|
4. **Reflect**: Generates contextual analysis using stored memories
|
||||||
|
5. **Temporal Search**: Queries memories within specific time periods
|
||||||
|
|
||||||
|
### Tech Stack
|
||||||
|
|
||||||
|
- **Frontend**: Next.js 16, React, TypeScript, TailwindCSS
|
||||||
|
- **Visualization**: Recharts for timeline graphs
|
||||||
|
- **Backend**: Next.js API routes
|
||||||
|
- **Memory**: Hindsight (from github.com/vectorize-io/hindsight)
|
||||||
|
- **Database**: JSON file storage (no database required)
|
||||||
|
- **Web Search**: Tavily API
|
||||||
|
- **LLM**: OpenAI/Anthropic/Groq (configurable)
|
||||||
|
- **Scheduling**: node-cron
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. **Hindsight API** running (from github.com/vectorize-io/hindsight)
|
||||||
|
2. **API Keys**:
|
||||||
|
- Tavily API key (for web search)
|
||||||
|
- LLM provider API key (OpenAI, Anthropic, or Groq)
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### 1. Install Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Configure Environment
|
||||||
|
|
||||||
|
Copy `.env.example` to `.env` and fill in your credentials:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit `.env`:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Hindsight API (from github.com/vectorize-io/hindsight)
|
||||||
|
HINDSIGHT_API_URL=http://localhost:8888
|
||||||
|
|
||||||
|
# Tavily API (for web search)
|
||||||
|
TAVILY_API_KEY=your_tavily_api_key_here
|
||||||
|
|
||||||
|
# LLM Provider
|
||||||
|
LLM_PROVIDER=openai # or anthropic, groq
|
||||||
|
LLM_API_KEY=your_llm_api_key_here
|
||||||
|
LLM_MODEL=gpt-4-turbo-preview
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Start Hindsight
|
||||||
|
|
||||||
|
Clone and run Hindsight from github.com/vectorize-io/hindsight:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone and run github.com/vectorize-io/hindsight
|
||||||
|
cd /path/to/hindsight
|
||||||
|
cargo run --bin hindsight-server
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify Hindsight is running at `http://localhost:8888`
|
||||||
|
|
||||||
|
### 4. Run the Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Visit `http://localhost:3000`
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Creating a Tracking Session
|
||||||
|
|
||||||
|
1. **Set Location**: Enter country (required), state/province, and city (optional)
|
||||||
|
2. **Choose Topic**: Specify the issue to track (e.g., "Climate Change Policy")
|
||||||
|
3. **Add Candidates**: Enter names of candidates/politicians to track
|
||||||
|
4. **Configure Time Range**: Set historical start/end dates for initial analysis
|
||||||
|
5. **Set Frequency**: Choose how often to check for updates (hourly/daily/weekly)
|
||||||
|
6. **Start Tracking**: Click "Start Tracking" to begin
|
||||||
|
|
||||||
|
### Viewing Results
|
||||||
|
|
||||||
|
- **Timeline Graph**: Shows confidence levels of each candidate's stance over time
|
||||||
|
- **Stance Changes**: Red circles on the graph indicate detected position changes
|
||||||
|
- **Click Points**: Click any point to see detailed stance information and sources
|
||||||
|
- **Source Links**: Each stance includes links to original references
|
||||||
|
|
||||||
|
### Managing Sessions
|
||||||
|
|
||||||
|
- **Pause/Resume**: Temporarily stop or restart tracking
|
||||||
|
- **Run Now**: Trigger an immediate update outside the schedule
|
||||||
|
- **Status**: View current session status and frequency
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
### Sessions
|
||||||
|
|
||||||
|
- `POST /api/sessions` - Create new tracking session
|
||||||
|
- `GET /api/sessions?id={id}` - Get session details
|
||||||
|
- `GET /api/sessions` - List all sessions
|
||||||
|
- `PATCH /api/sessions` - Update session status
|
||||||
|
|
||||||
|
### Stances
|
||||||
|
|
||||||
|
- `POST /api/stances` - Process candidate stance
|
||||||
|
- `GET /api/stances?sessionId={id}&candidate={name}` - Get stances
|
||||||
|
|
||||||
|
### Scheduler
|
||||||
|
|
||||||
|
- `POST /api/scheduler` - Control session scheduling
|
||||||
|
- Actions: `start`, `stop`, `run`
|
||||||
|
|
||||||
|
## Hindsight Integration Examples
|
||||||
|
|
||||||
|
### 1. Storing Memories
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Store web scraping results
|
||||||
|
await hindsightClient.retain(bankId, articleContent, {
|
||||||
|
context: 'web_search_result',
|
||||||
|
timestamp: articleDate,
|
||||||
|
metadata: { url: articleUrl }
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Semantic Search
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Search for relevant memories
|
||||||
|
const results = await hindsightClient.recall(bankId, query, {
|
||||||
|
budget: 'high',
|
||||||
|
maxTokens: 8192
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Temporal Filtering
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Query memories up to a specific point in time
|
||||||
|
const results = await hindsightClient.recall(bankId, query, {
|
||||||
|
queryTimestamp: '2024-12-01T00:00:00Z'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Contextual Analysis
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Generate analysis using stored memories
|
||||||
|
const response = await hindsightClient.reflect(bankId,
|
||||||
|
'What is the candidate\'s stance on this issue?',
|
||||||
|
{ budget: 'high' }
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production Deployment
|
||||||
|
|
||||||
|
### Vercel Deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install Vercel CLI
|
||||||
|
npm i -g vercel
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
vercel
|
||||||
|
|
||||||
|
# Set environment variables in Vercel dashboard:
|
||||||
|
# - HINDSIGHT_API_URL
|
||||||
|
# - TAVILY_API_KEY
|
||||||
|
# - LLM_PROVIDER
|
||||||
|
# - LLM_API_KEY
|
||||||
|
# - LLM_MODEL
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: The `data/` directory for JSON storage will be ephemeral on Vercel. For production, consider using a persistent database or object storage.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
stancetracker/
|
||||||
|
├── app/
|
||||||
|
│ ├── api/ # API routes
|
||||||
|
│ ├── globals.css # Global styles
|
||||||
|
│ ├── layout.tsx # Root layout
|
||||||
|
│ └── page.tsx # Main page
|
||||||
|
├── components/ # React components
|
||||||
|
├── lib/
|
||||||
|
│ ├── db/ # JSON database utilities
|
||||||
|
│ ├── hindsight-client.ts # Hindsight API client
|
||||||
|
│ ├── llm-client.ts # LLM provider client
|
||||||
|
│ ├── web-scraper.ts # Tavily web scraper
|
||||||
|
│ ├── scraper-agent.ts # Content scraper
|
||||||
|
│ ├── rag-system.ts # Memory retrieval
|
||||||
|
│ ├── stance-extractor.ts # Stance analysis
|
||||||
|
│ ├── stance-pipeline.ts # Main pipeline
|
||||||
|
│ └── scheduler.ts # Job scheduling
|
||||||
|
└── types/ # TypeScript types
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding New LLM Providers
|
||||||
|
|
||||||
|
Edit `lib/llm-client.ts` and add a new method:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
private async newProviderComplete(messages, options) {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
- **Web Search**: Uses Tavily API which has rate limits
|
||||||
|
- **Source Verification**: Manual verification recommended for critical applications
|
||||||
|
- **Stance Extraction**: LLM-based, subject to model limitations
|
||||||
|
- **Storage**: JSON file storage is not suitable for high-scale production use
|
||||||
|
- **Rate Limits**: Respect API rate limits for Tavily, Hindsight, and LLM providers
|
||||||
|
|
||||||
|
## Future Enhancements
|
||||||
|
|
||||||
|
- [ ] Real-time social media monitoring
|
||||||
|
- [ ] Speech/video transcription analysis
|
||||||
|
- [ ] Multi-language support
|
||||||
|
- [ ] Sentiment analysis integration
|
||||||
|
- [ ] Comparative analysis dashboard
|
||||||
|
- [ ] Export to CSV/PDF
|
||||||
|
- [ ] Email notifications for stance changes
|
||||||
|
- [ ] Public API for third-party integrations
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues or questions, please check:
|
||||||
|
- Hindsight documentation: `github.com/vectorize-io/hindsight/README.md`
|
||||||
|
- Tavily API docs: https://tavily.com/
|
||||||
|
- Project issues: Create an issue in the repository
|
||||||
|
|
@ -15,13 +15,25 @@ Practical patterns, recipes, and complete applications for building with Hindsig
|
||||||
{ title: "Per-User Memory", href: "/cookbook/recipes/per-user-memory" },
|
{ title: "Per-User Memory", href: "/cookbook/recipes/per-user-memory" },
|
||||||
{ title: "Support Agent with Shared Knowledge", href: "/cookbook/recipes/support-agent-shared-knowledge" },
|
{ title: "Support Agent with Shared Knowledge", href: "/cookbook/recipes/support-agent-shared-knowledge" },
|
||||||
{ title: "Memory with LiteLLM", href: "/cookbook/recipes/litellm-memory-demo" },
|
{ title: "Memory with LiteLLM", href: "/cookbook/recipes/litellm-memory-demo" },
|
||||||
{ title: "Routing Tool Learning", href: "/cookbook/recipes/tool-learning-demo" }
|
{ title: "Routing Tool Learning", href: "/cookbook/recipes/tool-learning-demo" },
|
||||||
|
{ title: "Fitness Coach with Hindsight Memory", href: "/cookbook/recipes/fitness_tracker" },
|
||||||
|
{ title: "Healthcare Assistant with Hindsight Memory", href: "/cookbook/recipes/healthcare_assistant" },
|
||||||
|
{ title: "Movie Recommendation Assistant with Hindsight Memory", href: "/cookbook/recipes/movie_recommendation" },
|
||||||
|
{ title: "Personal AI Assistant with Hindsight Memory", href: "/cookbook/recipes/personal_assistant" },
|
||||||
|
{ title: "Personalized Search Agent with Hindsight Memory", href: "/cookbook/recipes/personalized_search" },
|
||||||
|
{ title: "Study Buddy with Hindsight Memory", href: "/cookbook/recipes/study_buddy" }
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RecipeCarousel
|
<RecipeCarousel
|
||||||
title="Applications"
|
title="Applications"
|
||||||
items={[
|
items={[
|
||||||
{ title: "OpenAI Agent + Hindsight Memory Integration", href: "/cookbook/applications/openai-fitness-coach" }
|
{ title: "Chat Memory App", href: "/cookbook/applications/chat-memory" },
|
||||||
|
{ title: "Deliveryman Demo", href: "/cookbook/applications/deliveryman-demo" },
|
||||||
|
{ title: "Memory Approaches Comparison Demo", href: "/cookbook/applications/hindsight-litellm-demo" },
|
||||||
|
{ title: "Tool Learning Demo", href: "/cookbook/applications/hindsight-tool-learning-demo" },
|
||||||
|
{ title: "OpenAI Agent + Hindsight Memory Integration", href: "/cookbook/applications/openai-fitness-coach" },
|
||||||
|
{ title: "Sanity CMS Blog Memory", href: "/cookbook/applications/sanity-blog-memory" },
|
||||||
|
{ title: "Stance Tracker", href: "/cookbook/applications/stancetracker" }
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
306
hindsight-docs/docs/cookbook/recipes/fitness_tracker.md
Normal file
306
hindsight-docs/docs/cookbook/recipes/fitness_tracker.md
Normal file
|
|
@ -0,0 +1,306 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 6
|
||||||
|
---
|
||||||
|
|
||||||
|
# Fitness Coach with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/fitness_tracker.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A personalized fitness assistant that tracks your workouts, diet, recovery, and progress over time to give contextual advice.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Logs workout sessions with exercises and weights
|
||||||
|
- Tracks meals and dietary preferences
|
||||||
|
- Monitors recovery and sleep patterns
|
||||||
|
- Provides personalized training advice
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
!pip install -q hindsight-client openai nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure OpenAI API Key
|
||||||
|
|
||||||
|
Enter your OpenAI API key when prompted (used by both Hindsight and the demo).
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
print("API key configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
USER_ID = "fitness-user-demo"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def log_workout(workout_details: str) -> str:
|
||||||
|
"""Log a workout session with timestamp."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"{today} - WORKOUT LOG: {workout_details}",
|
||||||
|
metadata={"category": "workout", "date": today},
|
||||||
|
)
|
||||||
|
return f"Logged workout for {today}: {workout_details}"
|
||||||
|
|
||||||
|
|
||||||
|
def log_meal(meal_details: str) -> str:
|
||||||
|
"""Log a meal with timestamp."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"{today} - MEAL LOG: {meal_details}",
|
||||||
|
metadata={"category": "nutrition", "date": today},
|
||||||
|
)
|
||||||
|
return f"Logged meal for {today}: {meal_details}"
|
||||||
|
|
||||||
|
|
||||||
|
def log_recovery(recovery_details: str) -> str:
|
||||||
|
"""Log recovery information (sleep, soreness, etc.)."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"{today} - RECOVERY LOG: {recovery_details}",
|
||||||
|
metadata={"category": "recovery", "date": today},
|
||||||
|
)
|
||||||
|
return f"Logged recovery for {today}: {recovery_details}"
|
||||||
|
|
||||||
|
|
||||||
|
def store_user_profile(profile_info: str) -> str:
|
||||||
|
"""Store user profile information."""
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"USER PROFILE: {profile_info}",
|
||||||
|
metadata={"category": "profile"},
|
||||||
|
)
|
||||||
|
return f"Stored profile info: {profile_info}"
|
||||||
|
|
||||||
|
|
||||||
|
def fitness_coach(user_query: str) -> str:
|
||||||
|
"""Get personalized fitness advice based on query and user history."""
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=f"fitness workout diet recovery goals {user_query}",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
|
||||||
|
memory_context = ""
|
||||||
|
if memories and memories.results:
|
||||||
|
memory_context = "\n".join(f"- {m.text}" for m in memories.results[:10])
|
||||||
|
|
||||||
|
system_prompt = f"""You are a knowledgeable and supportive fitness coach.
|
||||||
|
You have access to the user's workout history, diet logs, recovery notes, and personal profile.
|
||||||
|
|
||||||
|
What you know about this user:
|
||||||
|
{memory_context if memory_context else "No history recorded yet."}
|
||||||
|
|
||||||
|
Provide personalized, actionable advice based on their:
|
||||||
|
- Training history and progress
|
||||||
|
- Dietary preferences and restrictions
|
||||||
|
- Recovery patterns
|
||||||
|
- Personal goals
|
||||||
|
|
||||||
|
Be encouraging but realistic. Reference their specific history when relevant."""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_query},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=600,
|
||||||
|
)
|
||||||
|
|
||||||
|
advice = response.choices[0].message.content
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"User asked: {user_query}\nCoach advised: {advice[:200]}...",
|
||||||
|
metadata={"category": "coaching"},
|
||||||
|
)
|
||||||
|
|
||||||
|
return advice
|
||||||
|
|
||||||
|
|
||||||
|
def get_progress_report() -> str:
|
||||||
|
"""Generate a progress report based on workout history."""
|
||||||
|
report = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query="""Analyze this user's fitness journey:
|
||||||
|
1. How consistent have they been with workouts?
|
||||||
|
2. What progress have they made (weight lifted, exercises)?
|
||||||
|
3. How is their recovery and sleep?
|
||||||
|
4. What dietary patterns do you notice?
|
||||||
|
5. What should they focus on next?""",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return report.text if hasattr(report, 'text') else str(report)
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Set Up User Profile
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Setting up user profile...")
|
||||||
|
|
||||||
|
profile_data = [
|
||||||
|
"Name: Anish, Age: 26, Height: 5'10\", Weight: 72kg",
|
||||||
|
"Goal: Building lean muscle, started gym 6 months ago",
|
||||||
|
"Routine: Push-pull-legs split, 5x per week",
|
||||||
|
"Rest days: Wednesday and Sunday",
|
||||||
|
"Dietary restriction: Mild lactose intolerance, uses almond milk",
|
||||||
|
"Health note: Occasional knee pain, avoids deep squats",
|
||||||
|
"Supplements: Whey protein (lactose-free), magnesium",
|
||||||
|
"Sleep: Aims for 7+ hours, performance drops under 6 hours",
|
||||||
|
]
|
||||||
|
|
||||||
|
for info in profile_data:
|
||||||
|
store_user_profile(info)
|
||||||
|
print(f" Stored: {info[:50]}...")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Log Workout History
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Logging workout history...")
|
||||||
|
|
||||||
|
workouts = [
|
||||||
|
"Push day: Bench press 3x8 @ 60kg, overhead press 4x12, tricep dips 3x10. Felt strong.",
|
||||||
|
"Pull day: Deadlift 3x5 @ 80kg, barbell rows 4x10, bicep curls 3x12. Good session.",
|
||||||
|
"Leg day: Leg press 4x12, hamstring curls 3x12, glute bridges 3x15. Knee felt okay.",
|
||||||
|
]
|
||||||
|
|
||||||
|
for workout in workouts:
|
||||||
|
print(f" {log_workout(workout)[:60]}...")
|
||||||
|
|
||||||
|
print("\nLogging recent meals...")
|
||||||
|
meals = [
|
||||||
|
"Post-workout: Whey shake with almond milk, banana, oats",
|
||||||
|
"Dinner: Grilled chicken, brown rice, steamed vegetables",
|
||||||
|
"Snack: Greek yogurt (lactose-free) with berries",
|
||||||
|
]
|
||||||
|
|
||||||
|
for meal in meals:
|
||||||
|
print(f" {log_meal(meal)[:60]}...")
|
||||||
|
|
||||||
|
print("\nLogging recovery notes...")
|
||||||
|
recovery = [
|
||||||
|
"Slept 7.5 hours, feeling well rested",
|
||||||
|
"Some DOMS in legs from yesterday, using turmeric milk",
|
||||||
|
]
|
||||||
|
|
||||||
|
for note in recovery:
|
||||||
|
print(f" {log_recovery(note)[:60]}...")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Talk to Your Fitness Coach
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Talking to your fitness coach...")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
queries = [
|
||||||
|
"How much was I lifting for bench press recently?",
|
||||||
|
"I slept poorly last night (only 5 hours). What should I do for today's workout?",
|
||||||
|
"Suggest a post-workout meal that works with my dietary restrictions.",
|
||||||
|
"My knee has been bothering me more. Any exercise modifications?",
|
||||||
|
]
|
||||||
|
|
||||||
|
for query in queries:
|
||||||
|
print(f"\nUser: {query}")
|
||||||
|
print("-" * 40)
|
||||||
|
response = fitness_coach(query)
|
||||||
|
print(f"Coach: {response}")
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Generate Progress Report
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Progress Report")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_progress_report())
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Try Your Own Query
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
your_query = "What exercises should I do today?" # Change this!
|
||||||
|
|
||||||
|
print(f"You: {your_query}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(f"Coach: {fitness_coach(your_query)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10. Cleanup
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
299
hindsight-docs/docs/cookbook/recipes/healthcare_assistant.md
Normal file
299
hindsight-docs/docs/cookbook/recipes/healthcare_assistant.md
Normal file
|
|
@ -0,0 +1,299 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 7
|
||||||
|
---
|
||||||
|
|
||||||
|
# Healthcare Assistant with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/healthcare_assistant.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A supportive healthcare chatbot that remembers patient history, symptoms, medications, and preferences to provide personalized guidance.
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
**This is a demo application and should NOT be used for actual medical advice. Always consult qualified healthcare professionals.**
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Tracks symptoms, medications, and allergies
|
||||||
|
- Maintains patient history across conversations
|
||||||
|
- Provides health information and wellness tips
|
||||||
|
- Schedules appointments
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
!pip install -q hindsight-client openai nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure OpenAI API Key
|
||||||
|
|
||||||
|
Enter your OpenAI API key when prompted (used by both Hindsight and the demo).
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
print("API key configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
import random
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
PATIENT_ID = "patient-demo"
|
||||||
|
|
||||||
|
def get_patient_bank_id(patient_id: str) -> str:
|
||||||
|
return f"patient-{patient_id}"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def store_patient_info(patient_id: str, info: str, category: str = "general") -> str:
|
||||||
|
"""Store patient information."""
|
||||||
|
bank_id = get_patient_bank_id(patient_id)
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=bank_id,
|
||||||
|
content=f"{today} - {category.upper()}: {info}",
|
||||||
|
metadata={"category": category, "date": today},
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"Recorded {category}: {info}"
|
||||||
|
|
||||||
|
|
||||||
|
def get_patient_history(patient_id: str, query: str) -> str:
|
||||||
|
"""Retrieve relevant patient history."""
|
||||||
|
bank_id = get_patient_bank_id(patient_id)
|
||||||
|
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=bank_id,
|
||||||
|
query=query,
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
|
||||||
|
if memories and memories.results:
|
||||||
|
return "\n".join(f"- {m.text}" for m in memories.results[:10])
|
||||||
|
return "No relevant history found."
|
||||||
|
|
||||||
|
|
||||||
|
def healthcare_chat(patient_id: str, user_message: str) -> str:
|
||||||
|
"""Chat with the healthcare assistant."""
|
||||||
|
bank_id = get_patient_bank_id(patient_id)
|
||||||
|
|
||||||
|
history = get_patient_history(
|
||||||
|
patient_id,
|
||||||
|
f"symptoms medications allergies conditions {user_message}"
|
||||||
|
)
|
||||||
|
|
||||||
|
system_prompt = f"""You are a supportive healthcare assistant chatbot.
|
||||||
|
|
||||||
|
IMPORTANT DISCLAIMERS:
|
||||||
|
- You are NOT a doctor and cannot provide medical diagnoses
|
||||||
|
- Always recommend consulting healthcare professionals for serious concerns
|
||||||
|
- Never prescribe medications or suggest stopping prescribed treatments
|
||||||
|
|
||||||
|
Your role:
|
||||||
|
- Listen empathetically to patient concerns
|
||||||
|
- Remember and reference their medical history
|
||||||
|
- Provide general health information and wellness tips
|
||||||
|
- Help track symptoms over time
|
||||||
|
- Remind about medications and appointments
|
||||||
|
- Suggest when to seek professional care
|
||||||
|
|
||||||
|
Patient History:
|
||||||
|
{history}
|
||||||
|
|
||||||
|
Guidelines:
|
||||||
|
- Be warm and supportive
|
||||||
|
- Ask clarifying questions when needed
|
||||||
|
- Reference their history when relevant
|
||||||
|
- Flag any concerning symptoms for professional review"""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_message},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=600,
|
||||||
|
)
|
||||||
|
|
||||||
|
answer = response.choices[0].message.content
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=bank_id,
|
||||||
|
content=f"Patient concern: {user_message}\nGuidance provided: {answer[:200]}...",
|
||||||
|
metadata={"category": "consultation"},
|
||||||
|
)
|
||||||
|
|
||||||
|
return answer
|
||||||
|
|
||||||
|
|
||||||
|
def get_health_summary(patient_id: str) -> str:
|
||||||
|
"""Generate a health summary for the patient."""
|
||||||
|
bank_id = get_patient_bank_id(patient_id)
|
||||||
|
|
||||||
|
summary = hindsight.reflect(
|
||||||
|
bank_id=bank_id,
|
||||||
|
query="""Summarize this patient's health profile:
|
||||||
|
1. Known conditions and diagnoses
|
||||||
|
2. Current medications
|
||||||
|
3. Allergies and sensitivities
|
||||||
|
4. Recent symptoms reported
|
||||||
|
5. Lifestyle factors mentioned
|
||||||
|
6. Any patterns or trends in their health""",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return summary.text if hasattr(summary, 'text') else str(summary)
|
||||||
|
|
||||||
|
|
||||||
|
def schedule_appointment(patient_id: str, appointment_type: str, preferred_time: str) -> str:
|
||||||
|
"""Schedule an appointment (demo)."""
|
||||||
|
confirmation_id = f"APT-{random.randint(10000, 99999)}"
|
||||||
|
|
||||||
|
store_patient_info(
|
||||||
|
patient_id,
|
||||||
|
f"Appointment scheduled: {appointment_type} - Preferred time: {preferred_time} - Confirmation: {confirmation_id}",
|
||||||
|
category="appointment"
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"Appointment requested: {appointment_type}\nPreferred time: {preferred_time}\nConfirmation ID: {confirmation_id}\n\nA staff member will confirm the exact time within 24 hours."
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Set Up Patient Profile
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Setting up patient profile...")
|
||||||
|
|
||||||
|
patient_info = [
|
||||||
|
("Age: 45, Male, Height: 5'11\", Weight: 185 lbs", "demographics"),
|
||||||
|
("Allergy: Penicillin - causes hives", "allergies"),
|
||||||
|
("Allergy: Shellfish - causes throat swelling", "allergies"),
|
||||||
|
("Current medication: Lisinopril 10mg daily for blood pressure", "medications"),
|
||||||
|
("Current medication: Metformin 500mg twice daily for Type 2 diabetes", "medications"),
|
||||||
|
("Condition: Diagnosed with Type 2 diabetes in 2020", "conditions"),
|
||||||
|
("Condition: Mild hypertension, well-controlled", "conditions"),
|
||||||
|
("Family history: Father had heart disease", "family_history"),
|
||||||
|
("Lifestyle: Sedentary job, trying to exercise more", "lifestyle"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for info, category in patient_info:
|
||||||
|
result = store_patient_info(PATIENT_ID, info, category)
|
||||||
|
print(f" {result}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Healthcare Chat
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Healthcare Chat")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
conversations = [
|
||||||
|
"Hi, I've been having headaches for the past few days. Should I be worried?",
|
||||||
|
"The headaches are mostly in the afternoon. I've also been feeling more tired than usual.",
|
||||||
|
"I've been checking my blood sugar and it's been a bit higher lately, around 140-150 fasting.",
|
||||||
|
"Can you remind me what allergies I have? I'm going to a new restaurant.",
|
||||||
|
]
|
||||||
|
|
||||||
|
for message in conversations:
|
||||||
|
print(f"\nPatient: {message}")
|
||||||
|
print("-" * 40)
|
||||||
|
response = healthcare_chat(PATIENT_ID, message)
|
||||||
|
print(f"Assistant: {response}")
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Schedule Appointment
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Scheduling Appointment")
|
||||||
|
print("=" * 60)
|
||||||
|
print(schedule_appointment(PATIENT_ID, "General checkup", "Next Tuesday afternoon"))
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Health Summary
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Patient Health Summary")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_health_summary(PATIENT_ID))
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Try Your Own Question
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
your_question = "Should I adjust my Metformin dose?" # Change this!
|
||||||
|
|
||||||
|
print(f"You: {your_question}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(f"Assistant: {healthcare_chat(PATIENT_ID, your_question)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10. Cleanup
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
246
hindsight-docs/docs/cookbook/recipes/movie_recommendation.md
Normal file
246
hindsight-docs/docs/cookbook/recipes/movie_recommendation.md
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 8
|
||||||
|
---
|
||||||
|
|
||||||
|
# Movie Recommendation Assistant with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/movie_recommendation.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A personalized movie recommender that remembers your preferences, watch history, and tastes to give better suggestions over time.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Remembers favorite genres, directors, and actors
|
||||||
|
- Tracks movies you've watched and enjoyed
|
||||||
|
- Provides contextual recommendations based on mood
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
!pip install -q hindsight-client openai nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure OpenAI API Key
|
||||||
|
|
||||||
|
Enter your OpenAI API key when prompted (used by both Hindsight and the demo).
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
print("API key configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initialize OpenAI client
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
# Unique identifier for this user's memory bank
|
||||||
|
USER_ID = "movie-fan-demo"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
These functions demonstrate the three core Hindsight operations:
|
||||||
|
- **retain()**: Store memories
|
||||||
|
- **recall()**: Retrieve relevant memories
|
||||||
|
- **reflect()**: Synthesize insights from memories
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_recommendation(user_query: str) -> str:
|
||||||
|
"""
|
||||||
|
Get a movie recommendation based on user query and remembered preferences.
|
||||||
|
"""
|
||||||
|
# Recall relevant memories about this user's movie preferences
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=f"movie preferences tastes genres {user_query}",
|
||||||
|
budget="mid",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Build context from memories
|
||||||
|
memory_context = ""
|
||||||
|
if memories and memories.results:
|
||||||
|
memory_context = "\n".join(
|
||||||
|
f"- {m.text}" for m in memories.results[:5]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate recommendation with context
|
||||||
|
system_prompt = f"""You are a helpful movie recommendation assistant.
|
||||||
|
You remember the user's preferences and past conversations to give personalized suggestions.
|
||||||
|
|
||||||
|
What you know about this user:
|
||||||
|
{memory_context if memory_context else "No previous preferences recorded yet."}
|
||||||
|
|
||||||
|
Give thoughtful, personalized recommendations based on their tastes.
|
||||||
|
If they mention new preferences, acknowledge them."""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_query},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=500,
|
||||||
|
)
|
||||||
|
|
||||||
|
recommendation = response.choices[0].message.content
|
||||||
|
|
||||||
|
# Store this interaction for future context
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"User asked: {user_query}\nRecommendation given: {recommendation}",
|
||||||
|
metadata={"category": "movie_recommendation"},
|
||||||
|
)
|
||||||
|
|
||||||
|
return recommendation
|
||||||
|
|
||||||
|
|
||||||
|
def store_preference(preference: str) -> None:
|
||||||
|
"""Store an explicit user preference."""
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"User preference: {preference}",
|
||||||
|
metadata={"category": "preference"},
|
||||||
|
)
|
||||||
|
print(f"Stored preference: {preference}")
|
||||||
|
|
||||||
|
|
||||||
|
def get_preference_summary() -> str:
|
||||||
|
"""Get a summary of what we know about the user's movie tastes."""
|
||||||
|
summary = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query="Summarize this user's movie preferences, favorite genres, actors they like, and movies they've mentioned enjoying or disliking.",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return summary.text if hasattr(summary, 'text') else str(summary)
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Run the Demo
|
||||||
|
|
||||||
|
Watch how the assistant learns and remembers preferences across conversations.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Movie Recommendation Assistant with Memory")
|
||||||
|
print("=" * 60)
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Simulate a conversation over time
|
||||||
|
conversations = [
|
||||||
|
"I'm looking for a movie to watch tonight. Any suggestions?",
|
||||||
|
"I really loved Inception and Interstellar. Christopher Nolan is amazing!",
|
||||||
|
"Can you suggest something similar to those? I like mind-bending plots.",
|
||||||
|
"Actually, I'm not in the mood for something heavy. Something lighter?",
|
||||||
|
"I watched The Grand Budapest Hotel last week and loved it!",
|
||||||
|
"What should I watch tonight? Remember what I like!",
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, query in enumerate(conversations, 1):
|
||||||
|
print(f"\n[Conversation {i}]")
|
||||||
|
print(f"User: {query}")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
response = get_recommendation(query)
|
||||||
|
print(f"Assistant: {response}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. View Learned Preferences
|
||||||
|
|
||||||
|
Use `reflect()` to synthesize what Hindsight has learned about your movie tastes.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" What I've learned about your movie tastes:")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_preference_summary())
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Try Your Own Queries
|
||||||
|
|
||||||
|
Experiment with your own movie preferences!
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Try your own query!
|
||||||
|
your_query = "I'm in the mood for a sci-fi thriller" # Change this!
|
||||||
|
|
||||||
|
print(f"You: {your_query}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(f"Assistant: {get_recommendation(your_query)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Cleanup
|
||||||
|
|
||||||
|
Close the Hindsight client connection.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
|
||||||
|
```
|
||||||
266
hindsight-docs/docs/cookbook/recipes/personal_assistant.md
Normal file
266
hindsight-docs/docs/cookbook/recipes/personal_assistant.md
Normal file
|
|
@ -0,0 +1,266 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 9
|
||||||
|
---
|
||||||
|
|
||||||
|
# Personal AI Assistant with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/personal_assistant.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A general-purpose personal assistant that remembers your preferences, schedule, family, work context, and past conversations.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Remembers family, work, and personal details
|
||||||
|
- Tracks preferences and habits
|
||||||
|
- Helps with scheduling and reminders
|
||||||
|
- Maintains context across conversations
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
!pip install -q hindsight-client openai nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure OpenAI API Key
|
||||||
|
|
||||||
|
Enter your OpenAI API key when prompted (used by both Hindsight and the demo).
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
print("API key configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
USER_ID = "assistant-user-demo"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def remember(info: str, category: str = "general") -> str:
|
||||||
|
"""Store information to remember."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"{today}: {info}",
|
||||||
|
metadata={"category": category, "date": today},
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"I'll remember: {info}"
|
||||||
|
|
||||||
|
|
||||||
|
def recall_context(query: str) -> str:
|
||||||
|
"""Recall relevant memories for context."""
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=query,
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
|
||||||
|
if memories and memories.results:
|
||||||
|
return "\n".join(f"- {m.text}" for m in memories.results[:8])
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def chat(user_message: str) -> str:
|
||||||
|
"""Chat with the personal assistant."""
|
||||||
|
context = recall_context(user_message)
|
||||||
|
|
||||||
|
system_prompt = f"""You are a helpful personal AI assistant with long-term memory.
|
||||||
|
You remember the user's preferences, schedule, family, work context, and past conversations.
|
||||||
|
|
||||||
|
What you remember about this user:
|
||||||
|
{context if context else "No memories recorded yet."}
|
||||||
|
|
||||||
|
Your capabilities:
|
||||||
|
- Remember things when asked ("Remember that...", "Don't forget...")
|
||||||
|
- Recall past information ("What did I tell you about...", "When is...")
|
||||||
|
- Provide personalized suggestions based on known preferences
|
||||||
|
- Help with scheduling and reminders
|
||||||
|
- Have natural conversations while maintaining context
|
||||||
|
|
||||||
|
Be helpful, proactive, and reference relevant memories naturally."""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_message},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=500,
|
||||||
|
)
|
||||||
|
|
||||||
|
answer = response.choices[0].message.content
|
||||||
|
|
||||||
|
# Check if user is asking to remember something
|
||||||
|
lower_msg = user_message.lower()
|
||||||
|
if any(phrase in lower_msg for phrase in ["remember that", "don't forget", "remind me", "note that"]):
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"User asked to remember: {user_message}",
|
||||||
|
metadata={"category": "reminder"},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Store the interaction
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"Conversation - User: {user_message[:100]} | Assistant: {answer[:100]}",
|
||||||
|
metadata={"category": "conversation"},
|
||||||
|
)
|
||||||
|
|
||||||
|
return answer
|
||||||
|
|
||||||
|
|
||||||
|
def get_summary(topic: str = None) -> str:
|
||||||
|
"""Get a summary of memories."""
|
||||||
|
query = f"Summarize what you know about {topic}" if topic else \
|
||||||
|
"Summarize everything you know about this user"
|
||||||
|
|
||||||
|
summary = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=query,
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return summary.text if hasattr(summary, 'text') else str(summary)
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Build Context
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Building context...")
|
||||||
|
|
||||||
|
initial_context = [
|
||||||
|
("My name is Alex and I work as a product manager at TechCorp", "personal"),
|
||||||
|
("My wife's name is Sarah and we have two kids: Emma (7) and Jack (4)", "family"),
|
||||||
|
("I prefer morning meetings and try to keep afternoons for deep work", "preference"),
|
||||||
|
("My mom's birthday is March 15th", "event"),
|
||||||
|
("I'm trying to read more - currently reading 'Atomic Habits'", "hobby"),
|
||||||
|
("I have a weekly team standup every Monday at 10am", "schedule"),
|
||||||
|
("I'm allergic to cats", "health"),
|
||||||
|
("My favorite coffee is a flat white with oat milk", "preference"),
|
||||||
|
("I'm training for a half marathon in April", "goal"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for info, category in initial_context:
|
||||||
|
result = remember(info, category)
|
||||||
|
print(f" {result}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Have a Conversation
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Conversation")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
conversations = [
|
||||||
|
"Hey, what's my wife's name again?",
|
||||||
|
"Remember that my Q1 review is next Thursday at 2pm",
|
||||||
|
"I need a gift idea for my mom's birthday",
|
||||||
|
"What time is my Monday standup?",
|
||||||
|
"Can you recommend a coffee order for me?",
|
||||||
|
"What books am I reading?",
|
||||||
|
]
|
||||||
|
|
||||||
|
for message in conversations:
|
||||||
|
print(f"\nAlex: {message}")
|
||||||
|
print("-" * 40)
|
||||||
|
response = chat(message)
|
||||||
|
print(f"Assistant: {response}")
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. View Summary
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" What I Know About You")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_summary())
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Your Family")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_summary("family"))
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Try Your Own Message
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
your_message = "What should I focus on this month with my training?" # Change this!
|
||||||
|
|
||||||
|
print(f"You: {your_message}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(f"Assistant: {chat(your_message)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Cleanup
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
299
hindsight-docs/docs/cookbook/recipes/personalized_search.md
Normal file
299
hindsight-docs/docs/cookbook/recipes/personalized_search.md
Normal file
|
|
@ -0,0 +1,299 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 10
|
||||||
|
---
|
||||||
|
|
||||||
|
# Personalized Search Agent with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/personalized_search.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A search assistant that learns your preferences, location, dietary needs, and lifestyle to provide contextually relevant search results.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Learns location, dietary restrictions, and lifestyle
|
||||||
|
- Personalizes search queries based on context
|
||||||
|
- Remembers past searches and preferences
|
||||||
|
- Integrates with Tavily for real web search (optional)
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
- Tavily API key (optional, for real web search)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Tavily is optional - demo works with simulated results if not installed
|
||||||
|
!pip install -q hindsight-client openai tavily-python nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure API Keys
|
||||||
|
|
||||||
|
Enter your API keys when prompted. Tavily is optional - press Enter to skip for simulated search results.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
# Tavily is optional - for real web search
|
||||||
|
if not os.getenv("TAVILY_API_KEY"):
|
||||||
|
tavily_key = getpass.getpass("Enter your Tavily API key (or press Enter to skip): ")
|
||||||
|
if tavily_key:
|
||||||
|
os.environ["TAVILY_API_KEY"] = tavily_key
|
||||||
|
|
||||||
|
print("API keys configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
# Optional: Tavily for real web search
|
||||||
|
try:
|
||||||
|
from tavily import TavilyClient
|
||||||
|
tavily = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
|
||||||
|
HAS_TAVILY = True
|
||||||
|
print("Tavily configured - using real web search!")
|
||||||
|
except (ImportError, Exception) as e:
|
||||||
|
HAS_TAVILY = False
|
||||||
|
print("Note: Using simulated search results (Tavily not configured)")
|
||||||
|
|
||||||
|
USER_ID = "search-user-demo"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def store_preference(preference: str) -> str:
|
||||||
|
"""Store a user preference."""
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"User preference: {preference}",
|
||||||
|
metadata={"category": "preference"},
|
||||||
|
)
|
||||||
|
return f"Learned: {preference}"
|
||||||
|
|
||||||
|
|
||||||
|
def store_interaction(query: str, response: str) -> None:
|
||||||
|
"""Store a search interaction."""
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"Search query: {query}\nResult highlights: {response[:200]}",
|
||||||
|
metadata={"category": "search_history"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_context(query: str) -> str:
|
||||||
|
"""Retrieve relevant user context."""
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=f"preferences location dietary lifestyle {query}",
|
||||||
|
budget="mid",
|
||||||
|
)
|
||||||
|
|
||||||
|
if memories and memories.results:
|
||||||
|
return "\n".join(f"- {m.text}" for m in memories.results[:6])
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def personalized_search(query: str) -> str:
|
||||||
|
"""Perform a personalized search."""
|
||||||
|
user_context = get_user_context(query)
|
||||||
|
|
||||||
|
enhancement_prompt = f"""Given this user's preferences and the search query, suggest how to enhance the search.
|
||||||
|
|
||||||
|
User preferences:
|
||||||
|
{user_context if user_context else "No preferences recorded yet."}
|
||||||
|
|
||||||
|
Search query: {query}
|
||||||
|
|
||||||
|
Return a JSON object with:
|
||||||
|
- "enhanced_query": The improved search query incorporating relevant preferences
|
||||||
|
- "filters": Any specific filters to apply (e.g., "vegetarian", "within 5 miles")
|
||||||
|
- "reasoning": Brief explanation of personalizations applied"""
|
||||||
|
|
||||||
|
enhancement = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[{"role": "user", "content": enhancement_prompt}],
|
||||||
|
temperature=0.3,
|
||||||
|
max_tokens=300,
|
||||||
|
)
|
||||||
|
|
||||||
|
enhanced_info = enhancement.choices[0].message.content
|
||||||
|
|
||||||
|
# Perform the search
|
||||||
|
if HAS_TAVILY:
|
||||||
|
search_results = tavily.search(
|
||||||
|
query=query,
|
||||||
|
search_depth="advanced",
|
||||||
|
max_results=5,
|
||||||
|
)
|
||||||
|
results_text = "\n".join(
|
||||||
|
f"- {r['title']}: {r['content'][:150]}..."
|
||||||
|
for r in search_results.get('results', [])
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
results_text = f"[Simulated search results for: {query}]"
|
||||||
|
|
||||||
|
response_prompt = f"""Based on the search results and user preferences, provide a personalized summary.
|
||||||
|
|
||||||
|
User preferences:
|
||||||
|
{user_context if user_context else "No preferences recorded yet."}
|
||||||
|
|
||||||
|
Query: {query}
|
||||||
|
|
||||||
|
Search enhancement applied:
|
||||||
|
{enhanced_info}
|
||||||
|
|
||||||
|
Search results:
|
||||||
|
{results_text}
|
||||||
|
|
||||||
|
Provide a helpful, personalized response that takes into account their preferences."""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[{"role": "user", "content": response_prompt}],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=500,
|
||||||
|
)
|
||||||
|
|
||||||
|
answer = response.choices[0].message.content
|
||||||
|
store_interaction(query, answer)
|
||||||
|
|
||||||
|
return answer
|
||||||
|
|
||||||
|
|
||||||
|
def get_preference_profile() -> str:
|
||||||
|
"""Get a summary of the user's preference profile."""
|
||||||
|
profile = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query="""Summarize what we know about this user:
|
||||||
|
- Location and neighborhood
|
||||||
|
- Dietary preferences and restrictions
|
||||||
|
- Work style and schedule
|
||||||
|
- Hobbies and interests
|
||||||
|
- Family situation
|
||||||
|
- Shopping preferences""",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return profile.text if hasattr(profile, 'text') else str(profile)
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Build User Profile
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Learning user preferences...")
|
||||||
|
|
||||||
|
preferences = [
|
||||||
|
"Lives in San Francisco, Mission District",
|
||||||
|
"Works remotely as a software engineer",
|
||||||
|
"Vegetarian, prefers organic food when possible",
|
||||||
|
"Has a 5-year-old daughter named Emma",
|
||||||
|
"Enjoys hiking and outdoor activities on weekends",
|
||||||
|
"Prefers quiet coffee shops for remote work",
|
||||||
|
"Lactose intolerant, uses oat milk",
|
||||||
|
"Interested in sustainable and eco-friendly products",
|
||||||
|
"Usually free on Tuesday and Thursday afternoons",
|
||||||
|
"Husband is allergic to nuts",
|
||||||
|
]
|
||||||
|
|
||||||
|
for pref in preferences:
|
||||||
|
result = store_preference(pref)
|
||||||
|
print(f" {result}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Personalized Search Results
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Personalized Search Results")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
searches = [
|
||||||
|
"Find a good coffee shop for working remotely",
|
||||||
|
"Restaurant recommendations for a family dinner",
|
||||||
|
"Birthday gift ideas for a 5-year-old",
|
||||||
|
]
|
||||||
|
|
||||||
|
for query in searches:
|
||||||
|
print(f"\nSearch: {query}")
|
||||||
|
print("-" * 40)
|
||||||
|
result = personalized_search(query)
|
||||||
|
print(result)
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. View Preference Profile
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" User Preference Profile")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_preference_profile())
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Try Your Own Search
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
your_search = "Best hiking trails near me" # Change this!
|
||||||
|
|
||||||
|
print(f"Search: {your_search}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(personalized_search(your_search))
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Cleanup
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
|
|
@ -127,7 +127,7 @@ for r in results.results:
|
||||||
|
|
||||||
## Reflect: Generate Insights
|
## Reflect: Generate Insights
|
||||||
|
|
||||||
The `reflect` operation performs reasoning over existing memories using the bank's disposition. It retrieves relevant facts and observations to generate contextual responses.
|
The `reflect` operation performs a more thorough analysis of existing memories. This allows the agent to form new connections between memories which are then persisted as opinions and/or observations.
|
||||||
|
|
||||||
Example use cases:
|
Example use cases:
|
||||||
- An AI Project Manager reflecting on what risks need to be mitigated
|
- An AI Project Manager reflecting on what risks need to be mitigated
|
||||||
|
|
@ -142,11 +142,12 @@ print(response)
|
||||||
|
|
||||||
## Memory Types
|
## Memory Types
|
||||||
|
|
||||||
Hindsight organizes knowledge into facts and consolidated observations:
|
Hindsight organizes memory into four networks to mimic human memory:
|
||||||
|
|
||||||
- **World**: Facts about the world ("The stove gets hot")
|
- **World**: Facts about the world ("The stove gets hot")
|
||||||
- **Experience**: Agent's own experiences ("I touched the stove and it really hurt")
|
- **Experiences**: Agent's own experiences ("I touched the stove and it really hurt")
|
||||||
- **Observation**: Consolidated knowledge synthesized from facts ("Always be careful around hot surfaces")
|
- **Opinion**: Beliefs with confidence scores ("I shouldn't touch the stove again" - .99 confidence)
|
||||||
|
- **Observation**: Complex mental models derived by reflecting on facts and experiences
|
||||||
|
|
||||||
## Cleanup
|
## Cleanup
|
||||||
|
|
||||||
|
|
|
||||||
335
hindsight-docs/docs/cookbook/recipes/study_buddy.md
Normal file
335
hindsight-docs/docs/cookbook/recipes/study_buddy.md
Normal file
|
|
@ -0,0 +1,335 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 11
|
||||||
|
---
|
||||||
|
|
||||||
|
# Study Buddy with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/study_buddy.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A personalized study assistant that tracks what you've learned, identifies knowledge gaps, and helps with spaced repetition.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Tracks study sessions and topics covered
|
||||||
|
- Monitors confidence levels per topic
|
||||||
|
- Identifies knowledge gaps
|
||||||
|
- Suggests topics for spaced repetition review
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
!pip install -q hindsight-client openai nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure OpenAI API Key
|
||||||
|
|
||||||
|
Enter your OpenAI API key when prompted (used by both Hindsight and the demo).
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
print("API key configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
USER_ID = "student-demo"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def record_study_session(topic: str, notes: str, confidence: str = "medium") -> str:
|
||||||
|
"""Record a study session with topic, notes, and self-assessed confidence."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
|
||||||
|
content = f"""{today} - STUDY SESSION
|
||||||
|
Topic: {topic}
|
||||||
|
Confidence Level: {confidence}
|
||||||
|
Notes: {notes}"""
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=content,
|
||||||
|
metadata={
|
||||||
|
"category": "study_session",
|
||||||
|
"topic": topic,
|
||||||
|
"confidence": confidence,
|
||||||
|
"date": today,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"Recorded study session on '{topic}' (confidence: {confidence})"
|
||||||
|
|
||||||
|
|
||||||
|
def record_question(topic: str, question: str, understood: bool) -> str:
|
||||||
|
"""Record a question asked during study."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
|
||||||
|
content = f"""{today} - QUESTION
|
||||||
|
Topic: {topic}
|
||||||
|
Question: {question}
|
||||||
|
Understood: {"Yes" if understood else "No - needs review"}"""
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=content,
|
||||||
|
metadata={
|
||||||
|
"category": "question",
|
||||||
|
"topic": topic,
|
||||||
|
"understood": str(understood),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"Recorded question on '{topic}'"
|
||||||
|
|
||||||
|
|
||||||
|
def study_buddy(user_query: str) -> str:
|
||||||
|
"""Interact with the study buddy."""
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=f"study session topic notes questions {user_query}",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
|
||||||
|
memory_context = ""
|
||||||
|
if memories and memories.results:
|
||||||
|
memory_context = "\n".join(f"- {m.text}" for m in memories.results[:8])
|
||||||
|
|
||||||
|
system_prompt = f"""You are a helpful study buddy and tutor.
|
||||||
|
You have access to the student's study history, including:
|
||||||
|
- Topics they've studied and their notes
|
||||||
|
- Their self-assessed confidence levels
|
||||||
|
- Questions they've asked and whether they understood the answers
|
||||||
|
|
||||||
|
Study History:
|
||||||
|
{memory_context if memory_context else "No study history recorded yet."}
|
||||||
|
|
||||||
|
Your role:
|
||||||
|
1. Answer questions about topics they're studying
|
||||||
|
2. Identify knowledge gaps based on their history
|
||||||
|
3. Suggest topics to review (spaced repetition)
|
||||||
|
4. Provide encouragement and study tips
|
||||||
|
5. Connect new concepts to things they've already learned
|
||||||
|
|
||||||
|
Be supportive and pedagogical. Reference their previous learning when relevant."""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_query},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=800,
|
||||||
|
)
|
||||||
|
|
||||||
|
answer = response.choices[0].message.content
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"Student asked: {user_query}\nExplanation given: {answer[:300]}...",
|
||||||
|
metadata={"category": "tutoring"},
|
||||||
|
)
|
||||||
|
|
||||||
|
return answer
|
||||||
|
|
||||||
|
|
||||||
|
def get_review_suggestions() -> str:
|
||||||
|
"""Get suggestions for topics to review."""
|
||||||
|
suggestions = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query="""Analyze this student's study history and suggest:
|
||||||
|
1. Topics with low confidence that need more review
|
||||||
|
2. Topics studied a while ago that should be revisited
|
||||||
|
3. Questions that weren't fully understood
|
||||||
|
4. Connections between topics they might have missed
|
||||||
|
|
||||||
|
Prioritize by what would most improve their understanding.""",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return suggestions.text if hasattr(suggestions, 'text') else str(suggestions)
|
||||||
|
|
||||||
|
|
||||||
|
def get_knowledge_summary(topic: str = None) -> str:
|
||||||
|
"""Get a summary of what the student knows."""
|
||||||
|
query = f"Summarize what this student knows about {topic}" if topic else \
|
||||||
|
"Summarize this student's overall knowledge and progress"
|
||||||
|
|
||||||
|
summary = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=query,
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return summary.text if hasattr(summary, 'text') else str(summary)
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Record Study Sessions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Recording study sessions...")
|
||||||
|
|
||||||
|
sessions = [
|
||||||
|
{
|
||||||
|
"topic": "Classical Mechanics - Newton's Laws",
|
||||||
|
"notes": "Covered F=ma, action-reaction pairs, inertia. Solved problems on inclined planes.",
|
||||||
|
"confidence": "high",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"topic": "Classical Mechanics - Conservation of Momentum",
|
||||||
|
"notes": "Elastic vs inelastic collisions. Struggled with 2D collision problems.",
|
||||||
|
"confidence": "low",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"topic": "Classical Mechanics - Generalized Coordinates",
|
||||||
|
"notes": "Introduction to Lagrangian mechanics. Degrees of freedom concept.",
|
||||||
|
"confidence": "medium",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"topic": "Waves - Simple Harmonic Motion",
|
||||||
|
"notes": "SHM equations, period, frequency. Connected to springs and pendulums.",
|
||||||
|
"confidence": "high",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"topic": "Waves - Frequency Domain",
|
||||||
|
"notes": "Started Fourier transforms. Math is confusing, need more practice.",
|
||||||
|
"confidence": "low",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
for session in sessions:
|
||||||
|
result = record_study_session(**session)
|
||||||
|
print(f" {result}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Record Questions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Recording questions...")
|
||||||
|
|
||||||
|
questions = [
|
||||||
|
("Conservation of Momentum", "Why is momentum conserved in collisions?", True),
|
||||||
|
("Conservation of Momentum", "How do I solve 2D collision problems?", False),
|
||||||
|
("Generalized Coordinates", "What's the advantage of Lagrangian over Newtonian?", True),
|
||||||
|
("Frequency Domain", "When do I use Fourier transforms vs Laplace?", False),
|
||||||
|
]
|
||||||
|
|
||||||
|
for topic, question, understood in questions:
|
||||||
|
result = record_question(topic, question, understood)
|
||||||
|
print(f" {result}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Interactive Study Session
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Study Session")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
queries = [
|
||||||
|
"Can you explain generalized coordinates again? I remember we covered it but I'm fuzzy on the details.",
|
||||||
|
"What topics should I review before my exam next week?",
|
||||||
|
"I'm still confused about 2D collision problems. Can you walk me through an example?",
|
||||||
|
]
|
||||||
|
|
||||||
|
for query in queries:
|
||||||
|
print(f"\nStudent: {query}")
|
||||||
|
print("-" * 40)
|
||||||
|
response = study_buddy(query)
|
||||||
|
print(f"Study Buddy: {response}")
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Get Review Suggestions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Recommended Review Topics")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_review_suggestions())
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Knowledge Summary
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Knowledge Summary")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_knowledge_summary())
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10. Try Your Own Question
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
your_question = "What are my biggest knowledge gaps right now?" # Change this!
|
||||||
|
|
||||||
|
print(f"You: {your_question}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(f"Study Buddy: {study_buddy(your_question)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 11. Cleanup
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
|
|
@ -240,6 +240,36 @@ const sidebars: SidebarsConfig = {
|
||||||
type: 'doc',
|
type: 'doc',
|
||||||
id: 'cookbook/recipes/tool-learning-demo',
|
id: 'cookbook/recipes/tool-learning-demo',
|
||||||
label: 'Routing Tool Learning',
|
label: 'Routing Tool Learning',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/recipes/fitness_tracker',
|
||||||
|
label: 'Fitness Coach with Hindsight Memory',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/recipes/healthcare_assistant',
|
||||||
|
label: 'Healthcare Assistant with Hindsight Memory',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/recipes/movie_recommendation',
|
||||||
|
label: 'Movie Recommendation Assistant with Hindsight Memory',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/recipes/personal_assistant',
|
||||||
|
label: 'Personal AI Assistant with Hindsight Memory',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/recipes/personalized_search',
|
||||||
|
label: 'Personalized Search Agent with Hindsight Memory',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/recipes/study_buddy',
|
||||||
|
label: 'Study Buddy with Hindsight Memory',
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
@ -248,10 +278,40 @@ const sidebars: SidebarsConfig = {
|
||||||
label: 'Applications',
|
label: 'Applications',
|
||||||
collapsible: false,
|
collapsible: false,
|
||||||
items: [
|
items: [
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/applications/chat-memory',
|
||||||
|
label: 'Chat Memory App',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/applications/deliveryman-demo',
|
||||||
|
label: 'Deliveryman Demo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/applications/hindsight-litellm-demo',
|
||||||
|
label: 'Memory Approaches Comparison Demo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/applications/hindsight-tool-learning-demo',
|
||||||
|
label: 'Tool Learning Demo',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'doc',
|
type: 'doc',
|
||||||
id: 'cookbook/applications/openai-fitness-coach',
|
id: 'cookbook/applications/openai-fitness-coach',
|
||||||
label: 'OpenAI Agent + Hindsight Memory Integration',
|
label: 'OpenAI Agent + Hindsight Memory Integration',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/applications/sanity-blog-memory',
|
||||||
|
label: 'Sanity CMS Blog Memory',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'cookbook/applications/stancetracker',
|
||||||
|
label: 'Stance Tracker',
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# Chat Memory App
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/chat-memory)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A demo chat application that uses Groq's `qwen/qwen3-32b` model with Hindsight for persistent per-user memory.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- 🧠 **Persistent Memory**: Each user gets their own memory bank that remembers conversations
|
||||||
|
- 🚀 **Fast AI**: Powered by Groq's high-speed inference
|
||||||
|
- 🎯 **Per-User Context**: Isolated memory per user with automatic context retrieval
|
||||||
|
- 💬 **Real-time Chat**: Instant responses with memory-augmented context
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### 1. Start Hindsight API
|
||||||
|
|
||||||
|
First, start the Hindsight API server using Docker:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export GROQ_API_KEY=your_groq_api_key_here
|
||||||
|
|
||||||
|
# Start Hindsight with Groq as the LLM provider
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_PROVIDER=groq \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$GROQ_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL="openai/gpt-oss-20b" \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
- **API**: http://localhost:8888
|
||||||
|
- **Control Plane UI**: http://localhost:9999
|
||||||
|
|
||||||
|
### 2. Configure Environment
|
||||||
|
|
||||||
|
Copy your Groq API key to the environment file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update .env.local with your Groq API key
|
||||||
|
echo "GROQ_API_KEY=your_groq_api_key_here" > .env.local
|
||||||
|
echo "HINDSIGHT_API_URL=http://localhost:8888" >> .env.local
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't have one, you can get a free Groq API key here: https://console.groq.com/home
|
||||||
|
|
||||||
|
### 3. Install Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Run the App
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open http://localhost:3000 in your browser.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. **User Identity**: Each browser session gets a unique user ID
|
||||||
|
2. **Memory Bank Creation**: First message creates a personal memory bank in Hindsight
|
||||||
|
3. **Context Retrieval**: Before responding, relevant memories are retrieved
|
||||||
|
4. **Memory Augmented Response**: Groq generates responses with memory context
|
||||||
|
5. **Conversation Storage**: Each conversation is stored for future context
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
User Message
|
||||||
|
↓
|
||||||
|
Next.js API Route (/api/chat)
|
||||||
|
↓
|
||||||
|
Hindsight.recall() → Get relevant memories
|
||||||
|
↓
|
||||||
|
Groq API → Generate response with memory context
|
||||||
|
↓
|
||||||
|
Hindsight.retain() → Store conversation
|
||||||
|
↓
|
||||||
|
Response to User
|
||||||
|
```
|
||||||
|
|
||||||
|
## Memory Bank Structure
|
||||||
|
|
||||||
|
Each user gets their own isolated memory bank with:
|
||||||
|
- **Name**: "Chat Memory for [userId]"
|
||||||
|
- **Background**: Conversational AI assistant context
|
||||||
|
- **Disposition**: Empathetic (4), Low Skepticism (2), Balanced Literalism (3)
|
||||||
|
|
||||||
|
## Try It Out
|
||||||
|
|
||||||
|
1. **First Conversation**: Tell the assistant about yourself
|
||||||
|
- "Hi! I'm a software engineer from San Francisco. I love Python and machine learning."
|
||||||
|
|
||||||
|
2. **Second Conversation**: Ask what it remembers
|
||||||
|
- "What do you know about me?"
|
||||||
|
- "What programming languages do I like?"
|
||||||
|
|
||||||
|
3. **Context Building**: Continue sharing preferences
|
||||||
|
- "I prefer VS Code over other editors"
|
||||||
|
- "I'm working on a React project"
|
||||||
|
|
||||||
|
4. **Memory Verification**: Visit the Hindsight Control Plane at http://localhost:9999 to see stored memories
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
- **Groq Model**: Uses `qwen/qwen3-32b` for fast, high-quality responses
|
||||||
|
- **Memory Storage**: Automatic conversation retention with context categorization
|
||||||
|
- **Memory Retrieval**: Semantic search with 2048 token budget for relevant context
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
# Deliveryman Demo
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/deliveryman-demo)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A delivery agent simulation that demonstrates Hindsight's long-term memory capabilities. An AI agent navigates a multi-building office complex to deliver packages, learning employee locations and optimal paths over time through mental models.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Python 3.11+
|
||||||
|
- Node.js 18+
|
||||||
|
- [uv](https://docs.astral.sh/uv/) (Python package manager)
|
||||||
|
|
||||||
|
## Setup (Fresh Environment)
|
||||||
|
|
||||||
|
### 1. Clone Repositories
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone Hindsight (memory engine)
|
||||||
|
git clone https://github.com/anthropics/hindsight.git
|
||||||
|
|
||||||
|
# Clone the cookbook (contains this demo)
|
||||||
|
git clone https://github.com/anthropics/hindsight-cookbook.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Start Hindsight API
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd hindsight
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit `.env` with your LLM configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
HINDSIGHT_API_LLM_PROVIDER=groq
|
||||||
|
HINDSIGHT_API_LLM_API_KEY=<your-groq-api-key>
|
||||||
|
HINDSIGHT_API_LLM_MODEL=openai/gpt-oss-120b
|
||||||
|
HINDSIGHT_API_HOST=0.0.0.0
|
||||||
|
HINDSIGHT_API_PORT=8888
|
||||||
|
HINDSIGHT_API_ENABLE_OBSERVATIONS=true
|
||||||
|
|
||||||
|
# Retain extraction settings (improves employee/location extraction)
|
||||||
|
HINDSIGHT_API_RETAIN_EXTRACTION_MODE=custom
|
||||||
|
HINDSIGHT_API_RETAIN_CUSTOM_INSTRUCTIONS="Delivery agent. Remember employee locations, building layout, and optimal paths."
|
||||||
|
|
||||||
|
# Embedded database storage
|
||||||
|
PG0_DATA_DIR=/tmp/hindsight-data
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the API:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/dev/start-api.sh
|
||||||
|
# Runs on http://localhost:8888
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Start Hindsight Control Plane (Optional)
|
||||||
|
|
||||||
|
The control plane provides a web UI for inspecting memory banks, facts, and mental models.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd hindsight
|
||||||
|
./scripts/dev/start-control-plane.sh
|
||||||
|
# Runs on a dynamic port (check terminal output)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Start Demo Backend
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd hindsight-cookbook/deliveryman-demo/backend
|
||||||
|
|
||||||
|
# Create virtual environment and install dependencies
|
||||||
|
python -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Create `backend/.env`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
OPENAI_API_KEY=<your-openai-api-key>
|
||||||
|
GROQ_API_KEY=<your-groq-api-key>
|
||||||
|
HINDSIGHT_API_URL=http://localhost:8888
|
||||||
|
LLM_MODEL=openai/gpt-4o
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the backend:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./run.sh
|
||||||
|
# Or manually:
|
||||||
|
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --ws wsproto --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** The `--ws wsproto` flag is required for WebSocket support. Without it, connections will fail with error 1006.
|
||||||
|
|
||||||
|
### 5. Start Demo Frontend
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd hindsight-cookbook/deliveryman-demo/frontend
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
# Runs on http://localhost:5173
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Open the Demo
|
||||||
|
|
||||||
|
Navigate to http://localhost:5173 in your browser.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. The agent receives a delivery task (e.g., "Deliver Package #3954 to Victor Huang")
|
||||||
|
2. It navigates a multi-building complex with floors, elevators, and sky bridges
|
||||||
|
3. Along the way it encounters employees and learns their locations
|
||||||
|
4. After each delivery, the conversation is sent to Hindsight via the **retain** API
|
||||||
|
5. Hindsight extracts facts (employee locations, building layout) and builds **mental models**
|
||||||
|
6. On subsequent deliveries, the agent queries Hindsight to recall what it learned
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Browser (5173) → Frontend (React + Phaser)
|
||||||
|
↓ WebSocket
|
||||||
|
Backend (8000) → FastAPI + Delivery Agent
|
||||||
|
↓ HTTP
|
||||||
|
Hindsight API (8888) → Memory Engine + PostgreSQL
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
| Problem | Solution |
|
||||||
|
|---------|----------|
|
||||||
|
| WebSocket error 1006 | Restart backend with `--ws wsproto` flag |
|
||||||
|
| Mental models missing employees | Check `HINDSIGHT_API_RETAIN_EXTRACTION_MODE=custom` is set |
|
||||||
|
| Hindsight connection refused | Verify Hindsight API is running on port 8888 |
|
||||||
|
| Frontend shows "Disconnected" | Check backend is running on port 8000 |
|
||||||
|
|
@ -0,0 +1,206 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# Memory Approaches Comparison Demo
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/hindsight-litellm-demo)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
Interactive Streamlit app comparing three memory approaches for LLM applications:
|
||||||
|
|
||||||
|
1. **No Memory** - Each query is independent (baseline)
|
||||||
|
2. **Full Conversation History** - Pass entire conversation (truncated to simulate context limits)
|
||||||
|
3. **Hindsight Memory** - Intelligent semantic memory retrieval
|
||||||
|
|
||||||
|
This demo showcases how Hindsight's semantic memory outperforms traditional approaches, especially as conversations grow longer.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Set your OpenAI API key
|
||||||
|
export OPENAI_API_KEY=your-key
|
||||||
|
|
||||||
|
# 2. Start Hindsight server
|
||||||
|
docker run -d -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_PROVIDER=openai \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
|
||||||
|
# 3. Run the demo
|
||||||
|
./run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open http://localhost:8501 in your browser.
|
||||||
|
|
||||||
|
## What This Demo Shows
|
||||||
|
|
||||||
|
### The Problem with Traditional Approaches
|
||||||
|
|
||||||
|
| Approach | How it Works | Limitation |
|
||||||
|
|----------|--------------|------------|
|
||||||
|
| **No Memory** | Each query standalone | Forgets everything between messages |
|
||||||
|
| **Full History** | Pass all messages to LLM | Token limits cause truncation - loses early context |
|
||||||
|
| **Hindsight** | Semantic retrieval of relevant facts | Retrieves what's relevant regardless of when it was said |
|
||||||
|
|
||||||
|
### Key Insight
|
||||||
|
|
||||||
|
After 5-10 messages, watch the **Full Conversation History** column start losing early context due to truncation (artificially set to 4 messages to demonstrate this quickly). Meanwhile, **Hindsight Memory** can still recall facts from the beginning because it uses semantic retrieval rather than sequential history.
|
||||||
|
|
||||||
|
## Testing the Demo
|
||||||
|
|
||||||
|
1. **Introduce yourself**:
|
||||||
|
- "Hi, I'm Sarah, a data scientist at Netflix"
|
||||||
|
- "I prefer Python and love machine learning"
|
||||||
|
|
||||||
|
2. **Have several exchanges** about different topics
|
||||||
|
|
||||||
|
3. **Test recall**:
|
||||||
|
- "What programming language should I use?"
|
||||||
|
- "What do you know about me?"
|
||||||
|
|
||||||
|
Watch how the three columns respond differently as the conversation grows.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Side-by-side comparison** of all three approaches
|
||||||
|
- **Debug panels** showing what context each approach uses
|
||||||
|
- **Memory explorer** to search Hindsight memories directly
|
||||||
|
- **Configurable settings** for history truncation, max memories, etc.
|
||||||
|
- **Multi-provider support** via LiteLLM (OpenAI, Anthropic, Groq)
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Python 3.10+
|
||||||
|
- Hindsight server running (Docker recommended)
|
||||||
|
- At least one LLM API key (OpenAI recommended)
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### Using run.sh (Recommended)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set API key
|
||||||
|
export OPENAI_API_KEY=your-key
|
||||||
|
|
||||||
|
# Start Hindsight, then run:
|
||||||
|
./run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The script will check and install dependencies automatically.
|
||||||
|
|
||||||
|
### Manual Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
pip install streamlit litellm
|
||||||
|
|
||||||
|
# Install Hindsight packages
|
||||||
|
pip install hindsight-client hindsight-litellm
|
||||||
|
|
||||||
|
# Run the app
|
||||||
|
streamlit run app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Starting Hindsight Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_PROVIDER=openai \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
|
||||||
|
# Verify it's running
|
||||||
|
curl http://localhost:8888/health
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Sidebar Options
|
||||||
|
|
||||||
|
**Model Selection:**
|
||||||
|
- Provider: OpenAI, Anthropic, Groq
|
||||||
|
- Model: Various models per provider
|
||||||
|
- Custom model ID support
|
||||||
|
|
||||||
|
**Full History Config:**
|
||||||
|
- Max Messages to Keep (default: 4 to demonstrate truncation)
|
||||||
|
|
||||||
|
**Hindsight Config:**
|
||||||
|
- API URL (default: http://localhost:8888)
|
||||||
|
- Bank ID and Entity ID for memory isolation
|
||||||
|
- Max Memories to retrieve
|
||||||
|
- Recall Budget (low/mid/high)
|
||||||
|
|
||||||
|
**Generation Settings:**
|
||||||
|
- Temperature
|
||||||
|
- Max Tokens
|
||||||
|
- System Prompt
|
||||||
|
|
||||||
|
## Supported Models
|
||||||
|
|
||||||
|
### OpenAI
|
||||||
|
- gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-4, gpt-3.5-turbo
|
||||||
|
|
||||||
|
### Anthropic
|
||||||
|
- claude-3-5-sonnet-20241022, claude-3-5-haiku-20241022
|
||||||
|
- claude-3-opus-20240229, claude-3-sonnet-20240229
|
||||||
|
|
||||||
|
### Groq
|
||||||
|
- groq/llama-3.1-70b-versatile, groq/llama-3.1-8b-instant
|
||||||
|
- groq/mixtral-8x7b-32768
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Required
|
||||||
|
export OPENAI_API_KEY=sk-...
|
||||||
|
|
||||||
|
# Optional (for other providers)
|
||||||
|
export ANTHROPIC_API_KEY=sk-ant-...
|
||||||
|
export GROQ_API_KEY=gsk_...
|
||||||
|
|
||||||
|
# Optional
|
||||||
|
export HINDSIGHT_URL=http://localhost:8888
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Hindsight server not responding
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check if running
|
||||||
|
curl http://localhost:8888/health
|
||||||
|
|
||||||
|
# Start with Docker
|
||||||
|
docker run -d -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_PROVIDER=openai \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### hindsight-litellm not installed
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install hindsight-litellm
|
||||||
|
```
|
||||||
|
|
||||||
|
### API key errors
|
||||||
|
|
||||||
|
Make sure the appropriate API key is set:
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY=your-key
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [Hindsight](https://github.com/vectorize-io/hindsight) - Memory infrastructure for AI applications
|
||||||
|
- [hindsight-litellm](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/litellm) - LiteLLM integration package
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 4
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tool Learning Demo
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/hindsight-tool-learning-demo)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
An interactive Streamlit demo showing how Hindsight helps LLMs learn which tool to use when tool names are ambiguous.
|
||||||
|
|
||||||
|
## The Problem
|
||||||
|
|
||||||
|
When building AI agents with tool/function calling, tool names and descriptions aren't always clear. An LLM might randomly select between similarly-named tools, leading to incorrect behavior.
|
||||||
|
|
||||||
|
## The Scenario
|
||||||
|
|
||||||
|
This demo simulates a **customer service routing system** with two channels:
|
||||||
|
|
||||||
|
| Tool | Description (What the LLM sees) | Actual Purpose (Hidden) |
|
||||||
|
|------|--------------------------------|------------------------|
|
||||||
|
| `route_to_channel_alpha` | "Routes to channel Alpha for appropriate request types" | Financial issues (refunds, billing, payments) |
|
||||||
|
| `route_to_channel_omega` | "Routes to channel Omega for appropriate request types" | Technical issues (bugs, features, errors) |
|
||||||
|
|
||||||
|
The descriptions are **intentionally vague**! Without prior knowledge, the LLM must guess which channel handles what.
|
||||||
|
|
||||||
|
## The Solution: Learning with Hindsight
|
||||||
|
|
||||||
|
With Hindsight memory:
|
||||||
|
1. **Store routing feedback** about which channel handles which request type
|
||||||
|
2. **Retrieve learned knowledge** when making routing decisions
|
||||||
|
3. **Consistently route correctly** based on past experience
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
1. **Hindsight Server** running (Docker):
|
||||||
|
```bash
|
||||||
|
docker run -d -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_PROVIDER=openai \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **OpenAI API Key**:
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY=your-key-here
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run the Demo
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Or manually:
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
streamlit run app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to Use the Demo
|
||||||
|
|
||||||
|
### Step 1: Test Without Memory (Baseline)
|
||||||
|
|
||||||
|
1. Select a **Financial Request** (e.g., "I need a refund...")
|
||||||
|
2. Click **Route Request**
|
||||||
|
3. Observe: The "Without Hindsight" column may route incorrectly
|
||||||
|
|
||||||
|
### Step 2: Route First Customer and Learn
|
||||||
|
|
||||||
|
1. Route a customer → Both LLMs route simultaneously
|
||||||
|
2. Feedback is automatically stored to Hindsight
|
||||||
|
3. Wait ~5 seconds for Hindsight to index the memory
|
||||||
|
|
||||||
|
### Step 3: Test With Memory
|
||||||
|
|
||||||
|
1. Select another request (financial or technical)
|
||||||
|
2. Click **Route Request**
|
||||||
|
3. Observe: The "With Hindsight" column should now route correctly!
|
||||||
|
|
||||||
|
### Step 4: View Statistics
|
||||||
|
|
||||||
|
- See accuracy comparison between "Without Memory" vs "With Hindsight"
|
||||||
|
- Review test history to see the improvement over time
|
||||||
|
|
||||||
|
## Demo Features
|
||||||
|
|
||||||
|
- **Side-by-side comparison**: See routing results with and without memory
|
||||||
|
- **Pre-defined test requests**: Financial and technical scenarios
|
||||||
|
- **Custom requests**: Enter your own customer requests
|
||||||
|
- **Memory Explorer**: Query stored routing knowledge directly
|
||||||
|
- **Live statistics**: Track accuracy improvement
|
||||||
|
|
||||||
|
## Key Insight
|
||||||
|
|
||||||
|
> Even when tool names and descriptions don't reveal their purpose, Hindsight allows the LLM to **learn from experience** which tool to use for which type of request.
|
||||||
|
|
||||||
|
This is especially valuable for:
|
||||||
|
- Enterprise systems with legacy tool names
|
||||||
|
- Multi-tenant systems where tools have generic names
|
||||||
|
- Agents that need to learn organization-specific workflows
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
| Setting | Default | Description |
|
||||||
|
|---------|---------|-------------|
|
||||||
|
| Model | gpt-4o-mini | LLM model for routing decisions |
|
||||||
|
| Temperature (No Memory) | 0.7 | Randomness for baseline tests |
|
||||||
|
| Hindsight API URL | http://localhost:8888 | Hindsight server URL |
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `app.py` - Main Streamlit application
|
||||||
|
- `requirements.txt` - Python dependencies
|
||||||
|
- `run.sh` - Launch script with dependency checking
|
||||||
|
- `README.md` - This file
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 1
|
sidebar_position: 5
|
||||||
---
|
---
|
||||||
|
|
||||||
# OpenAI Agent + Hindsight Memory Integration
|
# OpenAI Agent + Hindsight Memory Integration
|
||||||
|
|
@ -7,7 +7,7 @@ sidebar_position: 1
|
||||||
|
|
||||||
:::info Complete Application
|
:::info Complete Application
|
||||||
This is a complete, runnable application demonstrating Hindsight integration.
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/openai-fitness-coach)
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/openai-fitness-coach)
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ This example showcases:
|
||||||
- **Function calling** to bridge them together
|
- **Function calling** to bridge them together
|
||||||
- **Streaming responses** for real-time interaction (enabled by default)
|
- **Streaming responses** for real-time interaction (enabled by default)
|
||||||
- **Bidirectional memory** - both user data AND coach observations stored
|
- **Bidirectional memory** - both user data AND coach observations stored
|
||||||
- **System-level post-processing** - automatic knowledge consolidation
|
- **System-level post-processing** - automatic opinion storage for reliability
|
||||||
- **Temporal-semantic memory** queries via function tools
|
- **Temporal-semantic memory** queries via function tools
|
||||||
- **Enhanced preference learning** - coach learns and respects user likes/dislikes
|
- **Enhanced preference learning** - coach learns and respects user likes/dislikes
|
||||||
- **Real-world integration pattern** for adding memory to AI agents
|
- **Real-world integration pattern** for adding memory to AI agents
|
||||||
|
|
@ -46,9 +46,9 @@ Hindsight API (returns workouts + preferences)
|
||||||
|
|
|
|
||||||
OpenAI Assistant (analyzes, gives advice)
|
OpenAI Assistant (analyzes, gives advice)
|
||||||
|
|
|
|
||||||
Function Call: store_memory(advice as experience)
|
Function Call: store_memory(advice as opinion)
|
||||||
|
|
|
|
||||||
Hindsight API (stores coach's advice, consolidates into observations)
|
Hindsight API (stores coach's observation)
|
||||||
|
|
|
|
||||||
Personalized Answer
|
Personalized Answer
|
||||||
```
|
```
|
||||||
|
|
@ -57,10 +57,10 @@ Personalized Answer
|
||||||
|
|
||||||
| Component | Standard Demo | OpenAI Integration |
|
| Component | Standard Demo | OpenAI Integration |
|
||||||
|-----------|---------------|-------------------|
|
|-----------|---------------|-------------------|
|
||||||
| **Conversation** | Hindsight `/reflect` endpoint | OpenAI Assistant API |
|
| **Conversation** | Hindsight `/think` endpoint | OpenAI Assistant API |
|
||||||
| **Memory** | Hindsight (built-in) | Hindsight (via function calling) |
|
| **Memory** | Hindsight (built-in) | Hindsight (via function calling) |
|
||||||
| **LLM** | Configured in Hindsight | OpenAI GPT-4 |
|
| **LLM** | Configured in Hindsight | OpenAI GPT-4 |
|
||||||
| **Knowledge Consolidation** | Automatic after retain | Automatic after retain |
|
| **Opinion Formation** | Automatic in `/think` | Explicit via `store_memory(type="opinion")` |
|
||||||
| **Best For** | Hindsight-native apps | Integrating memory into existing OpenAI agents |
|
| **Best For** | Hindsight-native apps | Integrating memory into existing OpenAI agents |
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
@ -126,7 +126,7 @@ retrieve_memories(query, fact_types, top_k)
|
||||||
search_workouts(after_date, before_date, workout_type)
|
search_workouts(after_date, before_date, workout_type)
|
||||||
get_nutrition_summary(after_date, before_date)
|
get_nutrition_summary(after_date, before_date)
|
||||||
get_user_goals()
|
get_user_goals()
|
||||||
get_coach_insights(about) # Retrieves observations
|
get_coach_opinions(about)
|
||||||
```
|
```
|
||||||
|
|
||||||
Each function makes API calls to Hindsight to fetch relevant memories.
|
Each function makes API calls to Hindsight to fetch relevant memories.
|
||||||
|
|
@ -191,8 +191,8 @@ The agent will automatically:
|
||||||
The OpenAI Agent can retrieve different memory types from Hindsight:
|
The OpenAI Agent can retrieve different memory types from Hindsight:
|
||||||
|
|
||||||
- **World Facts** (`fact_type: "world"`): Workouts, meals, activities
|
- **World Facts** (`fact_type: "world"`): Workouts, meals, activities
|
||||||
- **Experience Facts** (`fact_type: "experience"`): Goals, intentions, coach advice
|
- **Agent Facts** (`fact_type: "agent"`): Goals, intentions
|
||||||
- **Observations** (`fact_type: "observation"`): Consolidated knowledge about user patterns
|
- **Opinions** (`fact_type: "opinion"`): Coach's observations about patterns
|
||||||
|
|
||||||
## Customization
|
## Customization
|
||||||
|
|
||||||
|
|
@ -266,9 +266,9 @@ The key benefit: **Separation of concerns**
|
||||||
|
|
||||||
**Use Hindsight directly when:**
|
**Use Hindsight directly when:**
|
||||||
- You want a complete memory-first solution
|
- You want a complete memory-first solution
|
||||||
- You want automatic memory retrieval and observation consolidation
|
- You want automatic memory retrieval and opinion formation
|
||||||
- You want to use different LLM providers (not just OpenAI)
|
- You want to use different LLM providers (not just OpenAI)
|
||||||
- You want the `/reflect` endpoint's integrated approach
|
- You want the `/think` endpoint's integrated approach
|
||||||
|
|
||||||
## Learning Points
|
## Learning Points
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,371 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 6
|
||||||
|
---
|
||||||
|
|
||||||
|
# Sanity CMS Blog Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/sanity-blog-memory)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A Hindsight cookbook recipe demonstrating how to sync blog posts from **Sanity CMS** to Hindsight agent memory, enabling semantic search, temporal queries, and AI-powered content insights.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Blog Post Sync**: Automatically sync all blog posts from Sanity to Hindsight
|
||||||
|
- **Document-based Upsert**: Idempotent syncing with `document_id` - re-running sync updates existing content
|
||||||
|
- **Semantic Search**: Find related content using natural language queries
|
||||||
|
- **Temporal Queries**: Ask "What did I write in January 2025?"
|
||||||
|
- **Reflect for Insights**: Generate AI-powered analysis of your blog content
|
||||||
|
- **Related Content Discovery**: Power "Related Posts" features with semantic similarity
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ Sanity CMS │───────▶│ Sync Script │───────▶│ Hindsight │
|
||||||
|
│ (Content) │ GROQ │ (TypeScript) │ HTTP │ (Memory) │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ │
|
||||||
|
│ Your App │
|
||||||
|
│ - Recall │
|
||||||
|
│ - Reflect │
|
||||||
|
│ │
|
||||||
|
└─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Start Hindsight
|
||||||
|
|
||||||
|
Choose your preferred LLM provider:
|
||||||
|
|
||||||
|
**Option A: Using Docker Compose (Recommended)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set your API key
|
||||||
|
export OPENAI_API_KEY=sk-...
|
||||||
|
# OR
|
||||||
|
export GOOGLE_API_KEY=... # Gemini (free tier available)
|
||||||
|
# OR
|
||||||
|
export GROQ_API_KEY=... # Groq (free tier available)
|
||||||
|
|
||||||
|
# Start Hindsight
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option B: Using Docker directly**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY=sk-...
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
- **API**: http://localhost:8888
|
||||||
|
- **Control Plane UI**: http://localhost:9999
|
||||||
|
|
||||||
|
### 2. Configure Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy example config
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
# Edit with your values
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Required settings:
|
||||||
|
```bash
|
||||||
|
# Hindsight
|
||||||
|
HINDSIGHT_API_URL=http://localhost:8888
|
||||||
|
HINDSIGHT_BANK_ID=blog-memory
|
||||||
|
|
||||||
|
# Sanity CMS
|
||||||
|
SANITY_PROJECT_ID=your-project-id
|
||||||
|
SANITY_DATASET=production
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Install Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Sync Your Blog Posts
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run sync
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
```
|
||||||
|
=======================================
|
||||||
|
Sanity -> Hindsight Blog Sync
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Setting up memory bank...
|
||||||
|
Memory bank "blog-memory" ready
|
||||||
|
|
||||||
|
Fetching posts from Sanity CMS...
|
||||||
|
Found 10 posts to sync
|
||||||
|
|
||||||
|
Syncing posts to Hindsight...
|
||||||
|
[1/10] "Why I Chose Qwik"... done
|
||||||
|
[2/10] "Building AI Agents"... done
|
||||||
|
...
|
||||||
|
|
||||||
|
=======================================
|
||||||
|
Sync Complete
|
||||||
|
=======================================
|
||||||
|
Synced: 10 posts
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Query Your Content
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run query
|
||||||
|
```
|
||||||
|
|
||||||
|
## Query Examples
|
||||||
|
|
||||||
|
### Semantic Search
|
||||||
|
|
||||||
|
Find related content using natural language:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { recallMemory } from './hindsight-client.js';
|
||||||
|
|
||||||
|
// Find posts about AI agents
|
||||||
|
const result = await recallMemory('AI agents and automation', {
|
||||||
|
budget: 'mid',
|
||||||
|
maxTokens: 2048,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Found ${result.results.length} relevant posts`);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Temporal Queries
|
||||||
|
|
||||||
|
Ask about content from specific time periods:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Posts from January 2025
|
||||||
|
const result = await recallMemory('What did I write about in January 2025?', {
|
||||||
|
queryTimestamp: '2025-01-31T23:59:59Z',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reflect for Insights
|
||||||
|
|
||||||
|
Generate AI-powered analysis of your content:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { reflectOnMemory } from './hindsight-client.js';
|
||||||
|
|
||||||
|
// Analyze blog themes
|
||||||
|
const insights = await reflectOnMemory(
|
||||||
|
'What are the main themes of my blog? What topics do I write about most?',
|
||||||
|
{ budget: 'high' }
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(insights.text);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Related Content Discovery
|
||||||
|
|
||||||
|
Power your "Related Posts" feature:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Find posts similar to a specific article
|
||||||
|
const related = await recallMemory(
|
||||||
|
'Find posts related to "Why I Chose Qwik for My Personal Website"',
|
||||||
|
{ budget: 'mid' }
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Memory Structure
|
||||||
|
|
||||||
|
Each blog post is stored with rich metadata for optimal recall:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Blog Post: {title}
|
||||||
|
|
||||||
|
**Published:** {date}
|
||||||
|
**URL:** {base_url}/blog/{slug}
|
||||||
|
**Tags:** {tags}
|
||||||
|
**Reading Time:** {reading_time}
|
||||||
|
|
||||||
|
## Description
|
||||||
|
{description}
|
||||||
|
|
||||||
|
## Content
|
||||||
|
{full_content}
|
||||||
|
```
|
||||||
|
|
||||||
|
Key features:
|
||||||
|
- **document_id**: `post:{slug}` - Enables upsert on re-sync
|
||||||
|
- **context**: `blog-post` - Categorizes the memory type
|
||||||
|
- **timestamp**: Post publication date - Enables temporal queries
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
### 1. AI-Powered Blog Search
|
||||||
|
|
||||||
|
Replace keyword search with semantic understanding:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Old: keyword matching
|
||||||
|
const results = posts.filter(p => p.title.includes('React'));
|
||||||
|
|
||||||
|
// New: semantic understanding
|
||||||
|
const result = await recallMemory('frontend framework tutorials');
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Content Recommendation Engine
|
||||||
|
|
||||||
|
Generate personalized recommendations:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const recommendations = await reflectOnMemory(
|
||||||
|
'Based on a reader interested in "AI automation", recommend related posts'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Writing Assistant
|
||||||
|
|
||||||
|
Get topic suggestions based on your existing content:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const suggestions = await reflectOnMemory(
|
||||||
|
'What topics should I write about next? What gaps exist in my content?'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Content Analytics
|
||||||
|
|
||||||
|
Analyze your blog's evolution:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const analysis = await reflectOnMemory(
|
||||||
|
'How have my writing topics evolved over the past year?'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `HINDSIGHT_API_URL` | Hindsight API endpoint | `http://localhost:8888` |
|
||||||
|
| `HINDSIGHT_BANK_ID` | Memory bank identifier | `blog-memory` |
|
||||||
|
| `SANITY_PROJECT_ID` | Your Sanity project ID | (required) |
|
||||||
|
| `SANITY_DATASET` | Sanity dataset name | `production` |
|
||||||
|
| `SANITY_API_TOKEN` | Sanity API token (for private datasets) | (none) |
|
||||||
|
| `SANITY_API_VERSION` | Sanity API version | `2024-01-09` |
|
||||||
|
| `SITE_URL` | Your blog's base URL | `https://example.com` |
|
||||||
|
|
||||||
|
### Memory Bank Disposition
|
||||||
|
|
||||||
|
The memory bank is configured with disposition traits optimized for blog content:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
skepticism: 2, // Trusting - blog content is authoritative
|
||||||
|
literalism: 4, // Literal - exact content matters
|
||||||
|
empathy: 3, // Balanced
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extending for Other CMS Platforms
|
||||||
|
|
||||||
|
This pattern can be adapted for any CMS. The key components:
|
||||||
|
|
||||||
|
### 1. CMS Client
|
||||||
|
|
||||||
|
Replace `sanity-client.ts` with your CMS:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// contentful-client.ts
|
||||||
|
import { createClient } from 'contentful';
|
||||||
|
|
||||||
|
export async function getAllPosts(): Promise<BlogPost[]> {
|
||||||
|
const client = createClient({...});
|
||||||
|
const entries = await client.getEntries({ content_type: 'blogPost' });
|
||||||
|
return entries.items.map(transformPost);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Content Transformation
|
||||||
|
|
||||||
|
Ensure your content is formatted for semantic search:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function formatPostContent(post: BlogPost): string {
|
||||||
|
return `# ${post.title}
|
||||||
|
|
||||||
|
**Published:** ${post.date}
|
||||||
|
...
|
||||||
|
${post.content}`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Document ID Strategy
|
||||||
|
|
||||||
|
Use a consistent document ID for upsert behavior:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await retainBlogPost(content, {
|
||||||
|
documentId: `post:${post.slug}`, // Unique, stable identifier
|
||||||
|
timestamp: post.date,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "Connection refused" error
|
||||||
|
|
||||||
|
Make sure Hindsight is running:
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
curl http://localhost:8888/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### "No posts found" during sync
|
||||||
|
|
||||||
|
Check your Sanity configuration:
|
||||||
|
```bash
|
||||||
|
# Verify project ID
|
||||||
|
echo $SANITY_PROJECT_ID
|
||||||
|
|
||||||
|
# Test GROQ query
|
||||||
|
npx sanity query '*[_type == "post"][0..2]{title}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Slow recall/reflect responses
|
||||||
|
|
||||||
|
This is normal for the first query as Hindsight builds embeddings. Subsequent queries are faster. Use `budget: 'low'` for faster responses at the cost of recall quality.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [Hindsight Documentation](https://hindsight.vectorize.io/)
|
||||||
|
- [Hindsight GitHub](https://github.com/vectorize-io/hindsight)
|
||||||
|
- [Sanity CMS Documentation](https://www.sanity.io/docs)
|
||||||
|
- [Hindsight Cookbook](https://github.com/vectorize-io/hindsight-cookbook)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
@ -0,0 +1,276 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 7
|
||||||
|
---
|
||||||
|
|
||||||
|
# Stance Tracker
|
||||||
|
|
||||||
|
|
||||||
|
:::info Complete Application
|
||||||
|
This is a complete, runnable application demonstrating Hindsight integration.
|
||||||
|
[**View source on GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/stancetracker)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
An AI-powered application that tracks political candidates' stances on issues over time using Hindsight memory system and web scraping.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Geographic Targeting**: Track stances by country, state/province, and city
|
||||||
|
- **Multi-Candidate Tracking**: Monitor multiple candidates simultaneously
|
||||||
|
- **Temporal Analysis**: Historical stance tracking with configurable time ranges
|
||||||
|
- **Automated Scraping**: Periodic content collection with configurable frequencies (hourly/daily/weekly)
|
||||||
|
- **Stance Change Detection**: Automatic detection and highlighting of position changes
|
||||||
|
- **Interactive Timeline**: Visual graph showing stance evolution with reference callouts
|
||||||
|
- **Source Attribution**: All stances linked to verified sources with excerpts
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Memory System (Hindsight Integration)
|
||||||
|
|
||||||
|
This app uses the Hindsight memory system from `github.com/vectorize-io/hindsight`:
|
||||||
|
|
||||||
|
1. **Banks**: Each scraper agent has its own memory bank
|
||||||
|
2. **Retain**: Stores candidate statements and web scraping results
|
||||||
|
3. **Recall**: Semantic search to retrieve relevant memories
|
||||||
|
4. **Reflect**: Generates contextual analysis using stored memories
|
||||||
|
5. **Temporal Search**: Queries memories within specific time periods
|
||||||
|
|
||||||
|
### Tech Stack
|
||||||
|
|
||||||
|
- **Frontend**: Next.js 16, React, TypeScript, TailwindCSS
|
||||||
|
- **Visualization**: Recharts for timeline graphs
|
||||||
|
- **Backend**: Next.js API routes
|
||||||
|
- **Memory**: Hindsight (from github.com/vectorize-io/hindsight)
|
||||||
|
- **Database**: JSON file storage (no database required)
|
||||||
|
- **Web Search**: Tavily API
|
||||||
|
- **LLM**: OpenAI/Anthropic/Groq (configurable)
|
||||||
|
- **Scheduling**: node-cron
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. **Hindsight API** running (from github.com/vectorize-io/hindsight)
|
||||||
|
2. **API Keys**:
|
||||||
|
- Tavily API key (for web search)
|
||||||
|
- LLM provider API key (OpenAI, Anthropic, or Groq)
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### 1. Install Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Configure Environment
|
||||||
|
|
||||||
|
Copy `.env.example` to `.env` and fill in your credentials:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit `.env`:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Hindsight API (from github.com/vectorize-io/hindsight)
|
||||||
|
HINDSIGHT_API_URL=http://localhost:8888
|
||||||
|
|
||||||
|
# Tavily API (for web search)
|
||||||
|
TAVILY_API_KEY=your_tavily_api_key_here
|
||||||
|
|
||||||
|
# LLM Provider
|
||||||
|
LLM_PROVIDER=openai # or anthropic, groq
|
||||||
|
LLM_API_KEY=your_llm_api_key_here
|
||||||
|
LLM_MODEL=gpt-4-turbo-preview
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Start Hindsight
|
||||||
|
|
||||||
|
Clone and run Hindsight from github.com/vectorize-io/hindsight:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone and run github.com/vectorize-io/hindsight
|
||||||
|
cd /path/to/hindsight
|
||||||
|
cargo run --bin hindsight-server
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify Hindsight is running at `http://localhost:8888`
|
||||||
|
|
||||||
|
### 4. Run the Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Visit `http://localhost:3000`
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Creating a Tracking Session
|
||||||
|
|
||||||
|
1. **Set Location**: Enter country (required), state/province, and city (optional)
|
||||||
|
2. **Choose Topic**: Specify the issue to track (e.g., "Climate Change Policy")
|
||||||
|
3. **Add Candidates**: Enter names of candidates/politicians to track
|
||||||
|
4. **Configure Time Range**: Set historical start/end dates for initial analysis
|
||||||
|
5. **Set Frequency**: Choose how often to check for updates (hourly/daily/weekly)
|
||||||
|
6. **Start Tracking**: Click "Start Tracking" to begin
|
||||||
|
|
||||||
|
### Viewing Results
|
||||||
|
|
||||||
|
- **Timeline Graph**: Shows confidence levels of each candidate's stance over time
|
||||||
|
- **Stance Changes**: Red circles on the graph indicate detected position changes
|
||||||
|
- **Click Points**: Click any point to see detailed stance information and sources
|
||||||
|
- **Source Links**: Each stance includes links to original references
|
||||||
|
|
||||||
|
### Managing Sessions
|
||||||
|
|
||||||
|
- **Pause/Resume**: Temporarily stop or restart tracking
|
||||||
|
- **Run Now**: Trigger an immediate update outside the schedule
|
||||||
|
- **Status**: View current session status and frequency
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
### Sessions
|
||||||
|
|
||||||
|
- `POST /api/sessions` - Create new tracking session
|
||||||
|
- `GET /api/sessions?id={id}` - Get session details
|
||||||
|
- `GET /api/sessions` - List all sessions
|
||||||
|
- `PATCH /api/sessions` - Update session status
|
||||||
|
|
||||||
|
### Stances
|
||||||
|
|
||||||
|
- `POST /api/stances` - Process candidate stance
|
||||||
|
- `GET /api/stances?sessionId={id}&candidate={name}` - Get stances
|
||||||
|
|
||||||
|
### Scheduler
|
||||||
|
|
||||||
|
- `POST /api/scheduler` - Control session scheduling
|
||||||
|
- Actions: `start`, `stop`, `run`
|
||||||
|
|
||||||
|
## Hindsight Integration Examples
|
||||||
|
|
||||||
|
### 1. Storing Memories
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Store web scraping results
|
||||||
|
await hindsightClient.retain(bankId, articleContent, {
|
||||||
|
context: 'web_search_result',
|
||||||
|
timestamp: articleDate,
|
||||||
|
metadata: { url: articleUrl }
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Semantic Search
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Search for relevant memories
|
||||||
|
const results = await hindsightClient.recall(bankId, query, {
|
||||||
|
budget: 'high',
|
||||||
|
maxTokens: 8192
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Temporal Filtering
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Query memories up to a specific point in time
|
||||||
|
const results = await hindsightClient.recall(bankId, query, {
|
||||||
|
queryTimestamp: '2024-12-01T00:00:00Z'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Contextual Analysis
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Generate analysis using stored memories
|
||||||
|
const response = await hindsightClient.reflect(bankId,
|
||||||
|
'What is the candidate\'s stance on this issue?',
|
||||||
|
{ budget: 'high' }
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production Deployment
|
||||||
|
|
||||||
|
### Vercel Deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install Vercel CLI
|
||||||
|
npm i -g vercel
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
vercel
|
||||||
|
|
||||||
|
# Set environment variables in Vercel dashboard:
|
||||||
|
# - HINDSIGHT_API_URL
|
||||||
|
# - TAVILY_API_KEY
|
||||||
|
# - LLM_PROVIDER
|
||||||
|
# - LLM_API_KEY
|
||||||
|
# - LLM_MODEL
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: The `data/` directory for JSON storage will be ephemeral on Vercel. For production, consider using a persistent database or object storage.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
stancetracker/
|
||||||
|
├── app/
|
||||||
|
│ ├── api/ # API routes
|
||||||
|
│ ├── globals.css # Global styles
|
||||||
|
│ ├── layout.tsx # Root layout
|
||||||
|
│ └── page.tsx # Main page
|
||||||
|
├── components/ # React components
|
||||||
|
├── lib/
|
||||||
|
│ ├── db/ # JSON database utilities
|
||||||
|
│ ├── hindsight-client.ts # Hindsight API client
|
||||||
|
│ ├── llm-client.ts # LLM provider client
|
||||||
|
│ ├── web-scraper.ts # Tavily web scraper
|
||||||
|
│ ├── scraper-agent.ts # Content scraper
|
||||||
|
│ ├── rag-system.ts # Memory retrieval
|
||||||
|
│ ├── stance-extractor.ts # Stance analysis
|
||||||
|
│ ├── stance-pipeline.ts # Main pipeline
|
||||||
|
│ └── scheduler.ts # Job scheduling
|
||||||
|
└── types/ # TypeScript types
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding New LLM Providers
|
||||||
|
|
||||||
|
Edit `lib/llm-client.ts` and add a new method:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
private async newProviderComplete(messages, options) {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
- **Web Search**: Uses Tavily API which has rate limits
|
||||||
|
- **Source Verification**: Manual verification recommended for critical applications
|
||||||
|
- **Stance Extraction**: LLM-based, subject to model limitations
|
||||||
|
- **Storage**: JSON file storage is not suitable for high-scale production use
|
||||||
|
- **Rate Limits**: Respect API rate limits for Tavily, Hindsight, and LLM providers
|
||||||
|
|
||||||
|
## Future Enhancements
|
||||||
|
|
||||||
|
- [ ] Real-time social media monitoring
|
||||||
|
- [ ] Speech/video transcription analysis
|
||||||
|
- [ ] Multi-language support
|
||||||
|
- [ ] Sentiment analysis integration
|
||||||
|
- [ ] Comparative analysis dashboard
|
||||||
|
- [ ] Export to CSV/PDF
|
||||||
|
- [ ] Email notifications for stance changes
|
||||||
|
- [ ] Public API for third-party integrations
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues or questions, please check:
|
||||||
|
- Hindsight documentation: `github.com/vectorize-io/hindsight/README.md`
|
||||||
|
- Tavily API docs: https://tavily.com/
|
||||||
|
- Project issues: Create an issue in the repository
|
||||||
|
|
@ -15,13 +15,25 @@ Practical patterns, recipes, and complete applications for building with Hindsig
|
||||||
{ title: "Per-User Memory", href: "/cookbook/recipes/per-user-memory" },
|
{ title: "Per-User Memory", href: "/cookbook/recipes/per-user-memory" },
|
||||||
{ title: "Support Agent with Shared Knowledge", href: "/cookbook/recipes/support-agent-shared-knowledge" },
|
{ title: "Support Agent with Shared Knowledge", href: "/cookbook/recipes/support-agent-shared-knowledge" },
|
||||||
{ title: "Memory with LiteLLM", href: "/cookbook/recipes/litellm-memory-demo" },
|
{ title: "Memory with LiteLLM", href: "/cookbook/recipes/litellm-memory-demo" },
|
||||||
{ title: "Routing Tool Learning", href: "/cookbook/recipes/tool-learning-demo" }
|
{ title: "Routing Tool Learning", href: "/cookbook/recipes/tool-learning-demo" },
|
||||||
|
{ title: "Fitness Coach with Hindsight Memory", href: "/cookbook/recipes/fitness_tracker" },
|
||||||
|
{ title: "Healthcare Assistant with Hindsight Memory", href: "/cookbook/recipes/healthcare_assistant" },
|
||||||
|
{ title: "Movie Recommendation Assistant with Hindsight Memory", href: "/cookbook/recipes/movie_recommendation" },
|
||||||
|
{ title: "Personal AI Assistant with Hindsight Memory", href: "/cookbook/recipes/personal_assistant" },
|
||||||
|
{ title: "Personalized Search Agent with Hindsight Memory", href: "/cookbook/recipes/personalized_search" },
|
||||||
|
{ title: "Study Buddy with Hindsight Memory", href: "/cookbook/recipes/study_buddy" }
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RecipeCarousel
|
<RecipeCarousel
|
||||||
title="Applications"
|
title="Applications"
|
||||||
items={[
|
items={[
|
||||||
{ title: "OpenAI Agent + Hindsight Memory Integration", href: "/cookbook/applications/openai-fitness-coach" }
|
{ title: "Chat Memory App", href: "/cookbook/applications/chat-memory" },
|
||||||
|
{ title: "Deliveryman Demo", href: "/cookbook/applications/deliveryman-demo" },
|
||||||
|
{ title: "Memory Approaches Comparison Demo", href: "/cookbook/applications/hindsight-litellm-demo" },
|
||||||
|
{ title: "Tool Learning Demo", href: "/cookbook/applications/hindsight-tool-learning-demo" },
|
||||||
|
{ title: "OpenAI Agent + Hindsight Memory Integration", href: "/cookbook/applications/openai-fitness-coach" },
|
||||||
|
{ title: "Sanity CMS Blog Memory", href: "/cookbook/applications/sanity-blog-memory" },
|
||||||
|
{ title: "Stance Tracker", href: "/cookbook/applications/stancetracker" }
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,306 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 6
|
||||||
|
---
|
||||||
|
|
||||||
|
# Fitness Coach with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/fitness_tracker.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A personalized fitness assistant that tracks your workouts, diet, recovery, and progress over time to give contextual advice.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Logs workout sessions with exercises and weights
|
||||||
|
- Tracks meals and dietary preferences
|
||||||
|
- Monitors recovery and sleep patterns
|
||||||
|
- Provides personalized training advice
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
!pip install -q hindsight-client openai nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure OpenAI API Key
|
||||||
|
|
||||||
|
Enter your OpenAI API key when prompted (used by both Hindsight and the demo).
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
print("API key configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
USER_ID = "fitness-user-demo"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def log_workout(workout_details: str) -> str:
|
||||||
|
"""Log a workout session with timestamp."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"{today} - WORKOUT LOG: {workout_details}",
|
||||||
|
metadata={"category": "workout", "date": today},
|
||||||
|
)
|
||||||
|
return f"Logged workout for {today}: {workout_details}"
|
||||||
|
|
||||||
|
|
||||||
|
def log_meal(meal_details: str) -> str:
|
||||||
|
"""Log a meal with timestamp."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"{today} - MEAL LOG: {meal_details}",
|
||||||
|
metadata={"category": "nutrition", "date": today},
|
||||||
|
)
|
||||||
|
return f"Logged meal for {today}: {meal_details}"
|
||||||
|
|
||||||
|
|
||||||
|
def log_recovery(recovery_details: str) -> str:
|
||||||
|
"""Log recovery information (sleep, soreness, etc.)."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"{today} - RECOVERY LOG: {recovery_details}",
|
||||||
|
metadata={"category": "recovery", "date": today},
|
||||||
|
)
|
||||||
|
return f"Logged recovery for {today}: {recovery_details}"
|
||||||
|
|
||||||
|
|
||||||
|
def store_user_profile(profile_info: str) -> str:
|
||||||
|
"""Store user profile information."""
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"USER PROFILE: {profile_info}",
|
||||||
|
metadata={"category": "profile"},
|
||||||
|
)
|
||||||
|
return f"Stored profile info: {profile_info}"
|
||||||
|
|
||||||
|
|
||||||
|
def fitness_coach(user_query: str) -> str:
|
||||||
|
"""Get personalized fitness advice based on query and user history."""
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=f"fitness workout diet recovery goals {user_query}",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
|
||||||
|
memory_context = ""
|
||||||
|
if memories and memories.results:
|
||||||
|
memory_context = "\n".join(f"- {m.text}" for m in memories.results[:10])
|
||||||
|
|
||||||
|
system_prompt = f"""You are a knowledgeable and supportive fitness coach.
|
||||||
|
You have access to the user's workout history, diet logs, recovery notes, and personal profile.
|
||||||
|
|
||||||
|
What you know about this user:
|
||||||
|
{memory_context if memory_context else "No history recorded yet."}
|
||||||
|
|
||||||
|
Provide personalized, actionable advice based on their:
|
||||||
|
- Training history and progress
|
||||||
|
- Dietary preferences and restrictions
|
||||||
|
- Recovery patterns
|
||||||
|
- Personal goals
|
||||||
|
|
||||||
|
Be encouraging but realistic. Reference their specific history when relevant."""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_query},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=600,
|
||||||
|
)
|
||||||
|
|
||||||
|
advice = response.choices[0].message.content
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"User asked: {user_query}\nCoach advised: {advice[:200]}...",
|
||||||
|
metadata={"category": "coaching"},
|
||||||
|
)
|
||||||
|
|
||||||
|
return advice
|
||||||
|
|
||||||
|
|
||||||
|
def get_progress_report() -> str:
|
||||||
|
"""Generate a progress report based on workout history."""
|
||||||
|
report = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query="""Analyze this user's fitness journey:
|
||||||
|
1. How consistent have they been with workouts?
|
||||||
|
2. What progress have they made (weight lifted, exercises)?
|
||||||
|
3. How is their recovery and sleep?
|
||||||
|
4. What dietary patterns do you notice?
|
||||||
|
5. What should they focus on next?""",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return report.text if hasattr(report, 'text') else str(report)
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Set Up User Profile
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Setting up user profile...")
|
||||||
|
|
||||||
|
profile_data = [
|
||||||
|
"Name: Anish, Age: 26, Height: 5'10\", Weight: 72kg",
|
||||||
|
"Goal: Building lean muscle, started gym 6 months ago",
|
||||||
|
"Routine: Push-pull-legs split, 5x per week",
|
||||||
|
"Rest days: Wednesday and Sunday",
|
||||||
|
"Dietary restriction: Mild lactose intolerance, uses almond milk",
|
||||||
|
"Health note: Occasional knee pain, avoids deep squats",
|
||||||
|
"Supplements: Whey protein (lactose-free), magnesium",
|
||||||
|
"Sleep: Aims for 7+ hours, performance drops under 6 hours",
|
||||||
|
]
|
||||||
|
|
||||||
|
for info in profile_data:
|
||||||
|
store_user_profile(info)
|
||||||
|
print(f" Stored: {info[:50]}...")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Log Workout History
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Logging workout history...")
|
||||||
|
|
||||||
|
workouts = [
|
||||||
|
"Push day: Bench press 3x8 @ 60kg, overhead press 4x12, tricep dips 3x10. Felt strong.",
|
||||||
|
"Pull day: Deadlift 3x5 @ 80kg, barbell rows 4x10, bicep curls 3x12. Good session.",
|
||||||
|
"Leg day: Leg press 4x12, hamstring curls 3x12, glute bridges 3x15. Knee felt okay.",
|
||||||
|
]
|
||||||
|
|
||||||
|
for workout in workouts:
|
||||||
|
print(f" {log_workout(workout)[:60]}...")
|
||||||
|
|
||||||
|
print("\nLogging recent meals...")
|
||||||
|
meals = [
|
||||||
|
"Post-workout: Whey shake with almond milk, banana, oats",
|
||||||
|
"Dinner: Grilled chicken, brown rice, steamed vegetables",
|
||||||
|
"Snack: Greek yogurt (lactose-free) with berries",
|
||||||
|
]
|
||||||
|
|
||||||
|
for meal in meals:
|
||||||
|
print(f" {log_meal(meal)[:60]}...")
|
||||||
|
|
||||||
|
print("\nLogging recovery notes...")
|
||||||
|
recovery = [
|
||||||
|
"Slept 7.5 hours, feeling well rested",
|
||||||
|
"Some DOMS in legs from yesterday, using turmeric milk",
|
||||||
|
]
|
||||||
|
|
||||||
|
for note in recovery:
|
||||||
|
print(f" {log_recovery(note)[:60]}...")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Talk to Your Fitness Coach
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Talking to your fitness coach...")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
queries = [
|
||||||
|
"How much was I lifting for bench press recently?",
|
||||||
|
"I slept poorly last night (only 5 hours). What should I do for today's workout?",
|
||||||
|
"Suggest a post-workout meal that works with my dietary restrictions.",
|
||||||
|
"My knee has been bothering me more. Any exercise modifications?",
|
||||||
|
]
|
||||||
|
|
||||||
|
for query in queries:
|
||||||
|
print(f"\nUser: {query}")
|
||||||
|
print("-" * 40)
|
||||||
|
response = fitness_coach(query)
|
||||||
|
print(f"Coach: {response}")
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Generate Progress Report
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Progress Report")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_progress_report())
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Try Your Own Query
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
your_query = "What exercises should I do today?" # Change this!
|
||||||
|
|
||||||
|
print(f"You: {your_query}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(f"Coach: {fitness_coach(your_query)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10. Cleanup
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,299 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 7
|
||||||
|
---
|
||||||
|
|
||||||
|
# Healthcare Assistant with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/healthcare_assistant.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A supportive healthcare chatbot that remembers patient history, symptoms, medications, and preferences to provide personalized guidance.
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
**This is a demo application and should NOT be used for actual medical advice. Always consult qualified healthcare professionals.**
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Tracks symptoms, medications, and allergies
|
||||||
|
- Maintains patient history across conversations
|
||||||
|
- Provides health information and wellness tips
|
||||||
|
- Schedules appointments
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
!pip install -q hindsight-client openai nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure OpenAI API Key
|
||||||
|
|
||||||
|
Enter your OpenAI API key when prompted (used by both Hindsight and the demo).
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
print("API key configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
import random
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
PATIENT_ID = "patient-demo"
|
||||||
|
|
||||||
|
def get_patient_bank_id(patient_id: str) -> str:
|
||||||
|
return f"patient-{patient_id}"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def store_patient_info(patient_id: str, info: str, category: str = "general") -> str:
|
||||||
|
"""Store patient information."""
|
||||||
|
bank_id = get_patient_bank_id(patient_id)
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=bank_id,
|
||||||
|
content=f"{today} - {category.upper()}: {info}",
|
||||||
|
metadata={"category": category, "date": today},
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"Recorded {category}: {info}"
|
||||||
|
|
||||||
|
|
||||||
|
def get_patient_history(patient_id: str, query: str) -> str:
|
||||||
|
"""Retrieve relevant patient history."""
|
||||||
|
bank_id = get_patient_bank_id(patient_id)
|
||||||
|
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=bank_id,
|
||||||
|
query=query,
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
|
||||||
|
if memories and memories.results:
|
||||||
|
return "\n".join(f"- {m.text}" for m in memories.results[:10])
|
||||||
|
return "No relevant history found."
|
||||||
|
|
||||||
|
|
||||||
|
def healthcare_chat(patient_id: str, user_message: str) -> str:
|
||||||
|
"""Chat with the healthcare assistant."""
|
||||||
|
bank_id = get_patient_bank_id(patient_id)
|
||||||
|
|
||||||
|
history = get_patient_history(
|
||||||
|
patient_id,
|
||||||
|
f"symptoms medications allergies conditions {user_message}"
|
||||||
|
)
|
||||||
|
|
||||||
|
system_prompt = f"""You are a supportive healthcare assistant chatbot.
|
||||||
|
|
||||||
|
IMPORTANT DISCLAIMERS:
|
||||||
|
- You are NOT a doctor and cannot provide medical diagnoses
|
||||||
|
- Always recommend consulting healthcare professionals for serious concerns
|
||||||
|
- Never prescribe medications or suggest stopping prescribed treatments
|
||||||
|
|
||||||
|
Your role:
|
||||||
|
- Listen empathetically to patient concerns
|
||||||
|
- Remember and reference their medical history
|
||||||
|
- Provide general health information and wellness tips
|
||||||
|
- Help track symptoms over time
|
||||||
|
- Remind about medications and appointments
|
||||||
|
- Suggest when to seek professional care
|
||||||
|
|
||||||
|
Patient History:
|
||||||
|
{history}
|
||||||
|
|
||||||
|
Guidelines:
|
||||||
|
- Be warm and supportive
|
||||||
|
- Ask clarifying questions when needed
|
||||||
|
- Reference their history when relevant
|
||||||
|
- Flag any concerning symptoms for professional review"""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_message},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=600,
|
||||||
|
)
|
||||||
|
|
||||||
|
answer = response.choices[0].message.content
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=bank_id,
|
||||||
|
content=f"Patient concern: {user_message}\nGuidance provided: {answer[:200]}...",
|
||||||
|
metadata={"category": "consultation"},
|
||||||
|
)
|
||||||
|
|
||||||
|
return answer
|
||||||
|
|
||||||
|
|
||||||
|
def get_health_summary(patient_id: str) -> str:
|
||||||
|
"""Generate a health summary for the patient."""
|
||||||
|
bank_id = get_patient_bank_id(patient_id)
|
||||||
|
|
||||||
|
summary = hindsight.reflect(
|
||||||
|
bank_id=bank_id,
|
||||||
|
query="""Summarize this patient's health profile:
|
||||||
|
1. Known conditions and diagnoses
|
||||||
|
2. Current medications
|
||||||
|
3. Allergies and sensitivities
|
||||||
|
4. Recent symptoms reported
|
||||||
|
5. Lifestyle factors mentioned
|
||||||
|
6. Any patterns or trends in their health""",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return summary.text if hasattr(summary, 'text') else str(summary)
|
||||||
|
|
||||||
|
|
||||||
|
def schedule_appointment(patient_id: str, appointment_type: str, preferred_time: str) -> str:
|
||||||
|
"""Schedule an appointment (demo)."""
|
||||||
|
confirmation_id = f"APT-{random.randint(10000, 99999)}"
|
||||||
|
|
||||||
|
store_patient_info(
|
||||||
|
patient_id,
|
||||||
|
f"Appointment scheduled: {appointment_type} - Preferred time: {preferred_time} - Confirmation: {confirmation_id}",
|
||||||
|
category="appointment"
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"Appointment requested: {appointment_type}\nPreferred time: {preferred_time}\nConfirmation ID: {confirmation_id}\n\nA staff member will confirm the exact time within 24 hours."
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Set Up Patient Profile
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Setting up patient profile...")
|
||||||
|
|
||||||
|
patient_info = [
|
||||||
|
("Age: 45, Male, Height: 5'11\", Weight: 185 lbs", "demographics"),
|
||||||
|
("Allergy: Penicillin - causes hives", "allergies"),
|
||||||
|
("Allergy: Shellfish - causes throat swelling", "allergies"),
|
||||||
|
("Current medication: Lisinopril 10mg daily for blood pressure", "medications"),
|
||||||
|
("Current medication: Metformin 500mg twice daily for Type 2 diabetes", "medications"),
|
||||||
|
("Condition: Diagnosed with Type 2 diabetes in 2020", "conditions"),
|
||||||
|
("Condition: Mild hypertension, well-controlled", "conditions"),
|
||||||
|
("Family history: Father had heart disease", "family_history"),
|
||||||
|
("Lifestyle: Sedentary job, trying to exercise more", "lifestyle"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for info, category in patient_info:
|
||||||
|
result = store_patient_info(PATIENT_ID, info, category)
|
||||||
|
print(f" {result}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Healthcare Chat
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Healthcare Chat")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
conversations = [
|
||||||
|
"Hi, I've been having headaches for the past few days. Should I be worried?",
|
||||||
|
"The headaches are mostly in the afternoon. I've also been feeling more tired than usual.",
|
||||||
|
"I've been checking my blood sugar and it's been a bit higher lately, around 140-150 fasting.",
|
||||||
|
"Can you remind me what allergies I have? I'm going to a new restaurant.",
|
||||||
|
]
|
||||||
|
|
||||||
|
for message in conversations:
|
||||||
|
print(f"\nPatient: {message}")
|
||||||
|
print("-" * 40)
|
||||||
|
response = healthcare_chat(PATIENT_ID, message)
|
||||||
|
print(f"Assistant: {response}")
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Schedule Appointment
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Scheduling Appointment")
|
||||||
|
print("=" * 60)
|
||||||
|
print(schedule_appointment(PATIENT_ID, "General checkup", "Next Tuesday afternoon"))
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Health Summary
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Patient Health Summary")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_health_summary(PATIENT_ID))
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Try Your Own Question
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
your_question = "Should I adjust my Metformin dose?" # Change this!
|
||||||
|
|
||||||
|
print(f"You: {your_question}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(f"Assistant: {healthcare_chat(PATIENT_ID, your_question)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10. Cleanup
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,246 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 8
|
||||||
|
---
|
||||||
|
|
||||||
|
# Movie Recommendation Assistant with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/movie_recommendation.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A personalized movie recommender that remembers your preferences, watch history, and tastes to give better suggestions over time.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Remembers favorite genres, directors, and actors
|
||||||
|
- Tracks movies you've watched and enjoyed
|
||||||
|
- Provides contextual recommendations based on mood
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
!pip install -q hindsight-client openai nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure OpenAI API Key
|
||||||
|
|
||||||
|
Enter your OpenAI API key when prompted (used by both Hindsight and the demo).
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
print("API key configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initialize OpenAI client
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
# Unique identifier for this user's memory bank
|
||||||
|
USER_ID = "movie-fan-demo"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
These functions demonstrate the three core Hindsight operations:
|
||||||
|
- **retain()**: Store memories
|
||||||
|
- **recall()**: Retrieve relevant memories
|
||||||
|
- **reflect()**: Synthesize insights from memories
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_recommendation(user_query: str) -> str:
|
||||||
|
"""
|
||||||
|
Get a movie recommendation based on user query and remembered preferences.
|
||||||
|
"""
|
||||||
|
# Recall relevant memories about this user's movie preferences
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=f"movie preferences tastes genres {user_query}",
|
||||||
|
budget="mid",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Build context from memories
|
||||||
|
memory_context = ""
|
||||||
|
if memories and memories.results:
|
||||||
|
memory_context = "\n".join(
|
||||||
|
f"- {m.text}" for m in memories.results[:5]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate recommendation with context
|
||||||
|
system_prompt = f"""You are a helpful movie recommendation assistant.
|
||||||
|
You remember the user's preferences and past conversations to give personalized suggestions.
|
||||||
|
|
||||||
|
What you know about this user:
|
||||||
|
{memory_context if memory_context else "No previous preferences recorded yet."}
|
||||||
|
|
||||||
|
Give thoughtful, personalized recommendations based on their tastes.
|
||||||
|
If they mention new preferences, acknowledge them."""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_query},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=500,
|
||||||
|
)
|
||||||
|
|
||||||
|
recommendation = response.choices[0].message.content
|
||||||
|
|
||||||
|
# Store this interaction for future context
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"User asked: {user_query}\nRecommendation given: {recommendation}",
|
||||||
|
metadata={"category": "movie_recommendation"},
|
||||||
|
)
|
||||||
|
|
||||||
|
return recommendation
|
||||||
|
|
||||||
|
|
||||||
|
def store_preference(preference: str) -> None:
|
||||||
|
"""Store an explicit user preference."""
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"User preference: {preference}",
|
||||||
|
metadata={"category": "preference"},
|
||||||
|
)
|
||||||
|
print(f"Stored preference: {preference}")
|
||||||
|
|
||||||
|
|
||||||
|
def get_preference_summary() -> str:
|
||||||
|
"""Get a summary of what we know about the user's movie tastes."""
|
||||||
|
summary = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query="Summarize this user's movie preferences, favorite genres, actors they like, and movies they've mentioned enjoying or disliking.",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return summary.text if hasattr(summary, 'text') else str(summary)
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Run the Demo
|
||||||
|
|
||||||
|
Watch how the assistant learns and remembers preferences across conversations.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Movie Recommendation Assistant with Memory")
|
||||||
|
print("=" * 60)
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Simulate a conversation over time
|
||||||
|
conversations = [
|
||||||
|
"I'm looking for a movie to watch tonight. Any suggestions?",
|
||||||
|
"I really loved Inception and Interstellar. Christopher Nolan is amazing!",
|
||||||
|
"Can you suggest something similar to those? I like mind-bending plots.",
|
||||||
|
"Actually, I'm not in the mood for something heavy. Something lighter?",
|
||||||
|
"I watched The Grand Budapest Hotel last week and loved it!",
|
||||||
|
"What should I watch tonight? Remember what I like!",
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, query in enumerate(conversations, 1):
|
||||||
|
print(f"\n[Conversation {i}]")
|
||||||
|
print(f"User: {query}")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
response = get_recommendation(query)
|
||||||
|
print(f"Assistant: {response}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. View Learned Preferences
|
||||||
|
|
||||||
|
Use `reflect()` to synthesize what Hindsight has learned about your movie tastes.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" What I've learned about your movie tastes:")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_preference_summary())
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Try Your Own Queries
|
||||||
|
|
||||||
|
Experiment with your own movie preferences!
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Try your own query!
|
||||||
|
your_query = "I'm in the mood for a sci-fi thriller" # Change this!
|
||||||
|
|
||||||
|
print(f"You: {your_query}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(f"Assistant: {get_recommendation(your_query)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Cleanup
|
||||||
|
|
||||||
|
Close the Hindsight client connection.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,266 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 9
|
||||||
|
---
|
||||||
|
|
||||||
|
# Personal AI Assistant with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/personal_assistant.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A general-purpose personal assistant that remembers your preferences, schedule, family, work context, and past conversations.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Remembers family, work, and personal details
|
||||||
|
- Tracks preferences and habits
|
||||||
|
- Helps with scheduling and reminders
|
||||||
|
- Maintains context across conversations
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
!pip install -q hindsight-client openai nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure OpenAI API Key
|
||||||
|
|
||||||
|
Enter your OpenAI API key when prompted (used by both Hindsight and the demo).
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
print("API key configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
USER_ID = "assistant-user-demo"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def remember(info: str, category: str = "general") -> str:
|
||||||
|
"""Store information to remember."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"{today}: {info}",
|
||||||
|
metadata={"category": category, "date": today},
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"I'll remember: {info}"
|
||||||
|
|
||||||
|
|
||||||
|
def recall_context(query: str) -> str:
|
||||||
|
"""Recall relevant memories for context."""
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=query,
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
|
||||||
|
if memories and memories.results:
|
||||||
|
return "\n".join(f"- {m.text}" for m in memories.results[:8])
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def chat(user_message: str) -> str:
|
||||||
|
"""Chat with the personal assistant."""
|
||||||
|
context = recall_context(user_message)
|
||||||
|
|
||||||
|
system_prompt = f"""You are a helpful personal AI assistant with long-term memory.
|
||||||
|
You remember the user's preferences, schedule, family, work context, and past conversations.
|
||||||
|
|
||||||
|
What you remember about this user:
|
||||||
|
{context if context else "No memories recorded yet."}
|
||||||
|
|
||||||
|
Your capabilities:
|
||||||
|
- Remember things when asked ("Remember that...", "Don't forget...")
|
||||||
|
- Recall past information ("What did I tell you about...", "When is...")
|
||||||
|
- Provide personalized suggestions based on known preferences
|
||||||
|
- Help with scheduling and reminders
|
||||||
|
- Have natural conversations while maintaining context
|
||||||
|
|
||||||
|
Be helpful, proactive, and reference relevant memories naturally."""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_message},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=500,
|
||||||
|
)
|
||||||
|
|
||||||
|
answer = response.choices[0].message.content
|
||||||
|
|
||||||
|
# Check if user is asking to remember something
|
||||||
|
lower_msg = user_message.lower()
|
||||||
|
if any(phrase in lower_msg for phrase in ["remember that", "don't forget", "remind me", "note that"]):
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"User asked to remember: {user_message}",
|
||||||
|
metadata={"category": "reminder"},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Store the interaction
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"Conversation - User: {user_message[:100]} | Assistant: {answer[:100]}",
|
||||||
|
metadata={"category": "conversation"},
|
||||||
|
)
|
||||||
|
|
||||||
|
return answer
|
||||||
|
|
||||||
|
|
||||||
|
def get_summary(topic: str = None) -> str:
|
||||||
|
"""Get a summary of memories."""
|
||||||
|
query = f"Summarize what you know about {topic}" if topic else \
|
||||||
|
"Summarize everything you know about this user"
|
||||||
|
|
||||||
|
summary = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=query,
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return summary.text if hasattr(summary, 'text') else str(summary)
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Build Context
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Building context...")
|
||||||
|
|
||||||
|
initial_context = [
|
||||||
|
("My name is Alex and I work as a product manager at TechCorp", "personal"),
|
||||||
|
("My wife's name is Sarah and we have two kids: Emma (7) and Jack (4)", "family"),
|
||||||
|
("I prefer morning meetings and try to keep afternoons for deep work", "preference"),
|
||||||
|
("My mom's birthday is March 15th", "event"),
|
||||||
|
("I'm trying to read more - currently reading 'Atomic Habits'", "hobby"),
|
||||||
|
("I have a weekly team standup every Monday at 10am", "schedule"),
|
||||||
|
("I'm allergic to cats", "health"),
|
||||||
|
("My favorite coffee is a flat white with oat milk", "preference"),
|
||||||
|
("I'm training for a half marathon in April", "goal"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for info, category in initial_context:
|
||||||
|
result = remember(info, category)
|
||||||
|
print(f" {result}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Have a Conversation
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Conversation")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
conversations = [
|
||||||
|
"Hey, what's my wife's name again?",
|
||||||
|
"Remember that my Q1 review is next Thursday at 2pm",
|
||||||
|
"I need a gift idea for my mom's birthday",
|
||||||
|
"What time is my Monday standup?",
|
||||||
|
"Can you recommend a coffee order for me?",
|
||||||
|
"What books am I reading?",
|
||||||
|
]
|
||||||
|
|
||||||
|
for message in conversations:
|
||||||
|
print(f"\nAlex: {message}")
|
||||||
|
print("-" * 40)
|
||||||
|
response = chat(message)
|
||||||
|
print(f"Assistant: {response}")
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. View Summary
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" What I Know About You")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_summary())
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Your Family")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_summary("family"))
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Try Your Own Message
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
your_message = "What should I focus on this month with my training?" # Change this!
|
||||||
|
|
||||||
|
print(f"You: {your_message}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(f"Assistant: {chat(your_message)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Cleanup
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,299 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 10
|
||||||
|
---
|
||||||
|
|
||||||
|
# Personalized Search Agent with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/personalized_search.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A search assistant that learns your preferences, location, dietary needs, and lifestyle to provide contextually relevant search results.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Learns location, dietary restrictions, and lifestyle
|
||||||
|
- Personalizes search queries based on context
|
||||||
|
- Remembers past searches and preferences
|
||||||
|
- Integrates with Tavily for real web search (optional)
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
- Tavily API key (optional, for real web search)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Tavily is optional - demo works with simulated results if not installed
|
||||||
|
!pip install -q hindsight-client openai tavily-python nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure API Keys
|
||||||
|
|
||||||
|
Enter your API keys when prompted. Tavily is optional - press Enter to skip for simulated search results.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
# Tavily is optional - for real web search
|
||||||
|
if not os.getenv("TAVILY_API_KEY"):
|
||||||
|
tavily_key = getpass.getpass("Enter your Tavily API key (or press Enter to skip): ")
|
||||||
|
if tavily_key:
|
||||||
|
os.environ["TAVILY_API_KEY"] = tavily_key
|
||||||
|
|
||||||
|
print("API keys configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
# Optional: Tavily for real web search
|
||||||
|
try:
|
||||||
|
from tavily import TavilyClient
|
||||||
|
tavily = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
|
||||||
|
HAS_TAVILY = True
|
||||||
|
print("Tavily configured - using real web search!")
|
||||||
|
except (ImportError, Exception) as e:
|
||||||
|
HAS_TAVILY = False
|
||||||
|
print("Note: Using simulated search results (Tavily not configured)")
|
||||||
|
|
||||||
|
USER_ID = "search-user-demo"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def store_preference(preference: str) -> str:
|
||||||
|
"""Store a user preference."""
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"User preference: {preference}",
|
||||||
|
metadata={"category": "preference"},
|
||||||
|
)
|
||||||
|
return f"Learned: {preference}"
|
||||||
|
|
||||||
|
|
||||||
|
def store_interaction(query: str, response: str) -> None:
|
||||||
|
"""Store a search interaction."""
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"Search query: {query}\nResult highlights: {response[:200]}",
|
||||||
|
metadata={"category": "search_history"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_context(query: str) -> str:
|
||||||
|
"""Retrieve relevant user context."""
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=f"preferences location dietary lifestyle {query}",
|
||||||
|
budget="mid",
|
||||||
|
)
|
||||||
|
|
||||||
|
if memories and memories.results:
|
||||||
|
return "\n".join(f"- {m.text}" for m in memories.results[:6])
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def personalized_search(query: str) -> str:
|
||||||
|
"""Perform a personalized search."""
|
||||||
|
user_context = get_user_context(query)
|
||||||
|
|
||||||
|
enhancement_prompt = f"""Given this user's preferences and the search query, suggest how to enhance the search.
|
||||||
|
|
||||||
|
User preferences:
|
||||||
|
{user_context if user_context else "No preferences recorded yet."}
|
||||||
|
|
||||||
|
Search query: {query}
|
||||||
|
|
||||||
|
Return a JSON object with:
|
||||||
|
- "enhanced_query": The improved search query incorporating relevant preferences
|
||||||
|
- "filters": Any specific filters to apply (e.g., "vegetarian", "within 5 miles")
|
||||||
|
- "reasoning": Brief explanation of personalizations applied"""
|
||||||
|
|
||||||
|
enhancement = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[{"role": "user", "content": enhancement_prompt}],
|
||||||
|
temperature=0.3,
|
||||||
|
max_tokens=300,
|
||||||
|
)
|
||||||
|
|
||||||
|
enhanced_info = enhancement.choices[0].message.content
|
||||||
|
|
||||||
|
# Perform the search
|
||||||
|
if HAS_TAVILY:
|
||||||
|
search_results = tavily.search(
|
||||||
|
query=query,
|
||||||
|
search_depth="advanced",
|
||||||
|
max_results=5,
|
||||||
|
)
|
||||||
|
results_text = "\n".join(
|
||||||
|
f"- {r['title']}: {r['content'][:150]}..."
|
||||||
|
for r in search_results.get('results', [])
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
results_text = f"[Simulated search results for: {query}]"
|
||||||
|
|
||||||
|
response_prompt = f"""Based on the search results and user preferences, provide a personalized summary.
|
||||||
|
|
||||||
|
User preferences:
|
||||||
|
{user_context if user_context else "No preferences recorded yet."}
|
||||||
|
|
||||||
|
Query: {query}
|
||||||
|
|
||||||
|
Search enhancement applied:
|
||||||
|
{enhanced_info}
|
||||||
|
|
||||||
|
Search results:
|
||||||
|
{results_text}
|
||||||
|
|
||||||
|
Provide a helpful, personalized response that takes into account their preferences."""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[{"role": "user", "content": response_prompt}],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=500,
|
||||||
|
)
|
||||||
|
|
||||||
|
answer = response.choices[0].message.content
|
||||||
|
store_interaction(query, answer)
|
||||||
|
|
||||||
|
return answer
|
||||||
|
|
||||||
|
|
||||||
|
def get_preference_profile() -> str:
|
||||||
|
"""Get a summary of the user's preference profile."""
|
||||||
|
profile = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query="""Summarize what we know about this user:
|
||||||
|
- Location and neighborhood
|
||||||
|
- Dietary preferences and restrictions
|
||||||
|
- Work style and schedule
|
||||||
|
- Hobbies and interests
|
||||||
|
- Family situation
|
||||||
|
- Shopping preferences""",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return profile.text if hasattr(profile, 'text') else str(profile)
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Build User Profile
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Learning user preferences...")
|
||||||
|
|
||||||
|
preferences = [
|
||||||
|
"Lives in San Francisco, Mission District",
|
||||||
|
"Works remotely as a software engineer",
|
||||||
|
"Vegetarian, prefers organic food when possible",
|
||||||
|
"Has a 5-year-old daughter named Emma",
|
||||||
|
"Enjoys hiking and outdoor activities on weekends",
|
||||||
|
"Prefers quiet coffee shops for remote work",
|
||||||
|
"Lactose intolerant, uses oat milk",
|
||||||
|
"Interested in sustainable and eco-friendly products",
|
||||||
|
"Usually free on Tuesday and Thursday afternoons",
|
||||||
|
"Husband is allergic to nuts",
|
||||||
|
]
|
||||||
|
|
||||||
|
for pref in preferences:
|
||||||
|
result = store_preference(pref)
|
||||||
|
print(f" {result}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Personalized Search Results
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Personalized Search Results")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
searches = [
|
||||||
|
"Find a good coffee shop for working remotely",
|
||||||
|
"Restaurant recommendations for a family dinner",
|
||||||
|
"Birthday gift ideas for a 5-year-old",
|
||||||
|
]
|
||||||
|
|
||||||
|
for query in searches:
|
||||||
|
print(f"\nSearch: {query}")
|
||||||
|
print("-" * 40)
|
||||||
|
result = personalized_search(query)
|
||||||
|
print(result)
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. View Preference Profile
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" User Preference Profile")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_preference_profile())
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Try Your Own Search
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
your_search = "Best hiking trails near me" # Change this!
|
||||||
|
|
||||||
|
print(f"Search: {your_search}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(personalized_search(your_search))
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Cleanup
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
|
|
@ -127,7 +127,7 @@ for r in results.results:
|
||||||
|
|
||||||
## Reflect: Generate Insights
|
## Reflect: Generate Insights
|
||||||
|
|
||||||
The `reflect` operation performs reasoning over existing memories using the bank's disposition. It retrieves relevant facts and observations to generate contextual responses.
|
The `reflect` operation performs a more thorough analysis of existing memories. This allows the agent to form new connections between memories which are then persisted as opinions and/or observations.
|
||||||
|
|
||||||
Example use cases:
|
Example use cases:
|
||||||
- An AI Project Manager reflecting on what risks need to be mitigated
|
- An AI Project Manager reflecting on what risks need to be mitigated
|
||||||
|
|
@ -142,11 +142,12 @@ print(response)
|
||||||
|
|
||||||
## Memory Types
|
## Memory Types
|
||||||
|
|
||||||
Hindsight organizes knowledge into facts and consolidated observations:
|
Hindsight organizes memory into four networks to mimic human memory:
|
||||||
|
|
||||||
- **World**: Facts about the world ("The stove gets hot")
|
- **World**: Facts about the world ("The stove gets hot")
|
||||||
- **Experience**: Agent's own experiences ("I touched the stove and it really hurt")
|
- **Experiences**: Agent's own experiences ("I touched the stove and it really hurt")
|
||||||
- **Observation**: Consolidated knowledge synthesized from facts ("Always be careful around hot surfaces")
|
- **Opinion**: Beliefs with confidence scores ("I shouldn't touch the stove again" - .99 confidence)
|
||||||
|
- **Observation**: Complex mental models derived by reflecting on facts and experiences
|
||||||
|
|
||||||
## Cleanup
|
## Cleanup
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,335 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 11
|
||||||
|
---
|
||||||
|
|
||||||
|
# Study Buddy with Hindsight Memory
|
||||||
|
|
||||||
|
|
||||||
|
:::tip Run this notebook
|
||||||
|
This recipe is available as an interactive Jupyter notebook.
|
||||||
|
[**Open in GitHub →**](https://github.com/vectorize-io/hindsight-cookbook/blob/main/notebooks/study_buddy.ipynb)
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
A personalized study assistant that tracks what you've learned, identifies knowledge gaps, and helps with spaced repetition.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Tracks study sessions and topics covered
|
||||||
|
- Monitors confidence levels per topic
|
||||||
|
- Identifies knowledge gaps
|
||||||
|
- Suggests topics for spaced repetition review
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- OpenAI API key
|
||||||
|
- Hindsight running locally via Docker (see setup below)
|
||||||
|
|
||||||
|
## Start Hindsight Locally
|
||||||
|
|
||||||
|
Before running this notebook, start Hindsight in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export OPENAI_API_KEY="your-openai-api-key"
|
||||||
|
|
||||||
|
docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
|
-e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \
|
||||||
|
-e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \
|
||||||
|
-v $HOME/.hindsight-docker:/home/hindsight/.pg0 \
|
||||||
|
ghcr.io/vectorize-io/hindsight:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Install Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
!pip install -q hindsight-client openai nest-asyncio
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Configure OpenAI API Key
|
||||||
|
|
||||||
|
Enter your OpenAI API key when prompted (used by both Hindsight and the demo).
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import getpass
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Set OpenAI API key (used by both Hindsight and the demo)
|
||||||
|
if not os.getenv("OPENAI_API_KEY"):
|
||||||
|
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
|
||||||
|
|
||||||
|
print("API key configured!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Initialize Clients
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import nest_asyncio
|
||||||
|
nest_asyncio.apply()
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from openai import OpenAI
|
||||||
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
|
# Initialize Hindsight client (connects to local Docker instance)
|
||||||
|
hindsight = Hindsight(
|
||||||
|
base_url=os.getenv("HINDSIGHT_BASE_URL", "http://localhost:8888"),
|
||||||
|
)
|
||||||
|
|
||||||
|
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
||||||
|
|
||||||
|
USER_ID = "student-demo"
|
||||||
|
|
||||||
|
print("Clients initialized!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Define Helper Functions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def record_study_session(topic: str, notes: str, confidence: str = "medium") -> str:
|
||||||
|
"""Record a study session with topic, notes, and self-assessed confidence."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
|
||||||
|
content = f"""{today} - STUDY SESSION
|
||||||
|
Topic: {topic}
|
||||||
|
Confidence Level: {confidence}
|
||||||
|
Notes: {notes}"""
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=content,
|
||||||
|
metadata={
|
||||||
|
"category": "study_session",
|
||||||
|
"topic": topic,
|
||||||
|
"confidence": confidence,
|
||||||
|
"date": today,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"Recorded study session on '{topic}' (confidence: {confidence})"
|
||||||
|
|
||||||
|
|
||||||
|
def record_question(topic: str, question: str, understood: bool) -> str:
|
||||||
|
"""Record a question asked during study."""
|
||||||
|
today = datetime.now().strftime("%B %d, %Y")
|
||||||
|
|
||||||
|
content = f"""{today} - QUESTION
|
||||||
|
Topic: {topic}
|
||||||
|
Question: {question}
|
||||||
|
Understood: {"Yes" if understood else "No - needs review"}"""
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=content,
|
||||||
|
metadata={
|
||||||
|
"category": "question",
|
||||||
|
"topic": topic,
|
||||||
|
"understood": str(understood),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"Recorded question on '{topic}'"
|
||||||
|
|
||||||
|
|
||||||
|
def study_buddy(user_query: str) -> str:
|
||||||
|
"""Interact with the study buddy."""
|
||||||
|
memories = hindsight.recall(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=f"study session topic notes questions {user_query}",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
|
||||||
|
memory_context = ""
|
||||||
|
if memories and memories.results:
|
||||||
|
memory_context = "\n".join(f"- {m.text}" for m in memories.results[:8])
|
||||||
|
|
||||||
|
system_prompt = f"""You are a helpful study buddy and tutor.
|
||||||
|
You have access to the student's study history, including:
|
||||||
|
- Topics they've studied and their notes
|
||||||
|
- Their self-assessed confidence levels
|
||||||
|
- Questions they've asked and whether they understood the answers
|
||||||
|
|
||||||
|
Study History:
|
||||||
|
{memory_context if memory_context else "No study history recorded yet."}
|
||||||
|
|
||||||
|
Your role:
|
||||||
|
1. Answer questions about topics they're studying
|
||||||
|
2. Identify knowledge gaps based on their history
|
||||||
|
3. Suggest topics to review (spaced repetition)
|
||||||
|
4. Provide encouragement and study tips
|
||||||
|
5. Connect new concepts to things they've already learned
|
||||||
|
|
||||||
|
Be supportive and pedagogical. Reference their previous learning when relevant."""
|
||||||
|
|
||||||
|
response = openai_client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_query},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=800,
|
||||||
|
)
|
||||||
|
|
||||||
|
answer = response.choices[0].message.content
|
||||||
|
|
||||||
|
hindsight.retain(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
content=f"Student asked: {user_query}\nExplanation given: {answer[:300]}...",
|
||||||
|
metadata={"category": "tutoring"},
|
||||||
|
)
|
||||||
|
|
||||||
|
return answer
|
||||||
|
|
||||||
|
|
||||||
|
def get_review_suggestions() -> str:
|
||||||
|
"""Get suggestions for topics to review."""
|
||||||
|
suggestions = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query="""Analyze this student's study history and suggest:
|
||||||
|
1. Topics with low confidence that need more review
|
||||||
|
2. Topics studied a while ago that should be revisited
|
||||||
|
3. Questions that weren't fully understood
|
||||||
|
4. Connections between topics they might have missed
|
||||||
|
|
||||||
|
Prioritize by what would most improve their understanding.""",
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return suggestions.text if hasattr(suggestions, 'text') else str(suggestions)
|
||||||
|
|
||||||
|
|
||||||
|
def get_knowledge_summary(topic: str = None) -> str:
|
||||||
|
"""Get a summary of what the student knows."""
|
||||||
|
query = f"Summarize what this student knows about {topic}" if topic else \
|
||||||
|
"Summarize this student's overall knowledge and progress"
|
||||||
|
|
||||||
|
summary = hindsight.reflect(
|
||||||
|
bank_id=USER_ID,
|
||||||
|
query=query,
|
||||||
|
budget="high",
|
||||||
|
)
|
||||||
|
return summary.text if hasattr(summary, 'text') else str(summary)
|
||||||
|
|
||||||
|
print("Helper functions defined!")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Record Study Sessions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Recording study sessions...")
|
||||||
|
|
||||||
|
sessions = [
|
||||||
|
{
|
||||||
|
"topic": "Classical Mechanics - Newton's Laws",
|
||||||
|
"notes": "Covered F=ma, action-reaction pairs, inertia. Solved problems on inclined planes.",
|
||||||
|
"confidence": "high",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"topic": "Classical Mechanics - Conservation of Momentum",
|
||||||
|
"notes": "Elastic vs inelastic collisions. Struggled with 2D collision problems.",
|
||||||
|
"confidence": "low",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"topic": "Classical Mechanics - Generalized Coordinates",
|
||||||
|
"notes": "Introduction to Lagrangian mechanics. Degrees of freedom concept.",
|
||||||
|
"confidence": "medium",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"topic": "Waves - Simple Harmonic Motion",
|
||||||
|
"notes": "SHM equations, period, frequency. Connected to springs and pendulums.",
|
||||||
|
"confidence": "high",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"topic": "Waves - Frequency Domain",
|
||||||
|
"notes": "Started Fourier transforms. Math is confusing, need more practice.",
|
||||||
|
"confidence": "low",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
for session in sessions:
|
||||||
|
result = record_study_session(**session)
|
||||||
|
print(f" {result}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Record Questions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("Recording questions...")
|
||||||
|
|
||||||
|
questions = [
|
||||||
|
("Conservation of Momentum", "Why is momentum conserved in collisions?", True),
|
||||||
|
("Conservation of Momentum", "How do I solve 2D collision problems?", False),
|
||||||
|
("Generalized Coordinates", "What's the advantage of Lagrangian over Newtonian?", True),
|
||||||
|
("Frequency Domain", "When do I use Fourier transforms vs Laplace?", False),
|
||||||
|
]
|
||||||
|
|
||||||
|
for topic, question, understood in questions:
|
||||||
|
result = record_question(topic, question, understood)
|
||||||
|
print(f" {result}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Interactive Study Session
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Study Session")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
queries = [
|
||||||
|
"Can you explain generalized coordinates again? I remember we covered it but I'm fuzzy on the details.",
|
||||||
|
"What topics should I review before my exam next week?",
|
||||||
|
"I'm still confused about 2D collision problems. Can you walk me through an example?",
|
||||||
|
]
|
||||||
|
|
||||||
|
for query in queries:
|
||||||
|
print(f"\nStudent: {query}")
|
||||||
|
print("-" * 40)
|
||||||
|
response = study_buddy(query)
|
||||||
|
print(f"Study Buddy: {response}")
|
||||||
|
time.sleep(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Get Review Suggestions
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Recommended Review Topics")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_review_suggestions())
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Knowledge Summary
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("=" * 60)
|
||||||
|
print(" Knowledge Summary")
|
||||||
|
print("=" * 60)
|
||||||
|
print(get_knowledge_summary())
|
||||||
|
```
|
||||||
|
|
||||||
|
## 10. Try Your Own Question
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
your_question = "What are my biggest knowledge gaps right now?" # Change this!
|
||||||
|
|
||||||
|
print(f"You: {your_question}")
|
||||||
|
print("-" * 40)
|
||||||
|
print(f"Study Buddy: {study_buddy(your_question)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 11. Cleanup
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
hindsight.close()
|
||||||
|
print("Client connection closed.")
|
||||||
|
```
|
||||||
|
|
@ -158,21 +158,16 @@ Use your ChatGPT Plus or Pro subscription for Hindsight without separate OpenAI
|
||||||
4. **Configure Hindsight:**
|
4. **Configure Hindsight:**
|
||||||
```bash
|
```bash
|
||||||
export HINDSIGHT_API_LLM_PROVIDER=openai-codex
|
export HINDSIGHT_API_LLM_PROVIDER=openai-codex
|
||||||
export HINDSIGHT_API_LLM_MODEL=gpt-5.2-codex # or gpt-5.1-codex
|
# export HINDSIGHT_API_LLM_MODEL=gpt-5.1-codex # defaults to gpt-5.2-codex
|
||||||
# No API key needed - reads from ~/.codex/auth.json automatically
|
# No API key needed - reads from ~/.codex/auth.json automatically
|
||||||
```
|
```
|
||||||
|
|
||||||
5. **Start Hindsight:**
|
5. **Start Hindsight:**
|
||||||
```bash
|
```bash
|
||||||
./scripts/dev/start-api.sh
|
hindsight-api
|
||||||
```
|
```
|
||||||
|
|
||||||
**Available Models:**
|
You can use any model supported by OpenAI Codex CLI
|
||||||
- `gpt-5.2-codex` - Latest frontier agentic coding model (default)
|
|
||||||
- `gpt-5.2` - Latest frontier model
|
|
||||||
- `gpt-5.1-codex` - Previous generation coding model
|
|
||||||
- `gpt-5.1-codex-max` - Maximum context variant
|
|
||||||
- `gpt-5.1-codex-mini` - Lightweight variant
|
|
||||||
|
|
||||||
**Important Notes:**
|
**Important Notes:**
|
||||||
- OAuth tokens are stored in `~/.codex/auth.json`
|
- OAuth tokens are stored in `~/.codex/auth.json`
|
||||||
|
|
@ -186,9 +181,6 @@ If authentication fails:
|
||||||
```bash
|
```bash
|
||||||
# Re-login to refresh tokens
|
# Re-login to refresh tokens
|
||||||
codex auth login
|
codex auth login
|
||||||
|
|
||||||
# Check auth file exists and has correct format
|
|
||||||
cat ~/.codex/auth.json | python3 -c "import json, sys; d=json.load(sys.stdin); print('auth_mode:', d.get('auth_mode')); print('has tokens:', 'tokens' in d)"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -225,50 +217,22 @@ Use your Claude Pro or Max subscription for Hindsight without separate Anthropic
|
||||||
4. **Configure Hindsight:**
|
4. **Configure Hindsight:**
|
||||||
```bash
|
```bash
|
||||||
export HINDSIGHT_API_LLM_PROVIDER=claude-code
|
export HINDSIGHT_API_LLM_PROVIDER=claude-code
|
||||||
export HINDSIGHT_API_LLM_MODEL=claude-sonnet-4-5-20250929
|
|
||||||
# No API key needed - uses claude auth login credentials
|
# No API key needed - uses claude auth login credentials
|
||||||
```
|
```
|
||||||
|
|
||||||
5. **Start Hindsight:**
|
5. **Start Hindsight:**
|
||||||
```bash
|
```bash
|
||||||
./scripts/dev/start-api.sh
|
hindsight-api
|
||||||
```
|
```
|
||||||
|
|
||||||
**Available Models:**
|
You can use any model supported by Claude Code CLI.
|
||||||
- `claude-sonnet-4-5-20250929` - Latest Claude Sonnet (default)
|
|
||||||
- `claude-opus-4-20250514` - Claude Opus for complex tasks
|
|
||||||
- `claude-sonnet-3-5-20241022` - Previous generation Sonnet
|
|
||||||
- Any model supported by Claude Code CLI
|
|
||||||
|
|
||||||
**Important Notes:**
|
**Important Notes:**
|
||||||
- Authentication handled by Claude Agent SDK (uses bundled CLI)
|
- Authentication handled by Claude Agent SDK (uses bundled CLI)
|
||||||
- Credentials managed securely by Claude Code
|
- Credentials managed securely by Claude Code
|
||||||
- Usage billed to your Claude subscription (not separate API costs)
|
- Usage billed to your Claude subscription (not separate API costs)
|
||||||
- Includes Claude Agent SDK as dependency (auto-installed)
|
|
||||||
- For personal development use only (see Claude Terms of Service)
|
- For personal development use only (see Claude Terms of Service)
|
||||||
|
|
||||||
**Troubleshooting:**
|
|
||||||
|
|
||||||
If authentication fails:
|
|
||||||
```bash
|
|
||||||
# Re-login to refresh credentials
|
|
||||||
claude auth login
|
|
||||||
|
|
||||||
# Check Claude CLI is working
|
|
||||||
claude --version
|
|
||||||
|
|
||||||
# Test authentication directly
|
|
||||||
claude query "test"
|
|
||||||
```
|
|
||||||
|
|
||||||
If the SDK is not found:
|
|
||||||
```bash
|
|
||||||
# Install Claude Agent SDK
|
|
||||||
pip install claude-agent-sdk
|
|
||||||
# Or with uv
|
|
||||||
uv add claude-agent-sdk
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Embedding Model
|
## Embedding Model
|
||||||
|
|
|
||||||
|
|
@ -238,6 +238,36 @@
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
"id": "cookbook/recipes/tool-learning-demo",
|
"id": "cookbook/recipes/tool-learning-demo",
|
||||||
"label": "Routing Tool Learning"
|
"label": "Routing Tool Learning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/recipes/fitness_tracker",
|
||||||
|
"label": "Fitness Coach with Hindsight Memory"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/recipes/healthcare_assistant",
|
||||||
|
"label": "Healthcare Assistant with Hindsight Memory"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/recipes/movie_recommendation",
|
||||||
|
"label": "Movie Recommendation Assistant with Hindsight Memory"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/recipes/personal_assistant",
|
||||||
|
"label": "Personal AI Assistant with Hindsight Memory"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/recipes/personalized_search",
|
||||||
|
"label": "Personalized Search Agent with Hindsight Memory"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/recipes/study_buddy",
|
||||||
|
"label": "Study Buddy with Hindsight Memory"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -246,10 +276,40 @@
|
||||||
"label": "Applications",
|
"label": "Applications",
|
||||||
"collapsible": false,
|
"collapsible": false,
|
||||||
"items": [
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/applications/chat-memory",
|
||||||
|
"label": "Chat Memory App"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/applications/deliveryman-demo",
|
||||||
|
"label": "Deliveryman Demo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/applications/hindsight-litellm-demo",
|
||||||
|
"label": "Memory Approaches Comparison Demo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/applications/hindsight-tool-learning-demo",
|
||||||
|
"label": "Tool Learning Demo"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
"id": "cookbook/applications/openai-fitness-coach",
|
"id": "cookbook/applications/openai-fitness-coach",
|
||||||
"label": "OpenAI Agent + Hindsight Memory Integration"
|
"label": "OpenAI Agent + Hindsight Memory Integration"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/applications/sanity-blog-memory",
|
||||||
|
"label": "Sanity CMS Blog Memory"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "cookbook/applications/stancetracker",
|
||||||
|
"label": "Stance Tracker"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue