”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 如何使用内省、单击和丰富格式为 Python CLI 构建交互式聊天

如何使用内省、单击和丰富格式为 Python CLI 构建交互式聊天

发布于2024-11-08
浏览:132

How to Build an Interactive Chat for Your Python CLI Using Introspection, Click, and Rich Formatting

如果您曾经想让您的 CLI 更具交互性和动态性,构建实时命令交互系统可能是答案。通过利用 Python 的自省功能、用于管理命令的 Click 以及用于格式化输出的 Rich,您可以创建一个强大、灵活的 CLI,以智能地响应用户输入。您的 CLI 可以自动发现并执行命令,而不是手动对每个命令进行硬编码,从而使用户体验更流畅、更具吸引力。

多彩的控制台混乱:点击命令与丰富的输出相遇——因为即使是终端也喜欢炫耀风格!

为什么使用 Click 和 Markdown?

Click 简化了命令管理、参数解析和帮助生成。它还允许轻松的命令结构和选项处理。

Rich 使您能够直接在终端中输出格式精美的 Markdown,使结果不仅实用,而且具有视觉吸引力。

通过将这两个库与 Python 自省相结合,您可以构建交互式聊天功能,该功能可以动态发现和执行命令,同时以丰富、可读的格式显示输出。 有关实际示例,请了解 StoryCraftr 如何使用类似的方法来简化 AI 驱动的写作工作流程: https://storycraftr.app.

构建互动聊天系统

1. 设置基本聊天命令

chat 命令初始化会话,允许用户与 CLI 交互。在这里,我们捕获用户输入,这些输入将动态映射到适当的单击命令。

import os
import click
import shlex
from rich.console import Console
from rich.markdown import Markdown

console = Console()

@click.command()
@click.option("--project-path", type=click.Path(), help="Path to the project directory")
def chat(project_path=None):
    """
    Start a chat session with the assistant for the given project.
    """
    if not project_path:
        project_path = os.getcwd()

    console.print(
        f"Starting chat for [bold]{project_path}[/bold]. Type [bold green]exit()[/bold green] to quit."
    )

    # Start the interactive session
    while True:
        user_input = console.input("[bold blue]You:[/bold blue] ")

        # Handle exit
        if user_input.lower() == "exit()":
            console.print("[bold red]Exiting chat...[/bold red]")
            break

        # Call the function to handle command execution
        execute_cli_command(user_input)

2. 自省以发现和执行命令

使用Python内省,我们动态地发现可用的命令并执行它们。这里的一个关键部分是 Click 命令是修饰函数。为了执行实际的逻辑,我们需要调用未修饰的函数(即回调)。

以下是如何使用内省动态执行命令并处理 Click 的装饰器:

import inspect
import your_project_cmd  # Replace with your actual module containing commands

command_modules = {"project": your_project_cmd}  # List your command modules here

def execute_cli_command(user_input):
    """
    Function to execute CLI commands dynamically based on the available modules,
    calling the undecorated function directly.
    """
    try:
        # Use shlex.split to handle quotes and separate arguments correctly
        parts = shlex.split(user_input)
        module_name = parts[0]
        command_name = parts[1].replace("-", "_")  # Replace hyphens with underscores
        command_args = parts[2:]  # Keep the rest of the arguments as a list

        # Check if the module exists in command_modules
        if module_name in command_modules:
            module = command_modules[module_name]

            # Introspection: Get the function by name
            if hasattr(module, command_name):
                cmd_func = getattr(module, command_name)

                # Check if it's a Click command and strip the decorator
                if hasattr(cmd_func, "callback"):
                    # Call the underlying undecorated function
                    cmd_func = cmd_func.callback

                # Check if it's a callable (function)
                if callable(cmd_func):
                    console.print(
                        f"Executing command from module: [bold]{module_name}[/bold]"
                    )

                    # Directly call the function with the argument list
                    cmd_func(*command_args)
                else:
                    console.print(
                        f"[bold red]'{command_name}' is not a valid command[/bold red]"
                    )
            else:
                console.print(
                    f"[bold red]Command '{command_name}' not found in {module_name}[/bold red]"
                )
        else:
            console.print(f"[bold red]Module {module_name} not found[/bold red]")
    except Exception as e:
        console.print(f"[bold red]Error executing command: {str(e)}[/bold red]")

这是如何运作的?

  • 输入解析:我们使用 shlex.split 来处理命令行参数等输入。这可确保正确处理带引号的字符串和特殊字符。
  • 模块和命令查找:输入分为 module_name 和 command_name。命令名称经过处理,将连字符替换为下划线,以匹配 Python 函数名称。
  • 内省:我们使用 getattr() 从模块动态获取命令函数。如果它是一个 Click 命令(即具有回调属性),我们通过剥离 Click 装饰器来访问实际的函数逻辑。
  • 命令执行:一旦我们检索到未修饰的函数,我们就传递参数并调用它,就像我们直接调用Python函数一样。

3. CLI 命令示例

让我们考虑项目模块中的一些示例命令,用户可以通过聊天交互调用这些命令:

@click.group()
def project():
    """Project management CLI."""
    pass

@project.command()
def init():
    """Initialize a new project."""
    console.print("[bold green]Project initialized![/bold green]")

@project.command()
@click.argument("name")
def create(name):
    """Create a new component in the project."""
    console.print(f"[bold cyan]Component {name} created.[/bold cyan]")

@project.command()
def status():
    """Check the project status."""
    console.print("[bold yellow]All systems operational.[/bold yellow]")

执行聊天界面

运行交互式聊天系统:

  1. 确保您的模块(如项目)已在 command_modules 中列出。
  2. 运行命令:
python your_cli.py chat --project-path /path/to/project

会话开始后,用户可以输入以下命令:

You: project init You: project create "Homepage"

输出将使用 Rich Markdown 以格式良好的方式显示:

[bold green]Project initialized![/bold green] [bold cyan]Component Homepage created.[/bold cyan]

结论

通过结合 Click 命令管理、Rich for Markdown 格式和 Python 自省,我们可以为 CLI 构建一个强大的交互式聊天系统。这种方法允许您动态发现和执行命令,同时以优雅、可读的格式呈现输出。

主要亮点:

  • 动态命令执行:内省使您能够发现和运行命令,而无需对其进行硬编码。
  • 丰富的输出:使用丰富的 Markdown 可确保输出易于阅读且具有视觉吸引力。
  • 灵活性:此设置允许命令结构和执行的灵活性。
版本声明 本文转载于:https://dev.to/rodrigo_estrada_79e6022e9/how-to-build-an-interactive-chat-for-your-python-cli-using-introspection-click-and-rich-formatting-4l9a?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • Android如何向PHP服务器发送POST数据?
    Android如何向PHP服务器发送POST数据?
    在android apache httpclient(已弃用) httpclient httpclient = new defaulthttpclient(); httppost httppost = new httppost(“ http://www.yoursite.com/script.p...
    编程 发布于2025-03-16
  • 如何从Google API中检索最新的jQuery库?
    如何从Google API中检索最新的jQuery库?
    从Google APIS 问题中提供的jQuery URL是版本1.2.6。对于检索最新版本,以前有一种使用特定版本编号的替代方法,它是使用以下语法:获取最新版本:未压缩)While these legacy URLs still remain in use, it is recommended ...
    编程 发布于2025-03-16
  • Java是否允许多种返回类型:仔细研究通用方法?
    Java是否允许多种返回类型:仔细研究通用方法?
    在Java中的多个返回类型:一种误解类型:在Java编程中揭示,在Java编程中,Peculiar方法签名可能会出现,可能会出现,使开发人员陷入困境,使开发人员陷入困境。 getResult(string s); ,其中foo是自定义类。该方法声明似乎拥有两种返回类型:列表和E。但这确实是如此吗...
    编程 发布于2025-03-16
  • \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    答案: 在大多数现代编译器中,while(1)和(1)和(;;)之间没有性能差异。编译器: perl: 1 输入 - > 2 2 NextState(Main 2 -E:1)V-> 3 9 Leaveloop VK/2-> A 3 toterloop(next-> 8 last-> 9 ...
    编程 发布于2025-03-16
  • 如何使用替换指令在GO MOD中解析模块路径差异?
    如何使用替换指令在GO MOD中解析模块路径差异?
    在使用GO MOD时,在GO MOD 中克服模块路径差异时,可能会遇到冲突,其中3个Party Package将另一个PAXPANCE带有导入式套件之间的另一个软件包,并在导入式套件之间导入另一个软件包。如回声消息所证明的那样: go.etcd.io/bbolt [&&&&&&&&&&&&&&&&...
    编程 发布于2025-03-16
  • 版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    在时间戳列上使用current_timestamp或MySQL版本中的current_timestamp或在5.6.5 此限制源于遗留实现的关注,这些限制需要对当前的_timestamp功能进行特定的实现。 创建表`foo`( `Productid` int(10)unsigned not n...
    编程 发布于2025-03-15
  • 为什么尽管有效代码,为什么在PHP中捕获输入?
    为什么尽管有效代码,为什么在PHP中捕获输入?
    在php ;?>" method="post">The intention is to capture the input from the text box and display it when the submit button is clicked.但是,输出...
    编程 发布于2025-03-15
  • 如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    postgresql:为每个唯一标识符在postgresql中提取最后一行,您可能需要遇到与数据集合中每个不同标识的信息相关的信息。考虑以下数据:[ 1 2014-02-01 kjkj 在数据集中的每个唯一ID中检索最后一行的信息,您可以在操作员上使用Postgres的有效效率: id dat...
    编程 发布于2025-03-15
  • 如何在Java字符串中有效替换多个子字符串?
    如何在Java字符串中有效替换多个子字符串?
    在java 中有效地替换多个substring,需要在需要替换一个字符串中的多个substring的情况下,很容易求助于重复应用字符串的刺激力量。 However, this can be inefficient for large strings or when working with nu...
    编程 发布于2025-03-15
  • 为什么不使用CSS`content'属性显示图像?
    为什么不使用CSS`content'属性显示图像?
    在Firefox extemers属性为某些图像很大,&& && && &&华倍华倍[华氏华倍华氏度]很少见,却是某些浏览属性很少,尤其是特定于Firefox的某些浏览器未能在使用内容属性引用时未能显示图像的情况。这可以在提供的CSS类中看到:。googlepic { 内容:url(&#...
    编程 发布于2025-03-15
  • 可以在纯CS中将多个粘性元素彼此堆叠在一起吗?
    可以在纯CS中将多个粘性元素彼此堆叠在一起吗?
    [2这里: https://webthemez.com/demo/sticky-multi-header-scroll/index.html </main> <section> { display:grid; grid-template-...
    编程 发布于2025-03-15
  • PHP阵列键值异常:了解07和08的好奇情况
    PHP阵列键值异常:了解07和08的好奇情况
    PHP数组键值问题,使用07&08 在给定数月的数组中,键值07和08呈现令人困惑的行为时,就会出现一个不寻常的问题。运行print_r($月份)返回意外结果:键“ 07”丢失,而键“ 08”分配给了9月的值。此问题源于PHP对领先零的解释。当一个数字带有0(例如07或08)的前缀时,PHP将...
    编程 发布于2025-03-15
  • 我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    将我的加密库从mcrypt升级到openssl 问题:是否可以将我的加密库从McRypt升级到OpenSSL?如果是这样,如何?答案:是的,可以将您的Encryption库从McRypt升级到OpenSSL。可以使用openssl。附加说明: [openssl_decrypt()函数要求iv参...
    编程 发布于2025-03-15
  • Python读取CSV文件UnicodeDecodeError终极解决方法
    Python读取CSV文件UnicodeDecodeError终极解决方法
    在试图使用已内置的CSV模块读取Python中时,CSV文件中的Unicode Decode Decode Decode Decode decode Error读取,您可能会遇到错误的错误:无法解码字节 在位置2-3中:截断\ uxxxxxxxx逃脱当CSV文件包含特殊字符或Unicode的路径逃...
    编程 发布于2025-03-15
  • 如何使用不同数量列的联合数据库表?
    如何使用不同数量列的联合数据库表?
    合并列数不同的表 当尝试合并列数不同的数据库表时,可能会遇到挑战。一种直接的方法是在列数较少的表中,为缺失的列追加空值。 例如,考虑两个表,表 A 和表 B,其中表 A 的列数多于表 B。为了合并这些表,同时处理表 B 中缺失的列,请按照以下步骤操作: 确定表 B 中缺失的列,并将它们添加到表的末...
    编程 发布于2025-03-15

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3