Shivani-Bhat commited on
Commit
9a2a7f3
Β·
verified Β·
1 Parent(s): 73c3be7

Update tools.py

Browse files
Files changed (1) hide show
  1. tools.py +44 -52
tools.py CHANGED
@@ -1697,21 +1697,21 @@ def _call_gemini_label(prompt: str, api_key: str) -> str:
1697
  return f'[Gemini: {e}]'
1698
 
1699
 
1700
- def _call_deepseek_label(prompt: str, api_key: str,
1701
- model: str = 'deepseek-chat') -> str:
1702
- """DeepSeek API (OpenAI-compatible) β€” free $5 credit on signup."""
1703
  try:
 
1704
  r = _httpx.post(
1705
- 'https://api.deepseek.com/v1/chat/completions',
1706
- headers={'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json'},
1707
  json={'model': model, 'messages': [{'role': 'user', 'content': prompt}],
1708
- 'max_tokens': 20, 'temperature': 0.2},
1709
- timeout=25.0,
1710
  )
1711
  r.raise_for_status()
1712
- return r.json()['choices'][0]['message']['content'].strip()
1713
  except Exception as e:
1714
- return f'[DeepSeek: {e}]'
1715
 
1716
 
1717
  def _label_prompt(titles: List[str]) -> str:
@@ -1731,10 +1731,10 @@ def label_clusters_3llm(
1731
  embeddings: np.ndarray,
1732
  mistral_api_key: str = '',
1733
  gemini_api_key: str = '',
1734
- deepseek_api_key: str = '',
1735
  max_clusters: int = 30,
1736
  ) -> pd.DataFrame:
1737
- """Label each cluster using Mistral + Gemini + DeepSeek (all free/affordable APIs).
1738
 
1739
  For each cluster:
1740
  1. Selects 3 most representative paper titles (closest to centroid).
@@ -1749,7 +1749,7 @@ def label_clusters_3llm(
1749
  embeddings : SPECTER2 embeddings aligned with cluster_df rows.
1750
  mistral_api_key : Mistral API key (free tier).
1751
  gemini_api_key : Google AI Studio API key (free tier).
1752
- deepseek_api_key : DeepSeek API key (free $5 credit β€” deepseek.com).
1753
  max_clusters : Cap API calls to this many clusters.
1754
 
1755
  Returns:
@@ -1761,10 +1761,10 @@ def label_clusters_3llm(
1761
  summary['label_mistral'] = ''
1762
  if 'label_gemini' not in summary.columns:
1763
  summary['label_gemini'] = ''
1764
- if 'label_hf' not in summary.columns:
1765
- summary['label_hf'] = ''
1766
 
1767
- has_any_key = any([mistral_api_key.strip(), gemini_api_key.strip(), deepseek_api_key.strip()])
1768
 
1769
  for idx, row in summary.iterrows():
1770
  if idx >= max_clusters:
@@ -1801,10 +1801,10 @@ def label_clusters_3llm(
1801
  candidates.append(gl)
1802
  _time.sleep(0.2)
1803
 
1804
- if deepseek_api_key.strip():
1805
- dl = _call_deepseek_label(prompt, deepseek_api_key)
1806
- summary.at[idx, 'label_deepseek'] = dl
1807
- candidates.append(dl)
1808
  _time.sleep(0.2)
1809
 
1810
  summary.at[idx, 'label'] = _majority_label(candidates) if candidates else 'Research Cluster'
@@ -1833,8 +1833,8 @@ Panel A (Mistral) said:
1833
  {mistral_response}
1834
  Panel B (Gemini) said:
1835
  {gemini_response}
1836
- Panel C (DeepSeek) said:
1837
- {deepseek_response}
1838
  Your task:
1839
  1. Identify the 2-3 points ALL panels AGREE on (consensus insights)
1840
  2. Identify where they DIVERGE and explain which view is most defensible
@@ -1864,7 +1864,7 @@ def _call_mistral(prompt: str, api_key: str, model: str = 'mistral-large-latest'
1864
  return f'[Mistral unavailable: {e}]'
1865
 
1866
 
1867
- def _call_gemini(prompt: str, api_key: str, model: str = 'gemini-2.0-flash') -> str:
1868
  try:
1869
  url = (f'https://generativelanguage.googleapis.com/v1beta/models/'
1870
  f'{model}:generateContent?key={api_key}')
@@ -1883,25 +1883,25 @@ def _call_gemini(prompt: str, api_key: str, model: str = 'gemini-2.0-flash') ->
1883
  return f'[Gemini unavailable: {e}]'
1884
 
1885
 
1886
- def _call_deepseek(
1887
  prompt: str,
1888
- api_key: str,
1889
- model: str = 'deepseek-chat',
1890
  ) -> str:
1891
- """DeepSeek API (OpenAI-compatible endpoint). Uses deepseek-chat (DeepSeek-V3)."""
1892
  try:
 
1893
  r = _httpx.post(
1894
- 'https://api.deepseek.com/v1/chat/completions',
1895
- headers={'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json'},
1896
  json={'model': model, 'messages': [{'role': 'user', 'content': prompt}],
1897
- 'max_tokens': 500, 'temperature': 0.4},
1898
- timeout=30.0,
1899
  )
1900
  r.raise_for_status()
1901
- return r.json()['choices'][0]['message']['content'].strip()
1902
  except Exception as e:
1903
- logger.error(f'DeepSeek call failed: {e}')
1904
- return f'[DeepSeek unavailable: {e}]'
1905
 
1906
 
1907
  def run_agentic_council(
@@ -1909,13 +1909,13 @@ def run_agentic_council(
1909
  topic_df: Optional[pd.DataFrame],
1910
  mistral_api_key: str = '',
1911
  gemini_api_key: str = '',
1912
- deepseek_api_key: str = '',
1913
  anthropic_api_key: str = '', # kept for backward compat β€” not used
1914
  ) -> Dict[str, str]:
1915
- """Run 4-stage agentic council: Mistral β†’ Gemini β†’ DeepSeek panels + DeepSeek synthesis.
1916
 
1917
  Returns dict with keys:
1918
- 'findings_summary', 'mistral', 'gemini', 'deepseek', 'synthesis'
1919
  """
1920
  gap = taxonomy_map.get('gap_analysis', {})
1921
  novel_themes = taxonomy_map.get('novel_themes', [])[:5]
@@ -1963,31 +1963,23 @@ def run_agentic_council(
1963
  else '[Gemini API key not provided]'
1964
  )
1965
 
1966
- # ── Stage 3: DeepSeek panel ──
1967
- logger.info('Council: calling DeepSeek (Panel C)…')
1968
- deepseek_resp = (
1969
- _call_deepseek(council_prompt, deepseek_api_key)
1970
- if deepseek_api_key.strip()
1971
- else '[DeepSeek API key not provided]'
1972
- )
1973
 
1974
- # ── Stage 4: DeepSeek synthesis judge ──
1975
  synthesis_prompt = SYNTHESIS_PROMPT_TEMPLATE.format(
1976
  mistral_response=mistral_resp,
1977
  gemini_response=gemini_resp,
1978
- deepseek_response=deepseek_resp,
1979
- )
1980
- logger.info('Council: calling DeepSeek (synthesis judge)…')
1981
- synthesis_resp = (
1982
- _call_deepseek(synthesis_prompt, deepseek_api_key, model='deepseek-reasoner')
1983
- if deepseek_api_key.strip()
1984
- else '[DeepSeek API key not provided β€” synthesis skipped]'
1985
  )
 
 
1986
 
1987
  return {
1988
  'findings_summary': findings,
1989
  'mistral': mistral_resp,
1990
  'gemini': gemini_resp,
1991
- 'deepseek': deepseek_resp,
1992
  'synthesis': synthesis_resp,
1993
  }
 
1697
  return f'[Gemini: {e}]'
1698
 
1699
 
1700
+ def _call_ollama_label(prompt: str, base_url: str = 'http://localhost:11434',
1701
+ model: str = 'llama3') -> str:
1702
+ """Ollama local inference API."""
1703
  try:
1704
+ url = f'{base_url.rstrip("/")}/api/chat'
1705
  r = _httpx.post(
1706
+ url,
 
1707
  json={'model': model, 'messages': [{'role': 'user', 'content': prompt}],
1708
+ 'stream': False},
1709
+ timeout=30.0,
1710
  )
1711
  r.raise_for_status()
1712
+ return r.json()['message']['content'].strip()[:80]
1713
  except Exception as e:
1714
+ return f'[Ollama: {e}]'
1715
 
1716
 
1717
  def _label_prompt(titles: List[str]) -> str:
 
1731
  embeddings: np.ndarray,
1732
  mistral_api_key: str = '',
1733
  gemini_api_key: str = '',
1734
+ ollama_url: str = 'http://localhost:11434',
1735
  max_clusters: int = 30,
1736
  ) -> pd.DataFrame:
1737
+ """Label each cluster using Mistral + Gemini + Ollama.
1738
 
1739
  For each cluster:
1740
  1. Selects 3 most representative paper titles (closest to centroid).
 
1749
  embeddings : SPECTER2 embeddings aligned with cluster_df rows.
1750
  mistral_api_key : Mistral API key (free tier).
1751
  gemini_api_key : Google AI Studio API key (free tier).
1752
+ ollama_url : URL of the local Ollama instance.
1753
  max_clusters : Cap API calls to this many clusters.
1754
 
1755
  Returns:
 
1761
  summary['label_mistral'] = ''
1762
  if 'label_gemini' not in summary.columns:
1763
  summary['label_gemini'] = ''
1764
+ if 'label_ollama' not in summary.columns:
1765
+ summary['label_ollama'] = ''
1766
 
1767
+ has_any_key = any([mistral_api_key.strip(), gemini_api_key.strip(), ollama_url.strip()])
1768
 
1769
  for idx, row in summary.iterrows():
1770
  if idx >= max_clusters:
 
1801
  candidates.append(gl)
1802
  _time.sleep(0.2)
1803
 
1804
+ if ollama_url.strip():
1805
+ ol = _call_ollama_label(prompt, ollama_url)
1806
+ summary.at[idx, 'label_ollama'] = ol
1807
+ candidates.append(ol)
1808
  _time.sleep(0.2)
1809
 
1810
  summary.at[idx, 'label'] = _majority_label(candidates) if candidates else 'Research Cluster'
 
1833
  {mistral_response}
1834
  Panel B (Gemini) said:
1835
  {gemini_response}
1836
+ Panel C (Ollama) said:
1837
+ {ollama_response}
1838
  Your task:
1839
  1. Identify the 2-3 points ALL panels AGREE on (consensus insights)
1840
  2. Identify where they DIVERGE and explain which view is most defensible
 
1864
  return f'[Mistral unavailable: {e}]'
1865
 
1866
 
1867
+ def _call_gemini(prompt: str, api_key: str, model: str = 'gemini-1.5-flash') -> str:
1868
  try:
1869
  url = (f'https://generativelanguage.googleapis.com/v1beta/models/'
1870
  f'{model}:generateContent?key={api_key}')
 
1883
  return f'[Gemini unavailable: {e}]'
1884
 
1885
 
1886
+ def _call_ollama(
1887
  prompt: str,
1888
+ base_url: str = 'http://localhost:11434',
1889
+ model: str = 'llama3',
1890
  ) -> str:
1891
+ """Ollama API (Local). Uses llama3 by default."""
1892
  try:
1893
+ url = f'{base_url.rstrip("/")}/api/chat'
1894
  r = _httpx.post(
1895
+ url,
 
1896
  json={'model': model, 'messages': [{'role': 'user', 'content': prompt}],
1897
+ 'stream': False},
1898
+ timeout=120.0,
1899
  )
1900
  r.raise_for_status()
1901
+ return r.json()['message']['content'].strip()
1902
  except Exception as e:
1903
+ logger.error(f'Ollama call failed: {e}')
1904
+ return f'[Ollama unavailable: {e}]'
1905
 
1906
 
1907
  def run_agentic_council(
 
1909
  topic_df: Optional[pd.DataFrame],
1910
  mistral_api_key: str = '',
1911
  gemini_api_key: str = '',
1912
+ ollama_url: str = 'http://localhost:11434',
1913
  anthropic_api_key: str = '', # kept for backward compat β€” not used
1914
  ) -> Dict[str, str]:
1915
+ """Run 4-stage agentic council: Mistral β†’ Gemini β†’ Ollama panels + Ollama synthesis.
1916
 
1917
  Returns dict with keys:
1918
+ 'findings_summary', 'mistral', 'gemini', 'ollama', 'synthesis'
1919
  """
1920
  gap = taxonomy_map.get('gap_analysis', {})
1921
  novel_themes = taxonomy_map.get('novel_themes', [])[:5]
 
1963
  else '[Gemini API key not provided]'
1964
  )
1965
 
1966
+ # ── Stage 3: Ollama panel ──
1967
+ logger.info('Council: calling Ollama (Panel C)…')
1968
+ ollama_resp = _call_ollama(council_prompt, ollama_url)
 
 
 
 
1969
 
1970
+ # ── Stage 4: Ollama synthesis judge ──
1971
  synthesis_prompt = SYNTHESIS_PROMPT_TEMPLATE.format(
1972
  mistral_response=mistral_resp,
1973
  gemini_response=gemini_resp,
1974
+ ollama_response=ollama_resp,
 
 
 
 
 
 
1975
  )
1976
+ logger.info('Council: calling Ollama (synthesis judge)…')
1977
+ synthesis_resp = _call_ollama(synthesis_prompt, ollama_url, model='llama3')
1978
 
1979
  return {
1980
  'findings_summary': findings,
1981
  'mistral': mistral_resp,
1982
  'gemini': gemini_resp,
1983
+ 'ollama': ollama_resp,
1984
  'synthesis': synthesis_resp,
1985
  }