fix(semantic_extract): Pass API key to Groq LLM provider in extraction methods

- Add API key handling in extract_entities_llm(), extract_relations_llm(), and extract_triplets_llm()
- Add llm_model parameter support in extract_triplets_llm() for consistency
- Fix relation extraction bug with type checking for subject_text/object_text
- Add environment variable fallback for API keys
- Include providers.py for context (GroqProvider implementation)

Fixes #145
This commit is contained in:
KaifAhmad1
2026-01-06 22:37:57 +05:30
parent 4eb69e5048
commit 9c59f97542
3 changed files with 166 additions and 46 deletions
@@ -57,7 +57,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"metadata": {},
"outputs": [
{
@@ -217,21 +217,36 @@
"# Step 3: Extract entities using NERExtractor with Groq\n",
"from semantica.semantic_extract import NERExtractor\n",
"\n",
"text_for_extraction = parsed_doc[\"full_text\"]\n",
"\n",
"ner = NERExtractor(\n",
" method=\"llm\",\n",
" provider=\"groq\",\n",
" llm_model=\"llama-3.1-8b-instant\",\n",
" min_confidence=0.7\n",
" min_confidence=0.5,\n",
" temperature=0.0\n",
")\n",
"\n",
"entity_types = [\n",
" \"ORGANIZATION\", \"ORG\", \"PERSON\", \"MONEY\", \"CURRENCY\",\n",
" \"PERCENT\", \"PERCENTAGE\", \"DATE\", \"TIME\", \"PRODUCT\",\n",
" \"LOCATION\", \"GPE\", \"EVENT\", \"QUANTITY\", \"CARDINAL\"\n",
"]\n",
"\n",
"entities = ner.extract_entities(\n",
" normalized_text,\n",
" entity_types=[\"ORG\", \"PERSON\", \"MONEY\", \"DATE\", \"PERCENT\"]\n",
" text_for_extraction,\n",
" entity_types=entity_types\n",
")\n",
"\n",
"print(f\"✓ Entities extracted: {len(entities)}\")\n",
"if entities:\n",
" print(f\" Sample: {entities[0].text} ({entities[0].label})\")\n"
" entity_by_type = {}\n",
" for entity in entities:\n",
" entity_by_type.setdefault(entity.label, []).append(entity.text)\n",
" \n",
" print(f\" Entity breakdown:\")\n",
" for label, texts in list(entity_by_type.items())[:5]:\n",
" print(f\" {label}: {len(texts)} entities (e.g., {texts[0]})\")\n"
]
},
{
@@ -260,17 +275,28 @@
"source": [
"# Step 4: Extract financial metrics using NERExtractor\n",
"financial_entities = ner.extract_entities(\n",
" normalized_text,\n",
" entity_types=[\"MONEY\", \"PERCENT\", \"DATE\"]\n",
" text_for_extraction,\n",
" entity_types=[\"MONEY\", \"CURRENCY\", \"PERCENT\", \"PERCENTAGE\", \"QUANTITY\", \"CARDINAL\"]\n",
")\n",
"\n",
"financial_metrics = {}\n",
"financial_metrics = {\"money\": [], \"percentages\": [], \"quantities\": []}\n",
"for entity in financial_entities:\n",
" if entity.label == \"MONEY\":\n",
" financial_metrics[entity.text] = entity.text\n",
" label_lower = entity.label.lower()\n",
" if \"money\" in label_lower or \"currency\" in label_lower:\n",
" financial_metrics[\"money\"].append(entity.text)\n",
" elif \"percent\" in label_lower:\n",
" financial_metrics[\"percentages\"].append(entity.text)\n",
" elif \"quantity\" in label_lower or \"cardinal\" in label_lower:\n",
" financial_metrics[\"quantities\"].append(entity.text)\n",
"\n",
"financial_metrics_flat = {v: v for category in financial_metrics.values() for v in category}\n",
"\n",
"print(f\"✓ Financial entities: {len(financial_entities)}\")\n",
"print(f\" Financial metrics: {len(financial_metrics)}\")\n"
"print(f\" Money/Currency: {len(financial_metrics['money'])}\")\n",
"print(f\" Percentages: {len(financial_metrics['percentages'])}\")\n",
"print(f\" Quantities: {len(financial_metrics['quantities'])}\")\n",
"if financial_entities:\n",
" print(f\" Sample: {financial_entities[0].text} ({financial_entities[0].label})\")\n"
]
},
{
@@ -299,23 +325,44 @@
"# Step 5: Extract relationships using RelationExtractor with Groq LLM\n",
"from semantica.semantic_extract import RelationExtractor\n",
"\n",
"relation_extractor = RelationExtractor(\n",
" method=\"llm\",\n",
" confidence_threshold=0.6,\n",
" relation_types=[\"HAS_REVENUE\", \"HAS_EPS\", \"STATES\", \"PROVIDES_GUIDANCE\", \"OPERATES_IN\"]\n",
")\n",
"if not entities:\n",
" print(\"⚠️ No entities found. Skipping relationship extraction.\")\n",
" relationships = []\n",
"else:\n",
" relation_extractor = RelationExtractor(\n",
" method=\"llm\",\n",
" confidence_threshold=0.5,\n",
" relation_types=[\n",
" \"HAS_REVENUE\", \"HAS_EPS\", \"HAS_MARGIN\", \"HAS_PROFIT\", \"HAS_GROWTH\",\n",
" \"PROVIDES_GUIDANCE\", \"STATES\", \"ANNOUNCES\", \"REPORTS\", \"EXPECTS\",\n",
" \"OPERATES_IN\", \"LOCATED_IN\", \"PARTNERS_WITH\", \"SERVES\",\n",
" \"COMPARED_TO\", \"INCREASED_BY\", \"DECREASED_BY\", \"CHANGED_BY\",\n",
" \"DURING\", \"IN_QUARTER\", \"FOR_PERIOD\",\n",
" \"RELATED_TO\", \"PART_OF\", \"AFFECTS\"\n",
" ]\n",
" )\n",
"\n",
"relationships = relation_extractor.extract_relations(\n",
" normalized_text,\n",
" entities=entities,\n",
" provider=\"groq\",\n",
" llm_model=\"llama-3.1-8b-instant\"\n",
")\n",
" relationships = relation_extractor.extract_relations(\n",
" text_for_extraction,\n",
" entities=entities,\n",
" provider=\"groq\",\n",
" llm_model=\"llama-3.1-8b-instant\",\n",
" temperature=0.0\n",
" )\n",
"\n",
"print(f\"✓ Relationships extracted: {len(relationships)}\")\n",
"if relationships:\n",
" rel = relationships[0]\n",
" print(f\" Sample: {rel.subject.text} → {rel.predicate} → {rel.object.text}\")\n"
" print(f\"✓ Relationships extracted: {len(relationships)}\")\n",
" if relationships:\n",
" rel_by_type = {}\n",
" for rel in relationships:\n",
" rel_by_type.setdefault(rel.predicate, []).append(rel)\n",
" \n",
" print(f\" Relationship breakdown:\")\n",
" for pred, rels in list(rel_by_type.items())[:5]:\n",
" sample = rels[0]\n",
" print(f\" {pred}: {len(rels)} relationships\")\n",
" print(f\" Sample: {sample.subject.text} → {sample.predicate} → {sample.object.text}\")\n",
" else:\n",
" print(\" ⚠️ No relationships extracted.\")\n"
]
},
{
@@ -362,26 +409,44 @@
"# Step 6: Extract RDF triplets using TripletExtractor with Groq LLM\n",
"from semantica.semantic_extract import TripletExtractor\n",
"\n",
"triplet_extractor = TripletExtractor(\n",
" method=\"llm\",\n",
" include_temporal=True,\n",
" include_provenance=True\n",
")\n",
"if not entities:\n",
" print(\"⚠️ No entities found. Skipping triplet extraction.\")\n",
" triplets = []\n",
" validated_triplets = []\n",
"else:\n",
" triplet_extractor = TripletExtractor(\n",
" method=\"llm\",\n",
" include_temporal=True,\n",
" include_provenance=True\n",
" )\n",
"\n",
"triplets = triplet_extractor.extract_triplets(\n",
" normalized_text,\n",
" entities=entities,\n",
" relations=relationships,\n",
" provider=\"groq\",\n",
" llm_model=\"llama-3.1-8b-instant\"\n",
")\n",
" triplets = triplet_extractor.extract_triplets(\n",
" text_for_extraction,\n",
" entities=entities,\n",
" relations=relationships if relationships else None,\n",
" provider=\"groq\",\n",
" llm_model=\"llama-3.1-8b-instant\",\n",
" temperature=0.0\n",
" )\n",
"\n",
"validated_triplets = triplet_extractor.validate_triplets(triplets)\n",
" if hasattr(triplet_extractor, 'triplet_validator'):\n",
" validated_triplets = triplet_extractor.triplet_validator.validate_triplets(triplets)\n",
" else:\n",
" validated_triplets = triplets\n",
"\n",
"print(f\"✓ RDF triplets extracted: {len(triplets)}\")\n",
"if triplets:\n",
" t = triplets[0]\n",
" print(f\" Sample: {t.subject} → {t.predicate} → {t.object}\")\n"
" print(f\"✓ RDF triplets extracted: {len(triplets)}\")\n",
" if triplets:\n",
" triplet_by_pred = {}\n",
" for t in triplets:\n",
" triplet_by_pred.setdefault(t.predicate, []).append(t)\n",
" \n",
" print(f\" Triplet breakdown:\")\n",
" for pred, ts in list(triplet_by_pred.items())[:5]:\n",
" sample = ts[0]\n",
" print(f\" {pred}: {len(ts)} triplets\")\n",
" print(f\" Sample: {sample.subject} → {sample.predicate} → {sample.object}\")\n",
" else:\n",
" print(\" ⚠️ No triplets extracted.\")\n"
]
},
{