大数跨境
0
0

《万物皆可 LLM》004:LangChain 自定义工具生成色板来制作 PPT 主题

《万物皆可 LLM》004:LangChain 自定义工具生成色板来制作 PPT 主题 数翼
2023-08-24
0
导读:上回说到怎么自定义 LangChain 的工具,今天正好做 PPT,图片配色成了个问题。 秉承 万事万物皆可 LLM 的原则,颜色啥的必须让 LLM 搞定。

PS:之前系列名字『AI 开发实战』总感觉像是买课的,还是 9.9 那种,所以之后系列合集名字更新成:《万物皆可 LLM》

上回说到怎么自定义 LangChain 的工具,今天正好做 PPT,图片配色成了个问题。 秉承 万事万物皆可 LLM 的原则,颜色啥的必须让 LLM 搞定。

先看结果:

可以实现指定颜色生成色板,比如提问:

生成 #8A2BE2 的色板

也可以支持描述颜色生成,比如提问:

生成淡蓝色色板
or
中国传统颜色水红色色板
or
活泼可爱一点的颜色色板
根据描述生成色板

当然描述颜色生成色板可能一下子达不到预期,比如:

更复杂的描述

可以先让 GPT 生成一些颜色,再挑选喜欢的颜色生成,

推荐颜色

然后指定 RGB 生成:

RGB色板

UI 改动

UI 也有两个改动 :

  • • 增加了工具栏,可以点击切换当前使用那些工具

  • • 消息实现了颜色解析,虽然还有点儿小 Bug,无伤大雅

接下来看怎么实现。

后端

后端的流程从入口开始讲,好理解一点。

定义接口

先约定 API 结构,我们使用 POST 格式传递数据,定义三个参数:

  • • llm:使用哪个大语言模型

  • • prompt:对话提示语

  • • tools:启用的工具

这三个参数都是前端传递过来的,代码如下:

class Prompt(BaseModel):
    llm: str
    prompt: str
    tools: list = []

处理工具

工具的话我们使用 LangChain 的 agent 加载,由于接口参数不允许0工具调用,我们简单粗暴的判断一下,如果客户端选择了工具就是用 agent, 如果没有选择工具就直接对话:

@app.post("/chat/")
async def create_item(item: Prompt):
    llm = llms[item.llm]

    logger.info('Prompt: ' + item.prompt)
    tool = [tools.get(x) for x in item.tools if tools.__contains__(x)]

    if tool:
        agent = initialize_agent(tool, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
        answer = agent.run(item.prompt)
        logger.info(answer)
        return {
            'content': answer,
            'llm': item.llm
        }
    else:
        messages = [
            SystemMessage(content="简单回答,使用中文"),
            HumanMessage(content=item.prompt)
        ]
        answer = llm(messages).content
        logger.info(answer)
        return {
            'content': answer,
            'llm': item.llm
        }

llms 实现

我们把 llm 重构到单独模块,让代码清晰一点:

claude = ChatClaude()
openai = ChatOpenAI()
bard = ChatBard()

llms = {
    "claude": claude,
    "openai": openai,
    "bard": bard
}

tools 实现

同样,tools 也重构到单独模块,使用的地方可以根据 key 选择,不用关心实现:

tools = {
    'colors': ColorTool(),
    'random-color': RandomColorTool(),
    'balabala': Balabala()
}

colors tool 实现

实现色板的代码并无新意,根据 HSL 明度和保护度递增递减。

我这版本实现的比较粗糙,想让变化曲线更平滑一点,但是值去的并不好,后面有时间用其他曲线来替换正弦曲线。

RGB 颜色 和 HSL 颜色的转换可以用下面函数实现:

colorsys.rgb_to_hls
colorsys.hls_to_rgb

生成五个浅色,默认输入颜色为第六个颜色(主色),如果输入颜色饱和明暗不够,最终的色板可能会有多个黑色或者白色。

浅色生成:

# 浅色
count = 5
for i in range(count):
    h -= hue_step
    l -= math.sin(light_step) * (i + 1) / (count + 3)
    s += math.sin(sat_step) * i / 20
    if l < 0:
        print('l=0')
        l = 0
    if s > 1:
        print('s=1')
        s = 1
    colors.insert(0, colorsys.hls_to_rgb(h, l, s))

同样再生成四个深色:

for i in range(count):
    h += hue_step
    l += math.sin(light_step) * (i + 1) / (count)
    s -= math.sin(sat_step) * i / 20
    if l > 1:
        print('l=1')
        l = 1
    if s < 0:
        print('s=0')
        s = 0
    color_scale.append(colorsys.hls_to_rgb(h, l, s))

LangChain Tool 实现

实现 Tool 和上文讲的一样,我这里提示写了好几个版本,效果有些差别但是差别不大。

中英文提示也有差异,但是 LLM 一般都是翻译成英文执行的,所以测试下来中文写还是英文写 LLM 自动翻译成英文之后也大差不差。

class ColorsTool(BaseTool):
    name = "colors"
    # description = "当需要生成色卡的时候,请使用它,输入的参数是一个十六进制的 RGB 颜色,比如 #FFFFFF,输出一个RGB颜色数组。"
    # description = "色卡或者色板生成的任务是请使用它,输入的参数是一个十六进制的 RGB 颜色,如果输入不是十六进制的 RGB 颜色,需要先转换成十六进制 RGB 颜色再使用该工具"
    # 任务是色卡或者色板生成时请使用该工具,输入需要是一个十六进制的颜色值,请先转换成十六进制格式后再调用。
    #
    description = "Use this tool when the task is to generate a color palette. The input should be a hexadecimal color value or the color name or descirption"
    return_direct = True

    def _run(self, rgb_hex: str, run_manager: Optional[CallbackManagerForToolRun] = None) -> str:
        r, g, b = hex_to_rgb(rgb_hex)
        hls = colorsys.rgb_to_hls(r / 255.0, g / 255.0, b / 255.0)
        pallet = generate_color_scale(hls, 0.020.20.1)
        pallet = [rgbscale_to_hex(x) for x in pallet]
        # return json.dumps(pallet)
        return ' '.join(pallet)

    async def _arun(self, url: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None, ) -> str:
        raise NotImplementedError("暂不支持异步")

前端

前端使用 Marked 实现了 Markdown 的解析,这次也加上了 颜色解析(颜色和背景是同一个颜色,选中之后就可以看到了)。

选择颜色

Vue 和 TS 代码,大家也不爱看就不贴了。

后记

说话间,又接到了个活:要负责公司 Gitlab 账号审批创建,继续开搞,明天见。


【声明】内容源于网络
0
0
数翼
专注 AIGC 人工智能知识传播和实践
内容 228
粉丝 0
数翼 专注 AIGC 人工智能知识传播和实践
总阅读13
粉丝0
内容228