Skip to content

Commit c8e1790

Browse files
committed
Replace requests with diffbot-kg client, and make some code style fixes
1 parent 902eead commit c8e1790

4 files changed

Lines changed: 64 additions & 52 deletions

File tree

api/app/enhance.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
1-
import logging
21
import os
32
from datetime import datetime
4-
from typing import Any, Dict, List, Optional, Union
5-
from urllib.parse import urlencode
3+
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
64

7-
import requests
8-
from utils import graph
5+
from diffbot_kg import DiffbotEnhanceClient
6+
7+
from .utils import graph
98

109
CATEGORY_THRESHOLD = 0.50
1110
params = []
1211

1312
DIFF_TOKEN = os.environ["DIFFBOT_API_KEY"]
1413

14+
client = DiffbotEnhanceClient(DIFF_TOKEN)
15+
1516

16-
def get_datetime(value: Optional[Union[str, int, float]]) -> datetime:
17-
if not value:
18-
return value
19-
return datetime.fromtimestamp(float(value) / 1000.0)
17+
def get_datetime(
18+
value: Optional[Union[str, int, float]]
19+
) -> datetime | float | Literal["", 0] | None:
20+
return datetime.fromtimestamp(float(value) / 1000.0) if value else value
2021

2122

22-
def process_entities(entity: str, type: str) -> Dict[str, Any]:
23+
async def process_entities(entity: str, type: str) -> Tuple[str, List[Dict]]:
2324
"""
2425
Fetch relevant articles from Diffbot KG endpoint
2526
"""
26-
search_host = "https://kg.diffbot.com/kg/v3/enhance?"
27-
params = {"type": type, "name": entity, "token": DIFF_TOKEN}
28-
encoded_query = urlencode(params)
29-
url = f"{search_host}{encoded_query}"
30-
return entity, requests.get(url).json()
27+
params = {"type": type, "name": entity}
28+
response = await client.enhance(params)
29+
30+
return entity, response.entities
3131

3232

3333
def get_people_params(row: Dict) -> Optional[Dict]:
@@ -138,7 +138,6 @@ def get_people_params(row: Dict) -> Optional[Dict]:
138138

139139
def get_organization_params(name: str, row: Dict) -> Dict:
140140
# Properties
141-
type = row["type"]
142141
node_properties = {
143142
"employees": row.get("nbEmployees"),
144143
"revenue": row.get("revenue", {}).get("value"),
@@ -335,11 +334,11 @@ def store_enhanced_data(data: List[Dict[str, Any]]) -> Dict:
335334
except Exception:
336335
no_data.append(name)
337336
continue
338-
type = entity["type"]
339-
if type == "Organization":
337+
etype = entity["type"]
338+
if etype == "Organization":
340339
params = get_organization_params(name, entity)
341340
organizations.append(params)
342-
elif type == "Person":
341+
elif etype == "Person":
343342
params = get_people_params(entity)
344343
people.append(params)
345344
# Save processes status to entities without any response

api/app/importing.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,48 @@
11
import logging
22
import os
3-
from typing import Any, Dict, List, Optional
3+
from typing import Dict, List, Optional
44

5-
import requests
6-
from utils import embeddings, text_splitter
5+
from diffbot_kg import DiffbotSearchClient
6+
7+
from .utils import embeddings, text_splitter
78

89
CATEGORY_THRESHOLD = 0.50
910
params = []
1011

1112
DIFF_TOKEN = os.environ["DIFFBOT_API_KEY"]
1213

14+
client = DiffbotSearchClient(token=DIFF_TOKEN)
15+
1316

14-
def get_articles(
17+
async def get_articles(
1518
query: Optional[str], tag: Optional[str], size: int = 5, offset: int = 0
16-
) -> Dict[str, Any]:
19+
) -> List[Dict]:
1720
"""
1821
Fetch relevant articles from Diffbot KG endpoint
1922
"""
2023
try:
21-
search_host = "https://kg.diffbot.com/kg/v3/dql?"
22-
search_query = f'query=type%3AArticle+strict%3Alanguage%3A"en"+sortBy%3Adate'
24+
search_query = 'query=type%3AArticle+strict%3Alanguage%3A"en"+sortBy%3Adate'
2325
if query:
2426
search_query += f'+text%3A"{query}"'
2527
if tag:
2628
search_query += f'+tags.label%3A"{tag}"'
27-
url = (
28-
f"{search_host}{search_query}&token={DIFF_TOKEN}&from={offset}&size={size}"
29-
)
30-
return requests.get(url).json()
29+
response = await client.search({query: query, size: size, offset: offset})
30+
return response.entities
3131
except Exception as ex:
3232
raise ex
3333

3434

3535
def get_tag_type(types: List[str]) -> str:
3636
try:
3737
return types[0].split("/")[-1]
38-
except:
38+
except Exception:
3939
return "Node"
4040

4141

42-
def process_params(data):
42+
def process_params(articles):
4343
params = []
4444
all_chunks = []
45-
for row in data["data"]:
46-
article = row["entity"]
45+
for article in articles:
4746
split_chunks = [
4847
{"text": el, "index": f"{article['id']}-{i}"}
4948
for i, el in enumerate(text_splitter.split_text(article["text"])[:5])

api/app/main.py

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
1+
import asyncio
12
import logging
23
import os
34
from concurrent.futures import ThreadPoolExecutor
45
from typing import Any, Dict
56

6-
from api_types import ArticleData, CountData, EntityData
7-
from chat import chain
8-
from enhance import process_entities, store_enhanced_data
97
from fastapi import FastAPI, HTTPException
108
from fastapi.middleware.cors import CORSMiddleware
11-
from graph_prefiltering import prefiltering_agent_executor
12-
from importing import get_articles, import_cypher_query, process_params
139
from langserve import add_routes
14-
from processing import process_document, store_graph_documents
15-
from text2cypher import text2cypher_chain
16-
from utils import graph, remove_null_properties
10+
11+
from .api_types import ArticleData, CountData, EntityData
12+
from .chat import chain
13+
from .enhance import process_entities, store_enhanced_data
14+
from .graph_prefiltering import prefiltering_agent_executor
15+
from .importing import get_articles, import_cypher_query, process_params
16+
from .processing import process_document, store_graph_documents
17+
from .text2cypher import text2cypher_chain
18+
from .utils import graph, remove_null_properties
1719

1820
logging.basicConfig(
1921
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
2022
)
2123

2224
# Multithreading for Diffbot API
23-
MAX_WORKERS = min(os.cpu_count() * 5, 20)
25+
MAX_WORKERS = min((os.cpu_count() or 1) * 5, 20)
2426

2527
app = FastAPI()
2628

@@ -35,21 +37,23 @@
3537

3638

3739
@app.post("/import_articles/")
38-
def import_articles_endpoint(article_data: ArticleData) -> int:
40+
async def import_articles_endpoint(article_data: ArticleData) -> int:
3941
logging.info(f"Starting to process article import with params: {article_data}")
4042
if not article_data.query and not article_data.tag:
4143
raise HTTPException(
4244
status_code=500, detail="Either `query` or `tag` must be provided"
4345
)
44-
data = get_articles(article_data.query, article_data.tag, article_data.size)
45-
logging.info(f"Articles fetched: {len(data['data'])} articles.")
46+
articles = await get_articles(
47+
article_data.query, article_data.tag, article_data.size
48+
)
49+
logging.info(f"Articles fetched: {len(articles)} articles.")
4650
try:
47-
params = process_params(data)
51+
params = process_params(articles)
4852
except Exception as e:
4953
# You could log the exception here if needed
50-
raise HTTPException(status_code=500, detail=e)
54+
raise HTTPException(status_code=500, detail=e) from e
5155
graph.query(import_cypher_query, params={"data": params})
52-
logging.info(f"Article import query executed successfully.")
56+
logging.info("Article import query executed successfully.")
5357
return len(params)
5458

5559

@@ -123,6 +127,11 @@ def fetch_unprocessed_count(count_data: CountData) -> int:
123127
return data[0]["output"]
124128

125129

130+
def run_async_function_in_executor(loop, async_func):
131+
future = asyncio.run_coroutine_threadsafe(async_func(), loop)
132+
return future.result()
133+
134+
126135
@app.post("/enhance_entities/")
127136
def enhance_entities(entity_data: EntityData) -> str:
128137
entities = graph.query(
@@ -133,11 +142,16 @@ def enhance_entities(entity_data: EntityData) -> str:
133142
params={"limit": entity_data.size},
134143
)
135144
enhanced_data = []
145+
loop = asyncio.get_event_loop()
136146
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
137147
# Submitting all tasks and creating a list of future objects
138148
for row in entities:
139149
futures = [
140-
executor.submit(process_entities, el, row["label"])
150+
executor.submit(
151+
run_async_function_in_executor(loop, process_entities),
152+
el,
153+
row["label"],
154+
)
141155
for el in row["entities"]
142156
]
143157

api/app/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def setup_indices():
5252
graph=graph,
5353
index_name=index_name,
5454
keyword_index_name=keyword_index_name,
55-
search_type="hybrid",
55+
search_type="hybrid", # type: ignore
5656
)
5757

5858
text_splitter = TokenTextSplitter(
@@ -121,7 +121,7 @@ def generate_full_text_query(input: str) -> str:
121121

122122
def remove_null_properties(data: Dict[str, Any]):
123123
if not data:
124-
return []
124+
return {}
125125
# Process the 'nodes' part of the data
126126
for node in data["nodes"]:
127127
# Create a list of keys to remove (those that are None)

0 commit comments

Comments
 (0)