将上图内容转为下面的代码,大家会怎么处理呢,手搓?
export const feeItemsOptions = [
{ value: 1, label: "物业费" },
{ value: 2, label: "供暖费" },
{ value: 3, label: "水费" },
{ value: 4, label: "电费" },
{ value: 5, label: "燃气费" },
{ value: 6, label: "有线电视费" },
{ value: 7, label: "网络通讯费" },
{ value: 8, label: "车位管理费" },
{ value: 9, label: "其他" },
];
export const feeItemsMap = feeItemsOptions.reduce((obj, { label, value }) => {
obj[value] = label;
return obj;
}, {});
ChatGPT 没出来之前,我们确实只能选择手搓。有了 ChatGPT 之后,我们可以让 ChatGPT 帮我们生成对象数组数据,prompt 可以是如下内容:
1物业费 2供暖费 3水费 4电费 5燃气费 6有线电视费 7网络通讯费 8车位管理费 9~其他
将上述文本转成 value、label 字段的对象数组,value 字段为整数类型,返回 json 格式数据
ChatGPT 返回内容如下:
这个结果已经符合我们的预期,只需要将生成的 json 复制粘贴就行了,已经极大的增加了摸鱼时间。
所以现在我们要完成文章开头所要求的代码,步骤是这样的,写好变量名:
export const xxxOptions = []
export const xxxMap = xxxOptions.reduce((obj, { label, value }) => {
obj[value] = label;
return obj;
}, {});
这部分代码,更多的时候是复制粘贴以前写好的代码
然后是复制接口文档的内容,粘贴到 ChatGPT 输入框中,将 prompt 补充完整,按下回车。复制 ChatGPT 返回的 json 粘贴到代码中。
整个流程下来,充满了复制粘贴的步骤,重复几次之后大部分人都会觉得无聊吧。所以在 ChatGPT API 开放调用的时候,我第一时间就以 vscode 插件的形式接入了,那已经是一年以前的事情了,感兴趣的可以查看我之前的文章。实现效果如下
可以看到,生成代码的过程中,选择了一个叫做生成 value-label 格式 JSON 的菜单,这是我在 vscode 插件里实现的管理 prompt 模板(或者叫代码片段也行)的方式,我之前的文章中也有专门介绍过。
最终的 prompt 是经过优化的,之前的 prompt ,ChatGPT 会在响应中添加无关紧要的内容,如下:
我们需要的只是 json 数据,当然你可以通过编码的形式将 json 部分内容匹配出来。
一种更加优秀的方式是通过 TS 类型去强化 ChatGPT 的应答质量,这个方案来自 TypeChat, 我之前的文章也有介绍过,最终的 prompt 如下:
You are a service that translates user requests into JSON objects of type "IOption" according to the following TypeScript definitions:
'''
export type IOption = { value: string; label: string }[];
'''
The following is a user request:
'''
1-电费,2-水费,3-煤气费,4-电视费,5-电话费,6-上网费,7-车位费,8-供暖费,9-物业费,10-其它
'''
The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:
生成结果如下,只有 json 数据,没有多余的废话:
上述功能去年的时候就已经在 vscode 插件里实现了,也写文章简单介绍过,为什么现在还要写这篇文章呢?
因为我在 uTools 插件里又实现了一遍。主要还是因为 vscode 插件的适用场景有限,只能在 vscode 里使用,而 uTools 插件几乎能在所有场景下做到随用随开,用完就关。以生成上面代码为例,效果如下:
uTools 插件也有不足的地方,就是无法获取到当前选中的文本,所以需要在生成代码之前手动输入变量名,而 vscode 插件中是先打出变量名然后选中就行。
uTools 中管理 prompt 模板(代码片段),我没有去重复造轮子,而是使用 uTools 的官方插件 “自动化脚本” 。在脚本的管理上做了功夫,比如以 TypeScript 编写脚本,实现脚本自动导入及更新。下面是本文例子中的脚本代码:
import path from 'path';
import fs from 'fs';
import { clipboard } from 'electron';
import { validate } from '@share/TypeChatSlim/utools';
import { compile as compileEjs } from '@share/utils/ejs';
import {
askChatGPT as askOpenai,
getBlockConfigPath,
getBlockJsonValidSchema,
} from '@share/utils/uTools';
export const bootstrap = async (scriptFile?: string) => {
const schema = getBlockJsonValidSchema(scriptFile!);
const clipboardText =
(clipboard.readText() || '').trim() ||
'客户验收状态:1.无需验收、2.待验收、3已验收';
const typeName = 'IOption';
const requestPrompt =
`You are a service that translates user requests into JSON objects of type "${typeName}" according to the following TypeScript definitions:\n` +
`\`\`\`\n${schema}\`\`\`\n` +
`The following is a user request:\n` +
`"""\n${clipboardText}\n"""\n` +
`The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\n`;
utools.redirect(['lowcode', 'lowcode'], {
type: 'text',
data: JSON.stringify({
scriptFile,
route: '/chat',
content: requestPrompt,
}),
});
};
type LLMMessage = (
| {
role: 'system';
content: string;
}
| {
role: 'user';
content:
| string
| (
| {
type: 'image_url';
image_url: { url: string };
}
| { type: 'text'; text: string }
)[];
}
)[];
// 给页面调用的
export const askChatGPT = async (data: {
messages: LLMMessage;
handleChunk: (chunck: string) => void;
scriptFile: string;
}) => {
const configPath = getBlockConfigPath(data.scriptFile);
const schema = getBlockJsonValidSchema(data.scriptFile);
const template = fs.readFileSync(
path.join(configPath, 'template.ejs'),
'utf8',
);
const typeName = 'IOption';
if (
data.messages.length >= 3 &&
(data.messages[data.messages.length - 1].content as string).includes('>>>')
) {
const name = (data.messages[data.messages.length - 1].content as string)
.split('>>>')[1]
.trim();
const jsonValid = validate(
data.messages[data.messages.length - 2].content as string,
schema,
typeName,
);
if (jsonValid.success) {
setTimeout(() => {
const code = compileEjs(template, {
rawSelectedText: name || '请手动修改名称',
content: JSON.stringify(jsonValid.data),
} as any);
clipboard.writeText(code);
utools.outPlugin();
utools.hideMainWindowPasteText(code);
}, 300);
} else {
data.handleChunk(`
> 生成代码时 JSON 校验不通过
${jsonValid.message}
`);
}
return '';
}
const content = await askOpenai({
messages: data.messages,
handleChunk: data.handleChunk,
});
const valid = validate(content.content, schema, typeName);
if (valid.success) {
data.handleChunk(`
JSON 校验通过,输入\`>>>\`生成代码
`);
} else {
data.handleChunk(`
> JSON 校验不通过
${valid.message}
`);
}
return content;
};
uTools 中选中命令后执行 bootstrap 方法,内部逻辑是获取剪贴板中的内容,拼接好 prompt, 调用另一个 uTools 插件,并且将 prompt 传过去。
被调起的 uTools 插件其实就是一个支持 LLM 会话的网页,接收到 prompt 后自动调用askChatGPT 方法。
不管是 vscode 插件还是 uTools 插件,都有好的地方和不足之处,所以工作中两者结合着使用更加事半功倍。