1+ import asyncio
12import logging
23import os
34from concurrent .futures import ThreadPoolExecutor
45from 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
97from fastapi import FastAPI , HTTPException
108from fastapi .middleware .cors import CORSMiddleware
11- from graph_prefiltering import prefiltering_agent_executor
12- from importing import get_articles , import_cypher_query , process_params
139from 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
1820logging .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
2527app = FastAPI ()
2628
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/" )
127136def 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
0 commit comments