Keyword search works fine right up until someone types the question the way a human would say it. Then it returns nothing. That was the recurring annoyance behind this little side project: visitors to my blog would search for a topic I had definitely written about, using slightly different wording, and get an empty page. So I put together a Typecho plugin called DeepSearch that lets people ask questions in plain language instead of guessing at keywords.
Credit where it's due — the actual code was produced through AI-assisted coding; my part was testing, debugging, and steering the changes. The goal was narrow: give the blog a conversational search assistant. A visitor asks something, the plugin searches the local article index first, then hands the retrieved article content to DeepSeek so the answer is grounded in what's actually on the blog, with links to the source posts.
The plugin folder is named DeepSearch. Drop it into Typecho's /usr/plugins/ directory and it can be enabled. The distribution is hosted on LanZou cloud storage, and the archive password is gtch.

What it actually does
- Builds a local index from your published Typecho posts.
- Adds a floating AI search entry point on the front end.
- Accepts natural-language questions — no exact keyword required.
- Answers using your blog's own content and returns the related posts.
- Ships with light and dark front-end themes so it fits different blog styles.
- Backend settings for the DeepSeek API, model, prompts, and retrieval count.
- API connectivity test, index rebuild, and index clear, all from the admin panel.
- Rate limiting, per-question length limits, and a maximum output token cap.
- The API key stays server-side and is never exposed to the browser.
The interface uses a semi-transparent frosted-glass look. Opening the search window dims the page behind it and floats the chat panel on top, which keeps attention on the conversation. For lighter or cream-colored themes, you can set the default theme to light mode in the settings.


The retrieval comes first
DeepSearch doesn't just forward the question to a large model and hope for the best. Local search runs first:
user question -> backend request validation -> local post index search -> build context -> call DeepSeek -> return answer plus cited posts
The point is that answers stay tied to material the blog actually contains. Ask whether there's a post about certificate renewal, for example, and the plugin finds the relevant posts on the site before DeepSeek summarizes them into a reply.
If the DeepSeek endpoint is temporarily unavailable, the plugin falls back to local search mode, so at minimum a keyword-matched list of posts still comes back.
Installation
Place the plugin in the Typecho plugin directory:
/usr/plugins/DeepSearch/
Make sure the entry file sits at:
/usr/plugins/DeepSearch/Plugin.php
Then, in the Typecho admin:
- Go to Console → Plugins.
- Enable
DeepSearch. - Open the plugin settings page.
- Enter your DeepSeek API key.
- Click “Write” to save the key.
- Click “Test” to check whether DeepSeek responds.
- Click “Rebuild index now” to build the initial post index.
When that's done, an AI search button appears in the bottom-right corner of the front end.
Settings that matter
The admin page covers the usual configuration surface:
- DeepSeek API key
- API base URL
- Model name
- Custom model name
- Temperature
- Maximum tokens
- Number of conversation turns kept in context
- Local retrieval count (Top-K)
- System prompt
- Front-end display mode
- Default theme tone
- Per-question character limit
- Hourly request limit
- Automatic incremental index updates
“Test”, “Rebuild index now”, and “Clear index” all run over AJAX and report results in a popup on the same page, so you aren't bounced back to the plugin list each time.
On blogs with a lot of posts, the rebuild runs in batches — 20 posts per batch by default. That avoids a single long request hanging the page, dropping the server connection, or producing ERR_EMPTY_RESPONSE.



Keeping the bill under control
Once a paid model is in the loop, cost control stops being optional. DeepSearch applies several layers of limits:
- Per-question length: 150 characters by default, so nobody submits an essay as a question.
- Hourly request limit: 50 per visitor by default.
- Maximum tokens: caps how long a single answer can get.
- Request body size limit: blocks forged oversized JSON payloads.
- Context turn limit: stops conversation history from growing without bound.
If your blog gets decent traffic, set the hourly request limit and max tokens more conservatively than the defaults.
Where the API key lives
The DeepSeek API key never appears in front-end JavaScript.
The security boundaries are roughly these:
- The key is stored in the Typecho plugin configuration and encrypted by the plugin.
- The admin input field never echoes the plaintext key back — only a masked hint.
- The front-end
DeepSearchConfigobject contains no API key. - The browser only calls your own site at
/action/deepsearch?do=search. - The real
Authorization: Bearer ...header is generated server-side, only when calling DeepSeek. - Front-end requests are checked against a same-origin Referer and a CSRF token.
- After a key is written, it's read back immediately to verify, so you don't get a “saved” message for something that wasn't actually stored.
In short: a visitor can only reach your blog's own endpoint, and the DeepSeek key isn't something they can pull out of it.
Who this is for
- Typecho blogs with enough posts that the built-in search starts to feel useless.
- Anyone who wants visitors to find posts by asking naturally.
- Blogs with a deep archive that deserves another look.
- People who want an AI search entry point without rewriting their theme's core logic.
- Anyone who insists the API key stay on the server.


A few things I learned while testing
Rebuild the index right after enabling the plugin. Without it, the front-end Q&A has no article context to work from and the answers will be vague.
Cleaner titles, tags, and categories translate directly into better retrieval. The model doesn't magically know your blog — it only sees the post context the plugin hands it.
If answers feel too cautious or miss obvious connections, adjust the system prompt and the Top-K value. A larger Top-K gives the model more candidate posts to draw from, at the cost of a longer request context.
And if you run into compatibility or API quirks, patches are welcome — or just fix them with AI yourself, which is more or less how this thing got built.