Spaces:
Sleeping
Sleeping
File size: 3,577 Bytes
01543cd 333cede 01543cd 333cede 01543cd 333cede 01543cd 333cede 01543cd 333cede 01543cd 333cede 01543cd 333cede 01543cd 90e9ece 01543cd 333cede 01543cd 333cede 01543cd 333cede 01543cd 333cede 01543cd 333cede 01543cd f37f86c 333cede 01543cd 333cede 01543cd 333cede 01543cd 333cede 90e9ece 333cede 01543cd 333cede 01543cd 333cede | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | """Load and process FAQ data from a JSON file."""
import json
import logging
from pathlib import Path
from typing import Any
logger = logging.getLogger(__name__)
class FAQEntry:
"""Representation of a single FAQ entry."""
def __init__(self, formulation: str, theme: str, response: str) -> None:
"""
Initialize an FAQ entry.
Args:
formulation: The FAQ question text.
theme: The FAQ theme or category.
response: The associated response.
"""
self.formulation: str = formulation
self.theme: str = theme
self.response: str = response
def load_faq_data(json_path: str) -> list[FAQEntry]:
"""
Load FAQ data from a JSON file.
The JSON payload is expected to contain an "intents" array. For each intent
with enabled=True, a FAQEntry is created from:
- formulation: the utterances list, plus canonical_question if not already
present among the utterances
- theme: the intent_key
- response: the response text
Args:
json_path: Path to the JSON file containing FAQ intents.
Returns:
A list of FAQEntry objects with formulation, theme, and response.
Raises:
FileNotFoundError: If the JSON file does not exist.
ValueError: If the JSON is empty or malformed.
"""
path = Path(json_path)
if not path.exists():
raise FileNotFoundError(f"File not found: {json_path}")
try:
logger.info(f"Loading FAQ data from JSON: {json_path}")
with path.open("r", encoding="utf-8-sig") as handle:
payload: dict[str, Any] = json.load(handle)
except json.JSONDecodeError as exc:
raise ValueError(f"Invalid JSON payload: {exc}") from exc
intents = payload.get("intents")
if not isinstance(intents, list):
raise ValueError("The JSON payload does not contain a valid 'intents' list")
faq_entries: list[FAQEntry] = []
for intent in intents:
if not isinstance(intent, dict):
continue
enabled = intent.get("enabled", False)
if not enabled:
continue
utterances = intent.get("utterances")
if not isinstance(utterances, list) or not utterances:
continue
intent_key = intent.get("intent_key")
response = intent.get("response")
if not isinstance(intent_key, str) or not intent_key.strip():
continue
if not isinstance(response, str) or not response.strip():
continue
formulations = list(utterances)
canonical_question = intent.get("canonical_question")
if isinstance(canonical_question, str) and canonical_question.strip():
if canonical_question.strip() not in [u.strip() for u in utterances if isinstance(u, str)]:
formulations.append(canonical_question)
for formulation in formulations:
if not isinstance(formulation, str) or not formulation.strip():
continue
faq_entries.append(
FAQEntry(
formulation=formulation.strip(),
theme=intent_key.strip(),
response=response.strip(),
)
)
if not faq_entries:
raise ValueError("No valid FAQ entries were found in the JSON payload")
logger.info(f"✓ {len(faq_entries)} FAQ entries loaded successfully from JSON")
return faq_entries
|