An AI-powered journaling platform that enables users to journal via SMS text messages and receive intelligent, empathetic responses powered by advanced language models.
Click the image above to watch the full demo on X.
- Whats-App & Imessage based journaling: Journal by simply texting your thoughts and experiences
- AI-powered responses: Get personalized, empathetic responses from an AI companion
- Emotion analysis: Automatic emotion classification of journal entries
- Memory & reflection: AI can help you reflect on past experiences using semantic search
- Dual response modes:
- Reflection mode: Helps you revisit and reflect on past journal entries
- Current thoughts mode: Responds to your immediate feelings and experiences
- Multimodal Input: Works with images of written and voice entires
- Vector similarity search: Find related past entries using advanced embeddings
- User management: Phone number-based user accounts
- FastAPI: Modern, fast web framework for building APIs
- PostgreSQL with pgvector: Vector database for storing embeddings and journal entries
- SQLAlchemy: Python SQL toolkit and Object Relational Mapping (ORM)
- Alembic: Database migration tool
- OpenAI GPT-4o: Primary conversational AI model
- HuggingFace Transformers: Text embeddings using GTE-base model
- RoBERTa: Emotion classification (go_emotions model)
- LlamaIndex: Retrieval-Augmented Generation (RAG) framework
- LangChain: Chat memory and conversation management
- Cohere: Re-ranking for improved search results
- SendBlue API: SMS messaging service for text-based interactions
sequenceDiagram
autonumber
participant U as User
participant SB as SendBlue (SMS)
participant API as FastAPI /entries
participant CRUD as CRUD/Models
participant DB as PostgreSQL + pgvector
participant H as helpers (AI pipeline)
participant LLM as OpenAI (ChatOpenAI)
participant RAG as LlamaIndex + CustomSQLRetriever
participant CH as Cohere (Re-rank)
U->>SB: Send SMS
SB->>API: POST /entries (from_number, content, date_sent, β¦)
API->>CRUD: get_user_by_phone_number(from_number)
CRUD->>DB: SELECT users WHERE phone_number=β¦
DB-->>CRUD: user or none
CRUD-->>API: user found
API->>API: tokenizer.embed(content), tokenizer.emotion(content)
API->>CRUD: query_embeddings(user.id, embedding) // warms cache
API->>H: generate_response(user_phone, content, date_sent, settings, db)
rect rgb(245,245,245)
note over H,LLM: AI Response Pipeline (two modes)
H->>RAG: CustomSQLRetriever.retrieve(query)
RAG->>DB: Vector similarity search (entries.embedding <=> query)
DB-->>RAG: Top-k entries with similarity
RAG->>CH: Rerank top candidates
CH-->>H: Reranked nodes
H->>LLM: Prompt + context (reflection) OR conversational prompt (current thoughts)
LLM-->>H: Generated response
end
H-->>API: response
API->>CRUD: create_user_entry(EntryCreate{content, embedding, emotions}, author_id)
CRUD->>DB: INSERT INTO entries β¦
DB-->>CRUD: inserted row
API->>H: send_message(user_phone, response)
H->>H: split_paragraph_into_sentences (emoji-aware)
loop For each sentence
H->>SB: POST /api/send-message {number, content}
end
SB-->>U: SMS message(s)
API-->>SB: 200 OK (returns response text)
flowchart LR
subgraph CLIENT [Client]
U["User SMS"]
end
subgraph MESSAGING [Messaging]
SB["SendBlue SMS Webhook"]
end
subgraph API ["FastAPI Application"]
EP1["POST /entries/ MessagePayload"]
EP2["POST /users/ UserCreate"]
HLP["helpers.py"]
CR["crud.py"]
TOK["tokenizer embed, emotion"]
end
subgraph AI ["AI Layer"]
LC["LangChain ChatOpenAI gpt-4o"]
LI["LlamaIndex Query/RAG"]
CSR["CustomSQLRetriever utils.py"]
RR["Cohere Re-rank"]
end
subgraph DATA ["PostgreSQL + pgvector"]
USERS[(users)]
ENTRIES[(entries: content, emotions, embedding Vector 768)]
end
U --> SB --> EP1
EP2 --> CR --> USERS
EP1 --> CR --> USERS
EP1 --> TOK
EP1 --> HLP
HLP --> CSR --> ENTRIES
CSR --> RR --> HLP
HLP --> LC --> HLP
HLP --> CR --> ENTRIES
HLP --> SB
erDiagram
USERS ||--o{ ENTRIES : "has many"
USERS {
int id PK
string phone_number "length 12"
datetime created_at
string hashed_password
}
ENTRIES {
int id PK
datetime created_at
date date
string emotions "nullable"
text content
vector[768] embedding "pgvector"
int author_id FK "-> users.id"
}
- Python 3.9+
- PostgreSQL with pgvector extension
- API keys for:
- OpenAI
- Cohere
- LangChain (for tracing)
- SendBlue (for imessage)
-
Clone the repository
git clone https://github.com/vkodithala/tmj-api.git cd tmj-api -
Install dependencies
pip install -r requirements.txt
-
Set up environment variables Create a
.envfile in the root directory:# OpenAI Configuration OPENAI_API_KEY=your_openai_api_key_here # Cohere Configuration COHERE_API_KEY=your_cohere_api_key_here # LangChain Configuration (for tracing) LANGCHAIN_API_KEY=your_langchain_api_key_here # SendBlue SMS Configuration SENDBLUE_APIURL=https://api.sendblue.co/api/send-message SENDBLUE_APIKEY=your_sendblue_api_key_here SENDBLUE_APISECRET=your_sendblue_api_secret_here
-
Set up PostgreSQL with pgvector
-- Install pgvector extension CREATE EXTENSION vector; -- Update your database connection string in app/database.py
-
Run database migrations
alembic upgrade head
-
Start the API server
uvicorn app.main:app --reload
The API will be available at http://localhost:8000
POST /users/Creates a new user account and sends a welcome message.
Request Body:
{
"phone_number": "+1234567890",
"password": "user_password"
}Response:
{
"id": 1,
"phone_number": "+1234567890",
"created_at": "2024-01-01T00:00:00",
"entries": []
}POST /entries/Processes incoming journal entries from SMS webhook, analyzes content, and sends AI-generated response.
Request Body (SendBlue Webhook Format):
{
"accountEmail": "[email protected]",
"content": "I had a really tough day at work today...",
"media_url": "",
"is_outbound": false,
"status": "delivered",
"message_handle": "msg_123",
"date_sent": "2024-01-01T12:00:00Z",
"date_updated": "2024-01-01T12:00:00Z",
"from_number": "+1234567890",
"number": "+1234567890",
"plan": "blue"
}Response: AI-generated empathetic response text
The system uses a sophisticated AI pipeline:
- Input Processing: Incoming text is analyzed for emotional content
- Intent Classification: AI determines if user wants to reflect on past experiences or discuss current thoughts
- Retrieval: For reflection mode, similar past entries are retrieved using vector similarity
- Response Generation: AI generates contextual, empathetic responses
- Message Splitting: Long responses are intelligently split into multiple SMS messages
Triggered by queries like:
- "Tell me about a time when I felt sad"
- "Give me a time when I went on an adventure with friends"
- "Describe a moment when I felt lost"
Handles present-moment journaling:
- "I'm feeling anxious today"
- "Had a great day at the park with friends"
- "Feeling overwhelmed with work"
id: Primary keyphone_number: User's phone number (12 chars)created_at: Account creation timestamphashed_password: Encrypted password
id: Primary keycontent: Journal entry textembedding: 768-dimensional vector embeddingemotions: Classified emotion from the entrycreated_at: Entry creation timestampdate: Entry dateauthor_id: Foreign key to users table
| Variable | Description | Required |
|---|---|---|
OPENAI_API_KEY |
OpenAI API key for GPT-4o | Yes |
COHERE_API_KEY |
Cohere API key for re-ranking | Yes |
LANGCHAIN_API_KEY |
LangChain API key for tracing | Yes |
SENDBLUE_APIURL |
SendBlue API endpoint | Yes |
SENDBLUE_APIKEY |
SendBlue API key | Yes |
SENDBLUE_APISECRET |
SendBlue API secret | Yes |
Update the database connection string in app/database.py:
SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost/tmj_db"Run the test suite:
pytest app/test_main.pyCreate a new migration:
alembic revision --autogenerate -m "Description of changes"Apply migrations:
alembic upgrade head- Update database models in
app/models.py - Create corresponding Pydantic schemas in
app/schemas.py - Implement CRUD operations in
app/crud.py - Add API endpoints in
app/main.py - Update tests in
app/test_main.py
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Submit a pull request
This project is licensed under the MIT License.
For support, please contact the development team or create an issue in the GitHub repository.
