Please fix this:

import asyncio
import json
import logging
import os
import re

from crawl4ai import AsyncWebCrawler
from crawl4ai.extraction_strategy import JsonCssExtractionStrategy, LLMExtractionStrategy
from pydantic import BaseModel, Field


def classify_links(links):
    # code to classify links
    pass


def filter_links(links):
    # code to filter links
    pass


# Update the base URL as needed
BASE_URL = "https://playwright.dev/python/docs/intro"
# Define the schema for extracting URLs
url_schema = {
    "name": "Links",
    "baseSelector": "a",  # Target all anchor tags
    "fields": [
        {
            "name": "url",
            "selector": "a",  # Select anchor tags
            "attribute": "href",  # Extract the href attribute
            "type": "text",
        },
    ],
}

# Define the schema for extracting text content
text_schema = {
    "name": "Page Content",
    "baseSelector": "body",  # Target the entire body of the page
    "fields": [{"name": "text", "selector": "body", "type": "text"}],
}


class PageSummary(BaseModel):
    title: str = Field(..., description="Title of the page.")
    summary: str = Field(..., description="Summary of the page.")
    brief_summary: str = Field(..., description="Brief summary of the page.")
    keywords: list = Field(..., description="Keywords assigned to the page.")


settings = {
    "model": "groq/llama-3.1-70b-versatile",
    "temperature": 0.5,
    "max_tokens": 500,
    "top_p": 1,
    "frequency_penalty": 0,
    "presence_penalty": 0,
}


def sanitize_filename(name):
    """Sanitize the string to create a safe filename."""
    return re.sub(r'[\\/*?:"<>|]', "", name)


# Set up logging
logging.basicConfig(
    format="%(asctime)s [%(levelname)s] %(message)s",
    level=logging.INFO,
    handlers=[logging.FileHandler("crawl4ai.log"), logging.StreamHandler()],
)


async def extract_urls():
    logging.info("Extracting URLs from base page...")
    async with AsyncWebCrawler(verbose=True) as crawler:
        try:
            # Use JsonCssExtractionStrategy to extract URLs
            result = await crawler.arun(
                url=BASE_URL,
                extraction_strategy=JsonCssExtractionStrategy(url_schema),
                bypass_cache=True,
            )

            # Parse the extracted content
            links = json.loads(result.extracted_content)

            # Classify the links
            classified_links = classify_links(links)

            # Filter the links
            filtered_links = filter_links(
                classified_links["internal"],
                exclude_external_links=True,
                exclude_social_media_links=True,
                exclude_social_media_domains=[
                    "facebook.com",
                    "twitter.com",
                    "instagram.com",
                ],
                exclude_domains=["ads.playwright.dev"],
            )

            # Extract the internal URLs
            local_urls = [link["href"] for link in filtered_links]

            logging.info(f"Extracted {len(local_urls)} URLs.")

            # Ensure the directory exists
            os.makedirs("./data", exist_ok=True)

            # Save the extracted URLs to a JSON file
            with open("./data/local_urls.json", "w", encoding="utf-8") as f:
                json.dump(local_urls, f, indent=2)

            logging.info("Local URLs saved to ./data/local_urls.json")

            return local_urls

        except Exception as e:
            logging.error(f"An error occurred during URL extraction: {e}")
            return []


async def summarize_page(page_url):
    logging.info(f"Summarizing page: {page_url}...")
    async with AsyncWebCrawler(verbose=True) as crawler:
        try:
            result = await crawler.arun(
                url=page_url,
                word_count_threshold=1,
                extraction_strategy=LLMExtractionStrategy(
                    provider="groq/llama-3.1-70b-versatile",
                    api_token=os.getenv("GROQ_API_KEY"),
                    schema=PageSummary.model_json_schema(),
                    extraction_type="schema",
                    apply_chunking=False,
                    instruction=(
                        "From the crawled content, extract the following details: "
                        "1. Title of the page "
                        "2. Summary of the page, which is a detailed summary "
                        "3. Brief summary of the page, which is a paragraph text "
                        "4. Keywords assigned to the page, which is a list of keywords. "
                        "The extracted JSON format should look like this: "
                        '{ "title": "Page Title", "summary": "Detailed summary of the page.", "brief_summary": "Brief summary in a paragraph.", "keywords": ["keyword1", "keyword2", "keyword3"] }'
                    ),
                ),
                bypass_cache=True,
            )

            page_summary = json.loads(result.extracted_content)

            logging.info(f"Summarized page: {page_summary['title']}")

            # Ensure the directory exists
            os.makedirs("./data", exist_ok=True)

            # Sanitize the title for filename
            safe_title = sanitize_filename(page_summary["title"])

            # Save the extracted content to a JSON file
            with open(f"./data/{safe_title}.json", "w", encoding="utf-8") as f:
                json.dump(page_summary, f, indent=2)

            logging.info(f"Page summary saved to ./data/{safe_title}.json")

            return page_summary

        except Exception as e:
            logging.error(f"An error occurred while summarizing {page_url}: {e}")
            return None


async def scrape_text(page_url):
    logging.info(f"Scraping text from page: {page_url}...")
    async with AsyncWebCrawler(verbose=True) as crawler:
        try:
            # Use JsonCssExtractionStrategy to extract content
            result = await crawler.arun(
                url=page_url,
                extraction_strategy=JsonCssExtractionStrategy(text_schema),
                bypass_cache=True,
            )

            # Parse the extracted content
            page_content = json.loads(result.extracted_content)

            # Extract the text content
            if page_content and "text" in page_content[0]:
                text_content = page_content[0]["text"]
            else:
                logging.warning(f"No text content found for {page_url}")
                return

            # Ensure the directory exists
            os.makedirs("./data", exist_ok=True)

            # Sanitize the URL path for filename
            path_part = page_url.rstrip("/").split("/")[-1]
            safe_filename = sanitize_filename(path_part) or "index"

            # Save the extracted content to a Markdown file
            with open(f"./data/{safe_filename}.md", "w", encoding="utf-8") as f:
                f.write(text_content)

            logging.info(f"Page content saved to ./data/{safe_filename}.md")

        except Exception as e:
            logging.error(f"An error occurred while scraping text from {page_url}: {e}")







async def generate_toc(page_summaries):
    logging.info("Generating Table of Contents...")
    toc = []
    for summary in page_summaries:
        safe_title = sanitize_filename(summary["title"])
        toc.append(f"- [{summary['title']}](./data/{safe_title}.md)")

    # Ensure the directory exists
    os.makedirs("./data", exist_ok=True)

    with open("./data/toc.md", "w", encoding="utf-8") as f:
        f.write("# Table of Contents\n\n")
        f.write("\n".join(toc))

    logging.info("Table of Contents saved to ./data/toc.md")


async def main():
    logging.info("Starting crawl4ai script...")
    local_urls = await extract_urls()
    if not local_urls:
        logging.warning("No URLs to process.")
        return

    page_summaries = []

    for idx, url in enumerate(local_urls, start=1):
        full_url = f"https://www.nbcnews.com{url}"  # Updated to reflect the new base URL
        logging.info(f"\nProcessing ({idx}/{len(local_urls)}): {full_url}")

        page_summary = await summarize_page(full_url)
        if page_summary:
            page_summaries.append(page_summary)
            await scrape_text(full_url)

        # Limit the scraping rate to one page per minute to avoid overloading the server
        await asyncio.sleep(60)

    if page_summaries:
        # Generate the TOC at the end
        await generate_toc(page_summaries)
    else:
        logging.warning("No page summaries were generated.")


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        logging.info("\nScript interrupted by user.")

        full_url = f"{BASE_URL}{url}"
        full_url = f"https://www.nbcnews.com{url}"  # Updated to reflect the new base URL