melkani commited on
Commit
657c936
Β·
verified Β·
1 Parent(s): 691be06

Create main pipeline

Browse files
Files changed (1) hide show
  1. whatsafe_pipeline.py +235 -0
whatsafe_pipeline.py ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import traceback
3
+
4
+ from google.adk.agents import Agent, LlmAgent, SequentialAgent
5
+ from google.adk.models.google_llm import Gemini
6
+ from google.adk.runners import Runner
7
+ from google.adk.sessions import InMemorySessionService
8
+ from google.adk.memory import InMemoryMemoryService
9
+ from google.adk.tools import google_search, load_memory
10
+ from google.genai import types
11
+
12
+ # ---------- 1. API KEY SETUP (Hugging Face Secret) ----------
13
+
14
+ GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
15
+
16
+ if not GOOGLE_API_KEY:
17
+ # On HF, set this in: Settings -> Variables and secrets -> New secret: GOOGLE_API_KEY
18
+ raise RuntimeError(
19
+ "GOOGLE_API_KEY is not set. Please add it as a secret in your Hugging Face Space."
20
+ )
21
+
22
+ os.environ["GOOGLE_API_KEY"] = GOOGLE_API_KEY
23
+
24
+ # ---------- 2. ADK CONFIG ----------
25
+
26
+ retry_config = types.HttpRetryOptions(
27
+ attempts=5,
28
+ exp_base=7,
29
+ initial_delay=1,
30
+ http_status_codes=[429, 500, 503, 504],
31
+ )
32
+
33
+ APP_NAME = "FakeNewsApp"
34
+ USER_ID = "demo_user"
35
+
36
+ session_service = InMemorySessionService()
37
+ memory_service = InMemoryMemoryService()
38
+
39
+ # ---------- 3. AGENTS (same as your notebook) ----------
40
+
41
+ claim_extractor_agent = Agent(
42
+ name="ClaimExtractorAgent",
43
+ model=Gemini(
44
+ model="gemini-2.5-flash-lite",
45
+ retry_options=retry_config,
46
+ ),
47
+ instruction="""
48
+ You will receive a WhatsApp forward or viral message.
49
+
50
+ TASK:
51
+ 1. Identify ONE main factual claim in clean, simple form.
52
+ 2. Rewrite it in one sentence.
53
+ 3. Extract 3–5 search keywords.
54
+
55
+ OUTPUT FORMAT:
56
+ Claim: <cleaned claim>
57
+ Keywords: <comma separated keywords>
58
+ """,
59
+ output_key="extracted_claim",
60
+ )
61
+
62
+ evidence_search_agent = Agent(
63
+ name="EvidenceSearchAgent",
64
+ model=Gemini(
65
+ model="gemini-2.5-flash-lite",
66
+ retry_options=retry_config,
67
+ ),
68
+ tools=[google_search],
69
+ instruction="""
70
+ You will receive extracted claim info:
71
+
72
+ {extracted_claim}
73
+
74
+ TASK:
75
+ 1. Use google_search with 2–3 queries:
76
+ - "<claim> fact check"
77
+ - "<keywords> news"
78
+ - "<keywords> official site"
79
+ 2. Return 5–7 useful results with:
80
+ - title
81
+ - url
82
+ - snippet
83
+ - source type (gov, fact-check, news, blog)
84
+
85
+ OUTPUT FORMAT:
86
+ <list of sources in bullet points>
87
+ """,
88
+ output_key="search_results",
89
+ )
90
+
91
+ verdict_agent = Agent(
92
+ name="VerdictAgent",
93
+ model=Gemini(
94
+ model="gemini-2.5-flash-lite",
95
+ retry_options=retry_config,
96
+ ),
97
+ instruction="""
98
+ You will receive search results:
99
+
100
+ {search_results}
101
+
102
+ TASK:
103
+ 1. For each source, decide SUPPORT / REFUTE / IRRELEVANT.
104
+ 2. Produce a Markdown table:
105
+ | Source | Type | Stance | Summary |
106
+ 3. Decide the final verdict:
107
+ - Mostly refute β†’ Likely FALSE
108
+ - Mostly support β†’ Likely TRUE
109
+ - Mixed β†’ Partly true/misleading
110
+ - No credible sources β†’ Unverified – Do not share
111
+ 4. Write a SIMPLE explanation for elderly users.
112
+
113
+ OUTPUT FORMAT:
114
+ Evidence Table:
115
+ <table>
116
+
117
+ Verdict:
118
+ <verdict>
119
+
120
+ Explanation:
121
+ <simple explanation>
122
+ """,
123
+ output_key="final_report",
124
+ )
125
+
126
+ memory_agent = LlmAgent(
127
+ name="MemoryAgent",
128
+ model=Gemini(
129
+ model="gemini-2.5-flash-lite",
130
+ retry_options=retry_config,
131
+ ),
132
+ tools=[load_memory],
133
+ instruction="""
134
+ You are a background history fetcher. You are NOT a chatbot.
135
+
136
+ YOUR STRICT COMMANDS:
137
+ 1. IGNORE any input text you receive from previous agents.
138
+ 2. IMMEDIATELY call the function `load_memory` to get the user's past sessions.
139
+ 3. Once you receive the memory data, extract and list the distinct claims found.
140
+ 4. Return ONLY a bulleted list of the last 2 claims.
141
+
142
+ IF NO MEMORY DATA IS RETURNED:
143
+ - Output: "No previous checks found."
144
+
145
+ DO NOT ask "Would you like me to?". DO NOT explain what you are doing. JUST RUN THE TOOL.
146
+ """,
147
+ output_key="recent_claims",
148
+ )
149
+
150
+ root_agent = SequentialAgent(
151
+ name="FakeNewsPipeline",
152
+ sub_agents=[
153
+ claim_extractor_agent,
154
+ evidence_search_agent,
155
+ verdict_agent,
156
+ memory_agent,
157
+ ],
158
+ )
159
+
160
+ runner = Runner(
161
+ agent=root_agent,
162
+ app_name=APP_NAME,
163
+ session_service=session_service,
164
+ memory_service=memory_service,
165
+ )
166
+
167
+ # ---------- 4. PUBLIC FUNCTION USED BY GRADIO ----------
168
+
169
+ async def run_eldersafe(query: str, session_id: str = "default-session") -> dict:
170
+ """
171
+ Runs the full ElderSafe pipeline and returns a dict:
172
+ {
173
+ "clean_claim": str,
174
+ "final_report": str (markdown),
175
+ "memory_context": str,
176
+ }
177
+ This is the function Gradio will call.
178
+ """
179
+ try:
180
+ # Ensure session exists (ignore if already created)
181
+ try:
182
+ await session_service.create_session(
183
+ app_name=APP_NAME,
184
+ user_id=USER_ID,
185
+ session_id=session_id,
186
+ )
187
+ except Exception:
188
+ pass
189
+
190
+ # Prepare ADK content input
191
+ user_msg = types.Content(
192
+ role="user",
193
+ parts=[types.Part(text=query)],
194
+ )
195
+
196
+ # Run pipeline silently
197
+ async for _ in runner.run_async(
198
+ user_id=USER_ID,
199
+ session_id=session_id,
200
+ new_message=user_msg,
201
+ ):
202
+ pass
203
+
204
+ # Get session and store in memory
205
+ session = await session_service.get_session(
206
+ app_name=APP_NAME,
207
+ user_id=USER_ID,
208
+ session_id=session_id,
209
+ )
210
+
211
+ await memory_service.add_session_to_memory(session)
212
+
213
+ # Extract outputs
214
+ claim = session.state.get("extracted_claim", "No claim extracted.")
215
+ if isinstance(claim, str) and "Claim:" in claim:
216
+ clean_claim = claim.split("Keywords:")[0].replace("Claim:", "").strip()
217
+ else:
218
+ clean_claim = str(claim)
219
+
220
+ final_report = session.state.get("final_report", "Analysis failed.")
221
+ memory_context = session.state.get("recent_claims", "")
222
+
223
+ return {
224
+ "clean_claim": clean_claim,
225
+ "final_report": final_report,
226
+ "memory_context": memory_context,
227
+ }
228
+
229
+ except Exception:
230
+ # In case something goes wrong, return a debug string
231
+ return {
232
+ "clean_claim": query,
233
+ "final_report": "❌ An error occurred:\n\n" + traceback.format_exc(),
234
+ "memory_context": "",
235
+ }