掘金 人工智能 05月13日 15:08
使用 Firecrawl API 监控 Web 内容变更
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文详细介绍了如何使用Firecrawl API构建一个自动化的Web内容变更检测系统,用于监控弹壳回声游戏Wiki的更新。该系统通过定期抓取Wiki页面,利用Firecrawl的变更追踪功能,自动检测内容的新增、更新或删除。文章阐述了项目配置、数据模型定义、核心代码实现以及如何使用GitHub Actions实现自动化部署,从而保证检索增强生成(RAG)系统知识库的实时更新。

💡Firecrawl API是构建自动化Web内容变更检测系统的关键,它能够定期抓取Wiki页面并检测内容变化。

⚙️该系统涉及项目配置、数据模型定义、核心代码实现以及GitHub Actions的自动化部署,确保了检索增强生成(RAG)系统知识库的实时更新。

🔍系统通过changeTracking功能检测页面是否发生变化,包括新增、更新或删除,并据此采取相应行动。

🛠️文章详细介绍了如何使用Pydantic库定义数据模型,以及使用诸如is_changed()和save_status_data()等辅助函数。

🔄该系统包含每月和每周抓取任务,分别用于获取完整的文章列表和检测单个页面的变更,从而实现高效的内容更新。

本文介绍了使用 Firecrawl API 监控 Web 内容变更,以弹壳回声游戏 Wiki 为例,构建自动化内容更新系统。

摘要

本文详细介绍了如何利用 Firecrawl API 构建一个自动化的 Web 内容变更检测系统,以监控弹壳回声游戏 Wiki 的更新。该系统利用 Firecrawl 的变更追踪功能(changeTracking),定期抓取 Wiki 页面,自动检测内容的新增、更新或删除。文章分步骤讲解了项目配置,包括 uv、.env 和 git 等工具的使用;数据模型的定义(使用了 Pydantic 库);核心代码的实现(涉及 changeTracking 和 batch_scrape_urls 等关键功能);以及如何使用 GitHub Actions 实现自动化部署,保证检索增强生成 (RAG) 系统知识库的实时更新。

变化检测简介

今天,许多 AI 应用依赖于最新的信息。例如,检索增强系统需要当前的网页数据以提供准确的回答,而知识库必须反映最新的产品信息。然而,面对成千上万下载的页面,识别原始来源何时发生变化是困难的。

这个问题影响到实际系统。如果客服聊天机器人使用过时的文档,可能会给出错误的答案。如果金融分析工具没有捕捉到最新的市场报告,可能会错过重要的变化。在医疗保健领域,治疗建议必须基于最新的临床指南和研究。

为了解决这些挑战,我们已经将变化检测集成到我们的网络抓取 API 中。这是如何工作的:

from firecrawl import FirecrawlApp# Initialize the appapp = FirecrawlApp()# Check if a page has changedbase_url = "https://bullet-echo.fandom.com/wiki/Special:AllPages"result = app.scrape_url(    base_url,    formats=["changeTracking", "markdown"],)tracking_data = result.changeTrackingprint(tracking_data)

输出结果:

ChangeTrackingData(previousScrapeAt='2025-05-03T15:47:57.21162+00:00', changeStatus='changed', visibility='visible', diff=None, json=None)

代码片段首先初始化了 FirecrawlApp,然后使用格式 "changeTracking" 和 "markdown" 抓取指定的 URL。在格式列表中包含 "changeTracking" 可以使 Firecrawl 将当前抓取结果与之前存在的页面版本进行比较。

结果中的 tracking_data 对象提供了几个关键字段:

这允许您通过程序检测页面是否已更改、是否为新页面或已被删除,并相应地采取行动。

注意:如果您完全不了解 Firecrawl,请参阅我们的文档 

在本教程中,我们将构建一个 Wiki 监控系统,跟踪托管在 Fandom 上的游戏 Wiki 页面的变化。我们的系统将每周和每月进行抓取,智能地识别哪些页面发生了变化,并仅下载更新的内容。

关于 Web 数据集

Bullet Echo 是我最喜欢的移动游戏,游戏玩法出色。它包含一个俯视 2D 多人吃鸡模式,快速反应和潜行至关重要。游戏 trivia 和文档由社区在 Bullet Echo 维基 维护,其中包含超过 180 篇文章:

我们的目的是下载所有这些页面为 markdown 文件,并构建一个系统,定期更新这些页面,因为经常添加新的游戏功能。

逐步构建变化检测系统

现在,让我们从增量步骤开始构建我们的项目。

项目设置和配置

在本节中,我们将设置用于变更检测系统的项目环境。我们将使用 uv,这是一个快速的 Python 包安装器和解析器,来创建和管理我们的 Python 项目。我们还将配置使用 Firecrawl API 所需的环境。

    安装 uv

    pip install uv

    创建项目目录结构

    mkdir -p change-detectioncd change-detection

    使用 uv 初始化项目

    uv init --python=3.12

    这会创建一个基本的 pyproject.toml 文件,并将 Python 3.12 设置为项目的 Python 版本。

    使用 uv 添加项目依赖:

    uv add firecrawl-py pydantic python-dotenv

    创建数据和代码目录:

    mkdir -p data src

    设置环境变量:  在项目根目录创建一个 .env 文件,用于存储您的 Firecrawl API 密钥:

    echo "FIRECRAWL_API_KEY=your_api_key_here" > .env

    创建一个.gitignore 文件:

    echo ".env" > .gitignoreecho ".venv" > .gitignore

    获取 Firecrawl API 密钥

      访问 Firecrawl 的网站注册账户或登录导航到您的账户设置生成一个新的 API 密钥将此密钥复制到你的 .env 文件中

    设置 Git 仓库

    git initgit add .git commit -m "Initial project setup"

    在 GitHub 上初始化仓库

      创建一个新的 GitHub 仓库

      将你的本地仓库推送到 GitHub:

      git remote add origin https://github.com/yourusername/change-detection.gitgit push -u origin main

      在你的 GitHub 仓库中,前往设置 > 秘密和变量 > 行动

      添加一个新的仓库秘密,命名为 FIRECRAWL_API_KEY,并输入你的 Firecrawl API 密钥

我们的项目环境设置完成后,我们现在可以创建数据模型并在接下来的步骤中实现变更检测系统的核心功能。

定义数据模型和工具函数

首先,我们需要从位于 https://bullet-echo.fandom.com/wiki/Special:AllPages 处的“所有页面”URL 抓取每个单独页面的链接。

让我们定义数据模型和实用函数,这些组件将为我们的变更检测系统提供动力。这些组件将帮助我们结构化数据并在我们的抓取工作流中处理常见操作。

结构化数据提取的数据模型

我们将从创建 models.py 开始,该文件定义了 Pydantic 模型,用于结构化抓取的数据:

from pydantic import BaseModelfrom typing import Listclass Article(BaseModel):    url: str    title: strclass ArticleList(BaseModel):    articles: List[Article]

这段代码创建了两个关键模型:

这些 Pydantic 模型起着至关重要的作用:它们定义了 Firecrawl 结构化数据提取的模式。当我们使用批量抓取和提取时,Firecrawl 可以直接填充我们的数据模型。这种方法比手动解析 HTML 更稳健。

例如,我们将在这个脚本的提取中使用这个模型作为模式:

# Example usage in our scraping coderesult = app.batch_scrape_urls(    [BASE_URL],    formats=["extract"],    extract={"schema": ArticleList.model_json_schema()},)# Now we can access the structured dataall_articles = [a["url"] for a in result.data[0].extract["articles"]]

变化检测的辅助函数

接下来,我们将创建 utils.py,其中包含一些基本的辅助函数:

from pathlib import Pathdef is_changed(firecrawl_app, url):    result = firecrawl_app.scrape_url(url, formats=["changeTracking", "markdown"])    return result.changeTracking.changeStatus == "changed"

这个 is_changed() 函数是我们的变更检测系统的中心。它:

    使用 changeTracking 格式抓取 URL

    检查返回的 changeStatus,它可以是:

      "new":第一次看到这个页面"same": 未检测到更改"changed": 内容已更新"removed": 该页面不再存在

    仅在内容更改时返回 True

def save_markdown(markdown, path):    with open(path, "w") as f:        f.write(markdown)def save_status_data(status_data, path):    # Create the directory if it doesn't exist    Path(path).mkdir(parents=True, exist_ok=True)    for s in status_data.data:        url = s.metadata.get("url")        title = s.metadata.get("og:title")        if url and title:            # Get a clean title            title = title.replace(" ", "-").replace("/", "-").replace("|", "-")            filename = Path(path) / f"{title}.md"            # Check if the file already exists            if not filename.exists():                save_markdown(s.markdown, filename)

这些附加功能处理:

这些模型和实用函数共同为我们构建变更检测系统提供了强大的基础。Pydantic 模型为提取的数据提供了一个干净的结构,而实用函数则处理变更检测和文件管理的机制。

在下一节中,我们将使用这些组件来实现核心抓取逻辑,以监控子弹回声维基的更改。

第三步:初始基础 URL 抓取

现在让我们实现每月抓取逻辑,该逻辑将获取维基文章的完整列表并跟踪更改。此脚本将每月运行一次,以确保我们捕获所有新内容和更新内容。

让我们创建 src/monthly_scrape.py

import timefrom pathlib import Pathfrom firecrawl import FirecrawlAppfrom dotenv import load_dotenvfrom models import ArticleListfrom utils import is_changed, save_status_data# Load environment variablesload_dotenv()# Configuration variablesBASE_URL = "https://bullet-echo.fandom.com/wiki/Special:AllPages"# Data directoryDATA_DIR = Path("data")# Files and PathsARTICLES_LIST_FILE = DATA_DIR / "all_articles.txt"OUTPUT_DIRECTORY = DATA_DIR / "bullet-echo-wiki"OUTPUT_DIRECTORY.mkdir(exist_ok=True, parents=True)# Job ParametersTIMEOUT_SECONDS = 180  # 3 minutes timeoutPOLLING_INTERVAL = 30  # Seconds between status checks# Initialize Firecrawl appapp = FirecrawlApp()

这初始化了 Firecrawl 客户端,需要一个 API 密钥,该密钥将从我们的环境变量中加载。我们还为文件路径和作业参数设置了常量。

现在让我们检查我们在函数中使用的 Firecrawl 核心功能:

def get_article_list():    """Get the list of articles from the wiki or from the cached file."""    if is_changed(app, BASE_URL) or not ARTICLES_LIST_FILE.exists():        print("The wiki pages list has changed. Scraping the wiki pages list...")        # Scrape the wiki pages list        result = app.batch_scrape_urls(            [BASE_URL],            formats=["extract"],            extract={"schema": ArticleList.model_json_schema()},        )        # Extract all article URLs        all_articles = [a["url"] for a in result.data[0].extract["articles"]]        print(f"Found {len(all_articles)} articles")        # Write the links to a text file        with open(ARTICLES_LIST_FILE, "w") as f:            for article in all_articles:                f.write(article + "\n")        return all_articles    else:        print("The wiki pages list has not changed. Scraping from existing list...")        with open(ARTICLES_LIST_FILE, "r") as f:            return [line.strip() for line in f.readlines()]

这个函数使用了两个关键的 Firecrawl 方法:

    该 is_changed() 实用函数(我们定义的)调用了 app.scrape_url(),使用了 ["changeTracking", "markdown"] 格式。changeTracking 格式返回了 URL 上次抓取以来是否发生变化的元数据。

    该 app.batch_scrape_urls() 方法接受:

      要爬取的 URL 列表(这里只有一个 URL)一个 formats 参数指定输出格式,这里使用 extract一个 extract 参数包含从我们的 Pydantic 模型中推导出的结构化数据提取模式

批量爬取函数会智能地处理页面内容,并根据我们的模式提取结构化数据,从而消除手动解析 HTML 的需要。

def scrape_and_monitor_articles(article_urls):    """Scrape articles and monitor the process until completion or timeout."""    print(f"Scraping {len(article_urls)} articles...")    # Start the batch scrape job    job = app.async_batch_scrape_urls(article_urls)    start_time = time.time()    # Monitor the job status and save results    while True:        status = app.check_batch_scrape_status(job.id)        if status.status == "completed":            print("Batch scrape completed successfully!")            break        # Check if timeout has been reached        if time.time() - start_time > TIMEOUT_SECONDS:            print(f"Timeout of {TIMEOUT_SECONDS} seconds reached. Exiting.")            break        # Save the partial results        save_status_data(status, OUTPUT_DIRECTORY)        print("Waiting for batch scrape to complete...")        time.sleep(POLLING_INTERVAL)

这个函数展示了 Firecrawl 的异步批量处理功能:

    app.async_batch_scrape_urls() 启动一个异步任务并返回一个带有 ID 的工作对象app.check_batch_scrape_status(job.id) 监控任务状态直到完成返回的状态对象包含可以逐增量处理的部分结果

这种方法对于大型 URL 批次非常高效,因为它允许在作业完全完成之前监控进度并处理部分结果。

结合变更检测和结构化数据提取功能,提供了一种有效的方法来监控和更新我们的维基数据,而无需重新下载未更改的内容。

在下一步中,我们将实现每周抓取脚本,该脚本更频繁地关注检查单个页面的变更。

第4步:个体页面抓取和调度

现在我们已经建立了每月抓取系统,让我们实现一个更频繁的每周检查,专注于检测单个页面的变更,而无需重新抓取所有内容。

让我们创建 src/weekly_scrape.py

from pathlib import Pathfrom firecrawl import FirecrawlAppfrom dotenv import load_dotenvfrom utils import save_markdown# Load environment variablesload_dotenv()# Configuration variables# URLsBASE_URL = "https://bullet-echo.fandom.com/wiki/Special:AllPages"# Data directoryDATA_DIR = Path("data")# Files and PathsARTICLES_LIST_FILE = DATA_DIR / "all_articles.txt"OUTPUT_DIRECTORY = DATA_DIR / "bullet-echo-wiki"OUTPUT_DIRECTORY.mkdir(exist_ok=True, parents=True)# Job ParametersTIMEOUT_SECONDS = 180  # 3 minutes timeoutPOLLING_INTERVAL = 30  # Seconds between status checks# Initialize Firecrawl appapp = FirecrawlApp()

这个设置类似于我们的月度脚本,但请注意,我们只需要导入 save_markdown 工具,因为我们将在本脚本中以不同的方式处理文件。

现在让我们实现读取文章列表的函数:

def read_article_list():    """Read the article list from the file."""    if ARTICLES_LIST_FILE.exists():        with open(ARTICLES_LIST_FILE, "r") as f:            return [line.strip() for line in f.readlines()]    else:        return []

与月度脚本不同,我们不需要检查文章列表是否已更改或重新生成它。我们只需读取由月度任务创建的现有列表。如果文件不存在,我们返回一个空列表。

现在来看看检查每篇文章是否有更改的核心功能:

def scrape_and_monitor_articles(article_urls):    """Scrape and monitor the articles."""    for url in article_urls:        print(f"Checking {url} for changes...")        try:            scrape_result = app.scrape_url(url, formats=["markdown", "changeTracking"])        except Exception as e:            print(f"Error scraping {url}: {e}")            continue        if scrape_result.changeTracking.changeStatus == "changed":            print(f"The article {url} has changed. Saving the new version...")            title = (                url.split("/")[-1]                .replace("%27s", "'")                .replace("_", "-")                .replace(" ", "-")            )            save_markdown(scrape_result.markdown, OUTPUT_DIRECTORY / f"{title}.md")        else:            print(f"The article {url} has not changed.")    print("All articles have been checked for changes.")

这个函数逐个处理每篇文章,而不是批量处理:

    它会遍历我们文章列表中的每个 URL对于每个 URL,它会调用 app.scrape_url() 方法它会检查 changeStatus 以确定页面自上次抓取以来是否发生变化如果页面已更改,它将从 URL 中提取干净的标题并保存更新的 Markdown 内容

这种方法与我们每月的批量处理方式有很大不同:

最后,让我们实现主函数:

def main():    article_urls = read_article_list()    scrape_and_monitor_articles(article_urls)if __name__ == "__main__":    main()

周度脚本比月度脚本更专注且轻量级。虽然月度脚本建立了所有内容的全面基线,但周度脚本可以高效地检查单个页面的变化,并仅下载已更新的内容。

这种两层方法优化了我们的变更检测系统:

    每月扫描会重建文章列表并提供全面的内容更新每周扫描专注于检测并更新仅更改的内容

通过将这两个过程结合起来,我们在维基监控系统中实现了全面性和高效性。

在下一步中,我们将通过增强错误处理和监控功能来提升我们的系统。

第 5 步:设置 GitHub Actions 以调度脚本

现在我们已经有了抓取脚本,我们需要一种方法来定期自动运行它们。GitHub Actions 为我们直接从仓库自动化这些任务提供了很好的方式。

让我们设置 GitHub Actions 工作流来自动运行我们的脚本:

    首先,创建必要的目录:

    mkdir -p .github/workflows

    在 .github/workflows/monthly-scrape.yml 创建每月抓取工作流文件:

name: Monthly Scraping Bullet Echo Base URLon:  schedule:    # Run at midnight (00:00) on the first day of every month    - cron: "0 0 1 * *"  workflow_dispatch: # Allow manual triggeringpermissions:  contents: writejobs:  scrape:    runs-on: ubuntu-latest    steps:      - name: Checkout code        uses: actions/checkout@v3      - name: Set up Python        uses: actions/setup-python@v4        with:          python-version: "3.12"          cache: "pip"      - name: Install dependencies        run: |          python -m pip install --upgrade pip          pip install .      - name: Run scraping script        run: python src/monthly_scrape.py        env:          # Include any environment variables needed by the script          # These should be set as secrets in your repository settings          FIRECRAWL_API_KEY: ${{ secrets.FIRECRAWL_API_KEY }}      - name: Commit and push changes        run: |          git config --global user.name 'github-actions'          git config --global user.email 'github-actions@github.com'          git add data/          git commit -m "Update data from monthly scrape" || echo "No changes to commit"          git push

3. 您还必须在 .github/workflows/weekly-scrape.yml 创建每周抓取工作流文件:

name: Weekly Scraping Bullet Echo Base URLon:  schedule:    # Run at midnight (00:00) on the first day of every week    - cron: "0 0 * * 1"  workflow_dispatch: # Allow manual triggeringpermissions:  contents: writejobs:  scrape:    runs-on: ubuntu-latest    steps:      - name: Checkout code        uses: actions/checkout@v3      - name: Set up Python        uses: actions/setup-python@v4        with:          python-version: "3.12"          cache: 'pip'      - name: Install dependencies        run: |          python -m pip install --upgrade pip          pip install .      - name: Run scraping script        run: python src/weekly_scrape.py        env:          FIRECRAWL_API_KEY: ${{ secrets.FIRECRAWL_API_KEY }}      - name: Commit and push changes        run: |          git config --global user.name 'github-actions'          git config --global user.email 'github-actions@github.com'          git add data/          git commit -m "Update data from weekly scrape" || echo "No changes to commit"          git push

让我们分解一下工作流文件:

使用 Cron 调度

on:  schedule:    # Run at midnight (00:00) on the first day of every month    - cron: "0 0 1 * *"  workflow_dispatch: # Allow manual triggering

代码 cron 的语法结构为 minute hour day-of-month month day-of-week :

对于每周的工作流,cron 表达式 0 0 * * 1 每周一午夜运行。

手动运行工作流

两个工作流都包含 workflow_dispatch 触发器,这允许您通过 GitHub UI 手动运行它们。要手动运行工作流:

    导航到你的 GitHub 仓库在仓库页面顶部点击“Actions”选项卡在左侧边栏中选择要运行的工作流(“Monthly Scraping Bullet Echo Base URL” 或 “Weekly Scraping Bullet Echo Base URL”)在页面右侧点击“运行工作流”按钮选择要运行工作流的分支(通常是“main”)点击绿色的“运行工作流”按钮以启动此过程

这特别适用于测试您的工作流或在计划时间之外运行它们。

权限和工作流步骤

两种工作流的权限和步骤相同,唯一的区别在于执行哪个脚本。

通过设置这两种工作流,您将创建一个完全自动化的系统:

    每月的第一天,GitHub Actions 运行月度抓取,重建文章列表并执行全面内容更新每周一,GitHub Actions 会运行每周抓取任务,高效地检查并仅更新已更改的内容

结果会自动提交回仓库,创建一个受版本控制的数据变更历史记录。

在下一步中,我们将讨论存储我们抓取数据的策略以及如何使其更易于下游应用程序访问。

第六步:生产环境的存储策略

当前的实现将抓取的维基内容存储为本地目录结构中的 markdown 文件。虽然这种方法适用于演示,但在生产环境中使用时有几个限制:

    有限的可扩展性 : 本地文件系统存储对于包含数千页的大数据集扩展性不佳。有限的可访问性 : 本地存储的文件不容易被其他系统或应用程序访问。没有索引 : 简单的文件存储使得高效地搜索或查询内容变得困难。有限的元数据 : 我们当前的方法仅存储关于更改和内容的少量元数据。没有版本控制 : 内容变化时我们会覆盖文件,导致历史版本丢失。

对于生产环境,我们应该考虑更 robust 的存储解决方案:

数据库存储

实施数据库解决方案将有助于更好地组织和检索:

# Example using SQLAlchemy with SQLite (for simplicity)from sqlalchemy import create_engine, Column, Integer, String, Text, DateTimefrom sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy.orm import sessionmakerimport datetimeBase = declarative_base()class WikiArticle(Base):    __tablename__ = 'wiki_articles'        id = Column(Integer, primary_key=True)    url = Column(String, unique=True, index=True)    title = Column(String)    content = Column(Text)    last_updated = Column(DateTime)    last_checked = Column(DateTime)    change_status = Column(String)  # new, same, changed, removed        def __repr__(self):        return f"<WikiArticle(title='{self.title}')>"# Initialize databaseengine = create_engine('sqlite:///data/wiki_articles.db')Base.metadata.create_all(engine)Session = sessionmaker(bind=engine)

这将使我们能够:

云存储选项

对于生产环境,请考虑使用云存储解决方案:

    Amazon S3 或类似对象存储

    import boto3def save_to_s3(content, title, bucket_name="wiki-content"):    s3 = boto3.client('s3')    s3.put_object(        Body=content,        Bucket=bucket_name,        Key=f"articles/{title}.md",        ContentType="text/markdown"    )

    向量数据库对于语义搜索:

    from pinecone import Pineconedef store_with_embeddings(content, title, url):    # Generate embeddings using a model like OpenAI's    embedding = get_embedding(content)        # Store in vector database    pc = Pinecone(api_key="your-api-key")    index = pc.Index("wiki-articles")    index.upsert(        vectors=[{            "id": url,            "values": embedding,            "metadata": {"title": title, "last_updated": datetime.now().isoformat()}        }]    )

下游应用的内容 API

创建一个简单的 REST API 来提供内容:

from fastapi import FastAPI, HTTPExceptionfrom sqlalchemy.orm import Sessionapp = FastAPI()@app.get("/articles/")def list_articles(session: Session = Depends(get_session)):    articles = session.query(WikiArticle).all()    return articles@app.get("/articles/{title}")def get_article(title: str, session: Session = Depends(get_session)):    article = session.query(WikiArticle).filter(WikiArticle.title == title).first()    if not article:        raise HTTPException(status_code=404, detail="Article not found")    return article@app.get("/search/")def search_articles(query: str, session: Session = Depends(get_session)):    # Implement full-text search    articles = session.query(WikiArticle).filter(        WikiArticle.content.like(f"%{query}%")    ).all()    return articles

变更历史和版本控制

实施版本控制以保留历史内容:

class WikiArticleVersion(Base):    __tablename__ = 'wiki_article_versions'        id = Column(Integer, primary_key=True)    article_id = Column(Integer, ForeignKey('wiki_articles.id'))    content = Column(Text)    version_date = Column(DateTime, default=datetime.datetime.utcnow)    change_description = Column(String)

通过实现这些更 robust 的存储解决方案,我们的变更检测系统对于生产应用变得更加有用:

    知识获取系统可以直接查询 API 获取最新的内容分析工具可以监控和可视化变更模式通知系统可以提醒内容所有者关于内容更新内容管道可以自动处理和转换更新的内容

这些改进将我们的基于文件的简单演示转变为一个可以可靠地将数据传递给下游应用程序并保持内容更改完整历史的生产就绪系统。

结论

这就是我们如何使用 Firecrawl 构建变更检测系统的逐步指南。我们创建了一个强大的解决方案,可以高效地监控网页内容的变化,并仅下载更新的页面。该系统使用每月的全面扫描来建立基线,并使用每周的增量检查来捕捉最近的变化。通过利用 Firecrawl 的变更跟踪和结构化数据提取功能,我们已经消除了复杂的 HTML 解析和手动变更检测逻辑的需要。

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Firecrawl API Web内容变更 自动化更新 Wiki监控 GitHub Actions
相关文章