Zsh Codex 代码解析二
前言
在前面的文章中,我在 MacOS
中使用了 Zsh Codex
插件来实现 AI
命令自动补全。
我对这个AI实现的小工具的实现过程非常感兴趣,它的代码也写得非常清晰。
因此,接下来的文章,将一步步对 Zsh Codex
的代码进行解析,更好地理解其工作原理。
仓库地址:github.com/tom-doerr/z...
services.py
这篇文章,我们来分析服务层,这个服务层就只有一个文件,services/service.py
。
这个文件有将近300行代码,我们分两个部分来分析,非AI调用和AI调用部分。
首先我们分析非AI调用部分:
python
import os
import sys
from abc import ABC, abstractmethod
from configparser import ConfigParser
CONFIG_DIR = os.getenv("XDG_CONFIG_HOME", os.path.expanduser("~/.config"))
CONFIG_PATH = os.path.join(CONFIG_DIR, "zsh_codex.ini")
class BaseClient(ABC):
"""Base class for all clients"""
api_type: str = None
system_prompt = "You are a zsh shell expert, please help me complete the following command, you should only output the completed command, no need to include any other explanation. Do not put completed command in a code block."
@abstractmethod
def get_completion(self, full_command: str) -> str:
pass
1、导入模块 :
os
:用于与操作系统进行交互,如获取环境变量和路径操作。sys
:用于与Python
解释器进行交互。abc
:提供了抽象基类(ABC)的功能,用于定义抽象方法。ConfigParser
:用于读取和解析配置文件。
2、配置目录和路径 :
CONFIG_DIR
:获取环境变量XDG_CONFIG_HOME
的值,如果未设置,则默认为用户主目录下的.config
目录。CONFIG_PATH
:将CONFIG_DIR
与zsh_codex.ini
文件名拼接,形成配置文件的完整路径。
3、BaseClient类 :
BaseClient
是一个抽象基类,用于所有客户端的基础类。api_type
:一个类属性,用于标识API的类型,初始值为None
。system_prompt
:一个类属性,包含一个提示字符串,用于告诉语言模型它是一个Zsh shell专家,并且只输出补全的命令,不需要包含其他解释,也不需要将补全的命令放在代码块中。get_completion
:一个抽象方法,子类必须实现该方法。它接受一个完整的命令字符串作为参数,并返回补全后的命令字符串。
通过定义这个基础类,代码为所有客户端提供了一个统一的接口和默认的配置路径,使得子类可以专注于实现与特定语言模型API的交互逻辑。
python
class ClientFactory:
api_types = [OpenAIClient.api_type, GoogleGenAIClient.api_type, GroqClient.api_type, MistralClient.api_type, AmazonBedrock.api_type]
@classmethod
def create(cls):
config_parser = ConfigParser()
config_parser.read(CONFIG_PATH)
service = config_parser["service"]["service"]
try:
config = {k: v for k, v in config_parser[service].items()}
except KeyError:
raise KeyError(f"Config for service {service} is not defined")
api_type = config["api_type"]
match api_type:
case OpenAIClient.api_type:
return OpenAIClient(config)
case GoogleGenAIClient.api_type:
return GoogleGenAIClient(config)
case GroqClient.api_type:
return GroqClient(config)
case MistralClient.api_type:
return MistralClient(config)
case AmazonBedrock.api_type:
return AmazonBedrock(config)
case _:
raise KeyError(
f"Specified API type {api_type} is not one of the supported services {cls.api_types}"
)
类属性 api_types:
这是一个类属性,它是一个列表,包含了所有支持的客户端类型的 api_type
属性。
这些客户端类型包括 OpenAIClient
、GoogleGenAIClient
、GroqClient
、MistralClient
和 AmazonBedrock
。
类方法 create:
这是一个类方法,用于创建客户端对象。
- 首先,它创建了一个
ConfigParser
对象,并读取了配置文件(CONFIG_PATH)。 - 然后,它从配置文件的
service
部分获取了service
键的值,这个值指定了要使用的客户端类型。 - 接着,它尝试从配置文件中读取与
service
键对应的部分,并将其转换为一个字典config。如果配置
-文件中没有定义该服务的配置,它会抛出一个KeyError。
- 然后,它从
config
字典中获取api_type
键的值,这个值指定了要使用的 API 类型。 - 最后,它使用
match
语句根据api_type
的值创建并返回相应的客户端对象。如果api_type
的值不在api_types
列表中,它会抛出一个KeyError
总结
总的来说,services
中的非AI调用部分主要实现了一个基础类 BaseClient
,以及一个工厂类 ClientFactory
,用于根据配置文件中的信息创建相应的客户端对象。
这种创建方式非常符合工厂模式,通过工厂类来隐藏具体的客户端实现细节,使得客户端的创建和使用更加灵活和可扩展,一目了然。
在接下来的文章中,我们将继续分析 services
中的 AI 调用部分,这部分代码主要实现了与不同语言模型 API 的交互逻辑。
-- 欢迎点赞、关注、转发、收藏【我码玄黄】,各大平台同名。