This project is a full-stack demonstration of AI chatbot application with NestJS backend and React (Vite + Axios) as frontend. On top with the integration with Langgraph.js, Langchain.js, and Azure OpenAI as assistant
- UUID-based chat sessions
- Persistent chat history in JSON format
- RESTful API with Swagger documentation
- CLI-based interaction
- Basic browser-based interface
- search agent with Tavily
- database with PostgreSQL server
- CRUD operation on database
- vector embedding
- similarity search using vector & cosine similarity
src
├── ai
│ ├── agent.state.ts
│ ├── ai.controller.spec.ts
│ ├── ai.controller.ts
│ ├── ai.graph.ts
│ ├── ai.module.ts
│ ├── ai.service.spec.ts
│ ├── ai.service.ts
│ ├── ask.dto.ts
│ ├── nodes
│ │ └── agent.node.ts
│ └── utils
│ └── tool.logger.ts
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
├── chat
│ ├── chat.controller.ts
│ ├── chat.module.ts
│ ├── chat.repository.ts
│ ├── chat.service.ts
│ └── chat.types.ts
├── cli.ts
├── data
│ └── chats.json
├── database
│ ├── database.controller.spec.ts
│ ├── database.controller.ts
│ ├── database.module.ts
│ ├── database.service.spec.ts
│ ├── database.service.ts
│ ├── database.types.ts
│ ├── dto
│ │ ├── create-company.dto.ts
│ │ ├── create-person.dto.ts
│ │ ├── create-worksfor.dto.ts
│ │ ├── update-company.dto.ts
│ │ ├── update-person.dto.ts
│ │ └── update-works-for.dto.ts
│ ├── models
│ │ ├── company.model.ts
│ │ ├── person.model.ts
│ │ └── works-for.model.ts
│ └── sequelize.provider.ts
├── llm
│ └── llm.module.ts
├── main.ts
├── seed.ts
└── tools
├── database
│ ├── database.tool.schema.ts
│ └── database.tool.ts
├── search
│ ├── candidate-search.tool.ts
│ ├── safe-tavily.tool.ts
│ └── search-qa.util.ts
├── tools.module.ts
├── tools.service.spec.ts
└── tools.service.ts- State:
{ messages: BaseMessage[] }usingMessagesAnnotation - Nodes: agent and tools
- Use
addConditionalEdgesto detect tool calls
SafeTavilySearchTool (in search/safe-tavily-tool.ts): perform web search, QA by score and freshnessDatabaseManagerTool (in database/database.tool.ts): Database CRUD operationcandidate-search.tool.ts (in tools/search/candidate-search.tool.ts): more complex search, web search for more info about the role/skills of candidate -> perform RAG -> answer- schema: zod discriminated union
- Chat session creation (no delete feature yet)
- Chat history retrieval
- JSON storage at
data/chats.json - main functionalities in
chat.repository.ts
-
sequelize provider: postgreSQL
-
3 entities (Found in
models/)- person:
['id', 'full_name', 'email'] - company:
['id', 'company_name'] - works_for:
['person_id', 'company_id', 'duration', 'position', 'responsibility']
- person:
-
supported methods
- select
- join
- insert
- update
- delete
- for llm modules for both chatbot and embedding
src/cli.tsnpm run start:devgo to chat
npm run start:cli- Used for adding data to database
npm run seed- use Axios to send requests to http://localhost:3000/api/ai/ask (foun in
frontend/src/api/chat.api.js) - generate a uniquue
sessionIDper load - configuration:
main.tsupdated to enable CORS for port 5173
services:
postgres:
image: pgvector/pgvector:pg16
container_name: ai-postgres
restart: unless-stopped
environment:
POSTGRES_DB: ai_system
POSTGRES_USER: ai_user
POSTGRES_PASSWORD: ai_password
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./postgres:/postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 5
volumes:
postgres_data:CREATE EXTENSION IF NOT EXISTS vector;
DROP TABLE IF EXISTS works_for;
DROP TABLE IF EXISTS person;
DROP TABLE IF EXISTS company;
CREATE TABLE person (
id SERIAL PRIMARY KEY,
full_name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE
);
CREATE TABLE company (
id SERIAL PRIMARY KEY,
company_name TEXT NOT NULL
);
CREATE TABLE works_for (
person_id INT NOT NULL,
company_id INT NOT NULL,
duration INTERVAL,
position TEXT,
responsibility TEXT,
PRIMARY KEY (person_id, company_id),
CONSTRAINT fk_person
FOREIGN KEY (person_id)
REFERENCES person(id)
ON DELETE CASCADE,
CONSTRAINT fk_company
FOREIGN KEY (company_id)
REFERENCES company(id)
ON DELETE CASCADE
);
ALTER TABLE works_for
ADD COLUMN embedding vector(1536);