用 Python 自动创建 Markdown 表格 - 每天5分钟玩转 GPT 编程系列(4)
1. 他们居然问我要 Prompts
早几天我用 GPT-4 写了一个 Golang Worker Pool 程序,测试了一把居然性能爆表,然后“他们”就问我要完整的 prompts,想看下到底是 GPT-4 写出来的 GoPool,还是我自己手撕的。(我哪有手撕的本事,你们还真是看得起我。)
GoPool 是一个 95% 代码用 GPT-4 生成的高性能、功能强大且简单易用的 Golang Worker Pool 开源库,详细介绍可以参考这篇文章:
好吧,那我就搞一个网站,把 GoPool 开发过程中用到的 prompts 以及对应的 commits 都列在一起,开源出去!
首先我需要在网页里加这样一张表格:
没错,表格的原始文本得是 Markdown 格式的,然后被转成 HTML(我总不能手撕 HTML 表格吧),放到 pro.devchat.ai。
这个表格对应的 Markdown 最终会长这样:
混乱不?抓狂不?我反正写了一行就放弃了:
| Commit | Commit Hash | Author | Prompts with GPT | 给 GPT 的 Prompts |
| :---------------------------------------------------------------------------------------------------------------------------------- | :---------- | :------------------------------------------- | :------------------------------------------------------------------------ | :---------------------------------------------------------------------------- |
| [Add README.md and go.mod for GoPool project](https://github.com/devchat-ai/gopool/commit/a6315922a026b4290b0b1cd54e95b25e93538047) | a631592 | [Daniel Hu](https://github.com/daniel-hutao) | [Prompts with GPT](./commits/a6315922a026b4290b0b1cd54e95b25e93538047.md) | [给 GPT 的 Prompts](./commits/a6315922a026b4290b0b1cd54e95b25e93538047_zh.md) |
写完一行,老眼昏花,内心久久不能平静。这种“重体力活”怎么能忍?
你想象一下我要到 GitHub 上的 GoPool 项目 commits 列表里,看着接近30个 commits,一个个去摘抄这些信息:
- Commit message 第一行;
- Commit hash 前7位;
- Author 信息;
- 完整的 commit 地址;
然后在本地创建和 commit 地址对应的一个个 Markdown 文件,类似:
- a6315922a026b4290b0b1cd54e95b25e93538047.md
- a6315922a026b4290b0b1cd54e95b25e93538047_zh.md
最后还要在这些 Markdown 文件里将这个 commit 对应的 Prompts 填进去,让大家看到这个效果:
真他喵不是人干的活。赶紧冲一杯咖啡提提神,搞不完今天下不了班了。
有事 GPT 干,没事干 GPT,有事 GPT 干,没事干 GPT,有事 GPT 干,没事干 GPT……
对呀,脏活累活,一律祭出 GPT!
2. 让 GPT-4 来写代码
直觉上这个任务适合用 Python 脚本来实现。不过我并不熟悉 Python,也就是说如果 GPT-4 给的 Python 代码能用,我就用。反之不能用,我就不得不自己用 Golang 来写了。
下文通过 DevChat 和 GPT-4 交互。DevChat 是一款开源的 VS Code 插件,默认对接 GPT-4,现在还在公测阶段,可以通过这个地址免费注册一个 key,然后不需要“ke xue 上网”就能用上 GPT-4 了。
关于 DevChat 的详细介绍欢迎跳转这篇文章:
2.1 我对 DevChat 说
如上图所示,在问这个问题的时候我加了一个“上下文”,也就是一行 Markdown 表格示例。
完整的问题如下:
我需要你写一个 python 脚本,脚本中要实现的功能是拉取GitHub上特定项目的Commit记录,然后写入本地特定文件中。
- 比如项目的 org 是 devchat-ai,name 是 gopool,那么你要找的项目是 https://github.com/devchat-ai/gopool
- 你要获取这个项目的main分支的所有 commits 历史,按照时间顺序依次写入本地的 devchat-ai/gopool/index.md 的中,但是你要考虑脚本重复执行需要幂等,所以你应该追加内容,而不是覆盖。
- 我已经将 index.md 的例子发给你,你不需要管里面的开头描述部分,只需要在文件后半部分的 Markdown 表格上操作。
2.2 DevChat 回答
要实现这个需求,我们需要做以下几步:
- 使用 GitHub API 来获取特定项目的 commit 历史记录。
- 解析 API 返回的数据,提取我们需要的信息,如 commit hash,author 等。
- 将这些信息以 Markdown 表格的形式追加到本地的 index.md 文件中。
这里有一个 Python 脚本的示例,它使用了 requests
库来发送 HTTP 请求,使用 pandas
库来处理和写入 Markdown 表格。如果你的环境中没有这两个库,你可以使用 pip 来安装它们:
pip install requests pandas
然后,你可以使用以下的 Python 脚本来实现你的需求:
import requests
import pandas as pd
from typing import Dict, List
def get_commits(org: str, repo: str) -> List[Dict[str, str]]:
url = f"https://api.github.com/repos/{org}/{repo}/commits"
response = requests.get(url)
response.raise_for_status()
commits = response.json()
return [
{
"Commit": commit["commit"]["message"],
"Commit Hash": commit["sha"],
"Author": commit["commit"]["author"]["name"],
}
for commit in commits
]
def append_commits_to_file(commits: List[Dict[str, str]], file_path: str) -> None:
df = pd.DataFrame(commits)
with open(file_path, "a") as f:
f.write(df.to_markdown(index=False))
def main():
org = "devchat-ai"
repo = "gopool"
file_path = "devchat-ai/gopool/index.md"
commits = get_commits(org, repo)
append_commits_to_file(commits, file_path)
if __name__ == "__main__":
main()
这个脚本首先从 GitHub API 获取 commit 历史记录,然后将这些记录追加到本地的 index.md 文件中。注意,这个脚本只会获取最近的 30 条 commit 记录,因为 GitHub API 的默认分页大小是 30。如果你需要获取更多的记录,你需要处理 API 的分页。
此外,这个脚本没有处理 API 的错误和异常,你可能需要根据你的需求来增加错误处理和异常处理的代码。
管它三七二十一,对着操作一波再说。运行后我得到了这个结果:
一口老血啊…… 克制,不动怒,继续“友好”沟通。
2.3 我又对 DevChat 说
hash 我只需要保留7位,Commit Message 只需要保留第一行。最后的结果需要是这样的:
| [Add GoPool and Worker structures](https://github.com/devchat-ai/gopool/commit/ee0b38ba85830d07046145583c2a568905d9839f) | ee0b38b | [Daniel Hu](https://github.com/daniel-hutao) | [Prompts with GPT](./commits/a6315922a026b4290b0b1cd54e95b25e93538047.md) | [给 GPT 的 Prompts](./commits/a6315922a026b4290b0b1cd54e95b25e93538047_zh.md) |
2.4 DevChat 的第二轮回答
了解了,我们需要对获取到的 commit 数据进行一些处理,以满足你的需求。具体来说,我们需要:
- 将 commit hash 截取为前 7 位。
- 只保留 commit message 的第一行。
- 生成 commit 的链接。
- 生成 commit 的作者的链接。
以下是修改后的 Python 脚本:
import requests
import pandas as pd
from typing import Dict, List
def get_commits(org: str, repo: str) -> List[Dict[str, str]]:
url = f"https://api.github.com/repos/{org}/{repo}/commits"
response = requests.get(url)
response.raise_for_status()
commits = response.json()
return [
{
"Commit": f"[{commit['commit']['message'].split('\n')[0]}](https://github.com/{org}/{repo}/commit/{commit['sha']})",
"Commit Hash": commit["sha"][:7],
"Author": f"[{commit['commit']['author']['name']}](https://github.com/{commit['author']['login']})",
"Prompts with GPT": f"[Prompts with GPT](./commits/{commit['sha']}.md)",
"给 GPT 的 Prompts": f"[给 GPT 的 Prompts](./commits/{commit['sha']}_zh.md)",
}
for commit in commits
]
def append_commits_to_file(commits: List[Dict[str, str]], file_path: str) -> None:
df = pd.DataFrame(commits)
with open(file_path, "a") as f:
f.write(df.to_markdown(index=False))
def main():
org = "devchat-ai"
repo = "gopool"
file_path = "devchat-ai/gopool/index.md"
commits = get_commits(org, repo)
append_commits_to_file(commits, file_path)
if __name__ == "__main__":
main()
这个脚本现在会生成你需要的 Markdown 表格,并将其追加到 index.md 文件中。
很快 DevChat 就给出了回答,不过这次的代码有语法错误:
一开始我就说了,我并不熟悉 Python。所以这里看似一个挺简单的错误,反正我改不来。所以,继续问 GPT-4 咯。
2.5 我再次对 DevChat 说
Escape sequence (backslash) not allowed in expression portion of f-string prior to Python 3.12
2.6 DevChat 回答
对不起,我犯了一个错误。在 f-string 表达式部分,我们不能使用反斜杠作为转义字符。在这种情况下,我们可以先将 commit message 分割成行,然后在 f-string 中使用第一行。以下是修改后的代码:
import requests
import pandas as pd
from typing import Dict, List
def get_commits(org: str, repo: str) -> List[Dict[str, str]]:
url = f"https://api.github.com/repos/{org}/{repo}/commits"
response = requests.get(url)
response.raise_for_status()
commits = response.json()
commit_data = []
for commit in commits:
commit_message_title = commit['commit']['message'].split('\n', 1)[0]
commit_data.append({
"Commit": f"[{commit_message_title}](https://github.com/{org}/{repo}/commit/{commit['sha']})",
"Commit Hash": commit["sha"][:7],
"Author": f"[{commit['commit']['author']['name']}](https://github.com/{commit['author']['login']})",
"Prompts with GPT": f"[Prompts with GPT](./commits/{commit['sha']}.md)",
"给 GPT 的 Prompts": f"[给 GPT 的 Prompts](./commits/{commit['sha']}_zh.md)",
})
return commit_data
def append_commits_to_file(commits: List[Dict[str, str]], file_path: str) -> None:
df = pd.DataFrame(commits)
with open(file_path, "a") as f:
f.write(df.to_markdown(index=False))
def main():
org = "devchat-ai"
repo = "gopool"
file_path = "devchat-ai/gopool/index.md"
commits = get_commits(org, repo)
append_commits_to_file(commits, file_path)
if __name__ == "__main__":
main()
这个脚本现在应该可以正常运行,生成你需要的 Markdown 表格,并将其追加到 index.md 文件中。
我再次运行了下这个代码,终于,表格出来了。
2.7 最后效果
后面我还继续聊了几轮,让 GPT-4 把本地创建表格中出现的 Markdown 文件的逻辑也加上了,所以最后我顺利的通过 Python 脚本生成了下图中的这个巨大无比的表格,以及对应的左侧五十多个 Markdown 文件。
Python 代码最终版本如下:
import os
import requests
import pandas as pd
from typing import Dict, List
def get_commits(org: str, repo: str) -> List[Dict[str, str]]:
url = f"https://api.github.com/repos/{org}/{repo}/commits"
response = requests.get(url)
response.raise_for_status()
commits = response.json()
commit_data = []
for commit in commits:
commit_message_title = commit['commit']['message'].split('\n', 1)[0]
commit_data.append({
"Commit": f"[{commit_message_title}](https://github.com/{org}/{repo}/commit/{commit['sha']})",
"Commit Hash": commit["sha"],
"Author": f"[{commit['commit']['author']['name']}](https://github.com/{commit['author']['login']})",
"Prompts with GPT": f"[Prompts with GPT](./commits/{commit['sha']}.md)",
"给 GPT 的 Prompts": f"[给 GPT 的 Prompts](./commits/{commit['sha']}_zh.md)",
})
return commit_data
def append_commits_to_file(commits: List[Dict[str, str]], file_path: str) -> None:
df = pd.DataFrame(commits)
df['Commit Hash'] = df['Commit Hash'].apply(lambda x: x[:7])
with open(file_path, "a") as f:
f.write(df.to_markdown(index=False))
def create_commit_files(commit: Dict[str, str], directory: str = "devchat-ai/gopool/commits") -> None:
"""
Create markdown files for each commit.
"""
for suffix in ["", "_zh"]:
file_path = os.path.join(directory, f"{commit['Commit Hash']}{suffix}.md")
if not os.path.exists(file_path):
with open(file_path, "w") as f:
f.write("")
def main():
org = "devchat-ai"
repo = "gopool"
file_path = "devchat-ai/gopool/index.md"
commits = get_commits(org, repo)
append_commits_to_file(commits, file_path)
for commit in commits:
create_commit_files(commit)
if __name__ == "__main__":
main()
3. 他们居然让我要写总结
那就总结一下吧。
今天挑战的是让 GPT-4 用我不熟悉的 Python 语言来完成一个自动化任务。
像这种大表格的编辑以及相应的50+个文件的创建,手动操作是很容易出错的,这类活天然适合交给 Python 脚本。不过放在以前,可能这种活我只能选择用自己熟悉的其他高级语言来完成,可以预见 Python 50 行代码对应的 Golang 估计得小100行了。100行啊,一杯水,一包烟,一个脚本写半天。不过现在可以让 GPT-4 来完成这类工作。
几轮“自然语言沟通”就搞定了,算下来可能花了不到30分钟,大约就是:0.5h VS 2.5h 吧。
又是 N 倍效率的一天,马克杯里的咖啡都还没凉,事情又干完了。呼…… 下班,等吃饭!