-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathllm_client.py
More file actions
226 lines (184 loc) · 6.99 KB
/
Copy pathllm_client.py
File metadata and controls
226 lines (184 loc) · 6.99 KB
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
"""
LLM client for FactCheckLIAR.
Provides integration with Ollama for LLM-based response generation,
with fallback to template-based responses when Ollama is unavailable.
"""
import os
from typing import Optional
import requests
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Default configuration from .env
DEFAULT_OLLAMA_URL = os.getenv("OLLAMA_API_URL", "http://localhost:11434")
DEFAULT_OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "gemma3:4b-it-qat")
def check_ollama_availability(api_url: str = DEFAULT_OLLAMA_URL) -> bool:
"""
Check if Ollama is available and responding.
Args:
api_url: Base URL of the Ollama API
Returns:
True if Ollama is available, False otherwise
"""
try:
response = requests.get(f"{api_url}/api/tags", timeout=5)
return response.status_code == 200
except (requests.ConnectionError, requests.Timeout):
return False
def generate_ollama_response(
prompt: str,
api_url: str = DEFAULT_OLLAMA_URL,
model: str = DEFAULT_OLLAMA_MODEL
) -> Optional[str]:
"""
Generate a response using Ollama's API.
Args:
prompt: The prompt to send to the LLM
api_url: Base URL of the Ollama API
model: Model name to use
Returns:
Generated response text, or None if generation failed
"""
try:
response = requests.post(
f"{api_url}/api/generate",
json={
"model": model,
"prompt": prompt,
"stream": False
},
timeout=60
)
if response.status_code == 200:
return response.json().get("response", "")
return None
except (requests.ConnectionError, requests.Timeout, requests.JSONDecodeError):
return None
def build_fact_check_prompt(
query: str,
retrieved_claim: dict,
predicted_label: str,
verbose: bool = False
) -> str:
"""
Build a prompt for the LLM to generate a fact-check response.
Args:
query: The user's claim to fact-check
retrieved_claim: Dictionary containing the retrieved similar claim data
predicted_label: The predicted veracity label
verbose: Whether to request a detailed response
Returns:
Formatted prompt string for the LLM
"""
# Map labels to descriptions
label_descriptions = {
"pants-fire": "categorically false",
"false": "false",
"barely-true": "mostly false",
"half-true": "partially true",
"mostly-true": "mostly true",
"true": "true"
}
label_desc = label_descriptions.get(predicted_label, predicted_label)
# Format speaker name
speaker = retrieved_claim.get('speaker', 'Unknown')
speaker = speaker.replace('-', ' ').title()
if verbose:
prompt = f"""You are a fact-checking assistant. Analyze the following claim and provide a detailed fact-check response.
User's Claim: "{query}"
Similar Claim from Database:
- Statement: "{retrieved_claim.get('statement', '')}"
- Speaker: {speaker} ({retrieved_claim.get('job_title', 'N/A')})
- Context: {retrieved_claim.get('context', 'N/A')}
- Original Label: {retrieved_claim.get('label', 'N/A')}
Our AI classifier predicts this claim is: {label_desc}
Please provide a detailed fact-check response that:
1. Explains the relationship between the user's claim and the similar claim found
2. Discusses the evidence and context
3. Provides a clear verdict based on the predicted label
Keep your response informative but concise (2-3 paragraphs)."""
else:
prompt = f"""You are a fact-checking assistant. Provide a brief, clear verdict on this claim.
User's Claim: "{query}"
Similar claim found from {speaker}: "{retrieved_claim.get('statement', '')}"
Our AI classifier predicts this claim is: {label_desc}
Provide a single, clear sentence stating the verdict. Be direct and factual."""
return prompt
def generate_template_response(
query: str,
retrieved_claim: dict,
predicted_label: str,
verbose: bool = False
) -> str:
"""
Generate a template-based response (fallback when LLM unavailable).
Args:
query: The user's claim to fact-check
retrieved_claim: Dictionary containing the retrieved similar claim data
predicted_label: The predicted veracity label
verbose: Whether to provide a detailed response
Returns:
Formatted response string
"""
# Map labels to descriptions
label_descriptions = {
"pants-fire": "categorically false",
"false": "false",
"barely-true": "mostly false",
"half-true": "partially true",
"mostly-true": "mostly true",
"true": "true"
}
label_desc = label_descriptions.get(predicted_label, predicted_label)
# Format speaker name
speaker = retrieved_claim.get('speaker', 'Unknown')
speaker = speaker.replace('-', ' ').title()
if not verbose:
return (
f"If you are referring to a claim by {speaker} that "
f"{retrieved_claim.get('statement', '')}\n"
f"It is {label_desc}."
)
else:
return (
f"Claim: \"{query}\"\n"
f"Predicted Label: {predicted_label}\n\n"
"Supporting Evidence from the Dataset:\n"
f"- Statement: \"{retrieved_claim.get('statement', '')}\"\n"
f"- Speaker: {retrieved_claim.get('speaker', '')} ({retrieved_claim.get('job_title', '')})\n"
f"- Context: {retrieved_claim.get('context', '')}\n"
f"- Dataset Label: {retrieved_claim.get('label', '')}\n\n"
f"If you are referring to the claim above, it is {label_desc}."
)
def generate_response(
query: str,
retrieved_claim: dict,
predicted_label: str,
verbose: bool = False,
use_llm: bool = True
) -> str:
"""
Generate a fact-check response, using LLM if available or template fallback.
Args:
query: The user's claim to fact-check
retrieved_claim: Dictionary containing the retrieved similar claim data
predicted_label: The predicted veracity label
verbose: Whether to provide a detailed response
use_llm: Whether to attempt LLM generation (False = use template only)
Returns:
Generated response string
"""
if not use_llm:
return generate_template_response(query, retrieved_claim, predicted_label, verbose)
# Check if Ollama is available
if not check_ollama_availability():
print("Warning: Ollama is not available. Using template-based response.")
return generate_template_response(query, retrieved_claim, predicted_label, verbose)
# Build prompt and generate response
prompt = build_fact_check_prompt(query, retrieved_claim, predicted_label, verbose)
llm_response = generate_ollama_response(prompt)
if llm_response:
return llm_response
else:
print("Warning: LLM generation failed. Using template-based response.")
return generate_template_response(query, retrieved_claim, predicted_label, verbose)