One drop zone. No mode-picking. Drop a file (PDF, text, image) or ask a question that needs live web info, and a router automatically decides which specialized tool should handle it — you never have to tell it what kind of task it is.
File / Query
│
▼
Type Detector ──► Loader (PDF / text / image) ──► Chunker ──► FAISS index
│
▼
Router (LLM) ──► decides: tool + retrieval query + k
│
├── chat_summarizer → summarizes a chat/conversation
├── pdf_digester → explains / answers questions about a document
├── draft_reducer → tightens/shortens a piece of writing
├── image_tool → describes/analyzes an image
└── web_search → answers using live Tavily search results
│
▼
Answer
Built with LangGraph as a state machine — the router node picks the next node with a conditional edge, so adding a new tool means adding one node + one edge, not new if/else branches.
Both the router and the main answering LLM run through a fallback chain (Groq → Gemini), so a single provider outage or rate limit doesn't take the whole pipeline down mid-demo.
clickless_ai/
├── main.py # graph definition: router + tool nodes + fallback LLM chains
├── file_loader.py # PDF / text / image loaders (vision model for images)
├── vectorstore.py # chunking + FAISS indexing + retrieval
├── app.py # Streamlit UI (drag-and-drop upload)
├── requirements.txt
├── .env.example
└── .gitignore
git clone https://github.com/Dwarkesh-code/clickless_ai.git
cd clickless_ai
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # then fill in your API keysStreamlit UI (recommended):
streamlit run app.pyDrag and drop a file, type your question, and the router handles the rest.
CLI:
python main.pySee .env.example. You need API keys for Groq, Google (Gemini), and Tavily. The image tool additionally uses an NVIDIA vision endpoint as its primary model with Gemini vision models as fallback.
- Website ingestion (
detect_input_typereturns"website") is not implemented yet — a URL input will raiseNotImplementedErroruntil a website loader is added tofile_loader.py. - The FAISS index is wiped on start and on exit — there is no persistence across runs by design (each session starts clean).
- No automated tests yet.
- Website loader (requests + BeautifulSoup)
- Persistent/optional vectorstore across sessions
- Streaming answers in the Streamlit UI
- More tool types