Last active
February 3, 2026 18:59
-
-
Save eliasdabbas/0a621df7d3924cbf64721a078ce2b36d to your computer and use it in GitHub Desktop.
Chatbot that searches and generates answers from the given domains
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # /// script | |
| # requires-python = ">=3.13" | |
| # dependencies = [ | |
| # "anthropic>=0.77.0", | |
| # "chatnificent>=0.0.10", | |
| # "dash-bootstrap-components>=2.0.4", | |
| # ] | |
| # /// | |
| import chatnificent as chat | |
| from anthropic.types import TextBlock | |
| from chatnificent import Chatnificent | |
| ALLOWED_DOMAINS = ["dash.plotly.com"] # <-- change this | |
| class AnthropicSearch(chat.llm.Anthropic): | |
| def format_search_results(self, response, n_references=3) -> str: | |
| output = [] | |
| references = [] | |
| for block in response.content: | |
| if block.type == "web_search_tool_result": | |
| for i, result in enumerate(block.content): | |
| if ( | |
| result.type == "web_search_result" | |
| and i < n_references | |
| and result.url | |
| ): | |
| title = result.title or result.url | |
| references.append(f"- [{title}]({result.url})") | |
| elif block.type == "text": | |
| if block.text.strip(): | |
| output.append(block.text) | |
| if references: | |
| output.append("\n\nReferences:") | |
| output.extend(references) | |
| return "\n".join(output) | |
| def generate_response(self, messages): | |
| response = self.client.messages.create( | |
| model="claude-opus-4-5-20251101", | |
| max_tokens=20024, | |
| messages=messages, | |
| system="""You are the Dash search bot. You only provide answers from | |
| the given domains. | |
| Assume users are searching for stuff related to Plotly's Dash framework. | |
| An "app" should be understood as a Dash app, a "callback" is a Dash app's callback | |
| function, and so on. | |
| Check these domains for answers every single time. | |
| If you don't find a good answer from the domains, you apologize with a polite message.""", | |
| tools=[ | |
| { | |
| "type": "web_search_20250305", | |
| "name": "web_search", | |
| "max_uses": 5, | |
| "allowed_domains": ALLOWED_DOMAINS, | |
| } | |
| ], | |
| tool_choice={"type": "tool", "name": "web_search"}, | |
| ) | |
| formatted_output = self.format_search_results(response, n_references=3) | |
| response.content = [TextBlock(type="text", text=formatted_output)] | |
| return response | |
| app = Chatnificent( | |
| llm=AnthropicSearch(), | |
| store=chat.store.File("chat_history"), # <-- chat history will be saved to this directory | |
| ) | |
| if __name__ == "__main__": | |
| app.run(debug=True) |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
An AI website search bot built with Chatnificent
uv:ANTHROPIC_API_KEY(or the other providers)