File size: 4,235 Bytes
0214972
0430df4
0214972
 
 
cb13dc9
0214972
a64025f
0214972
 
cb13dc9
 
edb155f
2844ebb
6a345f5
 
 
 
 
2844ebb
edb155f
 
a64025f
330e02a
2844ebb
 
dfe42e8
2844ebb
edb155f
2844ebb
 
 
 
 
 
 
0430df4
2844ebb
 
 
 
 
a64025f
edb155f
 
 
 
 
a64025f
 
edb155f
 
 
 
 
0430df4
a64025f
 
edb155f
a64025f
 
330e02a
 
edb155f
0214972
330e02a
 
6a345f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2844ebb
 
edb155f
 
 
330e02a
edb155f
330e02a
 
 
 
 
 
0430df4
 
2844ebb
0430df4
2844ebb
0430df4
a64025f
0430df4
a64025f
0430df4
a64025f
0430df4
a64025f
 
 
 
 
5d60eec
 
a64025f
5d60eec
 
a64025f
70b94cb
 
a64025f
70b94cb
 
a64025f
 
70b94cb
a64025f
 
 
 
 
 
 
 
 
 
 
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
"""
LLM module. HuggingFace Inference API as primary, OpenRouter as fallback.
"""

import os
import logging
from dotenv import load_dotenv
from tenacity import retry, stop_after_attempt, wait_exponential

load_dotenv()
logger = logging.getLogger(__name__)

# ── OpenRouter (primary) ──────────────────────────────────
_openrouter_client = None
_openrouter_models = [
    "arcee-ai/trinity-large-preview:free",
    "nvidia/nemotron-3-super-120b-a12b:free",
    "nvidia/nemotron-3-nano-30b-a3b:free"    
]

# ── HuggingFace Inference API (fallback) ──────────────────
_hf_client = None


def _init_openrouter():
    global _openrouter_client
    api_key = os.getenv("OPENROUTER_API_KEY" )
    if not api_key:
        logger.warning("OPENROUTER_API_KEY not set — OpenRouter disabled")
        return False
    try:
        from openai import OpenAI
        _openrouter_client = OpenAI(
            base_url="https://openrouter.ai/api/v1",
            api_key=api_key,
        )
        logger.info("OpenRouter ready (fallback)")
        return True
    except Exception as e:
        logger.error(f"OpenRouter init failed: {e}")
        return False


def _init_hf():
    global _hf_client
    token = os.getenv("HF_TOKEN")
    if not token:
        logger.warning("HF_TOKEN not set — HF Inference API disabled")
        return False
    try:
        from huggingface_hub import InferenceClient
        _hf_client = InferenceClient(
            model="meta-llama/Llama-3.3-70B-Instruct",
            token=token
        )
        logger.info("HF Inference API ready (primary)")
        return True
    except Exception as e:
        logger.error(f"HF Inference API init failed: {e}")
        return False


_openrouter_ready = _init_openrouter()
_hf_ready = _init_hf()


def _call_openrouter(messages: list) -> str:
    """Call OpenRouter with fallback across multiple models."""
    for model in _openrouter_models:
        try:
            response = _openrouter_client.chat.completions.create(
                model=model,
                messages=messages,
                max_tokens=1500,
                temperature=0.3,
            )
            logger.info(f"OpenRouter success with {model}")
            return response.choices[0].message.content
        except Exception as e:
            logger.warning(f"OpenRouter model {model} failed: {e}")
            continue
    
    raise Exception("All OpenRouter models failed")


def _call_hf(messages: list) -> str:
    """Call HuggingFace Inference API."""
    response = _hf_client.chat_completion(
        messages=messages,
        max_tokens=1500,
        temperature=0.3,
    )
    return response.choices[0].message.content


def _call_with_fallback(messages: list) -> str:
    """Try HF first, then OpenRouter."""
    if _hf_ready and _hf_client:
        try:
            return _call_hf(messages)
        except Exception as e:
            logger.warning(f"HF Inference failed: {e}, trying OpenRouter")

    if _openrouter_ready and _openrouter_client:
        try:
            return _call_openrouter(messages)
        except Exception as e:
            logger.error(f"OpenRouter also failed: {e}")

    raise Exception("All LLM providers failed")


@retry(stop=stop_after_attempt(3), wait=wait_exponential(min=2, max=8))
def call_llm_raw(messages: list) -> str:
    """
    Call LLM with pre-built messages list.
    Used by V2 agent for Pass 1 and Pass 3.
    """
    return _call_with_fallback(messages)


@retry(stop=stop_after_attempt(3), wait=wait_exponential(min=2, max=8))
def call_llm(query: str, context: str) -> str:
    """
    Call LLM with query and context.
    Used by V1 agent.
    """
    messages = [
        {
            "role": "system",
            "content": "You are NyayaSetu, an Indian legal research assistant. Answer only from provided excerpts. Cite judgment IDs. End with: NOTE: This is not legal advice."
        },
        {
            "role": "user",
            "content": f"QUESTION: {query}\n\nSOURCES:\n{context}\n\nAnswer based on sources. Cite judgment IDs."
        }
    ]
    return _call_with_fallback(messages)