Skip to content

Commit 0ff3461

Browse files
committed
Add Diffbot LLM integration tutorial
1 parent d80086e commit 0ff3461

File tree

1 file changed

+330
-0
lines changed

1 file changed

+330
-0
lines changed

llm/diffbot-llm.py

Lines changed: 330 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,330 @@
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+
![](images/runpod-instances.png)
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

Comments
 (0)