Tag: Python

  • 如何使用Neon Serverless Postgres构建OpenAI矢量数据库

    如何使用Neon Serverless Postgres构建OpenAI矢量数据库

    随着人工智能和深度学习技术的迅猛发展,矢量数据在数据科学和应用领域中扮演着越来越重要的角色。从自然语言处理到图像识别,矢量数据是我们理解和处理各种信息的关键。然而,有效地存储和查询矢量数据一直是一个挑战,特别是在云计算环境中。在本教程中,我们将介绍如何使用Neon Serverless Postgres构建OpenAI矢量数据库,以便存储和查询OpenAI生成的嵌入向量。

    准备工作

    在开始之前,请确保您具备以下条件:

    1. 一个Neon Postgres数据库。您可以在几个简单的步骤中创建一个带有现成的neondb数据库的帐户并设置项目。有关说明,请参阅注册并创建您的第一个项目。
    2. 您的Neon数据库连接字符串。您可以从Neon仪表板上的连接详细信息小部件中复制它。请参阅从任何应用程序连接。
    3. pgvector扩展。在Neon中运行CREATE EXTENSION vector;来安装扩展。有关说明,请参阅启用pgvector扩展。
    4. 您的OpenAI API密钥。
    5. Python和pip。

    安装所需模块

    这个笔记本需要openai、psycopg2、pandas、wget和python-dotenv模块。您可以使用pip来安装它们:

    !pip install openai psycopg2 pandas wget python-dotenv

    准备您的OpenAI API密钥

    为了生成文档和查询的向量,需要一个OpenAI API密钥。

    如果您没有OpenAI API密钥,请从https://platform.openai.com/account/api-keys获取一个。

    将OpenAI API密钥添加为操作系统环境变量或在会话中提供它。如果您定义了一个环境变量,请将变量命名为OPENAI_API_KEY。

    测试您的OpenAI密钥

    import os
    from getpass import getpass
    
    # 检查是否将OPENAI_API_KEY设置为环境变量
    if os.getenv("OPENAI_API_KEY") is not None:
        print("您的OPENAI_API_KEY已准备就绪")
    else:
        # 如果没有,请提示输入
        api_key = getpass("请输入您的OPENAI_API_KEY: ")
        if api_key:
            print("您的OPENAI_API_KEY现在可用于此会话")
            # 可选地,您可以将其设置为当前会话的环境变量
            os.environ["OPENAI_API_KEY"] = api_key
        else:
            print("您未输入OPENAI_API_KEY")

    连接到您的Neon数据库

    请在下面提供您的Neon数据库连接字符串,或者使用DATABASE_URL变量在.env文件中定义它。有关获取Neon连接字符串的信息,请参阅从任何应用程序连接。

    import os
    import psycopg2
    from dotenv import load_dotenv
    
    # 从.env文件加载环境变量
    load_dotenv()
    
    # 连接字符串可以直接在这里提供。
    # 用您的Neon连接字符串替换下一行。
    connection_string = "postgres://<user>:<password>@<hostname>/<dbname>"
    
    # 如果上面没有直接提供connection_string,
    # 则检查环境或.env中是否设置了DATABASE_URL。
    if not connection_string:
        connection_string = os.environ.get("DATABASE_URL")
    
        # 如果两种方法都没有提供连接字符串,则引发错误。
        if not connection_string:
            raise ValueError("请在代码中或.env文件中提供有效的连接字符串作为DATABASE_URL。")
    
    # 使用连接字符串连接
    connection = psycopg2.connect(connection_string)
    
    # 创建新的游标对象
    cursor = connection.cursor()
    
    # 测试数据库连接
    cursor.execute("SELECT 1;")
    result = cursor.fetchone()
    
    # 检查查询结果
    if result == (1,):
        print("您的数据库连接成功!")
    else:
        print("连接失败。")

    加载数据

    将预先计算的矢量数据加载到名为articles的数据库表中,从.csv文件加载数据。由于有25000条记录,因此预计操作将花费几分钟。

    import io
    
    # 本地CSV文件的路径
    csv_file_path = '../../data/vector_database_wikipedia_articles_embedded.csv'
    
    # 定义一个生成器函数来处理csv文件
    def process_file(file_path):
        with open(file_path, 'r', encoding='utf-8') as file:
            for line in file:
                yield line
    
    # 创建一个StringIO对象来存储修改后的行
    modified_lines = io.StringIO(''.join(list(process_file(csv_file_path))))
    
    # 创建用于copy_expert的COPY命令
    copy_command = '''
    COPY public.articles (id, url, title, content, title_vector, content_vector, vector_id)
    FROM STDIN WITH (FORMAT CSV, HEADER true, DELIMITER ',');
    '''
    
    # 使用copy_expert执行COPY命令
    cursor.copy_expert(copy_command, modified_lines)
    
    # 提交更改
    connection.commit()
    
    # 检查记录数以确保数据已加载。应该有25000条记录。
    count_sql = """select count(*) from public.articles;"""
    cursor.execute(count_sql)
    result = cursor.fetchone()
    print(f"记录数:{result[0]}")

    搜索您的数据

    在将数据存储在Neon数据库中后,您可以查询最近的邻居。

    首先,定义query_neon函数,当运行矢量相似性搜索时,该函数将执行。该函数基于用户的查询创建一个嵌入向量,准备SQL查询,并使用嵌入向量运行SQL查询。您加载到数据库中的预计算嵌入是使用text-embedding-ada-002 OpenAI模型创建的,因此您必须使用相同的模型来创建用于相似性搜索的嵌入。

    提供了一个vector_name参数,允许基于“标题”或“内容”搜索。

    def query_neon(query, collection
    
    _name, vector_name="title_vector", top_k=20):
    
        # 从用户查询创建嵌入向量
        embedded_query = openai.Embedding.create(
            input=query,
            model="text-embedding-ada-002",
        )["data"][0]["embedding"]
    
        # 将嵌入查询转换为PostgreSQL兼容格式
        embedded_query_pg = "[" + ",".join(map(str, embedded_query)) + "]"
    
        # 创建SQL查询
        query_sql = f"""
        SELECT id, url, title, l2_distance({vector_name},'{embedded_query_pg}'::VECTOR(1536)) AS similarity
        FROM {collection_name}
        ORDER BY {vector_name} <-> '{embedded_query_pg}'::VECTOR(1536)
        LIMIT {top_k};
        """
        # 执行查询
        cursor.execute(query_sql)
        results = cursor.fetchall()
    
        return results
    
    # 基于title_vector嵌入运行相似性搜索
    query_results = query_neon("Greek mythology", "Articles")
    for i, result in enumerate(query_results):
        print(f"{i + 1}. {result[2]} (分数: {round(1 - result[3], 3)})")
    
    # 基于content_vector嵌入运行相似性搜索
    query_results = query_neon("Famous battles in Greek history", "Articles", "content_vector")
    for i, result in enumerate(query_results):
        print(f"{i + 1}. {result[2]} (分数: {round(1 - result[3], 3)})")

    结论

    通过使用Neon Serverless Postgres构建OpenAI矢量数据库,您可以有效地存储和查询OpenAI生成的嵌入向量。这为您提供了强大的工具来处理和分析文本数据,从而使您能够更好地理解和利用矢量数据的潜力。

  • 如何使用搜索API和重新排序来进行问题回答

    如何使用搜索API和重新排序来进行问题回答

    有时候,寻找相关信息就像大海捞针一样困难,但不要绝望,GPT可以为我们做很多工作。在本指南中,我们将探讨一种使用各种人工智能技术增强现有搜索系统的方法,帮助我们筛选信息中的噪音。

    GPT检索信息的两种方式如下:

    1. 模仿人类浏览:GPT触发搜索,评估结果,如果必要的话,修改搜索查询。它还可以跟踪特定的搜索结果,形成思维链,就像人类用户会做的那样。
    2. 使用嵌入进行检索:为你的内容和用户查询计算嵌入,然后根据余弦相似度测量选择与用户查询最相关的内容。这种技术在像Google这样的搜索引擎中被广泛使用。

    这两种方法都有潜力,但各自都有缺点:第一种方法由于其迭代性质可能较慢,第二种方法需要预先嵌入整个知识库,不断嵌入新内容并维护矢量数据库。

    通过结合这些方法,并从重新排序方法中汲取灵感,我们找到了一种介于两者之间的方法。这种方法可以在任何现有搜索系统的基础上实施,如Slack搜索API或带有私有数据的内部ElasticSearch实例。它的工作原理如下:

    步骤1:搜索

    1. 用户提出问题。
    2. GPT生成一组潜在的查询。
    3. 并行执行搜索查询。

    步骤2:重新排序

    1. 使用每个结果的嵌入来计算与生成的假设理想答案对用户问题的语义相似性。
    2. 根据此相似性度量对结果进行排序和过滤。

    步骤3:回答

    1. 针对前几名搜索结果,模型生成回答用户问题的答案,包括引用和链接。

    这种混合方法提供了相对较低的延迟,并且可以集成到任何现有的搜索端点中,而无需维护矢量数据库。下面让我们深入了解吧!我们将以News API作为示例领域进行搜索。

    设置

    除了你的OPENAI_API_KEY,你还需要在环境中包含一个NEWS_API_KEY。你可以在这里获取API密钥。

    %env NEWS_API_KEY = YOUR_NEWS_API_KEY
    
    # 依赖项
    from datetime import date, timedelta  # 用于获取最近新闻的日期处理
    from IPython import display  # 用于漂亮的打印
    import json  # 用于解析JSON API响应和模型输出
    from numpy import dot  # 用于余弦相似度
    import openai  # 用于使用GPT和获取嵌入
    import os  # 用于加载环境变量
    import requests  # 用于进行API请求
    from tqdm.notebook import tqdm  # 用于显示进度条

    以上是初始化所需的依赖项和环境变量设置。接下来,我们将逐步执行三个主要步骤:搜索、重新排序和回答。

    步骤1:搜索

    一切都始于用户的问题。首先,用户提出一个问题,然后我们使用GPT生成一系列多样化的查询,以尽可能详尽的方式回答问题。

    # 用户提出问题
    USER_QUESTION = "谁赢得了NBA总冠军?最有价值球员是谁?告诉我一些关于最后一场比赛的情况。"
    
    # 为了尽可能详尽,我们使用模型生成基于此问题的各种查询。
    QUERIES_INPUT = f"""
    你有访问一个返回最近新闻文章的搜索API。
    生成一个与这个问题相关的搜索查询数组。
    为查询使用相关关键字的变体,尽量做到通用。
    包括尽可能多的查询,包括和不包括术语。
    例如,包括像['关键词1 关键词2','关键词1','关键词2']这样的查询。
    要有创造性。包括的查询越多,找到相关结果的可能性就越大。
    
    用户问题: {USER_QUESTION}
    
    格式: {{"queries": ["query_1", "query_2", "query_3"]}}
    """
    
    queries = json_gpt(QUERIES_INPUT)["queries"]
    
    # 让我们也包括原始问题以确保全面。
    queries.append(USER_QUESTION)
    
    queries

    以上代码生成了一系列搜索查询,这些查询包括与用户问题相关的多个关键字和变体。这些查询将在接下来的搜索步骤中用于检索新闻文章。

    接下来,让我们运行这些搜索查询以获取新闻文章。

    def search_news(
        query: str,
        news_api_key: str = news_api_key,
        num_articles: int = 50,
        from_datetime: str = "2023-06-01",  # 2023年NBA总决赛于2023年6月举行
        to_datetime: str = "2023-06-30",
    ) -> dict:
        response = requests.get(
            "https://newsapi.org/v2/everything",
            params={
                "q": query,
                "apiKey": news_api_key,
                "pageSize": num_articles,
                "sortBy": "relevancy",
                "from": from_datetime,
                "to": to_datetime,
            },
        )
    
        return response.json()
    
    articles = []
    
    for query in tqdm(queries):
        result = search_news(query)
        if result["status"] == "ok":
            articles = articles + result["articles"]
    
        else:
            raise Exception(result["message"])
    
    # 移除重复文章
    articles = list({article["url"]: article for article in articles}.values())
    
    print("文章总数:", len(articles))
    print("查询1的前5篇文章:", "\n")
    
    for article in articles[0:5]:
        print("标题:", article["title"])
        print("描述:", article["description"])
        print("内容:", article["content"][0:100] + "...")
        print()

    以上代码执行了搜索查询并获取了与这些查询相关的新闻文章。注意,为了减少重复,我们在获取文章后删除了重复的文章。

    现在,我们已经获得了新闻文章,但很多时候搜索查询会返回大量结果,其中许多与用户最初提出的问题无关。为了提高最终答案的质量,我们将使用嵌入来重新排序和过滤结果。

    步骤2:重新排序

    受HyDE(Gao等人)启发,我们首先生成一个假设理想答案,用于对比和重新排列我们的结果。这有助于优先考虑看起来是好答案的结果,而不是与我们的问题类似的结果。下面是我们用来生成假设答案的提示。

    HA_INPUT = f"""
    生成一个假设的答案,以回答用户的问题。这个答案将用于排名搜索结果。
    假装你拥有回答所需的所有信息,但不要使用任何实际的事实。而是使用占位符
    比如,NAME在某地做了某事,或者NAME在某地说了某话。
    
    用户问题: {USER_QUESTION}
    
    格式: {{"hypotheticalAnswer": "假设答案文本"}}
    """
    
    hypothetical_answer = json_gpt(HA_INPUT)["hypotheticalAnswer"]
    
    hypothetical_answer

    以上代码生成了一个假设答案,这个答案包含了关于NBA总决赛的信息,但没有使用实际的事实,而是使用了占位符。接下来,我们将为搜索结果和假设答案生成嵌入,然后计算这些嵌入之间的余弦距离,得到语义相似性度量。请注意,由于OpenAI嵌入在API中返回时已经归一化,我们可以简单地计算点积来代替进行完整的余弦相似性计算。

    hypothetical_answer_embedding = embeddings(hypothetical_answer)[0]
    article_embeddings = embeddings(
        [
            f"{article['title']} {article['description']} {article['content'][0:100]}"
            for article in articles
        ]
    )
    
    # 计算余弦相似度
    cosine_similarities = []
    for article_embedding in article_embeddings:
        cosine_similarities.append(dot(hypothetical_answer_embedding, article_embedding))
    
    cosine_similarities[0:10]

    以上代码计算了假设答案与每篇文章的嵌入之间的余弦相似性。这些相似性分数将用于对结果进行排序和过滤。

    最后,我们使用这些相似性分数对结果进行排序和过滤。

    scored_articles = zip(articles, cosine_similarities)
    
    # 根据余弦相似度对文章进行排序
    sorted_articles = sorted(scored_articles, key=lambda x: x[1], reverse=True)
    
    # 打印前5篇文章
    print("前5篇文章:", "\n")
    
    for article, score in sorted_articles[0:5]:
        print("标题:", article["title"])
        print("描述:", article["description"])
        print("内容:", article["content"][0:100] + "...")
        print("分数:", score)
        print()

    以上代码对文章进行了排序,按照与假设答案的语义相似性得分降序排列。这些排序后的文章看起来与我们最初的查询更相关。现在,让我们使用前5个结果生成最终答案。

    步骤3:回答

    formatted_top_results = [
        {
            "title": article["title"],
            "description": article["description"],
            "url": article["url"],
        }
        for article, _score in sorted_articles[0:5]
    ]
    
    ANSWER_INPUT = f"""
    根据给定的搜索结果为用户的问题生成答案。 
    顶部结果: {formatted_top_results}
    用户问题: {USER_QUESTION}
    
    在答案中包括尽可能多的信息。引用相关的搜索结果URL作为Markdown链接。
    """
    
    completion = openai.ChatCompletion.create(
        model=GPT_MODEL,
        messages=[{"role": "user", "content": ANSWER_INPUT}],
        temperature=0.5,
        stream=True,
    )
    
    text = ""
    for chunk in completion:
        text += chunk.choices[0].delta.get("content", "")
        display.clear_output(wait=True)
        display.display(display.Markdown(text))

    以上代码使用前5个搜索结果生成了最终的答案,其中包括引用了相关搜索结果的链接。

    至此,我们已经完成了搜索、重新排序和回答的所有步骤。下面,让我们根据以上内容编写一篇优秀的教程文章,满足指定的要求。

    如何使用搜索API和重新排序进行问题回答

    开篇故事

    搜索相关信息有时候就像在庞大的信息海洋中寻找一根针一样困难。但不要担心,人工智能技术可以帮助我们在这个任务中取得很大进展。在本文中,我们将探讨一种方法,利用搜索API和嵌入技术,以及重新排序方法,来实现更准确的问题回答。

    故事开始于一个充满好奇心的用户,他有一个问题:谁赢得了NBA总冠军?最有价值球员是谁?告诉我一些关于最后一场比赛的情况。这个问题看似简单,但

    要从海量的新闻文章中找到相关的信息可能会让人望而却步。

    步骤1:搜索

    首先,用户提出了一个问题。这个问题是我们开始寻找答案的出发点。但为了尽可能全面地查找相关信息,我们使用人工智能模型生成了多个不同的查询,这些查询都与用户的问题相关。这些查询包括谁赢得了NBA总冠军、NBA总决赛的MVP是谁,以及最后一场比赛的概述等等。这些查询一起被发送到搜索API中,以并行方式执行搜索。

    步骤2:重新排序

    一旦我们获得了搜索结果,接下来的步骤是对这些结果进行重新排序。这一步骤受到了HyDE(Gao等人)的启发。我们首先生成了一个假设的理想答案,该答案包含了关于NBA总决赛的信息,但没有使用任何实际的事实,而是使用了占位符。然后,我们为搜索结果和假设答案生成了嵌入,这些嵌入可以帮助我们度量它们之间的语义相似性。最终,我们使用语义相似性分数对结果进行排序,以找出最相关的答案。

    步骤3:回答

    最后,我们使用排名最高的搜索结果生成最终的答案。这个答案包括了与NBA总决赛有关的信息,并引用了相关搜索结果的链接,以便用户可以深入了解。

    通过这个混合方法,我们能够在相对低的延迟下获得高质量的答案,而无需维护一个向量数据库。这种方法可以集成到任何现有的搜索系统中,无论是Slack搜索API还是具有私有数据的内部ElasticSearch实例。

    希望本文对你理解如何使用搜索API和重新排序来回答问题有所帮助!

  • 如何使用tiktoken计算文本中的标记数

    如何使用tiktoken计算文本中的标记数

    在现代自然语言处理中,标记是一种重要的概念,因为它们是语言模型处理文本的基本单元。本教程将向您展示如何使用OpenAI开源的快速分词工具tiktoken来计算文本中的标记数。通过了解文本中有多少标记,您可以:

    1. 判断文本是否太长以至于超出模型处理的限制。
    2. 了解使用OpenAI API调用的成本,因为计费是按标记计算的。

    1. 引言故事

    假设您是一名程序员,正在为自己的聊天应用项目编写代码。您已经集成了一个强大的自然语言处理模型,但现在需要确定用户输入的文本有多少标记,以便确保不会超出模型的限制。在解决这个问题之前,您曾不止一次被意想不到的文本长度问题困扰。一天,您在互联网上发现了一个名为tiktoken的开源工具,它能够快速准确地计算文本中的标记数。这似乎是您解决问题的完美工具,因此您决定深入了解它并开始使用它来解决您的标记计数问题。

    2. 安装tiktoken

    首先,您需要安装tiktoken工具。您可以使用pip来安装它:

    pip install --upgrade tiktoken

    安装完成后,您就可以开始使用tiktoken来计算文本中的标记数了。

    3. 导入tiktoken

    在您的Python项目中,首先导入tiktoken库:

    import tiktoken

    4. 加载编码

    接下来,您需要加载一个编码,以告诉tiktoken如何将文本转换为标记。不同的模型使用不同的编码。在本示例中,我们使用了“cl100k_base”编码,它适用于一些OpenAI模型,包括gpt-4和gpt-3.5-turbo。您可以这样加载编码:

    encoding = tiktoken.get_encoding("cl100k_base")

    5. 使用编码.encode()方法将文本转换为标记

    现在,您可以使用编码对象的.encode()方法将文本转换为标记。该方法将文本字符串转换为标记的整数列表。例如,如果我们有文本字符串”tiktoken is great!”,您可以这样做:

    tokens = encoding.encode("tiktoken is great!")

    这将返回一个整数列表,代表文本中的标记。在这个示例中,返回的标记列表为[83, 1609, 5963, 374, 2294, 0]。

    要计算文本中的标记数,只需查看标记列表的长度:

    num_tokens = len(tokens)

    这将给您文本中的标记数,本例中为6个标记。

    6. 使用编码.decode()方法将标记转换回文本

    如果您需要将标记转换回文本,可以使用编码对象的.decode()方法。例如,如果我们有标记列表[83, 1609, 5963, 374, 2294, 0],您可以这样做:

    text = encoding.decode([83, 1609, 5963, 374, 2294, 0])

    这将返回文本字符串”tiktoken is great!”。

    请注意,虽然.decode()方法可以应用于单个标记,但对于不在utf-8边界上的标记,它可能会导致信息丢失。对于单个标记,.decode_single_token_bytes()方法可以安全地将单个整数标记转换为其表示的字节。

    7. 比较不同编码

    不同编码在分割单词、分组空格和处理非英文字符方面有所不同。使用上述方法,我们可以比较不同编码在几个示例字符串上的效果。以下是一个比较不同编码的函数示例:

    def compare_encodings(example_string: str) -> None:
        """打印三种字符串编码的比较结果。"""
        # 打印示例字符串
        print(f'\n示例字符串: "{example_string}"')
        # 对于每个编码,打印标记数、标记整数和标记字节
        for encoding_name in ["r50k_base", "p50k_base", "cl100k_base"]:
            encoding = tiktoken.get_encoding(encoding_name)
            token_integers = encoding.encode(example_string)
            num_tokens = len(token_integers)
            token_bytes = [encoding.decode_single_token_bytes(token) for token in token_integers]
            print()
            print(f"{encoding_name}: {num_tokens} 个标记")
            print(f"标记整数: {token_integers}")
            print(f"标记字节: {token_bytes}")
    
    compare_encodings("antidisestablishmentarianism")

    8. 为聊天完成API调用计算标记数

    对于像gpt-3.5-turbo和gpt-4这样的ChatGPT模型,它们使用标记方式与较早的完成模型相同,但由于它们基于消息格式,因此更难计算消息将使用多少标记。

    以下是一个用于计算传递给gpt-3.5-turbo或gpt-4的消息标记数的示例函数。请注意,从消息中计算标记的方式可能会因模型而异。考虑到下面的函数中计算的标记数量是一个估计值,而不是一个永恒的保证。

    def num_tokens_from_messages(messages, model="gpt-3.5-turbo-0613"):
        """返回消息列表使用的标记数。"""
        try:
            encoding
    
     = tiktoken.get_encoding(model)
        except Exception as e:
            print(f"获取编码时发生错误:{e}")
            return None
    
        total_tokens = 0
        for message in messages:
            tokens = encoding.encode(message["content"])
            num_tokens = len(tokens)
            # 添加额外的标记以表示用户或系统角色
            if message["role"] == "system":
                num_tokens += 1
            else:
                num_tokens += 2  # 一个用于角色,一个用于分隔符
            total_tokens += num_tokens
    
        return total_tokens
    
    # 示例消息列表
    messages = [
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Tell me a joke."},
        {"role": "assistant", "content": "Why did the chicken cross the road?"},
        {"role": "user", "content": "I don't know, why did the chicken cross the road?"}
    ]
    
    total_tokens = num_tokens_from_messages(messages, model="gpt-3.5-turbo-0613")
    print(f"消息列表中的总标记数:{total_tokens}")

    这个函数可以帮助您估算给定消息列表的标记数,以便控制文本长度和计费。请注意,不同模型的标记数限制可能会有所不同,因此在实际使用中请谨慎估算。

  • 使用Python创建带有特殊二维码的教程

    使用Python创建带有特殊二维码的教程

    有一天,王大神在他的办公室里坐着,思考着如何将编程技能与二维码相结合,以创建一种特殊的二维码。这个特殊的二维码不仅可以存储信息,还可以嵌入一些有趣的元素。于是,他开始了一项探索之旅,想要与你分享他的发现。

    准备工作

    在开始之前,我们需要准备一些东西:

    • Python编程知识
    • 一个二维码生成库(我们将使用qrcode库)
    • 一些有趣的元素,例如彩色的图像或徽标

    步骤1:安装qrcode库

    首先,确保你已经安装了qrcode库。如果没有安装,你可以使用以下命令在Python中安装它:

    pip install qrcode[pil]

    步骤2:生成基本二维码

    我们将从生成基本的二维码开始。下面是一个简单的Python代码示例,用于生成一个包含文本信息的基本二维码:

    import qrcode
    
    data = "Hello, World!"  # 你可以替换成你想要的文本信息
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=4,
    )
    qr.add_data(data)
    qr.make(fit=True)
    
    img = qr.make_image(fill_color="black", back_color="white")
    img.save("basic_qr.png")

    运行上述代码后,你将在当前目录下看到一个名为basic_qr.png的图片,其中包含了你输入的文本信息的二维码。

    步骤3:添加特殊元素

    现在,让我们来让这个二维码变得特殊起来。你可以添加一些有趣的元素,比如一张图片,作为二维码的一部分。这将使你的二维码更加吸引人。

    首先,确保你有一张你想要添加到二维码中的图片。然后,使用以下代码示例来将图片嵌入到二维码中:

    from PIL import Image
    
    # 打开你想要嵌入的图片
    icon = Image.open("icon.png")  # 替换成你的图片文件名
    
    # 创建一个新的QRCode对象
    qr_with_icon = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=10,
        border=4,
    )
    qr_with_icon.add_data(data)
    qr_with_icon.make(fit=True)
    
    # 创建一个二维码图片
    img_with_icon = qr_with_icon.make_image(fill_color="black", back_color="white")
    
    # 将图标嵌入到二维码中心
    img_with_icon.paste(icon, (50, 50))  # 调整图标的位置
    
    # 保存最终的特殊二维码图片
    img_with_icon.save("special_qr.png")

    这段代码将打开你选择的图片,并将其嵌入到二维码中心。保存后,你将得到一个特殊的二维码,其中包含了你的文本信息和添加的图片元素。

    结论

    通过这个教程,我们学会了如何使用Python和qrcode库创建特殊的二维码。你可以进一步探索,添加更多有趣的元素,以使你的二维码更加个性化和吸引人。希望你能享受这个创意的过程!

  • 优化签到流程:如何轻松自动签到并获取验证码

    优化签到流程:如何轻松自动签到并获取验证码

    你是否曾经厌倦了每天手动签到的重复工作?是否希望能够自动化这一过程,省下宝贵的时间?在这篇文章中,我将向你展示如何通过Python编写一个自动签到脚本,使签到过程更加便捷和高效。我们将使用Python的requests库来发送网络请求,并借助第三方验证码识别服务,自动获取验证码并完成签到。让我们一起来看看如何实现这一目标吧。

    步骤一:获取验证码

    首先,我们需要从签到网站获取验证码图片。这个过程涉及发送GET请求来获取验证码图片,然后将其传递给验证码识别服务。在这里,我们使用了一个名为imgcode_online的函数来完成这个任务。这个函数接受验证码图片的URL作为参数,将其转换为base64编码的数据,并将其发送到一个在线验证码识别服务。该服务将返回识别后的验证码文本。

    def imgcode_online(imgurl):
        data = {
            'token': token,  # 验证码识别服务的token
            'type': 'online',
            'uri': imgurl
        }
        response = requests.post('http://www.bhshare.cn/imgcode/', data=data)
        result = json.loads(response.text)
        if result['code'] == 200:
            return result['data']
        else:
            return 'error'

    步骤二:检查签到时间

    在签到之前,我们需要检查是否到达签到时间。为了做到这一点,我们首先需要发送GET请求来获取上次签到的时间,并将其转换为时间戳。然后,我们将当前时间与上次签到时间进行比较,如果时间间隔大于24小时,就说明可以进行签到。

    def tly():
        signUrl = "https://tly30.com/modules/index.php"
        header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
            'Cookie': cookie
        }
    
        res = requests.get(url=signUrl, headers=header).text
        signtime = getmidstring(res, '<p>上次签到时间:<code>', '</code></p>')
        timeArray = time.strptime(signtime, "%Y-%m-%d %H:%M:%S")
        timeStamp = int(time.mktime(timeArray))
        t = int(time.time())
    
        if t - timeStamp > 86400:
            print("距上次签到时间大于24小时啦,可以签到")
            # 签到操作
            captchaUrl = "https://tly30.com/other/captcha.php"
            signurl = "https://tly30.com/modules/_checkin.php?captcha="
            header = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36',
                'Cookie': cookie
            }
            res1 = requests.get(url=captchaUrl, headers=header)
            base64_data = base64.b64encode(res1.content)
            oocr = imgcode_online('data:image/jpeg;base64,' + str(base64_data, 'utf-8'))
            res2 = requests.get(url=signurl + oocr.upper(), headers=header).text
            print(res2)
        else:
            print("还未到时间!", t - timeStamp)

    总结

    通过这个简单的Python脚本,我们可以轻松地自动签到并获取验证码,省去了手动操作的麻烦。你可以将这个脚本设置为定时任务,每天自动完成签到。这不仅提高了签到的效率,还让你有更多的时间专注于其他重要的事情。

    希望这篇文章对你有所帮助,让你更好地理解如何使用Python自动化网站操作。如果你有任何问题或建议,欢迎在评论中分享。祝你签到顺利!

  • 从进程池到线程池:实现高效图片下载

    从进程池到线程池:实现高效图片下载

    在数字时代,我们每天都能够轻松访问到各种各样的图片,不论是美景、艺术品还是有趣的表情包。然而,有时候我们需要大量的图片数据,例如用于机器学习的训练集或者简单的个人收藏。在这种情况下,如何高效地获取和保存这些图片就成了一个挑战。今天,我将向大家介绍一种使用进程池和线程池相结合的方法,以实现高效的图片下载。

    准备工作

    首先,让我们明确一下需要的准备工作。我们将使用Python来完成这个任务,所以确保你已经安装了Python环境。此外,我们还需要以下库:

    • requests:用于发送HTTP请求和获取网页内容。
    • lxml:用于解析HTML文档。
    • multiprocessing:用于创建进程池和进程共享变量。
    • concurrent.futures:用于创建线程池。

    确保你已经安装了这些库,如果没有,可以使用pip来安装。

    获取图片地址

    首先,我们需要获取要下载的图片的地址。在这个例子中,我们将从一个网站上抓取动漫壁纸的图片地址。我们使用了requests库来发送GET请求,然后使用lxml来解析HTML文档,提取出图片的地址。这些地址将被放入一个进程队列中,以便后续的下载。

    # 获取图片地址
    def get_url(url, que):
        resp = requests.get(url, headers=headers)
        resp.encoding = resp.apparent_encoding
        date = resp.text
        tree = etree.HTML(date)
        list_url = tree.xpath('//ul[@class="clearfix"]/li/a')
        for i in list_url:
            url_img = i.xpath('./img/@src')
            que.put('https://pic.netbian.com' + str(*url_img))  # put写入进程变量队列中
        resp.close()

    下载并保存图片

    接下来,我们需要编写函数来下载并保存图片。我们使用requests库发送GET请求,然后将图片保存到本地。为了避免文件名冲突,我们可以使用一个共享的数值型变量来为每张图片分配一个唯一的文件名。这个变量会在多个进程之间共享,确保每张图片的文件名都不同。

    # 下载并保存图片
    def download_ove(url, name):
        try:
            resp = requests.get(url, headers=headers)
            path_img = os.path.join(path, f'{name.value}.jpg')
            with open(path_img, 'wb') as f:
                f.write(resp.content)
            print(f'保存成功{name.value}.jpg')
            name.value += 1  # 数值型进程变量自增
        except Exception as ex:
            print('下载出错', ex)

    下载图片的主函数

    现在,让我们来编写下载图片的主函数。我们使用了线程池来并发下载图片,这样可以提高下载速度。通过创建一个ThreadPoolExecutor对象,我们可以指定同时运行的线程数量,这里设置为20。然后,我们从进程队列中获取图片地址,并将下载任务提交给线程池处理。

    # 获取进程队列中的url并启用线程池下载保存图片
    def download_img(que, name):
        # 创建线程池,指定20个线程处理数据
        with ThreadPoolExecutor(20) as t:
            while True:
                try:
                    s = que.get(timeout=3)  # 获取进程队列中的数据,等待3秒若是还没获取到数据抛出异常
                    t.submit(download_ove, s, name)  # 添加进线程池
                except Exception as ec:
                    print(ec)
                    break

    异常处理

    在我们的代码中,我们还加入了异常处理机制。如果下载出现错误,我们会捕获异常并打印出错信息。这有助于我们及时发现问题并进行处理。

    # 接收进程池与线程池异常的回调函数
    def err_call_back(err):
        print(f'出错啦~ error:{str(err)}')

    执行主程序

    最后,我们在主程序中执行上述函数。我们首先创建了一个进程共享的队列变量和一个数值型的共享变量,用于存储图片地址和文件名计数。然后,我们根据需要获取多个页面的图片地址,将下载任务提交给进程池,并等待任务完成。这样,我们就能够高效地下载大量图片了。

    if __name__ == '__main__':
        if not os.path.exists(path):
            os.mkdir(path)
        que = multiprocessing.Manager().Queue()  # 创建一个进程之间共享的队列变量
        name = multiprocessing.Manager().Value('i', 0)  # 创建一个进程之间共享的数值型变量,'i'表示整型数字,0表示从0开始
        for i in range(1, 4):
            if i != 1:
                url = f'https://pic.netbian.com/4kdongman/index_{i}.html'
            else:
                url = 'https://pic.netbian.com/4kdongman/'
            get_url(url, que)
            #  创建进程池,并将函数添加到进程池内,指定最多开辟1个进程处理数据(开多了怕把网址玩崩)
            with multiprocessing.Pool(1) as pool:
                pool.apply(download_img, args=(que, name))  # 将函数以同步的方式添加进进程池
        pool.close()  # 结束进程池,不在往内添加数据
        pool.join()  # 等待进程池运行结束
        print('结束')

    结束语

    通过使用进程池和线程池的组合,我们能够高效地下载大量图片,提高了任务的并发性和效率。这种方法对于需要大规模获取图片数据的任务非常有用,例如构建图像数据集或爬取网站上的图片资源。

    希望这个教程对你有所帮助,如果你有任何问题或建议,欢迎在评论中留言。祝愿你在图片下载任务中取得成功!

  • Windows配置Python环境变量:解锁Python开发的便捷之路

    Windows配置Python环境变量:解锁Python开发的便捷之路

    故事开始于一个充满激情的程序员的电脑上。他正在追逐着一个创意,想要用Python语言来开发一款新的应用程序。但是,他发现在每次使用Python时都要手动指定Python的路径有些麻烦。于是,他决定学习如何在Windows操作系统上配置Python环境变量,以便能够轻松地在命令行中运行Python脚本和程序。现在,让我们跟随他的脚步,学习如何配置Python环境变量,解锁Python开发的便捷之路。

    什么是Python环境变量?

    Python环境变量是一组设置,用于告诉操作系统和开发工具在哪里找到Python解释器和相关工具。通过配置Python环境变量,你可以使Python可执行文件在任何目录中都能够被轻松访问,而无需手动指定Python的安装路径。这极大地简化了Python开发的流程。

    步骤一:安装Python

    首先,确保你已经在你的计算机上安装了Python。如果还没有安装,你可以从Python官方网站(https://www.python.org/)下载最新的Python安装程序,并按照安装向导的指导进行安装。在安装过程中,确保勾选上”Add Python X.Y to PATH”(X.Y表示你安装的Python版本号),以便自动配置环境变量。

    步骤二:查找Python安装路径

    在配置Python环境变量之前,你需要找到Python的安装路径。通常情况下,Python会被安装在”C:\Users\<你的用户名>\AppData\Local\Programs\Python\PythonX.Y”的位置,其中X.Y表示你安装的Python版本号。

    步骤三:配置Python环境变量

    现在,让我们来配置Python环境变量。以下是具体步骤:

    1. 右键单击”此电脑”:首先,在桌面上右键单击”此电脑”图标,然后选择”属性”。

    2. 进入高级系统设置:在系统窗口中,点击左侧的”高级系统设置”链接。

    3. 打开环境变量:在”高级”选项卡下,点击”环境变量”按钮。

    4. 编辑用户变量或系统变量:在弹出的窗口中,你将看到两个部分:用户变量和系统变量。要配置Python环境变量,我们通常选择”系统变量”部分。

    5. 查找Path变量:在系统变量部分,滚动查找名为”Path”的变量,然后点击”编辑”按钮。

    6. 添加Python路径:在编辑环境变量窗口中,点击”新建”按钮。然后在弹出的对话框中,输入变量值为Python的安装路径,例如:”C:\Users\<你的用户名>\AppData\Local\Programs\Python\PythonX.Y”。确保路径是准确的,并且没有拼写错误。

    7. 保存配置:点击”确定”按钮以保存配置。然后在环境变量窗口中点击”确定”按钮。

    步骤四:验证配置是否成功

    为了验证Python环境变量是否已经成功配置,你可以在命令行中执行以下命令:

    python --version

    如果成功配置,你将看到Python的版本信息,表示Python环境变量已经生效。

    结尾

    现在,你已经成功配置了Python环境变量,可以轻松地在Windows操作系统上进行Python开发。这将为你提供更好的控制和便捷性,让你的Python开发之旅更加愉快。

    无论你是初学者还是有经验的Python开发者,配置Python环境变量是一个基本而重要的任务。它为你提供了更好的开发体验,让你能够更轻松地编写、运行和测试Python代码。

  • 在Linux和Ubuntu上安装Python和Tkinter教程

    在Linux和Ubuntu上安装Python和Tkinter教程

    你是否曾经想过在你的Linux或Ubuntu系统上安装Python和Tkinter,以便开始编写GUI应用程序?或许你正在探索开发的世界,想要学习如何在这些操作系统上配置Python环境,那么你来对地方了。

    在这篇教程中,我们将带你步骤-by-步骤完成Python和Tkinter的安装过程。无论你是一位编程新手还是有经验的开发者,这个教程都会帮助你顺利完成安装,为你的下一个GUI项目做好准备。


    安装Python

    步骤1:打开终端

    首先,打开你的Linux或Ubuntu系统的终端。你可以在搜索栏中输入“终端”来找到它。

    步骤2:检查Python版本

    在终端中,输入以下命令来检查是否已经安装了Python以及它的版本:

    python3 --version

    如果你看到了Python的版本信息,那就表示Python已经安装在你的系统上了。如果没有,那就继续下一步。

    步骤3:安装Python

    如果你的系统没有安装Python或者你需要安装一个特定版本的Python,你可以使用包管理器来安装它。以下是一些常见的包管理器和相应的命令:

    • 对于Debian/Ubuntu系统,使用apt:
    sudo apt install python3
    • 对于CentOS/Fedora系统,使用dnf:
    sudo dnf install python3

    步骤4:验证安装

    安装完成后,再次运行以下命令来验证Python的版本:

    python3 --version

    你应该能够看到新安装的Python版本号。


    安装Tkinter

    步骤1:安装Tkinter

    Tkinter是Python的标准GUI库,通常与Python一起安装。你可以通过以下命令来安装Tkinter:

    sudo apt install python3-tk    # 对于Debian/Ubuntu系统
    sudo dnf install python3-tkinter    # 对于CentOS/Fedora系统

    步骤2:验证安装

    安装完成后,你可以创建一个简单的Tkinter窗口来验证它是否正常工作。创建一个名为hello_tkinter.py的Python脚本,内容如下:

    import tkinter as tk
    
    root = tk.Tk()
    label = tk.Label(root, text="Hello, Tkinter!")
    label.pack()
    
    root.mainloop()

    运行脚本:

    python3 hello_tkinter.py

    如果你看到一个弹出的窗口显示了“Hello, Tkinter!”,那么Tkinter已经成功安装并工作了。


    总结

    在这篇教程中,我们详细介绍了如何在Linux和Ubuntu系统上安装Python和Tkinter。现在,你已经准备好开始开发GUI应用程序了。无论你是想要创建一个简单的界面还是一个复杂的应用,Python和Tkinter将成为你的得力助手。

    希望这篇教程对你有所帮助。如果你有任何问题或需要进一步的帮助,请随时在下方留言,我们将竭诚为你解答。

  • 如何使用Python中的pip和pip3管理软件包

    如何使用Python中的pip和pip3管理软件包

    如何使用Python中的pip和pip3管理软件包 如何使用Python中的pip和pip3管理软件包

    故事开始于一个寒冷的冬天,王大神坐在电脑前,努力寻找一种简单而强大的方法来管理他的Python软件包。他正在思考如何更有效地安装、更新和删除Python库,以便更好地开发他的项目。正当他苦恼时,他听说了一个神奇的工具,那就是pip和pip3。这两个工具可以帮助他轻松地完成这些任务,而不必陷入混乱和繁琐的过程中。本文将向你介绍如何使用pip和pip3,以及它们在Python生态系统中的重要性。

    什么是pip和pip3?

    在深入了解如何使用pip和pip3之前,让我们首先了解它们是什么。

    • pip是Python的包管理器,它用于安装、升级和卸载Python库。它可以轻松地将第三方库引入你的Python项目中。
    • pip3是Python 3.x的包管理器,与pip功能相似,但专门用于Python 3.x版本。

    这两个工具的主要功能是管理Python软件包,使你能够轻松地管理你的项目依赖关系。

    安装pip和pip3

    如果你还没有安装pip和pip3,你需要先安装它们。以下是安装的步骤:

    安装pip

    1. 打开终端或命令提示符。

    2. 输入以下命令来安装pip:

      python -m ensurepip --default-pip
    3. 等待安装完成后,你可以验证pip是否成功安装,输入以下命令:

      pip --version

      这将显示pip的版本信息。

    安装pip3

    1. 打开终端或命令提示符。

    2. 输入以下命令来安装pip3:

      python3 -m ensurepip --default-pip
    3. 等待安装完成后,你可以验证pip3是否成功安装,输入以下命令:

      pip3 --version

      这将显示pip3的版本信息。

    使用pip和pip3

    一旦你成功安装了pip和pip3,你就可以开始使用它们来管理Python软件包了。以下是一些常用的命令:

    • 安装包:

      pip install 包名

      例如,要安装名为requests的包,你可以运行:

      pip install requests
    • 升级包:

      pip install --upgrade 包名

      例如,要升级requests包,你可以运行:

      pip install --upgrade requests
    • 卸载包:

      pip uninstall 包名

      例如,要卸载requests包,你可以运行:

      pip uninstall requests

    总结

    在本文中,我们介绍了pip和pip3,它们是Python生态系统中的重要工具,用于管理Python软件包。我们学习了如何安装这两个工具以及如何使用它们来安装、升级和卸载Python库。现在,你可以更轻松地管理你的Python项目依赖关系,提高开发效率。

  • 解决pip install报错的问题:一步步教你修复Python包安装错误

    解决pip install报错的问题:一步步教你修复Python包安装错误

    在Python编程的过程中,使用pip来安装第三方包是家常便饭。然而,有时候你可能会遇到各种各样的错误,让你无法成功安装所需的包。在这篇文章中,我们将一步步解决pip install报错的问题,确保你能够顺利安装Python包。

    开篇故事:挑战与成长的编程之路

    作为一名编程爱好者或专业开发者,你可能经历过不少挑战和成长。编写代码是一项充满乐趣和挑战的工作,但有时候,安装必要的包可能成为一道难以逾越的坎。在这篇文章中,我们将一起探讨如何解决pip install报错的问题,让你的编程之路更加顺畅。

    步骤一:检查Python版本

    在开始解决pip install报错之前,首先要确保你的Python版本是最新的。你可以通过运行以下命令来检查Python版本:

    python --version

    如果你的Python版本不是最新的,建议升级到最新的稳定版本,以确保兼容性和稳定性。

    步骤二:检查pip版本

    与Python一样,pip也需要保持最新。你可以使用以下命令来检查pip版本:

    pip --version

    如果pip版本不是最新的,可以使用以下命令来升级pip:

    pip install --upgrade pip

    步骤三:检查网络连接

    有时候pip install报错是由于网络连接问题引起的。确保你的计算机能够正常访问互联网,检查是否有防火墙或代理服务器阻止了pip的访问。

    步骤四:使用清华大学镜像源

    清华大学提供了一个稳定的Python镜像源,可以加速包的下载过程。你可以使用以下命令来更改pip的镜像源:

    pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

    这将把pip的默认镜像源更改为清华大学的源,提高包的下载速度并减少错误发生的可能性。

    步骤五:检查包名拼写

    有时候pip install报错是由于包名拼写错误引起的。确保你输入的包名是正确的,大小写也要匹配。

    步骤六:查看错误信息

    如果你仍然遇到pip install报错,不要着急。查看错误信息是解决问题的关键。错误信息通常会提供有关问题的线索,例如缺少依赖项或权限问题。根据错误信息,你可以更有针对性地解决问题。

    步骤七:尝试使用虚拟环境

    有时候包的安装问题可能与系统环境有关。尝试在虚拟环境中安装包,以隔离系统环境可能引起的冲突。

    结语

    在编程的道路上,解决pip install报错是一项常见的任务。通过按照以上步骤逐一排查问题,你将能够更轻松地安装所需的Python包,使你的编程工作更加高效和愉快。

    无论你是一名编程新手还是经验丰富的开发者,都要记住,挑战和问题是成长的机会。愿你在编程之路上不断进步,克服各种难题。