Turning the Easysearch CLI Assistant into a Web App: A Practical Upgrade Guide
This article walks through converting the Easysearch command‑line assistant into a web‑based tool by adding an Express API layer, reusing shared logic, and building a lightweight HTML/CSS/JS front‑end, while preserving the original CLI capabilities.
1. Recap of the CLI version
The previous article built an Easysearch assistant that uses DeepSeek’s API together with Tool Use to translate natural‑language queries into Easysearch (Elasticsearch‑compatible) REST calls for search, aggregation, indexing and data writing.
2. Overall architecture: one codebase, two entry points
The project keeps a minimal structure with the following core files: tools.js: declares eight tools covering query, write and index‑management operations. executor.js: turns tool calls into Easysearch REST requests. lib/chat.js: the conversation engine that handles DeepSeek interaction and Tool Use; this module is the shared “brain” for both CLI and Web. index.js: CLI entry point that uses readline for I/O. server.js: Express entry point exposing the API for the web front‑end. public/: contains index.html, styles.css and app.js for the front‑end.
The design principle is that lib/chat.js is the core, while CLI and Web are merely shells that invoke it.
3. Conversation core abstraction in lib/chat.js
3.1 Initialization and system prompt
A DeepSeek client is created via the OpenAI SDK (only the baseURL needs to be changed). The system prompt defines the assistant role:
You are an Easysearch assistant that supports natural‑language search and data writing.
The prompt also lists the assistant’s capabilities: full‑text search, aggregation, index management, mapping inspection, index creation, mapping extension, and single/batch writes.
3.2 Generic chat(messages, userMessage, opts) function
Add the new user message to the messages history.
Call chat.completions.create with model='deepseek-chat', the tools from tools.js, tool_choice='auto', and the full message list.
If no tool_calls are returned, forward the model’s text reply.
If tool_calls exist, parse the arguments (strip comments, JSON.parse), invoke executeTool(toolName, toolInput), append the tool’s result as a tool role message, and repeat until no further tool calls appear.
An optional hook opts.onToolCall(name, input) prints the call in the CLI and collects it as a tag in the Web UI.
4. Web service in server.js
4.1 Routing and static assets
express.static('public')serves the front‑end files.
POST /api/chat accepts {message, history?}, forwards them to chat(), and returns {reply, toolCalls, history}.
History is passed from the front‑end on each request, accumulated on the server, and sent back for the client to store.
4.2 Transparent tool‑call forwarding
The onToolCall hook gathers tool calls into an array that is returned alongside the reply, allowing users to see which tool was invoked and with what parameters.
The API remains simple and UI‑agnostic, making future extensions straightforward.
5. Front‑end implementation
The UI is built with plain HTML, CSS and JavaScript—no framework—so it is easy to transplant.
Visual style : light‑gray background, white card with shadow, blue accent colors (#1e40af / #2563eb), modern fonts (Plus Jakarta Sans for text, JetBrains Mono for code).
Layout : a scrollable message area, a welcome card with a product intro and example prompt, user messages shown in right‑aligned blue bubbles, assistant replies in left‑aligned white cards.
Tool call bar : renders tags such as [search_documents {params}] beneath each assistant message.
Input area : multi‑line textarea with a send button; Enter sends, Shift+Enter inserts a newline; a loading animation appears while awaiting a response. app.js handles fetch('/api/chat'), updates the DOM with messages and tool tags, and persists the conversation history in localStorage.
6. Why the CLI‑to‑Web transition is smooth
Conversation core is abstracted in lib/chat.js, providing a single interface for both entry points.
Execution and display are decoupled: executor.js talks to Easysearch, while the front‑end only sees tool names and parameters.
The /api/chat contract is stable and easy to extend for multi‑session support.
Thus the entry point can be swapped without touching the core logic.
7. Getting started and extension ideas
7.1 Quick start
Run npm install to install dependencies.
Create a .env file with DEEPSEEK_API_KEY=your_key and Easysearch connection settings, e.g.
EASYSEARCH_URL=http://127.0.0.1:9200, USER/PASS, PORT=13000Start the server with npm start and open http://localhost:13000 in a browser.
Use the provided test-flow-prompts.md to verify indexing, writing, searching, aggregation and mapping retrieval.
7.2 Extension directions
Add shortcut templates (buttons) that pre‑fill common prompts such as top‑N queries.
Support multiple environments by adding an env switch for dev/prod clusters.
Visualize aggregation results with charts (e.g., Chart.js).
The modular design makes it easy to add new tools, connect to any Elasticsearch‑compatible cluster, and let the front‑end handle presentation.
8. Conclusion
By abstracting the shared conversation layer, decoupling execution from presentation, and exposing a thin Express API, the Easysearch assistant moves from a pure CLI tool to a user‑friendly web interface without rewriting core logic.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Mingyi World Elasticsearch
The leading WeChat public account for Elasticsearch fundamentals, advanced topics, and hands‑on practice. Join us to dive deep into the ELK Stack (Elasticsearch, Logstash, Kibana, Beats).
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
