A Spring Boot service that integrates the OpenAI API via Spring AI to provide chat with persistent memory and retrieval-augmented generation (RAG) backed by PostgreSQL + pgvector.
The service supports stateless single-turn chat, stateful multi-turn conversations whose history is persisted in PostgreSQL, and document ingestion that embeds PDFs into a pgvector store so answers can be grounded in your own documents.
- Stateless chat — single-turn requests with no retained history
- Stateful chat — multi-turn conversations keyed by a
conversationId, with history persisted to PostgreSQL via a customChatMemoryimplementation - Retrieval-augmented generation — a
QuestionAnswerAdvisorretrieves relevant context from a pgvector store on every request - PDF ingestion — read a PDF from a file path, split it into chunks, and embed it into the vector store
- OpenAI embeddings —
text-embedding-3-small(1536-dim) stored in pgvector with HNSW indexing and cosine distance
- Java 21
- Spring Boot 3.5.10 (Web, Data JPA)
- Spring AI 1.1.2 — OpenAI model starter, pgvector vector store, vector-store advisors, PDF & Tika document readers
- PostgreSQL with the pgvector extension
- Lombok
- Maven (wrapper included)
- Java 21+
- Maven 3.9+ (or use the bundled
./mvnwwrapper) - An OpenAI API key
- PostgreSQL with the
pgvectorextension installed
Apply the provided schema (creates the conversations table for chat history and the vector_store table for embeddings, and enables the vector extension):
psql -U <username> -d <database> -f src/main/resources/queries/create_tables.sql./mvnw clean install
./mvnw spring-boot:runOr run the packaged JAR:
java -jar target/openai-0.0.1-SNAPSHOT.jarThe application starts on port 8080.
All sensitive values are read from environment variables (src/main/resources/application.yaml). Provide your own values:
| Environment variable | Description |
|---|---|
OPENAI_API_KEY |
OpenAI API key |
DB_URL |
PostgreSQL JDBC URL, e.g. jdbc:postgresql://localhost:5432/<database> |
DB_USERNAME |
Database username |
DB_PASSWORD |
Database password |
Model and vector-store defaults (also in application.yaml):
| Key | Value |
|---|---|
spring.ai.openai.chat.options.model |
gpt-4.1-nano |
spring.ai.openai.chat.options.temperature |
0.7 |
spring.ai.openai.embedding.model |
text-embedding-3-small |
spring.ai.vectorstore.pgvector.index-type |
HNSW |
spring.ai.vectorstore.pgvector.distance-type |
COSINE_DISTANCE |
spring.ai.vectorstore.pgvector.dimension |
1536 |
POST /v1/chat/stateless — body is the raw message text.
curl -X POST http://localhost:8080/v1/chat/stateless \
-H 'Content-Type: text/plain' \
-d 'What is machine learning?'Response:
{ "response": "...", "timeTaken": 2450 }POST /v1/chat/stateful — body is the raw message text. Pass ?conversationId=<id> to continue an existing conversation; omit it to start a new one (the response returns the generated id).
curl -X POST 'http://localhost:8080/v1/chat/stateful?conversationId=<id>' \
-H 'Content-Type: text/plain' \
-d 'And tell me more about its history'Response:
{ "conversationId": "<id>", "response": "...", "timeTaken": 1823 }GET /v1/ingest/filepath?filepath=<path> — ingest a PDF at the given file path into the vector store.
curl 'http://localhost:8080/v1/ingest/filepath?filepath=/path/to/document.pdf'| Table | Purpose |
|---|---|
conversations |
Persisted chat history (conversation_id, content, role, metadata, created_at) |
vector_store |
Document embeddings (id, content, metadata, embedding vector(1536)) |
src/main/java/com/navneet/openai/
├── OpenaiApplication.java # Spring Boot entry point
├── controller/
│ ├── ChatController.java # /v1/chat endpoints
│ └── IngestionController.java # /v1/ingest endpoint
├── service/
│ ├── ChatService.java / impl # Chat logic (RAG + memory advisors)
│ ├── IngestionService.java / impl # PDF read, split, embed
│ └── helper/ChatServiceHelper.java # Conversation-entity helpers
├── memory/
│ ├── PersistedChatMemory.java # Custom ChatMemory backed by JPA
│ ├── entity/Conversations.java # JPA entity
│ └── repo/ConversationRepo.java # Spring Data repository
├── models/ # Chat request/response DTOs
└── constants/AgentConstants.java # System prompt and role constants
Licensed under the MIT License — see LICENSE.