|
| 1 | +import marimo |
| 2 | + |
| 3 | +__generated_with = "0.13.7" |
| 4 | +app = marimo.App() |
| 5 | + |
| 6 | + |
| 7 | +@app.cell(hide_code=True) |
| 8 | +def _(mo): |
| 9 | + mo.md( |
| 10 | + r""" |
| 11 | + ## Getting started with Diffbot LLM |
| 12 | +
|
| 13 | + ```yaml |
| 14 | + pip install openai python dotenv |
| 15 | + touch .env # Create a .env file |
| 16 | + echo "DIFFBOT_API_TOKEN=your-token-here" >> .env # Add your token to a .env file |
| 17 | + ``` |
| 18 | + ### Your first query with citations |
| 19 | +
|
| 20 | + """ |
| 21 | + ) |
| 22 | + return |
| 23 | + |
| 24 | + |
| 25 | +@app.cell |
| 26 | +def _(): |
| 27 | + import os |
| 28 | + |
| 29 | + from dotenv import load_dotenv |
| 30 | + from openai import OpenAI |
| 31 | + |
| 32 | + load_dotenv() |
| 33 | + |
| 34 | + client = OpenAI( |
| 35 | + base_url="https://llm.diffbot.com/rag/v1", |
| 36 | + api_key=os.getenv("DIFFBOT_API_TOKEN"), |
| 37 | + ) |
| 38 | + |
| 39 | + def query_diffbot(query_text, model="diffbot-small-xl", temperature=0.5): |
| 40 | + completion = client.chat.completions.create( |
| 41 | + model=model, |
| 42 | + temperature=temperature, |
| 43 | + messages=[{"role": "user", "content": query_text}], |
| 44 | + ) |
| 45 | + return completion |
| 46 | + |
| 47 | + completion = query_diffbot("What is GraphRAG?") |
| 48 | + return completion, load_dotenv, os, query_diffbot |
| 49 | + |
| 50 | + |
| 51 | +@app.cell |
| 52 | +def _(completion): |
| 53 | + print(completion.choices[0].message.content[:1000]) |
| 54 | + return |
| 55 | + |
| 56 | + |
| 57 | +@app.cell |
| 58 | +def _(query_diffbot): |
| 59 | + completion_1 = query_diffbot("What is the weather in Tokyo?") |
| 60 | + print(completion_1.choices[0].message.content) |
| 61 | + return |
| 62 | + |
| 63 | + |
| 64 | +@app.cell |
| 65 | +def _(query_diffbot): |
| 66 | + completion_2 = query_diffbot( |
| 67 | + "Find me the information on the upcoming hackathon organized by HuggingFace" |
| 68 | + ) |
| 69 | + print(completion_2.choices[0].message.content) |
| 70 | + return |
| 71 | + |
| 72 | + |
| 73 | +@app.cell |
| 74 | +def _(query_diffbot): |
| 75 | + completion_3 = query_diffbot("Find the square root of 12394890235") |
| 76 | + print(completion_3.choices[0].message.content) |
| 77 | + return |
| 78 | + |
| 79 | + |
| 80 | +@app.cell |
| 81 | +def _(query_diffbot): |
| 82 | + _image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/Black_hole_-_Messier_87_crop_max_res.jpg/960px-Black_hole_-_Messier_87_crop_max_res.jpg" |
| 83 | + completion_4 = query_diffbot(f"Describe this image to me: {_image_url}") |
| 84 | + print(completion_4.choices[0].message.content) |
| 85 | + return |
| 86 | + |
| 87 | + |
| 88 | +@app.cell |
| 89 | +def _(query_diffbot): |
| 90 | + _image_url = "https://codecut.ai/wp-content/uploads/2025/01/Banner-updated-colors-fixed-maybe-1.png" |
| 91 | + completion_5 = query_diffbot(f"Describe this image to me: {_image_url}") |
| 92 | + print(completion_5.choices[0].message.content) |
| 93 | + return |
| 94 | + |
| 95 | + |
| 96 | +@app.cell(hide_code=True) |
| 97 | +def _(mo): |
| 98 | + mo.md( |
| 99 | + r""" |
| 100 | + ### Self-hosting for privacy |
| 101 | + """ |
| 102 | + ) |
| 103 | + return |
| 104 | + |
| 105 | + |
| 106 | +@app.cell(hide_code=True) |
| 107 | +def _(mo): |
| 108 | + mo.md( |
| 109 | + r""" |
| 110 | + If your use-case involves high-stakes sensitive information like financial or medical databases, you can get all the benefits of the Serverless API locally by running a couple of Docker commands: |
| 111 | +
|
| 112 | + For the 8B model, much smaller in disk size: |
| 113 | +
|
| 114 | + ```bash |
| 115 | + docker run --runtime nvidia --gpus all -p 8001:8001 --ipc=host -e VLLM_OPTIONS="--model diffbot/Llama-3.1-Diffbot-Small-2412 --served-model-name diffbot-small --enable-prefix-caching" docker.io/diffbot/diffbot-llm-inference:latest |
| 116 | + ``` |
| 117 | +
|
| 118 | + For the larger 70B model with full capabilities: |
| 119 | +
|
| 120 | + ```bash |
| 121 | + docker run --runtime nvidia --gpus all -p 8001:8001 --ipc=host -e VLLM_OPTIONS="--model diffbot/Llama-3.3-Diffbot-Small-XL-2412 --served-model-name diffbot-small-xl --enable-prefix-caching --quantization fp8 --tensor-parallel-size 2" docker.io/diffbot/diffbot-llm-inference:latest |
| 122 | + ``` |
| 123 | +
|
| 124 | + Once the application starts up successfully and you see a message like the following: |
| 125 | +
|
| 126 | + ```plaintext |
| 127 | + INFO: Application startup complete. |
| 128 | + INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) |
| 129 | + ``` |
| 130 | +
|
| 131 | + You can run all the examples above by replacing the base URL with the endpoint `http://localhost:8001/rag/v1`. |
| 132 | +
|
| 133 | + However, do note that these models require high-end GPUs like A100 and H100s to run at full precision. If you don't have the right hardware, consider using [RunPod.io](https://runpod.io) which cost: |
| 134 | +
|
| 135 | + - $5.98/hr for dual H100 GPU setup (total 160 GB VRAM) |
| 136 | + - $1.89/hr for a single A100 GPU setup (80 GB VRAM) |
| 137 | +
|
| 138 | +  |
| 139 | + """ |
| 140 | + ) |
| 141 | + return |
| 142 | + |
| 143 | + |
| 144 | +@app.cell(hide_code=True) |
| 145 | +def _(mo): |
| 146 | + mo.md( |
| 147 | + r""" |
| 148 | + ## Building real-world applications with Diffbot and LangChain |
| 149 | +
|
| 150 | + ### LangChain + Diffbot basics |
| 151 | +
|
| 152 | + ```bash |
| 153 | + pip install langchain langchain-openai python-dotenv |
| 154 | + ``` |
| 155 | + """ |
| 156 | + ) |
| 157 | + return |
| 158 | + |
| 159 | + |
| 160 | +@app.cell |
| 161 | +def _(load_dotenv, os): |
| 162 | + from langchain_openai import ChatOpenAI |
| 163 | + |
| 164 | + load_dotenv() |
| 165 | + |
| 166 | + llm = ChatOpenAI( |
| 167 | + model="diffbot-small-xl", |
| 168 | + temperature=0, |
| 169 | + max_tokens=None, |
| 170 | + timeout=None, |
| 171 | + base_url="https://llm.diffbot.com/rag/v1", |
| 172 | + api_key=os.getenv("DIFFBOT_API_TOKEN"), |
| 173 | + ) |
| 174 | + return ChatOpenAI, llm |
| 175 | + |
| 176 | + |
| 177 | +@app.cell |
| 178 | +def _(llm): |
| 179 | + messages = [ |
| 180 | + ("system", "You are a helpful assistant that translates English to French."), |
| 181 | + ("human", "I love programming."), |
| 182 | + ] |
| 183 | + |
| 184 | + ai_msg = llm.invoke(messages) |
| 185 | + print(ai_msg.content) # "J'aime le programmation." |
| 186 | + return |
| 187 | + |
| 188 | + |
| 189 | +@app.cell |
| 190 | +def _(llm): |
| 191 | + from langchain_core.prompts import ChatPromptTemplate |
| 192 | + |
| 193 | + prompt = ChatPromptTemplate.from_messages( |
| 194 | + [ |
| 195 | + ( |
| 196 | + "system", |
| 197 | + "You are a helpful assistant that translates {input_language} to {output_language}.", |
| 198 | + ), |
| 199 | + ("human", "{input}"), |
| 200 | + ] |
| 201 | + ) |
| 202 | + chain = prompt | llm |
| 203 | + _result = chain.invoke( |
| 204 | + { |
| 205 | + "input_language": "English", |
| 206 | + "output_language": "German", |
| 207 | + "input": "I love programming.", |
| 208 | + } |
| 209 | + ) |
| 210 | + return (ChatPromptTemplate,) |
| 211 | + |
| 212 | + |
| 213 | +@app.cell(hide_code=True) |
| 214 | +def _(mo): |
| 215 | + mo.md( |
| 216 | + r""" |
| 217 | + ### Building a RAG application with Diffbot and LangChain |
| 218 | + """ |
| 219 | + ) |
| 220 | + return |
| 221 | + |
| 222 | + |
| 223 | +@app.cell |
| 224 | +def _(ChatOpenAI, ChatPromptTemplate): |
| 225 | + import json |
| 226 | + from typing import Dict, List |
| 227 | + |
| 228 | + from langchain_core.output_parsers import StrOutputParser |
| 229 | + |
| 230 | + class ResearchAssistant: |
| 231 | + |
| 232 | + def __init__(self, diffbot_api_key: str): |
| 233 | + self.llm = ChatOpenAI( |
| 234 | + model="diffbot-small-xl", |
| 235 | + temperature=0.3, |
| 236 | + base_url="https://llm.diffbot.com/rag/v1", |
| 237 | + api_key=diffbot_api_key, |
| 238 | + ) |
| 239 | + self.setup_chains() |
| 240 | + |
| 241 | + def setup_chains(self): |
| 242 | + self.topic_extraction_prompt = ChatPromptTemplate.from_template( |
| 243 | + "\n Analyze the following document and extract 3-5 main topics or entities that would benefit \n from current information. Return as a JSON list of topics.\n \n Document: {document}\n \n Topics (JSON format):\n " |
| 244 | + ) |
| 245 | + self.research_prompt = ChatPromptTemplate.from_template( |
| 246 | + "\n Provide comprehensive, current information about: {topic}\n \n Context from document: {context}\n \n Include:\n 1. Current status and recent developments\n 2. Key statistics or data points \n 3. Recent news or updates\n 4. Relevant industry trends\n \n Ensure all facts are cited with sources.\n " |
| 247 | + ) |
| 248 | + self.report_prompt = ChatPromptTemplate.from_template( |
| 249 | + "\n Create a comprehensive research report based on the document analysis and current research.\n \n Original Document Summary: {document_summary}\n \n Research Findings: {research_findings}\n \n Generate a well-structured report that:\n 1. Summarizes the original document's main points\n 2. Provides current context for each major topic\n 3. Identifies any outdated information in the document\n 4. Suggests areas for further investigation\n \n Include proper citations throughout.\n " |
| 250 | + ) |
| 251 | + |
| 252 | + def extract_topics(self, document: str) -> List[str]: |
| 253 | + """Extract main topics from the document for research.""" |
| 254 | + chain = self.topic_extraction_prompt | self.llm | StrOutputParser() |
| 255 | + try: |
| 256 | + _result = chain.invoke({"document": document}) |
| 257 | + topics = json.loads(_result.strip()) |
| 258 | + return topics if isinstance(topics, list) else [] |
| 259 | + except (json.JSONDecodeError, Exception) as e: |
| 260 | + print(f"Error extracting topics: {e}") |
| 261 | + return [] |
| 262 | + |
| 263 | + def research_topic(self, topic: str, context: str) -> str: |
| 264 | + """Research current information about a specific topic.""" |
| 265 | + chain = self.research_prompt | self.llm | StrOutputParser() |
| 266 | + return chain.invoke({"topic": topic, "context": context}) |
| 267 | + |
| 268 | + def generate_report(self, document: str, research_findings: List[Dict]) -> str: |
| 269 | + """Generate comprehensive report with current information.""" |
| 270 | + summary_prompt = ChatPromptTemplate.from_template( |
| 271 | + "Provide a concise summary of this document: {document}" |
| 272 | + ) |
| 273 | + summary_chain = summary_prompt | self.llm | StrOutputParser() |
| 274 | + document_summary = summary_chain.invoke({"document": document}) |
| 275 | + findings_text = "\n\n".join( |
| 276 | + [ |
| 277 | + f"**{finding['topic']}:**\n{finding['research']}" |
| 278 | + for finding in research_findings |
| 279 | + ] |
| 280 | + ) |
| 281 | + report_chain = self.report_prompt | self.llm | StrOutputParser() |
| 282 | + return report_chain.invoke( |
| 283 | + { |
| 284 | + "document_summary": document_summary, |
| 285 | + "research_findings": findings_text, |
| 286 | + } |
| 287 | + ) |
| 288 | + |
| 289 | + def analyze_document(self, document: str) -> Dict: |
| 290 | + """Complete document analysis with current research.""" |
| 291 | + print("Extracting topics from document...") |
| 292 | + topics = self.extract_topics(document) |
| 293 | + if not topics: |
| 294 | + return {"error": "Could not extract topics from document"} |
| 295 | + print(f"Researching {len(topics)} topics...") |
| 296 | + research_findings = [] |
| 297 | + for topic in topics: |
| 298 | + print(f" - Researching: {topic}") |
| 299 | + research = self.research_topic(topic, document) |
| 300 | + research_findings.append({"topic": topic, "research": research}) |
| 301 | + print("Generating comprehensive report...") |
| 302 | + final_report = self.generate_report(document, research_findings) |
| 303 | + return { |
| 304 | + "topics": topics, |
| 305 | + "research_findings": research_findings, |
| 306 | + "final_report": final_report, |
| 307 | + "status": "completed", |
| 308 | + } |
| 309 | + |
| 310 | + return (ResearchAssistant,) |
| 311 | + |
| 312 | + |
| 313 | +@app.cell |
| 314 | +def _(ResearchAssistant, os): |
| 315 | + assistant = ResearchAssistant(os.getenv("DIFFBOT_API_TOKEN")) |
| 316 | + sample_document = "\nArtificial Intelligence has made significant progress in natural language processing. \nCompanies like OpenAI and Google have released powerful language models. \nThe field of machine learning continues to evolve with new architectures and techniques.\nInvestment in AI startups reached $25 billion in 2023.\n" |
| 317 | + _result = assistant.analyze_document(sample_document) |
| 318 | + print(_result["final_report"]) |
| 319 | + return |
| 320 | + |
| 321 | + |
| 322 | +@app.cell |
| 323 | +def _(): |
| 324 | + import marimo as mo |
| 325 | + |
| 326 | + return (mo,) |
| 327 | + |
| 328 | + |
| 329 | +if __name__ == "__main__": |
| 330 | + app.run() |
0 commit comments