-
-
Notifications
You must be signed in to change notification settings - Fork 83
Improve Article Tab Layout & Make AI Chat Use Article Context #157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,15 +28,24 @@ | |
|
|
||
|
|
||
| def search_google(query): | ||
| results = requests.get( | ||
| f"https://www.googleapis.com/customsearch/v1?key={GOOGLE_SEARCH}&cx=f637ab77b5d8b4a3c&q={query}" | ||
| ) | ||
| res = results.json() | ||
| first = {} | ||
| first["title"] = res["items"][0]["title"] | ||
| first["link"] = res["items"][0]["link"] | ||
| first["snippet"] = res["items"][0]["snippet"] | ||
|
|
||
| return [ | ||
| first, | ||
| ] | ||
| try: | ||
| results = requests.get( | ||
| f"https://www.googleapis.com/customsearch/v1?key={GOOGLE_SEARCH}&cx=f637ab77b5d8b4a3c&q={query}" | ||
| ) | ||
| res = results.json() | ||
|
|
||
| # Check if the response contains 'items' (successful search) | ||
| if "items" not in res: | ||
| # Handle error responses from Google API | ||
| error_msg = res.get("error", {}).get("message", "Unknown error") | ||
| raise ValueError(f"Google API Error: {error_msg}") | ||
|
|
||
| first = {} | ||
| first["title"] = res["items"][0]["title"] | ||
| first["link"] = res["items"][0]["link"] | ||
| first["snippet"] = res["items"][0]["snippet"] | ||
|
|
||
| return [first] | ||
| except Exception as e: | ||
| print(f"Search Google Error: {e}") | ||
| raise | ||
|
Comment on lines
+49
to
+51
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Use logger instead of print for error output. The module uses ♻️ Proposed fix+from app.logging.logging_config import setup_logger
+
+logger = setup_logger(__name__)
+
def search_google(query):
try:
# ... existing code ...
except Exception as e:
- print(f"Search Google Error: {e}")
+ logger.error(f"Search Google Error: {e}")
raise🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -30,7 +30,7 @@ | |||||||||
| """ | ||||||||||
|
|
||||||||||
|
|
||||||||||
| from fastapi import APIRouter | ||||||||||
| from fastapi import APIRouter, HTTPException | ||||||||||
| from pydantic import BaseModel | ||||||||||
| from app.modules.pipeline import run_scraper_pipeline | ||||||||||
| from app.modules.pipeline import run_langgraph_workflow | ||||||||||
|
|
@@ -52,6 +52,7 @@ class URlRequest(BaseModel): | |||||||||
|
|
||||||||||
| class ChatQuery(BaseModel): | ||||||||||
| message: str | ||||||||||
| article_context: str | None = None | ||||||||||
|
|
||||||||||
|
|
||||||||||
| @router.get("/") | ||||||||||
|
|
@@ -77,9 +78,20 @@ async def run_pipelines(request: URlRequest): | |||||||||
|
|
||||||||||
| @router.post("/chat") | ||||||||||
| async def answer_query(request: ChatQuery): | ||||||||||
| query = request.message | ||||||||||
| results = search_pinecone(query) | ||||||||||
| answer = ask_llm(query, results) | ||||||||||
| logger.info(f"Chat answer generated: {answer}") | ||||||||||
|
|
||||||||||
| return {"answer": answer} | ||||||||||
| try: | ||||||||||
| query = request.message.strip() | ||||||||||
| if not query: | ||||||||||
| raise HTTPException(status_code=400, detail="Message cannot be empty.") | ||||||||||
|
|
||||||||||
| article_context = (request.article_context or "").strip() | ||||||||||
|
|
||||||||||
| results = search_pinecone(query) | ||||||||||
| answer = ask_llm(query, results, article_context) | ||||||||||
|
Comment on lines
+88
to
+89
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '79,97p' backend/app/routes/routes.py
printf '\n--- search_pinecone definition ---\n'
rg -n -C3 '^(async\s+def|def)\s+search_pinecone\b' backend/app/modules/chat
printf '\n--- ask_llm definition ---\n'
rg -n -C3 '^(async\s+def|def)\s+ask_llm\b' backend/app/modules/chatRepository: AOSSIE-Org/Perspective Length of output: 1755 Wrap synchronous I/O calls in Lines 88–89 invoke Suggested fix- results = search_pinecone(query)
- answer = ask_llm(query, results, article_context)
+ results = await asyncio.to_thread(search_pinecone, query)
+ answer = await asyncio.to_thread(ask_llm, query, results, article_context)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| logger.info("Chat answer generated successfully.") | ||||||||||
|
|
||||||||||
| return {"answer": answer} | ||||||||||
| except HTTPException: | ||||||||||
| raise | ||||||||||
| except Exception as e: | ||||||||||
| logger.exception(f"Chat request failed: {e}") | ||||||||||
| raise HTTPException(status_code=500, detail="Failed to generate chat response.") | ||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -45,36 +45,39 @@ def run_fact_check_pipeline(state): | |||||||||||||||
| result = run_claim_extractor_sdk(state) | ||||||||||||||||
|
|
||||||||||||||||
| if state.get("status") != "success": | ||||||||||||||||
| logger.error("❌ Claim extraction failed.") | ||||||||||||||||
| logger.error("Claim extraction failed.") | ||||||||||||||||
| return [], "Claim extraction failed." | ||||||||||||||||
|
Comment on lines
47
to
49
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Checking wrong variable for extraction status. Line 47 checks 🐛 Proposed fix- if state.get("status") != "success":
+ if result.get("status") != "success":
logger.error("Claim extraction failed.")
return [], "Claim extraction failed."📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
|
|
||||||||||||||||
| # Step 1: Extract claims | ||||||||||||||||
| raw_output = result.get("verifiable_claims", "") | ||||||||||||||||
| claims = re.findall(r"^[\*\-•]\s+(.*)", raw_output, re.MULTILINE) | ||||||||||||||||
| claims = [claim.strip() for claim in claims if claim.strip()] | ||||||||||||||||
| logger.info(f"🧠 Extracted claims: {claims}") | ||||||||||||||||
| logger.info(f"Extracted claims: {claims}") | ||||||||||||||||
|
|
||||||||||||||||
| if not claims: | ||||||||||||||||
| return [], "No verifiable claims found." | ||||||||||||||||
|
|
||||||||||||||||
| # Step 2: Search each claim with polite delay | ||||||||||||||||
| search_results = [] | ||||||||||||||||
| for claim in claims: | ||||||||||||||||
| logger.info(f"\n🔍 Searching for claim: {claim}") | ||||||||||||||||
| logger.info(f"Searching for claim: {claim}") | ||||||||||||||||
| try: | ||||||||||||||||
| results = search_google(claim) | ||||||||||||||||
| if results: | ||||||||||||||||
| results[0]["claim"] = claim | ||||||||||||||||
| search_results.append(results[0]) | ||||||||||||||||
| logger.info(f"✅ Found result: {results[0]['title']}") | ||||||||||||||||
| logger.info(f"Found result: {results[0]['title']}") | ||||||||||||||||
| else: | ||||||||||||||||
| logger.warning(f"⚠️ No search result for: {claim}") | ||||||||||||||||
| logger.warning(f"No search result for: {claim}") | ||||||||||||||||
| except Exception as e: | ||||||||||||||||
| logger.error(f"❌ Search failed for: {claim} -> {e}") | ||||||||||||||||
| logger.error(f"Search failed for: {claim} -> {e}") | ||||||||||||||||
|
|
||||||||||||||||
| if not search_results: | ||||||||||||||||
| logger.error("All claim searches failed or returned no results.") | ||||||||||||||||
| return [], "All claim searches failed or returned no results." | ||||||||||||||||
|
|
||||||||||||||||
| # Step 3: Verify facts using LLM | ||||||||||||||||
| logger.info(f"Verifying {len(search_results)} claims using LLM...") | ||||||||||||||||
| final = run_fact_verifier_sdk(search_results) | ||||||||||||||||
| logger.info("Fact-checking pipeline completed successfully.") | ||||||||||||||||
| return final.get("verifications", []), None | ||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,7 +16,7 @@ import { | |||||||||||||||||||||||||||||
| import ThemeToggle from "@/components/theme-toggle"; | ||||||||||||||||||||||||||||||
| import axios from "axios"; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // const backend_url = process.env.NEXT_PUBLIC_API_URL; | ||||||||||||||||||||||||||||||
| const backend_url = process.env.NEXT_PUBLIC_API_URL; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
@@ -74,10 +74,10 @@ export default function LoadingPage() { | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||
| const [processRes, biasRes] = await Promise.all([ | ||||||||||||||||||||||||||||||
| axios.post("https://thunder1245-perspective-backend.hf.space/api/process", { | ||||||||||||||||||||||||||||||
| axios.post(`${backend_url}/api/process`, { | ||||||||||||||||||||||||||||||
| url: storedUrl, | ||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||
| axios.post("https://thunder1245-perspective-backend.hf.space/api/bias", { | ||||||||||||||||||||||||||||||
| axios.post(`${backend_url}/api/bias`, { | ||||||||||||||||||||||||||||||
| url: storedUrl, | ||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||
|
Comment on lines
76
to
82
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'Loading page requests:\n'
sed -n '75,83p' frontend/app/analyze/loading/page.tsx
printf '\nChat request config for comparison:\n'
sed -n '92,100p' frontend/app/analyze/results/page.tsxRepository: AOSSIE-Org/Perspective Length of output: 686 Add a timeout to the analysis requests. The POST calls to Suggested fix+ const requestConfig = { timeout: 45000 };
const [processRes, biasRes] = await Promise.all([
- axios.post(`${backend_url}/api/process`, {
- url: storedUrl,
- }),
- axios.post(`${backend_url}/api/bias`, {
- url: storedUrl,
- }),
+ axios.post(`${backend_url}/api/process`, { url: storedUrl }, requestConfig),
+ axios.post(`${backend_url}/api/bias`, { url: storedUrl }, requestConfig),
]);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a timeout to the HTTP request.
The
requests.getcall has no timeout, which can cause the request to hang indefinitely if the Google API is unresponsive. This is a reliability concern flagged by static analysis (S113).🛡️ Proposed fix to add timeout
📝 Committable suggestion
🧰 Tools
🪛 Ruff (0.15.6)
[error] 32-32: Probable use of
requestscall without timeout(S113)
🤖 Prompt for AI Agents