Gifted-oNe's picture
feat: Add Website Parser, LLM Summarization, and Document Types
2e6d372
Raw
History Blame Contribute Delete
3.06 kB
"""
Website Router — Scrapes websites and summarizes them.
POST /api/parse-url
"""
import time
import requests
from bs4 import BeautifulSoup
from fastapi import APIRouter, HTTPException, Header
from pydantic import BaseModel
from models.schemas import (
ExtractionResponse,
ExtractionMetadata,
ExtractedField,
FileType,
ProcessingLane,
DocumentType,
)
from services.summarizer import generate_summary
from services.tier_manager import record_usage
router = APIRouter(prefix="/api", tags=["website"])
class ParseUrlRequest(BaseModel):
url: str
document_type: str = "free_text"
@router.post("/parse-url", response_model=ExtractionResponse)
async def parse_url(
request: ParseUrlRequest,
x_session_token: str = Header(default="anonymous"),
x_user_registered: str = Header(default="false"),
):
start_time = time.time()
is_registered = x_user_registered.lower() == "true"
doc_type_enum = DocumentType(request.document_type) if request.document_type in [e.value for e in DocumentType] else DocumentType.FREE_TEXT
if not request.url.startswith("http"):
request.url = "https://" + request.url
# Try to fetch the URL
try:
# Add a common User-Agent to avoid simple blocks
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
response = requests.get(request.url, headers=headers, timeout=10)
response.raise_for_status()
except Exception as e:
raise HTTPException(status_code=400, detail=f"Failed to fetch URL: {str(e)}")
# Parse with BeautifulSoup
soup = BeautifulSoup(response.content, 'html.parser')
# Remove script and style elements
for script in soup(["script", "style", "nav", "footer", "header"]):
script.extract()
# Get text
raw_text = soup.get_text(separator='\n')
# Break into lines and remove leading and trailing space on each
lines = (line.strip() for line in raw_text.splitlines())
# Break multi-headlines into a line each
chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
# Drop blank lines
raw_text = '\n'.join(chunk for chunk in chunks if chunk)
fields = [ExtractedField(name="Website Content", value=raw_text, field_type="text", confidence=1.0)]
# Generate AI Summary
summary = generate_summary(raw_text, is_registered=is_registered)
record_usage(x_session_token)
processing_time = int((time.time() - start_time) * 1000)
return ExtractionResponse(
success=True,
fields=fields,
summary=summary,
metadata=ExtractionMetadata(
filename=request.url,
file_type=FileType.URL,
processing_lane=ProcessingLane.URL_PARSER,
document_type=doc_type_enum,
page_count=1,
processing_time_ms=processing_time,
),
message=f"Scraped and summarized {request.url} in {processing_time}ms",
)