Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various cleanup fixes #401

Merged
merged 8 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 16 additions & 19 deletions api/cache_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@

# Cache expiration times in seconds
CACHE_TIMES = {
"SHORT": 300, # 5 minutes
"MEDIUM": 3600, # 1 hour
"LONG": 864000, # 10 days
"SHORT": 86400, # 1 day
"MEDIUM": 604800, # 1 week
"LONG": 2592000, # 30 days
}


Expand Down Expand Up @@ -116,7 +116,7 @@ def cached_endpoint(expire: int = CACHE_TIMES["MEDIUM"]):
Decorator that implements Redis-based caching for API endpoints.

Args:
expire: Cache expiration time in seconds
expire: Cache expiration time in seconds. Use -1 for no expiration.
"""

def wrapper(func):
Expand All @@ -128,45 +128,42 @@ async def debug_wrapper(*args, **kwargs):

try:
redis = await aioredis.from_url(
"redis://redis:6379", encoding="utf8", decode_responses=True
"redis://redis:6379",
encoding="utf8",
decode_responses=True,
socket_timeout=300,
socket_connect_timeout=300,
retry_on_timeout=True,
)

exists = await redis.exists(cache_key)
logger.info("Cache key exists: %s", exists)

if exists:
cached_value = await redis.get(cache_key)
logger.info(
"Retrieved cached value of length: %s",
len(cached_value) if cached_value else 0,
)

if cached_value:
try:
decoded = CustomJsonCoder.decode(cached_value)
logger.info(
"Successfully decoded cached value of type: %s",
type(decoded),
)
logger.info("Cache hit for: %s", cache_key)
return decoded
except ValueError as e:
logger.error("Failed to decode cached value: %s", str(e))
else:
logger.warning("Cache key exists but value is None")

logger.info("Cache miss - calling original function")
result = await func(*args, **kwargs)

try:
encoded = CustomJsonCoder.encode(result)
await redis.set(cache_key, encoded, ex=expire)
if expire != -1:
await redis.set(cache_key, encoded, ex=expire)
else:
await redis.set(cache_key, encoded)
logger.info("Stored new result in cache with TTL: %s", expire)
except ValueError as e:
logger.error("Failed to store in cache: %s", str(e))

return result

except ConnectionError as e:
except (ConnectionError, TimeoutError) as e:
logger.error("Cache operation failed: %s", str(e))
return await func(*args, **kwargs)

Expand Down
23 changes: 13 additions & 10 deletions api/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,20 +362,23 @@ def get_category_dict(segment_parallels, categories_list):
"""
category_dict = {}
for parallel in segment_parallels:
if parallel["category"]:
try:
category_index = categories_list.index(parallel["category"]) + 1
except: # pylint: disable=bare-except
print("cannot find in categories list: ", parallel["category"])
continue
else:
if not parallel or not isinstance(parallel, dict):
continue
category = parallel.get("category")
if not category:
continue
try:
category_index = categories_list.index(category) + 1
except ValueError:
print("cannot find in categories list: ", category)
continue

if not category_index in category_dict:
category_dict[category_index] = []

category_dict[category_index].append(
shorten_segment_names(parallel["par_segnr"])
)
par_segnr = parallel.get("par_segnr")
if not par_segnr:
continue
category_dict[category_index].append(shorten_segment_names(par_segnr))

return category_dict
1 change: 0 additions & 1 deletion api/endpoints/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,4 @@ async def get_table_download(input: DownloadInput) -> Any:
language,
],
)

return
2 changes: 1 addition & 1 deletion api/endpoints/helpers/menu_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def structure_menu_data(query_result, language):
files=natsorted(cat_info["files"], key=lambda x: x.filename),
)
for cat_info in natsorted(
categories.values(), key=lambda x: x["categorydisplayname"]
categories.values(), key=lambda x: x["category"]
)
],
)
Expand Down
10 changes: 4 additions & 6 deletions api/endpoints/numbers_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,14 @@ def create_numbers_view_data(table_results):
parallels_list = []
if result["parallels"]:
for parallel in result["parallels"]:
if parallel["par_full_names"][0]:
if parallel:
parallel_dic = {}
parallel_dic["segmentnr"] = shorten_segment_names(
parallel["par_segnr"]
)
parallel_dic["displayName"] = parallel["par_full_names"][0][
"displayName"
]
parallel_dic["fileName"] = parallel["par_full_names"][0]["fileName"]
parallel_dic["category"] = parallel["par_full_names"][0]["category"]
parallel_dic["displayName"] = parallel["displayName"]
parallel_dic["fileName"] = parallel["fileName"]
parallel_dic["category"] = parallel["category"]
parallels_list.append(parallel_dic)

if parallels_list:
Expand Down
69 changes: 45 additions & 24 deletions api/endpoints/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,62 @@

@router.post("/search/", response_model=SearchOutput)
async def search(search_input: SearchInput):
# Execute query with preprocessed search strings
# Process search string only for requested language
search_strings = search_utils.preprocess_search_string(
search_input.search_string, search_input.filters.language
)
query_languages = [
"sa",
"bo",
"zh",
"pa",
] # lang codes here are hard-coded, sue me! for debugging purposes, when we only need sanskrit or pali, you can limit the indicies by supplying only the specific language tag
if search_input.filters.language != "all":
query_languages = [search_input.filters.language]

# Determine which languages to search
query_languages = (
["sa", "bo", "pa"]
if search_input.filters.language == "all"
else [search_input.filters.language]
)

# Build filter parameters with only relevant search strings
filter_params = {
"filter_include_files": search_input.filters.include_files,
"filter_exclude_files": search_input.filters.exclude_files,
"filter_include_categories": search_input.filters.include_categories,
"filter_exclude_categories": search_input.filters.exclude_categories,
"filter_include_collections": search_input.filters.include_collections,
"filter_exclude_collections": search_input.filters.exclude_collections,
"search_string_sa": search_strings["sa"],
"search_string_sa_fuzzy": search_strings["sa_fuzzy"],
"search_string_bo": search_strings["bo"],
"search_string_zh": search_strings["zh"],
"search_string_pa": search_strings["pa"],
"filter_include_files": search_input.filters.include_files or [],
"filter_exclude_files": search_input.filters.exclude_files or [],
"filter_include_categories": search_input.filters.include_categories or [],
"filter_exclude_categories": search_input.filters.exclude_categories or [],
"filter_include_collections": search_input.filters.include_collections or [],
"filter_exclude_collections": search_input.filters.exclude_collections or [],
}

# Only add search strings for requested languages
for lang in query_languages:
if lang in search_strings:
filter_params[f"search_string_{lang}"] = search_strings[lang]
if lang == "sa" and "sa_fuzzy" in search_strings:
filter_params["search_string_sa_fuzzy"] = search_strings["sa_fuzzy"]

# Create bind variables dictionary
bind_variables = {
"search_string_sa": search_strings["sa"] if "sa" in search_strings else None,
"search_string_sa_fuzzy": (
search_strings["sa_fuzzy"] if "sa_fuzzy" in search_strings else None
),
"search_string_bo": search_strings["bo"] if "bo" in search_strings else None,
"search_string_pa": search_strings["pa"] if "pa" in search_strings else None,
"search_string_zh": search_strings["zh"] if "zh" in search_strings else None,
}

# Build the query using the query builder
# Remove None values from bind_variables
bind_variables = {k: v for k, v in bind_variables.items() if v is not None}

# Build and execute query
query = build_query_search(
query_languages=query_languages, filters=filter_params, max_limit=1000
query_languages=query_languages,
bind_variables=bind_variables,
filters=filter_params,
max_limit=1000,
)
print(f"[search] query: {query}")
# Execute query with bind variables from filter_params

result = execute_query(query, bind_vars=filter_params)
result = result.result[0]

# Post-process results
processed_results = search_utils.postprocess_results(search_strings, result)
processed_results = calculate_color_maps_search(processed_results)

return {"searchResults": processed_results}
1 change: 0 additions & 1 deletion api/endpoints/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,4 @@ async def get_active_segment_for_folio(
utils_queries.QUERY_SEGMENT_FOR_FOLIO,
bind_vars={"folio": folio, "filename": filename},
)
print(f"[utils] query_result: {query_result.result}")
return {"active_segment": query_result.result[0]}
8 changes: 7 additions & 1 deletion api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,13 @@ async def startup():
"""
logger.info("Initializing FastAPI application...")
redis = aioredis.from_url(
"redis://redis:6379", encoding="utf8", decode_responses=False
"redis://redis:6379",
encoding="utf8",
decode_responses=False,
socket_timeout=300,
socket_connect_timeout=300,
retry_on_timeout=True,
health_check_interval=30,
)
FastAPICache.init(
backend=RedisBackend(redis),
Expand Down
Loading
Loading