第五章:通过 GitHub Copilot 和 Copilot Chat 管理数据
本章内容涵盖
- 将我们的数据持久化到关系型数据库
- 使用 Apache Kafka 进行数据流式传输
- 融合事件驱动原则
- 使用 Spark 分析我们的数据以监控位置
上一章为我们的信息技术资产管理系统奠定了基础。然而,没有数据,这个应用程序将无法满足我们的要求。数据是每个应用程序的命脉。这正是本章的主题:我们可以使用生成式 AI 来创建数据、流式传输数据、转换数据、对数据做出反应并从数据中学习的各种方式。
敏锐的人可能已经注意到在上一章中,我们的数据访问模式是无法正常工作的,因为它是不完整的。本章的开头部分将解决这个问题。之后,我们将设置我们的数据库,修复访问这些数据的类,并加载一些示例数据,以便在本章的其余部分使用。
5.1 积累我们的数据集
我们的第一个任务将是构建一个大量的数据集,以帮助我们在本章剩余的实验中。首先,我们将使用 GitHub Copilot 生成一千行资产信息。然而,我们很快会发现,这可能不是最适合这项任务的工具。使用这些工具的一个关键驱动因素是发现的概念:测试它们的边界,推动它们,有时候,反击它们。但旅程往往是快乐的源泉。一旦我们找到了这个边缘,我们将被介绍一个新的、以前从未见过的工具:GitHub Copilot Chat。最后,一旦我们创建了我们的资产列表,我们将再次使用 GitHub Copilot Chat 为这些资产添加位置信息。
在构建我们的初始数据集之前,我们需要让数据库运行起来。Docker 让这个任务变得微不足道,让我们能够快速启动一个空的 Postgres(或其他 RDBMS/NoSQL 服务器),几乎不费吹灰之力。你忘记了执行此操作的命令吗?别担心,我们可以问 Copilot。打开一个名为 data/initial_data_laod.sql 的新文件,并在你的新生成的 SQL 文件顶部输入以下提示。
片段 5.1 提示 GitHub Copilot 为我们提供一个 Docker 命令
-- Question: What is the command to run a docker container, running PostgreSQL for a database called itam_db. I would like to specify the password for this database.
Copilot 将逐渐揭示 Docker 命令:--Answer: docker run --name itam_db -e POSTGRES_PASSWORD=postgres -d -p 5432:5432 postgres.
一旦你在终端或命令行运行这个命令,我们就可以构建出我们的数据集。你应该能够连接到本地运行的数据库。你应该注意到里面有一个名为 itam_db 的数据库在运行。然而,这个数据库没有模式、表或数据。让我们首先设置一个新的模式。
在我们的 initial_data_file.sql 中,我们将添加一个提示,让 Copilot 起草模式创建命令。执行此命令将允许您从数据库客户端应用程序(例如 DataGrip、SQuirreL、pdAdmin,甚至使用 Docker exec 命令 docker exec -i itam_db psql -U postgres -c "create schema itam"
)中创建名为 itam 的新模式。
提示让 Copilot 创建新模式
-- create a schema called itam create schema itam;
接下来,我们应该为应用程序中使用的用户添加一个用户。此用户将能够对我们的数据执行CRUD(创建、读取、更新、删除)操作,但将无法影响数据库表或存储过程的结构。
注意
以双破折号开头的行是 SQL 中的注释。从 Copilot 的角度来看,注释这些行是可选的,因为它将生成没有注释的解决方案;这样做可以更轻松地将代码直接复制粘贴到我们选择的数据库工具中。
在此期间,我们还将添加一个管理帐户,以执行我们的读写用户无法执行的操作,例如创建或删除表。
提示创建新用户
-- create two users called itam_user and itam_admin. itam_user should be able to read from and write to the tables in the itam schema. itam_admin should be able to read from and write to the tables in the itam schema and create and drop tables in the itam schema. create user itam_user with password 'itam_user'; create user itam_admin with password 'itam_admin'; grant usage on schema itam to itam_user; grant usage on schema itam to itam_admin; grant select, insert, update, delete on all tables in schema itam to itam_user; grant select, insert, update, delete on all tables in schema itam to itam_admin; grant usage, drop on schema itam to itam_admin;
接下来,我们将把此模式的所有权授予 itam_admin 帐户。转移此所有权将确保只有此帐户可以更改表结构:数据定义。
将模式所有权转移给管理员帐户的提示
-- grant ownership of the itam schema to itam_admin alter schema itam owner to itam_admin;
配置完成、帐户创建和系统的崇拜已经完成,我们可以开始专注于数据。我们将从添加参考数据开始,即支持资产的数据:折旧策略。这些数据的性质更加静态;它们的变化频率较低,甚至根本不变。接下来,我们将定义并存储这些策略。
提示创建折旧策略表
-- create a table called depreciation_strategy in the itam schema. the table should have the following columns: id (int), name (varchar), and description (varchar). the table should have a primary key on id. -- id needs to be in quotes because it is a reserved word in postgresql -- there are two values for depreciation_strategy: straight line and double declining balance create table itam.depreciation_strategy ( "id" int primary key, "name" varchar, "description" varchar );
我们将使用序列作为此表的主键。虽然对于一个不会很大并且我们可以手动输入已知值的表而言,这并不是严格必要的,但是添加此序列将允许我们与 Copilot 更多地合作并让它提出一些建议。此外,询问 Copilot 并在文本文件中获得 Copilot 的回答是有趣的。
提示为折旧策略表的主键创建序列
-- create a sequence called depreciation_strategy_seq, which should start at 1 and increment by 1 and should be used as the primary key for the depreciation_strategy table. create sequence itam.depreciation_strategy_seq start 1 increment 1;
自然地,有了我们手中的序列,我们需要知道如何将序列与depreciation_stategy
表的主键列关联起来。幸运的是,Copilot 有答案。
询问 Copilot 如何将序列与主键关联
-- question: how do I make the sequence the primary key for the depreciation_strategy table? -- answer: use the following command alter table itam.depreciation_strategy alter column "id" set default nextval('itam.depreciation_strategy_seq'::regclass);
最后,我们将通过将以下静态条目插入表格来完成此表格。目前我们只使用两种折旧策略:直线法和双倍余额递减法。
将静态条目添加到折旧策略表
insert into depreciation_strategy (id, name, description) values (1, 'straight line', 'straight line'); insert into depreciation_strategy (id, name, description) values (2, 'double declining balance', 'double declining balance');
接下来,我们将转向资金细节表。这些信息告诉我们如何为我们的设备进行融资,再销售价值,并对资产在其有用生命周期结束后应采取的措施进行说明。我们在折旧策略中所做的步骤顺序将与此相同,唯一的区别是我们不会添加静态条目,因为这些数据直接与个体资产相关。我们将定义表,创建序列,并将该序列应用于表,作为主键的功能。
列表 5.6 资金详情表的完整代码列表
-- create a table called funding_details in the itam schema. the table should have the following columns: id (int), name (varchar),depreciation_strategy_id (int) and depreciation_rate (float). the table should have a primary key on id. -- depreciation_stategy_id is a foreign key to the depreciation_strategy table. -- id needs to be in quotes because it is a reserved word in postgresql create table itam.funding_details ( "id" int primary key, "name" varchar, "depreciation_strategy_id" int, "depreciation_rate" float ); -- create a sequence called funding_details_seq, which should start at 1 and increment by 1 and should be used as the primary key for the funding_details table. create sequence itam.funding_details_seq start 1 increment 1; alter table itam.funding_details alter column "id" set default nextval('itam.funding_details_seq'::regclass);
我们将定义和生成的最后信息是资产本身。这个列表也是冗余的,但出于完整性考虑已包括在内。最后,我们创建表,创建序列,并将其用作主键。
列表 5.7 资产表的完整代码列表
-- create a table called assets in the itam schema. the table should have the following columns: -- id (int), name (varchar), status (varchar), category (varchar), cost (float), useful_life (int), salvage_value (float), purchase_date (date), funding_details_id (int). The table should have a primary key on id and a foreign key on funding_details_id. -- id needs to be in quotes because it is a reserved word in postgresql -- the table should have a sequence called assets_id_seq, which should start at 1 and increment by 1 and should be used as the primary key for the assets table. create table itam.assets ( "id" int primary key, "name" varchar, "status" varchar, "category" varchar, "cost" float, "useful_life" int, "salvage_value" float, "purchase_date" date, "funding_details_id" int ); -- create a sequence called assets_seq, which should start at 1 and increment by 1 and should be used as the primary key for the assets table. create sequence itam.assets_seq start 1 increment 1; alter table itam.assets alter column "id" set default nextval('itam.assets_seq'::regclass);
在定义和创建表之后,我们现在将专注于创建数据。在我们的文本文件中,我们使用参数指示 Copilot 我们正在寻找的数据集。Copilot 可能会尝试帮助您概述围绕新数据集的属性。
列表 5.8 为资产表创建数据集
-- Generate a dataset of assets for an ITAM system. The dataset should include the following columns: id (int), name (varchar), status (varchar), category (varchar), cost (float), useful_life (int), salvage_value (float), purchase_date (date), funding_details_id (int). The dataset should have 1000 rows, sorted by id. Each row should have the following characteristics: -- - id should be a unique integer and sequential starting at 1. -- - name should be a random string of characters between 1 and 50 characters long. -- - status should be a random selection from the following valid asset statuses: in use, in storage, disposed of, in repair, in transit, other. -- - category should be a random selection from the following valid categories: hardware, software, other. -- - cost should be a random float between 0 and 100000. -- - useful_life should be a random int between 1 and 10. -- - salvage_value should be a random float greater than 0 but less than the cost of the asset. -- - purchase_date should be a random date between 1/1/2019 and 12/31/2022. -- - funding_details_id should be a random integer either 1 or 2. -- The dataset should be saved as a CSV file named assets.csv in the data directory. The file should have a header row and the columns should have the following data types: id (int), name (varchar), status (varchar), category (varchar), cost (float), useful_life (float), salvage_value (float), funding_details_id (int)
Copilot 提供的解决方案是新颖的。它使用 Postgres 内置功能构建了一个大系列,这意味着这不是一个可移植的解决方案。然而,考虑到这是我们将要使用的数据库,这是一个足够合适的解决方案。生成的数据集经过了精心制作。如果我们使用 Python 并要求 Copilot 帮助编写一个用于加载到 Postgres 的文件的脚本,我们可能会得到更好的结果。然而,鉴于这个数据集只是用来玩应用程序,目前我们不需要过于担心数据质量。尽管在现实世界中,数据质量是至关重要的。
列表 5.9 Copilot 的响应:基于一系列构建的插入语句
insert into itam.assets (id, name, status, category, cost, useful_life, salvage_value, purchase_date, funding_details_id) select id, name, status, category, cost, useful_life, salvage_value, purchase_date, funding_details_id from ( select row_number() over (order by random()) as id, md5(random()::text) as name, case when random() < 0.2 then 'in use' when random() < 0.4 then 'in storage' when random() < 0.6 then 'disposed of' when random() < 0.8 then 'in repair' when random() < 0.9 then 'in transit' else 'other' end as status, case when random() < 0.5 then 'hardware' when random() < 0.9 then 'software' else 'other' end as category, random() * 100000 as cost, (random() * 100)::int as useful_life, random() * (random() * 100000) as salvage_value, -- generate a random date between 1/1/2019 and 12/31/2022 -- this does not work please fix -- '2019-01-01'::date + random() * ('2022-12-31'::date - '2019-01-01'::date) as purchase_date, '2019-01-01'::date + (random() * (DATE '2022-12-31' - DATE '2019-01-01')::integer)::integer as purchase_date case when random() < 0.5 then 1 else 2 end as funding_details_id from generate_series(1, 1000) ) as assets;
如果我们仅仅转向 ChatGPT,我们可以得到如何创建这样的数据集的第二意见。ChatGPT 建议使用 Python 库faker
。faker
包用于生成虚假数据,例如常见的英文姓名。numpy
用于生成成本、有用生命和残值的随机浮点值。pandas
用于在DataFrame
(表)中管理数据。此外,我们可以使用df.to_csv('assets.csv', index=False)
方法将DataFrame
保存到 CSV 文件中。
列表 5.10 ChatGPT 建议使用 Faker 来生成虚假数据集
import pandas as pd import numpy as np import random from faker import Faker # Create Faker object fake = Faker() # Define our valid statuses, categories, funding_details and depreciation_strategies valid_statuses = ['in use', 'in storage', 'disposed', 'in repair', 'in transit', 'other'] valid_categories = ['hardware'] valid_funding_details = ['purchased'] valid_depreciation_strategies = ['straight line'] # Generate the data data = { 'id': list(range(1, 1001)), 'name': [fake.first_name() for _ in range(1000)], 'status': [random.choice(valid_statuses) for _ in range(1000)], 'category': [random.choice(valid_categories) for _ in range(1000)], 'cost': np.random.uniform(0, 100000, 1000), 'useful_life': np.random.uniform(1, 10, 1000), 'salvage_value': np.random.uniform(0, 10000, 1000), 'funding_details': [random.choice(valid_funding_details) for _ in range(1000)], 'depreciation_strategy': [random.choice(valid_depreciation_strategies) for _ in range(1000)], } # Create DataFrame df = pd.DataFrame(data) # Ensure the DataFrame is sorted by id df = df.sort_values('id') # Show the DataFrame print(df)
对于这些资产的每一项,我们也需要资金细节;它们是如何融资的(在这种情况下购买),以及折旧细节。毫不奇怪,我们从 Copilot 得到了类似的解决方案:使用与我们为资产使用的类似提示生成一系列条目。我们需要确保对于每个资产标识符(1-1000),我们都有相应的资金细节条目。否则,在运行我们的代码时会出现空指针的风险。
清单 5.11 创建funding_details
表的数据集
-- Generate a dataset of funding details for an ITAM system. The dataset should include the following columns: id (int), name (varchar), depreciation_strategy_id (int), depreciation_rate (float). The dataset should have 1000 rows, sorted by id. -- Each row should have the following characteristics: -- - id should be a unique integer and sequential starting at 1. -- - name should be a random string of characters between 1 and 10 characters long. -- - depreciation_strategy_id should be a random integer either 1 or 2. -- - depreciation_rate should be a random float between 0 and .4. insert into itam.funding_details (id, name, depreciation_strategy_id, depreciation_rate) select id, name, depreciation_strategy_id, depreciation_rate from ( select row_number() over (order by random()) as id, md5(random()::text) as name, case when random() < 0.5 then 1 else 2 end as depreciation_strategy_id, random() * 0.4 as depreciation_rate from generate_series(1, 1000) ) as funding_details;
有了在数据库中生成和存储的数据集,我们应该能够通过 REST API 连接我们应用程序的其余部分来存储和显示资产。然而,由于我们在构建阶段之前已经剥离了所有的 SQLAlchemy 元数据(请参阅上一章),我们需要一种不同的方法来将这些元数据与我们的适配器进行连接。
有了这个,我们已经达到了 Copilot 的能力边缘。我们对接下来会发生什么感到困惑;我们如何解决我们最近的困境。尽管诱人,我们不能放弃回家。因此,现在是时候介绍 Copilot 产品套件的最新成员了:Copilot Chat。Copilot Chat 是嵌入式的 GPT-4 模型,可以集成到你的 IDE 中(目前仅支持 Visual Studio Code)。我们将打开聊天对话框,询问如何保持我们的业务模型清晰,但仍然使用 SQLAlchemy 的 ORM(对象关系模型)功能。
图 5.1 GitHub Copilot Chat 对我们最近困境的解决方案
Copilot Chat 建议我们创建一个单独的数据访问层。这种方法与我们迄今为止使用的端口和适配器方法非常契合。此外,Copilot Chat 建议将这些类建模得与领域类类似,但包括 ORM 功能正常工作所需的元数据。生成的代码见清单 5.12。
清单 5.12 领域类之外的 ORM 支持。
Base = declarative_base() class FundingDetailsModel(Base): __tablename__ = 'funding_details' id = Column(Integer, primary_key=True) depreciation_rate = Column(Float) depreciation_strategy_id = Column(Integer) def get_depreciation_strategy(self) -> DepreciationStrategy: if self.depreciation_strategy_id is 1: return StraightLineDepreciationStrategy() else: return DoubleDecliningDepreciationStrategy() class AssetModel(Base): __tablename__ = 'assets' id = Column(Integer, primary_key=True) name = Column(String) status = Column(String) category = Column(String) cost = Column(Float) useful_life = Column(Float) salvage_value = Column(Float) purchase_date = Column(Date) funding_details_id = Column(Integer, ForeignKey('funding_details.id')) funding_details = relationship('FundingDetailsModel')
现在,外部模型类已经创建,我们必须将这些 ORM 实例映射到我们的领域模型,然后返回给系统核心。虽然对于这样一个简单的应用程序来说,这似乎是过度设计的代码,但这给了我们很大的灵活性,使我们的领域模型可以进行复杂的操作。例如,我们的模型可以执行 CRUD 之外的复杂操作。如果我们将我们的领域模型身份限制在数据访问层中使用的模型上,我们将受到这些操作的限制。
接下来,我们将使用 Copilot 和 Copilot Chat 探索将事件驱动思想纳入我们的应用程序中。事件驱动的概念将允许我们实时跟踪我们的 IT 资产:它们的位置、状态和市场价值,例如。
AI 驱动的开发者(MEAP)(二)(2)https://developer.aliyun.com/article/1516330