Dev local #2

Merged
utshodey merged 10 commits from dev-local into dev 2024-12-18 11:42:36 +00:00
6 changed files with 107 additions and 60 deletions
Showing only changes of commit 15a0061a0d - Show all commits

View file

@ -1,13 +1,17 @@
from fastapi import APIRouter, HTTPException
import httpx
from typing import Union
from app.config import GOOGLE_API_KEY, GOOGLE_FACT_CHECK_BASE_URL, OPENAI_API_KEY
from app.api.scrap_websites import search_websites, SearchRequest
from app.services.openai_client import OpenAIClient
from app.models.fact_check_models import (
FactCheckRequest,
FactCheckResponse,
UnverifiedFactCheckResponse,
ErrorResponse,
Source,
VerdictEnum,
ConfidenceEnum
)
from app.websites.fact_checker_website import get_all_sources
@ -15,7 +19,7 @@ fact_check_router = APIRouter()
openai_client = OpenAIClient(OPENAI_API_KEY)
async def generate_fact_report(query: str, fact_check_data: dict) -> FactCheckResponse:
async def generate_fact_report(query: str, fact_check_data: dict) -> Union[FactCheckResponse, UnverifiedFactCheckResponse]:
"""Generate a fact check report using OpenAI based on the fact check results."""
try:
base_system_prompt = """You are a professional fact-checking reporter. Your task is to create a detailed fact check report based on the provided data. Focus on accuracy, clarity, and proper citation of sources.
@ -24,7 +28,24 @@ Rules:
1. Include all source URLs and names in the sources list
2. Keep the explanation focused on verifiable facts
3. Include dates when available
4. Maintain objectivity in the report"""
4. Maintain objectivity in the report
5. If no reliable sources are found, provide a clear explanation why"""
# If no sources were found, return an unverified response
if not fact_check_data.get("claims") and (
not fact_check_data.get("urls_found") or
fact_check_data.get("status") == "no_results" or
fact_check_data.get("verification_result", {}).get("no_sources_found")
):
return UnverifiedFactCheckResponse(
claim=query,
verdict=VerdictEnum.UNVERIFIED,
confidence=ConfidenceEnum.LOW,
sources=[],
evidence="No fact-checking sources have verified this claim yet.",
explanation="Our search across reputable fact-checking websites did not find any formal verification of this claim. This doesn't mean the claim is false - just that it hasn't been formally fact-checked yet.",
additional_context="The claim may be too recent for fact-checkers to have investigated, or it may not have been widely circulated enough to warrant formal fact-checking."
)
base_user_prompt = """Generate a comprehensive fact check report in this exact JSON format:
{
@ -40,9 +61,7 @@ Rules:
"evidence": "A concise summary of the key evidence (1-2 sentences)",
"explanation": "A detailed explanation including who verified it, when it was verified, and the key findings (2-3 sentences)",
"additional_context": "Important context about the verification process, limitations, or broader implications (1-2 sentences)"
}
Ensure all URLs in sources are complete (including https:// if missing) and each source has both a URL and name."""
}"""
if "claims" in fact_check_data:
system_prompt = base_system_prompt
@ -71,75 +90,74 @@ Ensure all URLs in sources are complete (including https:// if missing) and each
4. Note any conflicting information between sources"""
response = await openai_client.generate_text_response(
system_prompt=system_prompt, user_prompt=user_prompt, max_tokens=1000
system_prompt=system_prompt,
user_prompt=user_prompt,
max_tokens=1000
)
try:
# First try to parse the response directly
response_data = response["response"]
# Clean up sources before validation
if isinstance(response_data.get("sources"), list):
cleaned_sources = []
for source in response_data["sources"]:
if isinstance(source, str):
# Convert string sources to Source objects
url = (
source if source.startswith("http") else f"https://{source}"
)
url = source if source.startswith("http") else f"https://{source}"
cleaned_sources.append({"url": url, "name": source})
elif isinstance(source, dict):
# Ensure URL has proper scheme
url = source.get("url", "")
if url and not url.startswith("http"):
source["url"] = f"https://{url}"
cleaned_sources.append(source)
response_data["sources"] = cleaned_sources
fact_check_response = FactCheckResponse(**response_data)
return fact_check_response
if response_data["verdict"] == "Unverified" or not response_data.get("sources"):
return UnverifiedFactCheckResponse(**response_data)
return FactCheckResponse(**response_data)
except Exception as validation_error:
print(f"Response validation error: {str(validation_error)}")
raise HTTPException(
status_code=422,
detail=ErrorResponse(
detail=f"Invalid response format: {str(validation_error)}",
error_code="VALIDATION_ERROR",
path="/check-facts",
).dict(),
return UnverifiedFactCheckResponse(
claim=query,
verdict=VerdictEnum.UNVERIFIED,
confidence=ConfidenceEnum.LOW,
sources=[],
evidence="An error occurred while processing the fact check results.",
explanation="The system encountered an error while validating the fact check results.",
additional_context="This is a technical error and does not reflect on the truthfulness of the claim."
)
except Exception as e:
print(f"Error generating fact report: {str(e)}")
raise HTTPException(
status_code=500,
detail=ErrorResponse(
detail="Error generating fact report",
error_code="FACT_CHECK_ERROR",
path="/check-facts",
).dict(),
return UnverifiedFactCheckResponse(
claim=query,
verdict=VerdictEnum.UNVERIFIED,
confidence=ConfidenceEnum.LOW,
sources=[],
evidence="An error occurred while generating the fact check report.",
explanation="The system encountered an unexpected error while processing the fact check request.",
additional_context="This is a technical error and does not reflect on the truthfulness of the claim."
)
@fact_check_router.post("/check-facts", response_model=FactCheckResponse)
@fact_check_router.post("/check-facts", response_model=Union[FactCheckResponse, UnverifiedFactCheckResponse])
async def check_facts(request: FactCheckRequest):
"""
Fetch fact check results and generate a comprehensive report.
"""
if not GOOGLE_API_KEY or not GOOGLE_FACT_CHECK_BASE_URL:
raise HTTPException(
status_code=500,
detail=ErrorResponse(
detail="Google API key or base URL is not configured",
error_code="CONFIGURATION_ERROR",
path="/check-facts",
).dict(),
return UnverifiedFactCheckResponse(
claim=request.query,
verdict=VerdictEnum.UNVERIFIED,
confidence=ConfidenceEnum.LOW,
sources=[],
evidence="The fact-checking service is not properly configured.",
explanation="The system is missing required API configuration for fact-checking services.",
additional_context="This is a temporary system configuration issue."
)
headers = {"Content-Type": "application/json"}
async with httpx.AsyncClient() as client:
# Get fact checker sources from the centralized configuration
fact_checker_sources = get_all_sources()
for source in fact_checker_sources:
@ -170,7 +188,8 @@ async def check_facts(request: FactCheckRequest):
try:
search_request = SearchRequest(
search_text=request.query, source_types=["fact_checkers"]
search_text=request.query,
source_types=["fact_checkers"]
)
ai_response = await search_websites(search_request)
@ -178,11 +197,10 @@ async def check_facts(request: FactCheckRequest):
except Exception as e:
print(f"Error in AI fact check: {str(e)}")
raise HTTPException(
status_code=404,
detail=ErrorResponse(
detail="No fact check results found",
error_code="NOT_FOUND",
path="/check-facts",
).dict(),
)
return await generate_fact_report(request.query, {
"status": "no_results",
"verification_result": {
"no_sources_found": True,
"reason": str(e)
}
})

View file

@ -33,12 +33,44 @@ class Source(BaseModel):
@validator("url")
def validate_url(cls, v):
# Basic URL validation without requiring HTTP/HTTPS
if not v or len(v) < 3:
raise ValueError("URL must not be empty and must be at least 3 characters")
return v
class UnverifiedFactCheckResponse(BaseModel):
claim: str = Field(
...,
min_length=10,
max_length=1000,
description="The exact claim being verified",
)
verdict: VerdictEnum = Field(..., description="The verification verdict")
confidence: ConfidenceEnum = Field(..., description="Confidence level in the verdict")
sources: List[Source] = Field(
default=[],
description="List of sources used in verification"
)
evidence: str = Field(
...,
min_length=20,
max_length=500,
description="Concise summary of key evidence",
)
explanation: str = Field(
...,
min_length=50,
max_length=1000,
description="Detailed explanation of verification findings",
)
additional_context: str = Field(
...,
min_length=20,
max_length=500,
description="Important context about the verification",
)
class FactCheckResponse(BaseModel):
claim: str = Field(
...,
@ -47,11 +79,11 @@ class FactCheckResponse(BaseModel):
description="The exact claim being verified",
)
verdict: VerdictEnum = Field(..., description="The verification verdict")
confidence: ConfidenceEnum = Field(
..., description="Confidence level in the verdict"
)
confidence: ConfidenceEnum = Field(..., description="Confidence level in the verdict")
sources: List[Source] = Field(
..., min_items=1, description="List of sources used in verification"
...,
min_items=1,
description="List of sources used in verification"
)
evidence: str = Field(
...,
@ -82,15 +114,11 @@ class FactCheckResponse(BaseModel):
{
"url": "https://www.nasa.gov/mars-exploration",
"name": "NASA Mars Exploration",
},
{
"url": "https://factcheck.org/2024/mars-claims",
"name": "FactCheck.org",
},
}
],
"evidence": "NASA has made no such announcement. Recent Mars rover images show natural rock formations.",
"explanation": "Multiple fact-checking organizations investigated this claim. NASA's official communications and Mars mission reports from 2024 contain no mention of alien structures. The viral images being shared are misidentified natural geological formations.",
"additional_context": "Similar false claims about alien structures on Mars have circulated periodically since the first Mars rovers began sending back images.",
"explanation": "Multiple fact-checking organizations investigated this claim. NASA's official communications and Mars mission reports from 2024 contain no mention of alien structures.",
"additional_context": "Similar false claims about alien structures on Mars have circulated periodically.",
}
}
@ -98,4 +126,4 @@ class FactCheckResponse(BaseModel):
class ErrorResponse(BaseModel):
detail: str
error_code: str = Field(..., example="VALIDATION_ERROR")
path: str = Field(..., example="/check-facts")
path: str = Field(..., example="/check-facts")

BIN
images-test.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -17,6 +17,7 @@ origins = [
"http://localhost:5173",
"http://0.0.0.0",
"http://0.0.0.0:5173",
"*"
]