Tag: Python

  • Python 3.12发布:哪个改动最有吸引力?

    Python 3.12发布:哪个改动最有吸引力?

    Python,这门被誉为“蟒蛇”的编程语言,在不断演进中迎来了全新的版本——Python 3.12。对于众多Python开发者和爱好者而言,每一次版本更新都像是一场期待已久的盛宴。而今天,我们将带您一探Python 3.12的新变化,看看哪些改动最有吸引力。

    Python 3.12的主要改动

    Python 3.12带来了一系列令人期待的改动,让我们逐一了解:

    1. f-string更复杂的解析:新版本的Python增强了f-string的功能,使其支持更复杂的解析。虽然这一改动或许对某些开发者来说并没有太大用处,但它为字符串格式化提供了更多的灵活性。

    2. Per-Interpreter GIL:在Python的多线程编程中,全局解释器锁(Global Interpreter Lock,简称GIL)一直是个热门话题。Python 3.12引入了Per-Interpreter GIL,但需要注意的是,这个改动仅限于C-API。所以,如果您是Python的裸写(不依赖C扩展的纯Python代码)爱好者,GIL仍然存在。预计在Python 3.13版本中将会引入可选的No-GIL Python解释器。

    3. 新的类型标注支持:对于类型提示(type hints)的泛型部分,Python 3.12进行了一些补充。虽然还有一些进步空间,但这个改动对于静态类型检查和代码可读性有着积极的影响。

    4. distutils包弃用:对于一些开发者来说,这可能是一个比较大的改动。Python 3.12将distutils包标记为弃用,这可能会对使用它的项目产生一些影响。这个改动表明Python生态系统正在逐渐淘汰旧的工具和库,以推动更现代化的开发方式。

    5. 各模块的优化改进:Python 3.12还带来了各种模块的优化改进,包括os和asyncio等。这些改进有望提高Python的性能和稳定性。

    哪个改动最有吸引力?

    在众多改动中,有哪个最有吸引力呢?从社区的反应来看,人们对Python 3.12的改动持不同意见。有人认为f-string的增强功能很有用,尤其是支持单引号套单引号,这使得字符串格式化更加灵活。同时,新的类型标注支持也受到一些开发者的欢迎,因为它有助于提高代码的可读性。

    然而,也有人对Python的版本更新持保守态度。有开发者表示,他们仍然在使用Python 3.9,而没有感到有必要升级到新版本。对于一些项目来说,稳定性和兼容性可能更重要。

    最后,有人提到了一个看似小改动却颇具吸引力的特性——模块中新增的itertools.batched(iterable, n)函数。对于这些开发者来说,这可能是Python 3.12中最大的改动,因为它为他们的工作带来了便利。

    总之,Python 3.12的改动各有千秋,最有吸引力的改动因人而异。无论您是追求新特性的激进派还是更注重稳定性的保守派,Python的发展始终在为您提供更好的编程体验而不断努力。

    在这个数字化时代,Python仍然是编程世界的明星,我们期待着未来更多令人兴奋的版本更新,以及Python生态系统的持续繁荣。

  • 声音魔法:VITS音频转换框架揭秘

    声音魔法:VITS音频转换框架揭秘

    在一个安静的夜晚,我坐在电脑前,思考着如何将我的声音转化成我的最爱的音乐人的声音。这似乎是一个不可能的任务,但却充满了神秘感。突然,我发现了一个名为Retrieval-based-Voice-Conversion-WebUI的项目,它基于VITS(Voice Inference from Text and Speech)框架,提供了一个轻松易用的声音转换工具。于是,我踏上了声音魔法之旅,今天我将与大家分享这一奇妙的经历。

    声音转换的魅力

    在开始揭秘Retrieval-based-Voice-Conversion-WebUI之前,让我们先来聊聊声音转换的魅力。声音是一种神奇的媒介,可以传达情感、表达个性,甚至改变现实。你是否曾经梦想过能够像你喜爱的歌手一样唱歌?或者是在特定场合中,用某位名人的声音发表演讲?声音转换技术为这些梦想提供了可能性。

    但是,要将声音从一种变成另一种,这绝非易事。声音转换涉及复杂的信号处理、深度学习模型和大量的数据。幸运的是,现在有了一些强大的工具和框架,它们使声音转换变得更加容易和有趣。

    Retrieva-based-Voice-Conversion-WebUI简介

    Retrieval-based-Voice-Conversion-WebUI是一个基于VITS框架的声音转换工具,它可以将一种声音转换为另一种声音,同时保留语音的自然感觉。这个项目的目标是让声音转换变得容易,并且可以在普通电脑上进行,无需高端硬件。

    以下是这个项目的一些关键特点:

    • 通过使用top1检索将源特征替换为训练集特征,减少音调泄漏。
    • 即使在相对较差的显卡上,也可以进行轻松快速的训练。
    • 即使使用少量数据进行训练,也可以获得相对好的结果(建议使用不少于10分钟的低噪音语音)。
    • 支持模型融合以改变音色。
    • 提供易于使用的WebUI界面。
    • 使用UVR5模型快速分离声音和乐器。
    • 使用最强大的高音提取算法InterSpeech2023-RMVPE来防止消音问题,提供了显著更好的结果,速度更快,资源消耗更低。

    现在,让我们一起来探索如何使用Retrieval-based-Voice-Conversion-WebUI进行声音转换。

    准备环境

    首先,确保你的Python版本是3.8或更高。然后,执行以下命令以安装主要依赖项:

    # 安装PyTorch相关核心依赖项,如果已安装,请跳过
    pip install torch torchvision torchaudio

    接下来,可以使用Poetry来安装其他依赖项:

    # 安装Poetry依赖管理工具,如果已安装,请跳过
    curl -sSL https://install.python-poetry.org | python3 -
    
    # 安装项目依赖项
    poetry install

    或者,你也可以使用pip来安装它们:

    # 对于Nvidia显卡
    pip install -r requirements.txt
    
    # 对于Windows上的AMD/Intel显卡(DirectML):
    pip install -r requirements-dml.txt
    
    # 对于Linux / WSL上的Intel ARC显卡,使用Python 3.10:
    pip install -r requirements-ipex.txt
    
    # 对于Linux上的AMD显卡(ROCm):
    pip install -r requirements-amd.txt

    接下来,你需要下载其他预模型文件,可以在项目的Huggingface空间中找到它们。这些文件包括了用于推断和训练的预模型文件。确保将它们放在正确的目录下。

    开始声音转换

    一旦你的环境准备好了,你可以使用以下命令启动WebUI:

    python infer-web.py

    如果你使用的是Windows或macOS,你可以直接下载并解压RVC-beta.7z文件,然后使用go-web.bat(Windows)或sh ./run.sh(macOS)来启动WebUI。

    结束语

    声音转换是一门神奇的艺术,它使我们能够在声音的世界中自由穿越。Retrieval-based-Voice-Conversion-WebUI为我们提供了一个便捷的工具,让我们能够将声音转换成我们想要的样子。无论是在娱乐还是工作中,这个项目都有着巨大的潜力。探索声音的可能性,释放声音的魔法吧!

  • 编程的奇妙之旅:Python多线程爬虫下载PDF教材

    编程的奇妙之旅:Python多线程爬虫下载PDF教材

    有一天,当我坐在电脑前,思考着编程的奇妙之处时,一种冒险的感觉涌上心头。我想,为什么不用编程来探索互联网的深处,下载一些有趣的教材呢?于是,我开始了这次奇妙的编程之旅,带着好奇心和激情,我将向你展示如何使用Python编写一个多线程爬虫,用于下载各种教材的PDF文件。

    准备工作

    在我们踏上这次冒险之前,我们需要做一些准备工作。

    初始化日志

    首先,我们需要设置日志记录,以便随时跟踪我们的编程冒险。

    import logging
    
    def init_logging():
        logging_format = '%(asctime)s\t[%(levelname)s]\t[%(name)s]\t[%(threadName)s]\t%(message)s'
        logging.basicConfig(format=logging_format, level=logging.INFO)

    导入必要的库

    为了让我们的编程冒险变得更加容易,我们需要使用requests库来进行网络请求和数据下载。如果你还没有安装这个库,请使用以下命令来安装它:

    pip install requests

    设置下载目录和线程数量

    这两个变量将在后面的代码中使用,你可以根据需要进行调整。

    download_base_dir = 'd:/book3'  # 设置下载文件保存的文件夹
    thread_count = 8  # 设置线程数量

    开始编写爬虫

    请求数据版本

    首先,我们需要获取教材数据的版本信息,这将有助于我们确定要下载的文件。

    def request_data_version() -> [str]:
        # 目标URL
        data_url = "https://s-file-1.ykt.cbern.com.cn/zxx/ndrs/resources/tch_material/version/data_version.json"
        try:
            logging.info("开始请求URL: %s", data_url)
            response = requests.get(data_url)
            logging.info("状态码 %s, 响应内容: %s", response.status_code, response.text)
            if response.status_code == 200:
                data = response.json()
                return data["urls"].split(",")
            else:
                logging.warning("无法获得正确的响应,程序退出 -1。")
                sys.exit(-1)
        except requests.exceptions.RequestException as e:
            logging.exception("请求数据版本失败", e)

    请求单个数据URL

    接下来,我们将请求每个教材的数据URL,并解析教材信息。

    def request_single_data_url(data_url: str) -> [dict]:
        try:
            logging.info("开始请求URL: %s", data_url)
            response = requests.get(data_url)
            logging.info("状态码 %s", response.status_code)
            if response.status_code == 200:
                data = response.json()
                books = []
                for d in data:
                    book_data = parse_book_data(d)
                    if len(book_data) != 0:
                        books.append(book_data)
                    else:
                        logging.warning("跳过此教材: %s", d['title'])
                return books
        except requests.exceptions.RequestException as e:
            logging.exception("请求单个数据URL失败", e)

    解析教材数据

    我们将解析每本教材的数据,包括教材名称和标签。

    def parse_book_data(data: dict) -> dict:
        book_id = data['id']
        book_name = data['title']
        book_tags = data['tag_list']
        book_tags = sorted(book_tags, key=custom_sort_tag_list, reverse=True)
        if '版' not in (book_tags[0]['tag_name']):
            return {}
        return {"id": book_id, "name": book_name, "dirs": get_dirs_from_tags(book_tags)}

    获取目录信息

    我们将从标签中提取目录信息,以便稍后创建文件夹。

    def get_dirs_from_tags(book_tags) -> str:
        return f"{book_tags[0]['tag_name']}/{book_tags[1]['tag_name']}/{book_tags[2]['tag_name']}"

    自定义标签排序

    为了确保我们获取的是正确的教材版本,我们需要自定义排序标签。

    def custom_sort_tag_list(tag):
        tag_name = tag['tag_name']
        school_level, edition, grade, semester, course_name = '', '', '', '', ''
        if "版" in tag_name:
            edition = tag_name
        elif "年级" in tag_name:
            grade = tag_name
        elif "册" in tag_name:
            semester = tag_name
        elif '小学' in tag_name or '初中' in tag_name or '高中' in tag_name:
            school_level = tag_name
        elif '教材' not in tag_name:
            course_name = tag_name
    
        return edition, school_level, grade, course_name, semester

    下载教材

    最后,我们将下载每本教材的PDF文件。

    def download_book(book):
        file_dir = f"{download_base_dir}/{book['dirs']}"
        file_name = f"{book['name']}.pdf"
        file_full_path = os.path.join(file_dir, file_name)
        logging.info("开始下载教材: %s/%s", file_dir, file_name)
        try:
            if not os.path.exists(file_dir):
                os.makedirs(file_dir)
        except FileExistsError:
            logging.warning("文件夹 %s 已经存在", file_dir)
    
        download_url = f"https://r1-ndr.ykt.cbern.com.cn/edu_product/esp/assets_document/{book['id']}.pkg/pdf.pdf"
        response = requests.get(download_url)
        if response.status_code == 200:
            with open(os.path.join(file_dir, file_name), "wb") as file:
                file.write(response.content)
                logging.info("教材下载成功: %s", file_full_path)
        else:
            logging.warning("教材下载失败,状态码: %s", response.status_code)

    多线程下载

    我们将使用多线程来提高下载速度。

    def multi_thread_download
    
    _books(shared_queue: queue.Queue):
        try:
            while True:
                item = shared_queue.get_nowait()
                download_book(item)
                shared_queue.task_done()
        except queue.Empty:
            logging.warning("队列为空")

    请求所有教材

    最后,我们将请求所有教材的信息并将其添加到共享队列中。

    def request_all_books_to_shared_queue():
        shared_queue = queue.Queue(maxsize=3000)
        urls = request_data_version()
        for url in urls:
            books = request_single_data_url(url)
            for book in books:
                shared_queue.put(book)
        return shared_queue

    执行下载

    现在,我们已准备好执行下载任务。

    if __name__ == '__main__':
        init_logging()
    
        # 下载文件保存的文件夹
        download_base_dir = 'd:/book3'
        # 线程数量
        thread_count = 8
    
        all_books_queue = request_all_books_to_shared_queue()
        with concurrent.futures.ThreadPoolExecutor(max_workers=thread_count) as executor:
            futures = [executor.submit(multi_thread_download_books, all_books_queue) for i in range(thread_count)]
            concurrent.futures.wait(futures)
    
        logging.info("完成下载!!!")

    结束语

    通过这个教程,你已经学会了如何使用Python编写一个多线程爬虫,用于下载各种教材的PDF文件。这个项目不仅展示了编程的实际应用,还提供了深入探索网络资源的机会。希望你能充分利用这些技能,探索更多有趣的项目和挑战!

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

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

    你是否曾经想知道一个文本字符串包含多少个标记?标记在GPT模型中是很重要的,因为它们决定了文本的长度和模型处理的成本。本教程将向你介绍如何使用OpenAI的开源工具tiktoken来轻松计算文本中的标记数。

    引子

    在开始之前,让我们来谈谈为什么需要计算标记数。标记是文本的最小单位,可以是一个字符,也可以是一个单词。GPT模型处理文本时以标记为基本单位,因此知道一个文本字符串包含多少标记对于以下两个方面非常重要:

    1. 文本长度限制:有时,你可能需要将文本输入到一个模型中,但模型对文本长度有限制。如果你的文本超过了模型的最大标记数限制,你需要截断或缩短它,以确保模型可以正确处理。

    2. 计算成本:使用OpenAI的API调用GPT模型是需要付费的,而费用是按照标记数计算的。因此,了解文本中有多少标记可以帮助你估算API调用的成本。

    使用不同的编码

    在使用tiktoken之前,你需要了解文本是如何被转换成标记的。不同的模型使用不同的编码方式。tiktoken支持三种OpenAI模型使用的编码:

    • cl100k_base:用于gpt-4、gpt-3.5-turbo、text-embedding-ada-002等模型。
    • p50k_base:用于Codex模型、text-davinci-002、text-davinci-003等模型。
    • r50k_base(或称为gpt2):用于GPT-3模型,如davinci。

    你可以使用以下方式获取特定模型的编码:

    import tiktoken
    
    # 获取gpt-3.5-turbo模型的编码
    encoding = tiktoken.encoding_for_model('gpt-3.5-turbo')

    请注意,p50k_base与r50k_base在非代码应用中有很大的重叠,在这种情况下,它们通常会产生相同的标记。

    使用tiktoken计算标记数

    现在,让我们看看如何使用tiktoken计算文本中的标记数。首先,你需要安装tiktoken库:

    pip install --upgrade tiktoken

    安装完成后,你可以按照以下方式计算标记数:

    import tiktoken
    
    def num_tokens_from_string(string: str, encoding_name: str) -> int:
        """返回文本字符串中的标记数。"""
        encoding = tiktoken.get_encoding(encoding_name)
        num_tokens = len(encoding.encode(string))
        return num_tokens
    
    # 示例:计算标记数
    text = "tiktoken is great!"
    encoding_name = "cl100k_base"
    num_tokens = num_tokens_from_string(text, encoding_name)
    print(f"文本中的标记数:{num_tokens}")

    上述代码将输出文本中的标记数。在这个示例中,文本 “tiktoken is great!” 有6个标记。

    将标记转换为文本

    如果你想将标记转换回文本,你可以使用以下方法:

    import tiktoken
    
    def tokens_to_text(tokens, encoding_name: str) -> str:
        """将标记列表转换为文本字符串。"""
        encoding = tiktoken.get_encoding(encoding_name)
        text = encoding.decode(tokens)
        return text
    
    # 示例:将标记转换为文本
    tokens = [83, 1609, 5963, 374, 2294, 0]
    encoding_name = "cl100k_base"
    text = tokens_to_text(tokens, encoding_name)
    print(f"标记转换为文本:{text}")

    在上面的示例中,标记列表 [83, 1609, 5963, 374, 2294, 0] 被转换回了文本 “tiktoken is great!”。

    比较不同的编码

    不同的编码方式可能在如何分割单词、处理空格以及处理非英文字符方面有所不同。使用上述方法,我们可以比较不同编码在几个示例文本上的表现:

    import tiktoken
    
    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")
    compare_encodings("2 + 2 = 4")
    compare_encodings("お誕生日おめでとう")

    通过上述代码,你可以比较不同编码在示例文本上的表现。这将有助于你选择最适合你的应用程序的编码方式。

    在聊天完成API调用中计算标记数

    对于ChatGPT模型,如gpt-3.5-turbo和gpt-4,它们使用的标记方式与旧的完成模型相同,但由于它们的消息格式,更难计算会话中将使用多少标记。

    以下是一个用于计算传递给gpt-3.5-turbo或gpt-

    4的消息中标记数的示例Python代码:

    import tiktoken
    
    def num_tokens_in_chat(messages: list, encoding_name: str) -> int:
        """计算聊天消息中的标记数。"""
        encoding = tiktoken.get_encoding(encoding_name)
        total_tokens = 0
        for message in messages:
            role = message["role"]
            content = message["content"]
            if role == "system":
                # 系统消息不包含标记
                continue
            elif role == "user" or role == "assistant":
                # 用户和助手消息包含标记
                tokens = encoding.encode(content)
                total_tokens += len(tokens)
        return total_tokens
    
    # 示例:计算聊天消息中的标记数
    chat_messages = [
        {"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"},
    ]
    encoding_name = "cl100k_base"
    num_tokens = num_tokens_in_chat(chat_messages, encoding_name)
    print(f"聊天消息中的标记数:{num_tokens}")

    在上面的示例中,我们计算了一个包含用户和助手消息的聊天中的标记数。你可以根据自己的聊天数据和所选的编码来计算标记数。

    这就是如何使用tiktoken计算文本中的标记数,无论是用于一般文本处理还是用于聊天API调用,这个工具都可以帮助你更好地管理标记。希望这个教程对你有所帮助!如果你有任何问题或需要进一步的协助,请随时提问。

  • ChatGPT技术揭秘:为什么它能如此强大

    ChatGPT技术揭秘:为什么它能如此强大

    曾几何时,我们沉浸在科幻小说和电影中,对于人工智能的无限想象中。如今,这些幻想正逐渐变为现实,而ChatGPT则是其中一个令人惊叹的成果。本文将深入探讨ChatGPT的技术内幕,揭示其为何如此强大,以及它是如何利用现有技术的潜力来实现这一壮举的。

    一、Transformer框架:变形金刚的崭露头角

    ChatGPT采用了Transformer框架,这一框架被誉为“变形金刚”,因为它具备处理空间信息和时序信息的能力。相对于传统的CNN和RNN模型,Transformer可以同时处理空间信息和时序信息,这使得它在自然语言处理任务中表现出色。Transformer的自注意力机制和多头注意力机制更进一步增强了模型捕捉文本中的前后依赖关系,使其在处理长序列信息时领先于传统的RNN模型。

    二、预训练和微调:提高泛化能力

    ChatGPT的成功离不开预训练技术。它首先使用大量无标签数据对模型进行初步训练,这有助于模型更好地理解和处理自然语言。然后,通过微调技术,在特定任务上进行有监督的训练,进一步提高了模型性能。这种方法不仅节省了训练时间和计算资源,还大幅提高了ChatGPT的泛化能力,使其能够在各种自然语言处理任务中表现出色。

    三、跨语言迁移学习:扩展应用场景

    ChatGPT还引入了跨语言迁移学习,这一技术使得模型在不同语言之间能够迁移知识。例如,通过在英文模型基础上进行中文语言的预训练,ChatGPT可以在中文自然语言处理任务中表现出色。这一技术扩展了ChatGPT的应用领域,使其能够处理多种语言。

    四、分布式机器学习框架Ray:强大的支持

    ChatGPT的训练需要大量的计算资源,参数量庞大,因此如何提高并行计算能力成为了研究重点。Ray是一个分布式机器学习框架,它能够将不同硬件作为一个单元来管理,协调训练过程,并解决硬件冲突问题。这使得ChatGPT的训练变得更加高效,可以在不同硬件上运行,包括谷歌云、AWS等。另外,Google的JAX框架也备受关注,被视为与Ray竞争的框架。

    五、分布式技术:提升训练速度和效率

    在深度学习中,分布式技术发挥了重要作用。以下是一些常见的分布式技术概念:

    • 数据并行:将输入数据分成多个小批次,分配到不同GPU内存进行处理,提高训练速度和效率。

    • 模型并行:将模型分解成多个子模型,分配到不同GPU芯片上进行处理,提高模型的处理能力。

    • 模型平行:将模型分解成多个层,分配到不同GPU芯片上进行处理,帮助模型处理更大的数据集。

    • 集群并行:将模型分布式部署在多个计算机上,连接不同计算机与GPU,处理更大规模的数据集。

    • 整合:使用以上多种技术的组合,以达到更高的训练速度和处理效率。

    六、强化学习中的算法和框架

    最后,让我们思考一下不同的算法和框架在强化学习中的应用。强化学习是一门涉及决策和行动的领域,各种算法和框架在此领域都有广泛的应用。例如,TensorFlow、PyTorch等深度学习框架与强化学习库结合使用,用于训练智能体。此外,Ray框架也与强化学习库兼容,为分布式强化学习提供了强大支持。

    结语

    ChatGPT之所以如此强大,不仅在于其采用了Transformer框架、预训练和微调技术,还在于分布式机器学习框架Ray的支持以及分布式技术的应用。这一组合使得ChatGPT能够在各种自然语言处理任务中表现出色,同时为强化学习等领域提供了有力的工具。

    希望本文能够帮助你更好地理解ChatGPT的技术内幕,并对人工智能和深度学习的未来充满期待。

  • 如何使用Python自动发送批量邮件

    如何使用Python自动发送批量邮件

    在现代社交网络和电子通信的时代,电子邮件仍然是一种重要的沟通工具。无论是向客户发送营销邮件,还是向团队成员发送通知,自动化发送批量邮件是提高效率的关键。在本教程中,我们将学习如何使用Python编写一个自动发送批量邮件的脚本。

    背景故事

    假设你是一名市场营销专家,你需要向数百位潜在客户发送个性化的邮件,以推广你的产品或服务。手动一个一个发送邮件将是一项繁琐且耗时的任务。但是,有了Python的帮助,你可以轻松地自动化这个过程,将你的邮件发送到每个收件人。

    准备工作

    在我们开始之前,让我们先进行一些准备工作:

    1. SMTP邮箱设置:你需要一个支持SMTP(Simple Mail Transfer Protocol)的邮箱,例如Gmail或QQ邮箱。确保开启SMTP服务,并获取SMTP服务器地址和端口号以及你的发件人邮箱和密码。

    2. CSV收件人列表:将你要发送邮件的收件人列表保存为CSV文件,每行一个邮箱地址。这个列表可以包含数百个收件人。

    使用Python编写自动发送邮件脚本

    我们将使用Python编写一个脚本,它将完成以下任务:

    1. 连接SMTP服务器:与SMTP服务器建立连接,使用TLS协议进行安全连接。

    2. 登录邮箱:使用你的发件人邮箱和密码登录SMTP服务器。

    3. 构造邮件内容:创建一封包含主题、正文、图片和附件的邮件。

    4. 发送邮件:将邮件发送给收件人。

    以下是Python代码的主要部分:

    import smtplib
    import csv
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    from email.mime.image import MIMEImage
    
    def send_email(sender_email, sender_password, receiver_email):
        # 与SMTP服务器建立连接
        smtp_server = 'smtp.qq.com'
        server_port = 587
        server = smtplib.SMTP(smtp_server, server_port)
        server.starttls()
    
        try:
            # 登录邮箱账号
            server.login(sender_email, sender_password)
    
            # 构造邮件内容
            msg_root = MIMEMultipart('related')
            msg_root['Subject'] = '测试一下'
            msg_root['From'] = sender_email
            msg_root['To'] = receiver_email
    
            subject = '测试一下111111'
            message = '''
            <html>
              <body>
                <p><img src="cid:image1" alt="升学教育图片" style="width:300px;height:200px;"></p>
                <p>班上新来一位学生,名字叫“马騳骉”。</p>
                <p>开学点名了,班主任不知怎么念,就说 : 马叉叉到了没?</p>
                <p>语文老师有点文学素养,点名道:万马奔腾到了没?</p>
              </body>
            </html>
            '''
    
            # 添加文本内容
            html_part = MIMEText(message, 'html')
            msg_root.attach(html_part)
    
            # 添加图片附件
            with open('path/to/your/image.jpg', 'rb') as image_file:
                image_part = MIMEImage(image_file.read())
                image_part.add_header('Content-Disposition', 'attachment; filename=image.jpg')
                image_part.add_header('Content-ID', '<image1>')
                msg_root.attach(image_part)
    
            # 添加附件
            with open('path/to/your/attachment.pdf', 'rb') as file:
                attachment_part = MIMEApplication(file.read(), Name='attachment.pdf')
                attachment_part.add_header('Content-Disposition', 'attachment; filename=attachment.pdf')
                msg_root.attach(attachment_part)
    
            # 发送邮件
            server.sendmail(sender_email, receiver_email, msg_root.as_string())
            print(f"邮件发送成功: {receiver_email}")
        except smtplib.SMTPException as e:
            print(f"邮件发送失败: {receiver_email},错误信息: {str(e)}")
    
        # 关闭连接
        server.quit()
    
    # 创建收件人邮箱列表
    receiver_emails = []
    
    # 读取CSV文件并获取收件人邮箱列表
    with open('path/to/your/email.csv', 'r') as file:
        reader = csv.reader(file)
        for row in reader:
            receiver_emails.append(row[0])
    
    # 循环发送邮件给收件人列表中的每个邮箱
    for receiver_email in receiver_emails:
        send_email(sender_email, sender_password, receiver_email)

    批量发送邮件

    要批量发送邮件,我们将创建一个函数 send_emails,它将循环遍历收件人列表,并在每个邮箱上启动一个线程以异步发送邮件。这可以大大提高邮件发送速度。

    以下是如何批量发送邮件的代码:

    import threading
    
    def send_emails(sender_email, sender_password, thread_count):
        # 创建线程列表
        threads = []
    
        # 创建发送邮件的函数
        def send_email_thread(receiver_email):
            send_email(sender_email, sender_password, receiver_email)
    
        # 创建并启动发送邮件的线程
        for receiver_email in receiver_emails:
            t = threading.Thread(target=send_email_thread, args=(receiver_email,))
            threads.append(t)
            t.start()
    
            # 控制最大线程数
            if len(threads) >= thread_count:
                for thread in threads:
                    thread.join()
                threads = []
    
        # 等待剩余线程完成
        for thread in threads:
            thread.join()
    
    # 调用批量发送邮件函数
    send_emails(sender_email, sender_password, thread_count)

    结论

    通过使用Python编写自动发送批量邮件的脚本,我们可以轻松地将邮件发送给大量收件人,提高工作效率。无论是市场营销还是通知,这个自动化方法都可以帮助你节省时间和精力。

    希望这篇教程对你有所帮助!如果你有任何问题或需要进一步的指导,请随时联系我们。

  • 如何自动加密和删除文件夹中的文件

    如何自动加密和删除文件夹中的文件

    你是否曾经担心过将重要文件存储在电脑上,担心它们可能被他人访问或丢失?在本教程中,我们将介绍如何使用Python编写一个自动化脚本,将文件夹中的文件压缩、加密,并安全地删除原始文件,以保护你的数据。让我们一起来看看如何做到这一点!

    背景故事

    假设你有一个包含敏感文件的文件夹,你希望将这些文件压缩并加密,以确保它们不会被未经授权的人访问。同时,你也想要删除原始文件,以释放磁盘空间并减少风险。这个任务可能会变得非常繁琐,但幸运的是,我们可以使用Python来自动化这个过程。

    准备工作

    在我们深入讨论代码之前,让我们先了解一些准备工作。首先,我们需要确保你的计算机上安装了WinRAR软件,因为我们将使用它来进行文件的压缩和加密。另外,你需要提供一个密码,用于加密压缩文件。

    使用Python编写自动化脚本

    我们将使用Python编写一个自动化脚本,执行以下操作:

    1. 压缩文件夹:我们将使用WinRAR来压缩文件夹中的文件,创建一个加密的压缩文件。

    2. 加密压缩文件:我们将设置密码来加密压缩文件,确保只有知道密码的人才能解压文件。

    3. 删除原始文件:一旦文件成功压缩并加密,我们将安全地删除原始文件夹中的文件,以保护数据。

    以下是Python代码的主要部分:

    import shutil
    import subprocess
    import os
    import time
    from pathlib import Path
    
    def encrypt_folder_with_winrar(folder_path, password):
        # WinRAR命令
        winrar_command = r'C:\Program Files\WinRAR\WinRAR.exe'
    
        # 获取当前日期
        current_date = time.strftime("%Y-%m-%d", time.localtime())
    
        # 获取桌面BD文件夹路径
        desktop_path = str(Path.home() / "Desktop")
        bd_folder_path = os.path.join(desktop_path, "DB")
    
        # 创建DB文件夹(如果不存在)
        if not os.path.exists(bd_folder_path):
            os.mkdir(bd_folder_path)
    
        # 压缩包文件名
        compressed_filename = f'压缩包-{current_date}.rar'
    
        # 压缩包路径
        compressed_filepath = os.path.join(bd_folder_path, compressed_filename)
    
        # 加密命令
        encryption_command = [winrar_command, 'a', '-r', '-hp' + password, compressed_filepath, folder_path]
    
        # 执行加密命令
        subprocess.run(encryption_command)
    
        return compressed_filepath
    
    def encrypt_and_delete_folder(folder_path, password):
        try:
            # 压缩并加密文件夹
            compressed_file = encrypt_folder_with_winrar(folder_path, password)
    
            # 等待一段时间,确保压缩文件完成
            time.sleep(10)
    
            # 删除源文件夹中的文件
            for root, dirs, files in os.walk(folder_path):
                for file in files:
                    os.remove(os.path.join(root, file))
    
            print("加密打包操作成功")
        except Exception as e:
            print(f"加密打包操作失败:{e}")
    
            # 出现错误时,删除已创建的压缩文件
            if os.path.exists(compressed_file):
                os.remove(compressed_file)
                print("压缩文件已删除.")
    
    # 文件夹路径
    folder_path = r'D:\BACK'
    
    # 密码
    password = '123456'
    
    # 加密并删除文件夹中的文件
    encrypt_and_delete_folder(folder_path, password)

    使用定时任务自动化操作

    如果你希望定期执行这个操作,我们可以使用Python的schedule库来安排任务。在上述代码中,我们创建了一个名为encrypt_and_delete_folder的函数,它将压缩、加密和删除文件夹中的文件。然后,我们使用schedule库来定期执行这个函数。

    以下是如何设置定时任务的代码:

    import schedule
    import time
    
    # 文件夹路径
    folder_path = r'D:\BACK'
    
    # 密码
    password = '123456'
    
    # 每天定时执行加密打包操作
    schedule.every().day.at("12:20").do(encrypt_and_delete_folder, folder_path=folder_path, password=password)
    
    # 循环执行任务,并写入日志
    while True:
        schedule.run_pending()
        time.sleep(60)

    结论

    通过使用Python编写自动化脚本和定时任务,我们成功地实现了文件夹中文件的

    压缩、加密和删除操作。这种自动化方法可以帮助你更好地保护你的敏感数据,同时也节省了你的时间和精力。

    希望这篇教程对你有所帮助,如果你有任何疑问或需要进一步的指导,请随时联系我们。保持数据安全,保持自动化!

  • 如何用克拉默法则解决罗盘谜题

    如何用克拉默法则解决罗盘谜题

    在这个教程中,我们将介绍如何使用克拉默法则解决一个有趣的罗盘谜题。这个谜题涉及三个旋转的圆盘,每个圆盘都可以按照不同的规则旋转,目标是将它们都旋转到特定的角度。我们将使用克拉默法则来解决这个谜题,找到满足条件的解。让我们开始吧!

    背景故事

    想象一下,你被困在一个神秘的房间里,房间的中心有一个奇怪的装置,上面有三个旋转的圆盘。每个圆盘都有不同的旋转规则,包括旋转方向和步长。你的任务是将这三个圆盘都旋转到角度为180度的位置,但是你不知道如何操作这些圆盘。

    幸运的是,你有一本关于克拉默法则的笔记,你决定使用这个方法来解决这个问题。你开始分析每个圆盘的旋转规则和它们之间的联动规则,然后使用克拉默法则计算出每个圆盘需要旋转的次数,最终找到了解决这个谜题的方法。

    罗盘谜题

    这个罗盘谜题涉及三个圆盘,分别是内圈、中圈和外圈。每个圆盘都有以下属性:

    • 旋转方向:可以是逆时针或顺时针。
    • 旋转步长:用亮着的星星数量表示。
    • 初始角度:以角度/60的值表示。

    除此之外,还有联动规则,规定了哪些圆盘会联动旋转,哪些不会。这些规则以列表的形式给出,其中0表示内圈,1表示中圈,2表示外圈,-1表示不联动。

    使用克拉默法则解决问题

    要解决这个罗盘谜题,我们可以使用克拉默法则,该方法通常用于解决线性方程组。我们将每个圆盘的旋转次数表示为x、y和z,然后设置以下方程:

    • 内圈旋转次数:存在(self.coordination[0], 0) x + 存在(self.coordination[1], 0) y + 存在(self.coordination[2], 0) * z = 计算(self.disk[0][“init”], self.disk[0][“direction”], self.disk[0][“rotate”])
    • 中圈旋转次数:存在(self.coordination[0], 1) x + 存在(self.coordination[1], 1) y + 存在(self.coordination[2], 1) * z = 计算(self.disk[1][“init”], self.disk[1][“direction”], self.disk[1][“rotate”])
    • 外圈旋转次数:存在(self.coordination[0], 2) x + 存在(self.coordination[1], 2) y + 存在(self.coordination[2], 2) * z = 计算(self.disk[2][“init”], self.disk[2][“direction”], self.disk[2][“rotate”])

    这些方程中的系数矩阵可以用克拉默法则来解决,我们首先计算原行列式值D。然后,我们可以通过遍历的方式,找到满足整数解和非负解的x、y和z。这将是解决罗盘谜题的答案。

    下面是用Python实现的代码和算法:

    import copy
    
    class CompassPuzzleSolver:
        def __init__(self):
            # 初始化罗盘信息...
            # 省略了与文章中相同的初始化部分
            # ...
    
        # 计算到达180度所需的次数
        @staticmethod
        def count(angle: int, direction: int, rotate: int) -> int:
            b = 0
            while True:
                if angle % 180 == 0 and angle % 360 != 0:
                    return b
                else:
                    angle = angle - direction * rotate
                    b += 1
    
        # 行列式计算
        @staticmethod
        def calculate(matrix_temp: list, replace: list = [], index: int = -1) -> int:
            matrix = copy.deepcopy(matrix_temp)
            if index != -1:
                matrix[0][index], matrix[1][index], matrix[2][index] = replace[0], replace[1], replace[2]
            return \
            matrix[0][0] * matrix[1][1] * matrix[2][2] + \
            matrix[0][1] * matrix[1][2] * matrix[2][0] + \
            matrix[0][2] * matrix[1][0] * matrix[2][1] - \
            matrix[0][2] * matrix[1][1] * matrix[2][0] - \
            matrix[0][1] * matrix[1][0] * matrix[2][2] - \
            matrix[0][0] * matrix[1][2] * matrix[2][1]
    
        # 答案计算主程序
        def solve_puzzle(self) -> bool:
            # 最终目标:三圈状态均为180
            # x, y, z 三个变量,分别对应三个联动规则所需次数
            # ...
    
            # 使用克拉默法则计算...
            # 省略了计算部分的代码
            # ...
    
            # 找到满足条件的解
            # 省略了遍历部分的代码
            # ...
    
    # 创建罗盘谜题解决器对象
    solver = CompassPuzzleSolver()
    # 解决谜题并打印答案
    if solver.solve_puzzle():
    
     print("成功找到解决罗盘谜题的方法!")
    else:
        print("未找到解决罗盘谜题的方法。")
    

    结论

    通过使用克拉默法则和Python编程,我们成功解决了这个有趣的罗盘谜题,找到了每个圆盘需要旋转的次数。这个方法可以用于解决类似的问题,其中涉及多个变量和约束条件。

    如果你也喜欢解决谜题和挑战性的问题,不妨尝试一下这个罗盘谜题,看看你能否找到更快的解决方法!

    希望这篇教程对你有所帮助,如果你对克拉默法则或其他数学方法有更多的兴趣,请继续关注我的博客,我们将继续分享有趣的数学和科学知识。

  • 如何在小红书上下载无水印的图片

    如何在小红书上下载无水印的图片

    嗨,大家好!今天我要和你分享一个有趣的技巧——如何在小红书上下载无水印的图片。你知道吗?小红书上有很多精彩的图片,但有时候我们想要保存它们却不知道该怎么办。别担心,我将向你展示一种简单的方法,让你轻松下载这些美丽的图片,而且不会留下任何水印。接下来,让我们一起来探索这个技巧吧!

    步骤 1:发起网络请求

    首先,我们需要发起网络请求,获取小红书上的网页源码。为了做到这一点,我们需要使用Python编程语言以及一些库来帮助我们完成这个任务。以下是一个简单的Python函数,用于发起网络请求:

    import requests
    
    def fetchUrl(url):
        headers = {
            'User-Agent': '你的浏览器User-Agent',
        }
        r = requests.get(url, headers=headers)
        return r.text

    这个函数允许我们向指定的URL发起请求并返回网页源码。

    步骤 2:解析网页源码

    一旦我们获得了网页源码,下一步就是解析它,以便提取无水印图片的URL。我们可以使用BeautifulSoup库来处理HTML文本。以下是解析链接的代码:

    from bs4 import BeautifulSoup
    
    def parsing_link(html):
        soup = BeautifulSoup(html, 'html.parser')
        script = soup.find('script', string=re.compile('window\.__INITIAL_STATE__'))
    
        # 处理字符串json数据不合理的地方
        # 转换成json数据
        # 获取对应字段
        # 提取图片
        # 调用生成以title为名的文件夹, 可自定义要保存的路径
        # 提取图片
        for i in imageList:
            picUrl = f"https://sns-img-qc.xhscdn.com/{i['traceId']}"
            yield picUrl, i['traceId'], title

    这段代码解析了HTML源码,提取了无水印图片的URL以及图片的标题。

    步骤 3:下载图片

    现在,我们已经获得了无水印图片的URL,下一步就是下载它们。以下是下载图片的代码:

    def download(url, filename, folder):
        headers = {
            'User-Agent': '你的浏览器User-Agent',
        }
        try:
            r = requests.get(url, headers=headers)
            # 获取图片格式
            content_type = r.headers.get('Content-Type')
            image_format = content_type.split('/')[-1]
    
            # 如果 image_format 不是图片格式的后缀,则将其更改为 jpeg
            if image_format not in ['jpeg', 'png', 'gif', 'bmp']:
                image_format = 'jpeg'
    
            # 根据检测到的格式保存文件
            with open(f'image/{folder}/{filename}.{image_format}', 'wb') as v:
                v.write(r.content)
        except Exception as e:
            print('图片下载错误!')

    这个函数将从给定的URL下载图片,并根据检测到的格式保存文件。

    步骤 4:修正文件夹命名

    为了确保文件夹的命名合法,我们可以使用以下代码:

    def sanitize_folder_name(name: str) -> str:
        # 替换非法字符
        name = re.sub(r'[<>:"/\\|?*]', '_', name)
        # 删除首尾空格
        name = name.strip()
        # 截断过长的名称
        if len(name) > 255:
            name = name[:255]
        return name

    这个函数将文件夹名称中的非法字符替换为下划线,并确保名称长度不超过255个字符。

    结语

    通过以上步骤,你现在已经知道如何在小红书上下载无水印的图片了!这个技巧可以帮助你保存你喜欢的图片,而且不会留下任何水印。希望这个教程对你有所帮助!

    如果你有任何问题或意见,请随时在下方留言,我将尽力回答。谢谢你的阅读!

  • 如何使用Gradio构建机器学习Web应用

    如何使用Gradio构建机器学习Web应用

    你好,亲爱的读者们!今天,我将向你们介绍一个强大的Python库,它可以让你在几分钟内构建出令人印象深刻的机器学习Web应用。无需深厚的编程知识,Gradio将成为你的得力助手,助你将机器学习模型和数据科学工作流变成令人愉悦的应用程序。

    开篇故事

    你是否曾经想要将你的机器学习模型展示给他人,但却发现这个过程充满了繁琐的工作和技术挑战?或者你是否希望快速部署你的模型,并让用户通过浏览器与之互动?如果是的话,那么Gradio正是你需要的工具。

    什么是Gradio?

    Gradio是一个开源的Python库,用于构建机器学习和数据科学演示和Web应用程序。通过Gradio,你可以快速创建一个漂亮的用户界面,围绕你的机器学习模型或数据科学工作流,并允许人们通过浏览器拖放他们自己的图像、粘贴文本、录制自己的声音,并与你的演示互动。

    Gradio的用途广泛,包括:

    • 演示 你的机器学习模型,供客户、合作伙伴、用户或学生使用。
    • 快速部署 模型,生成可分享的链接,并获得模型性能的反馈。
    • 在开发过程中交互式地调试 你的模型,使用内置的操作和解释工具。

    快速入门

    先决条件:Gradio需要Python 3.8或更高版本,仅此而已!

    Gradio的功能

    与他人分享你的机器学习模型、API或数据科学工作流的最佳方式之一是创建一个允许用户或同事在其浏览器中尝试演示的交互式应用程序。

    Gradio允许你在Python中构建演示并分享它们,通常只需几行代码!那么,让我们开始吧。

    Hello,世界

    要使用一个简单的“Hello,World”示例运行Gradio,请按照以下三个步骤进行操作:

    1. 使用pip安装Gradio:

    pip install gradio

    2. 将以下代码保存为Python脚本并运行,或在Jupyter Notebook(或Google Colab)中运行:

    import gradio as gr
    
    def greet(name):
        return "Hello " + name + "!"
    
    demo = gr.Interface(fn=greet, inputs="text", outputs="text")
    
    demo.launch()

    我们将导入的名称缩短为gr,以提高Gradio代码的可读性。这是一种被广泛采用的约定,你应该遵循,以便任何与你的代码一起工作的人都能轻松理解。

    3. 在Jupyter Notebook中,演示将自动显示,或者如果在脚本中运行,则会在浏览器中弹出,并在http://localhost:7860上运行:

    在本地开发时,如果希望将代码作为Python脚本运行,可以使用Gradio CLI以重新加载模式启动应用程序,这将提供无缝快速的开发。了解有关重新加载的更多信息,请参阅自动重新加载指南。

    gradio app.py

    注意:也可以使用python app.py,但它不会提供自动重新加载机制。

    Interface 类

    你会注意到,为了创建演示,我们创建了一个gr.Interface。这个Interface类可以将用户界面包装在任何Python函数周围。在上面的示例中,我们看到了一个简单的基于文本的函数,但该函数可以是任何东西,从音乐生成器到税收计算器再到预训练机器学习模型的预测函数。

    核心的Interface类初始化时需要三个必需参数:

    • fn:要在其周围包装UI的函数
    • inputs:用于输入的组件(例如 "text"、"image" 或 "audio")
    • outputs:用于输出的组件(例如 "text"、"image" 或 "label")

    让我们更详细地看看这些用于提供输入和输出的组件。

    组件属性

    我们在前面的示例中看到了一些简单的Textbox组件,但如果你想更改UI组件的外观或行为,该怎么办?

    假设你想要自定义输入文本字段 – 例如,你希望它更大,并且有一个文本占位符。如果我们使用Textbox的实际类而不是使用字符串快捷方式,你可以通过组件属性获得更多的自定义能力。

    import gradio as gr
    
    def greet(name
    
    ):
        return "Hello " + name + "!"
    
    demo = gr.Interface(
        fn=greet,
        inputs=gr.Textbox(lines=2, placeholder="在这里输入姓名..."),
        outputs="text",
    )
    demo.launch()

    多个输入和输出组件

    假设你有一个更复杂的函数,带有多个输入和输出。在下面的示例中,我们定义了一个函数,该函数接受一个字符串、一个布尔值和一个数字,并返回一个字符串和一个数字。请看如何传递输入和输出组件的列表。

    import gradio as gr
    
    def greet(name, is_morning, temperature):
        salutation = "早上好" if is_morning else "晚上好"
        greeting = f"{salutation} {name}。今天气温是{temperature}度"
        celsius = (temperature - 32) * 5 / 9
        return greeting, round(celsius, 2)
    
    demo = gr.Interface(
        fn=greet,
        inputs=["text", "checkbox", gr.Slider(0, 100)],
        outputs=["text", "number"],
    )
    demo.launch()

    你只需将组件包装在列表中。inputs列表中的每个组件与函数的参数对应,按顺序排列。outputs列表中的每个组件与函数返回的值对应,同样也按顺序排列。

    图像示例

    Gradio支持许多类型的组件,例如 Image、DataFrame、Video 或 Label。让我们尝试一个图像到图像的函数,以了解这些组件的感觉!

    import numpy as np
    import gradio as gr
    
    def sepia(input_img):
        sepia_filter = np.array([
            [0.393, 0.769, 0.189], 
            [0.349, 0.686, 0.168], 
            [0.272, 0.534, 0.131]
        ])
        sepia_img = input_img.dot(sepia_filter.T)
        sepia_img /= sepia_img.max()
        return sepia_img
    
    demo = gr.Interface(sepia, gr.Image(shape=(200, 200)), "image")
    demo.launch()

    当使用Image组件作为输入时,你的函数将收到一个形状为(height, width, 3)的NumPy数组,其中最后一个维度表示RGB值。我们也会返回一个图像,以NumPy数组的形式。

    你还可以使用type=关键字参数设置组件使用的数据类型。例如,如果你希望你的函数接受图像文件的文件路径而不是NumPy数组,那么输入的Image组件可以这样写:

    gr.Image(type="filepath", shape=...)

    还要注意,我们的输入Image组件附带了一个编辑按钮,允许裁剪和缩放图像。通过这种方式操作图像可以帮助揭示机器学习模型中的偏见或隐藏缺陷!

    你可以在Gradio文档中阅读更多关于许多组件以及如何使用它们的信息。

    聊天机器人

    Gradio包括一个高级类gr.ChatInterface,它类似于gr.Interface,但专门设计用于聊天机器人的UI。gr.ChatInterface类也包装一个函数,但这个函数必须具有特定的签名。函数应该接受两个参数:message和history(参数名可以是任何名字,但必须按照这个顺序)

    • message:表示用户输入的str
    • history:表示到目前为止的会话的list的list。每个内部列表包含两个str,表示一对:[用户输入,机器人回复]。

    除此之外,gr.ChatInterface没有必需的参数(尽管有几个用于自定义UI的参数可用)。

    以下是一个玩具示例:

    import random
    import gradio as gr
    
    def random_response(message, history):
        return random.choice(["是的", "不是"])
    
    demo = gr.ChatInterface(random_response)
    
    demo.launch()

    你可以在这里阅读更多关于gr.ChatInterface的信息。

    Blocks:更灵活和可控

    Gradio提供了两种构建应用程序的方法:

    1. Interface 和 ChatInterface,为创建演示提供了高级抽象,这是我们到目前为止讨论的内容。

    2. Blocks,这是一种低级API,用于设计具有更灵活布局和数据流的Web应用程序。Blocks允许你做一些事情,比如展示多个数据流和演示、控制组件出现在页面的位置、处理复杂的数据流(例如,输出可以作为其他函数的输入),以及根据用户交互更新组件的属性/可见性 – 仍然都是在Python中。如果你需要这种自定义能力,可以尝试使用Blocks!

    Hello,Blocks

    让我们看一个简单示例。请注意,此处的API与Interface不同。

    import gradio as gr
    
    def greet(name):
        return "Hello " + name + "!"
    
    with gr.Blocks() as demo:
        name = gr.Textbox(label="姓名")
        output = gr.Textbox(label="输出框")
        greet_btn = gr.Button("问候")
        greet_btn.click(fn=greet, inputs=name, outputs=output, api_name="greet")
    
    demo.launch()

    需要注意的事项:

    • 使用with子句制作Blocks,此子句中创建的任何组件都会自动添加到应用程序中。
    • 组件按垂直顺序出现在应用程序中,按照创建的顺序排列。(稍后我们将介绍如何自定义布局!)
    • 创建了一个Button,然后为该按钮添加了一个click事件侦听器。这个API看起来应该很熟悉!像Interface一样,click方法接受Python函数、输入组件和输出组件。

    更复杂的示例

    以下是一个应用程序,让你感受一下使用Blocks可以实现的可能性:

    import numpy as np
    import gradio as gr
    
    def flip_text(x):
        return x[::-1]
    
    def flip_image(x):
        return np.fliplr(x)
    
    with gr.Blocks() as demo:
        gr.Markdown("使用此演示翻转文本或图像文件。")
        with gr.Tab("翻转文本"):
            text_input = gr.Textbox()
            text_output = gr.Textbox()
            text_button = gr.Button("翻转")
        with gr.Tab("翻转图像"):
            with gr.Row():
                image_input = gr.Image()
                image_output = gr.Image()
            image_button = gr.Button("翻转")
    
        with gr.Accordion("展开查看更多!"):
            gr.Markdown("看看我...")
    
        text_button.click(flip_text, inputs=text_input, outputs=text_output)
        image_button.click(flip_image, inputs=image_input, outputs=image_output)
    
    demo.launch()

    这里有更多的东西!我们将在使用Blocks构建部分介绍如何创建像这样的复杂Blocks应用程序。

    恭喜,你现在已经熟悉了Gradio的基础知识! ? 转到我们的下一个指南了解更多关于Gradio的关键特性。

    许可证

    Gradio根据位于此存储库根目录的LICENSE文件中的Apache许可证2.0获得许可。

    引用

    还请阅读我们的论文Gradio:在野外轻松共享和测试ML模型,ICML HILL 2019,如果您在您的工作中使用了Gradio,请引用它。

    @article{abid2019gradio,
      title = {Gradio: Hassle-Free Sharing and Testing of ML Models in the Wild},
      author = {Abid, Abubakar and Abdalla, Ali and Abid, Ali and Khan, Dawood and Alfozan, Abdulrahman and Zou, James},
      journal = {arXiv preprint arXiv:1906.02569},
      year = {2019},
    }