Shivani-Bhat commited on
Commit
89392e5
·
verified ·
1 Parent(s): c003b0f

Update tools_additions.py

Browse files
Files changed (1) hide show
  1. tools_additions.py +25 -57
tools_additions.py CHANGED
@@ -4,6 +4,7 @@
4
  # GROUP 8: DBSCAN Clustering (title + abstract separate vectors)
5
  # GROUP 9: Cluster Splitting and Min-Membership Enforcement
6
  # GROUP 10: LLM Cluster Labeling (Anthropic API)
 
7
  # =============================================================================
8
 
9
  import os
@@ -366,7 +367,6 @@ def split_large_clusters(
366
  next_cid += len(unique_sub)
367
 
368
  indices = sub_df.index.tolist()
369
- noise_mask = sub_labels == -1
370
  for local_i, (orig_idx, sl) in enumerate(zip(indices, sub_labels)):
371
  if sl == -1:
372
  # Absorb noise into nearest non-noise neighbour's cluster
@@ -406,7 +406,7 @@ def split_large_clusters(
406
 
407
 
408
  # =============================================================================
409
- # GROUP 10: LLM CLUSTER LABELING (ANTHROPIC API + MISTRAL + GEMINI)
410
  # =============================================================================
411
 
412
  def _top3_sentences(group_df: pd.DataFrame) -> str:
@@ -510,35 +510,28 @@ def label_clusters_with_llm(
510
 
511
 
512
  # =============================================================================
513
- # GROUP 11: AGENTIC COUNCIL (MISTRAL + GEMINI + ANTHROPIC SYNTHESIS)
514
  # =============================================================================
515
 
516
  COUNCIL_PROMPT_TEMPLATE = """You are a senior Information Systems research analyst.
517
  You have been given a PAJAIS research gap analysis report with the following findings:
518
-
519
  {findings}
520
-
521
  Based on this analysis, provide your expert assessment covering:
522
  1. The 3 most strategically important research gaps for the field
523
  2. Which novel topics have the highest publication impact potential
524
  3. Recommended methodologies for addressing the top gap
525
  4. Any risks or caveats in the analysis
526
-
527
  Be specific, cite topic names from the report, and limit your response to 300 words."""
528
 
529
  SYNTHESIS_PROMPT_TEMPLATE = """You are the Chief Research Officer synthesizing advice from two expert panels.
530
-
531
  Panel A (Mistral) said:
532
  {mistral_response}
533
-
534
  Panel B (Gemini) said:
535
  {gemini_response}
536
-
537
  Your task:
538
  1. Identify the 2-3 points both panels AGREE on (consensus insights)
539
  2. Identify where they DIVERGE and explain which view is more defensible
540
  3. Produce a final 200-word synthesis recommendation
541
-
542
  Structure your response as:
543
  ### Consensus
544
  <points>
@@ -606,56 +599,30 @@ def _call_gemini(
606
  return f"[Gemini unavailable: {e}]"
607
 
608
 
609
- def _call_anthropic_synthesis(
610
- prompt: str,
611
- api_key: str,
612
- model: str = "claude-sonnet-4-20250514",
613
- ) -> str:
614
- """Call Anthropic for synthesis."""
615
- try:
616
- resp = httpx.post(
617
- "https://api.anthropic.com/v1/messages",
618
- headers={
619
- "x-api-key": api_key,
620
- "anthropic-version": "2023-06-01",
621
- "content-type": "application/json",
622
- },
623
- json={
624
- "model": model,
625
- "max_tokens": 600,
626
- "messages": [{"role": "user", "content": prompt}],
627
- },
628
- timeout=30.0,
629
- )
630
- resp.raise_for_status()
631
- return resp.json()["content"][0]["text"].strip()
632
- except Exception as e:
633
- logger.error(f"Anthropic synthesis call failed: {e}")
634
- return f"[Anthropic synthesis unavailable: {e}]"
635
-
636
-
637
  def run_agentic_council(
638
  taxonomy_map: Dict[str, Any],
639
  topic_df: Optional[pd.DataFrame],
640
  mistral_api_key: str = "",
641
  gemini_api_key: str = "",
642
- anthropic_api_key: str = "",
643
  ) -> Dict[str, str]:
644
  """
645
- Run the three-model agentic council:
646
- Mistral Gemini Anthropic (synthesis judge).
 
 
647
 
648
  Parameters
649
  ----------
650
  taxonomy_map : Output of generate_taxonomy_map.
651
  topic_df : Topic DataFrame (used to build findings summary).
652
  mistral_api_key : Mistral API key.
653
- gemini_api_key : Google AI Studio API key.
654
- anthropic_api_key : Anthropic API key. Falls back to ANTHROPIC_API_KEY env var.
655
 
656
  Returns
657
  -------
658
- Dict with keys: 'mistral', 'gemini', 'synthesis', 'findings_summary'
659
  """
660
  # Build findings summary
661
  gap = taxonomy_map.get("gap_analysis", {})
@@ -681,44 +648,45 @@ def run_agentic_council(
681
  PAJAIS Coverage: {gap.get('coverage_pct', 0):.1f}% ({gap.get('mapped_count', 0)} mapped, {gap.get('novel_count', 0)} novel)
682
  Covered themes (sample): {covered_str}
683
  Uncovered themes (sample): {uncovered_str}
684
-
685
  Top discovered topics: {top_topics_str}
686
-
687
  Novel research themes (top 5):
688
  {novel_str}
689
-
690
  Publishable gap candidates:
691
  {pub_str}
692
  """.strip()
693
 
694
  council_prompt = COUNCIL_PROMPT_TEMPLATE.format(findings=findings)
695
 
696
- logger.info("Council: calling Mistral…")
 
697
  mistral_resp = (
698
  _call_mistral(council_prompt, mistral_api_key)
699
  if mistral_api_key.strip()
700
  else "[Mistral API key not provided]"
701
  )
702
 
703
- logger.info("Council: calling Gemini…")
 
704
  gemini_resp = (
705
  _call_gemini(council_prompt, gemini_api_key)
706
  if gemini_api_key.strip()
707
  else "[Gemini API key not provided]"
708
  )
709
 
 
710
  synthesis_prompt = SYNTHESIS_PROMPT_TEMPLATE.format(
711
  mistral_response=mistral_resp,
712
  gemini_response=gemini_resp,
713
  )
714
-
715
- anth_key = anthropic_api_key or os.environ.get("ANTHROPIC_API_KEY", "")
716
- logger.info("Council: calling Anthropic synthesis judge…")
717
- synthesis_resp = (
718
- _call_anthropic_synthesis(synthesis_prompt, anth_key)
719
- if anth_key.strip()
720
- else "[Anthropic API key not provided]"
721
- )
 
722
 
723
  return {
724
  "findings_summary": findings,
 
4
  # GROUP 8: DBSCAN Clustering (title + abstract separate vectors)
5
  # GROUP 9: Cluster Splitting and Min-Membership Enforcement
6
  # GROUP 10: LLM Cluster Labeling (Anthropic API)
7
+ # GROUP 11: Agentic Council (Mistral + Gemini panels, Gemini synthesis judge)
8
  # =============================================================================
9
 
10
  import os
 
367
  next_cid += len(unique_sub)
368
 
369
  indices = sub_df.index.tolist()
 
370
  for local_i, (orig_idx, sl) in enumerate(zip(indices, sub_labels)):
371
  if sl == -1:
372
  # Absorb noise into nearest non-noise neighbour's cluster
 
406
 
407
 
408
  # =============================================================================
409
+ # GROUP 10: LLM CLUSTER LABELING (ANTHROPIC API)
410
  # =============================================================================
411
 
412
  def _top3_sentences(group_df: pd.DataFrame) -> str:
 
510
 
511
 
512
  # =============================================================================
513
+ # GROUP 11: AGENTIC COUNCIL (MISTRAL + GEMINI PANELS, GEMINI SYNTHESIS JUDGE)
514
  # =============================================================================
515
 
516
  COUNCIL_PROMPT_TEMPLATE = """You are a senior Information Systems research analyst.
517
  You have been given a PAJAIS research gap analysis report with the following findings:
 
518
  {findings}
 
519
  Based on this analysis, provide your expert assessment covering:
520
  1. The 3 most strategically important research gaps for the field
521
  2. Which novel topics have the highest publication impact potential
522
  3. Recommended methodologies for addressing the top gap
523
  4. Any risks or caveats in the analysis
 
524
  Be specific, cite topic names from the report, and limit your response to 300 words."""
525
 
526
  SYNTHESIS_PROMPT_TEMPLATE = """You are the Chief Research Officer synthesizing advice from two expert panels.
 
527
  Panel A (Mistral) said:
528
  {mistral_response}
 
529
  Panel B (Gemini) said:
530
  {gemini_response}
 
531
  Your task:
532
  1. Identify the 2-3 points both panels AGREE on (consensus insights)
533
  2. Identify where they DIVERGE and explain which view is more defensible
534
  3. Produce a final 200-word synthesis recommendation
 
535
  Structure your response as:
536
  ### Consensus
537
  <points>
 
599
  return f"[Gemini unavailable: {e}]"
600
 
601
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
602
  def run_agentic_council(
603
  taxonomy_map: Dict[str, Any],
604
  topic_df: Optional[pd.DataFrame],
605
  mistral_api_key: str = "",
606
  gemini_api_key: str = "",
607
+ anthropic_api_key: str = "", # retained for signature compatibility
608
  ) -> Dict[str, str]:
609
  """
610
+ Run the three-stage agentic council:
611
+ Stage 1 Mistral panel: independent analysis of findings.
612
+ Stage 2 — Gemini panel: independent analysis of findings.
613
+ Stage 3 — Gemini synthesis judge: reconciles both panels (gemini-1.5-pro).
614
 
615
  Parameters
616
  ----------
617
  taxonomy_map : Output of generate_taxonomy_map.
618
  topic_df : Topic DataFrame (used to build findings summary).
619
  mistral_api_key : Mistral API key.
620
+ gemini_api_key : Google AI Studio API key (used for both panel and judge).
621
+ anthropic_api_key : Ignored. Kept for backward-compatible call sites.
622
 
623
  Returns
624
  -------
625
+ Dict with keys: 'findings_summary', 'mistral', 'gemini', 'synthesis'
626
  """
627
  # Build findings summary
628
  gap = taxonomy_map.get("gap_analysis", {})
 
648
  PAJAIS Coverage: {gap.get('coverage_pct', 0):.1f}% ({gap.get('mapped_count', 0)} mapped, {gap.get('novel_count', 0)} novel)
649
  Covered themes (sample): {covered_str}
650
  Uncovered themes (sample): {uncovered_str}
 
651
  Top discovered topics: {top_topics_str}
 
652
  Novel research themes (top 5):
653
  {novel_str}
 
654
  Publishable gap candidates:
655
  {pub_str}
656
  """.strip()
657
 
658
  council_prompt = COUNCIL_PROMPT_TEMPLATE.format(findings=findings)
659
 
660
+ # Stage 1 — Mistral panel
661
+ logger.info("Council: calling Mistral (panel)…")
662
  mistral_resp = (
663
  _call_mistral(council_prompt, mistral_api_key)
664
  if mistral_api_key.strip()
665
  else "[Mistral API key not provided]"
666
  )
667
 
668
+ # Stage 2 — Gemini panel
669
+ logger.info("Council: calling Gemini (panel)…")
670
  gemini_resp = (
671
  _call_gemini(council_prompt, gemini_api_key)
672
  if gemini_api_key.strip()
673
  else "[Gemini API key not provided]"
674
  )
675
 
676
+ # Stage 3 — Gemini synthesis judge (upgraded model)
677
  synthesis_prompt = SYNTHESIS_PROMPT_TEMPLATE.format(
678
  mistral_response=mistral_resp,
679
  gemini_response=gemini_resp,
680
  )
681
+ logger.info("Council: calling Gemini (synthesis judge)…")
682
+ if gemini_api_key.strip():
683
+ synthesis_resp = _call_gemini(
684
+ synthesis_prompt,
685
+ gemini_api_key,
686
+ model="gemini-1.5-pro",
687
+ )
688
+ else:
689
+ synthesis_resp = "[Gemini API key not provided — synthesis skipped]"
690
 
691
  return {
692
  "findings_summary": findings,