Python练习——通过ExAPI让Live2DViewerEx接入kimi

今天突然发现发现Live2DViewerEx提供了api,于是便有了这么个有趣的小练习。

前置准备

pip install websocket-client
pip install openai

发送消息

根据ExAPI的说法,如果想要给桌宠发消息,只需要通过WebSocket向指定端口(通常是本地的10086端口)发送一个JSON。
于是我们先写一个函数用来发送消息:

def send_json_message(json_message: str):
    # 通信
    uri = "ws://127.0.0.1:10086/api"
    data = {
        "msg": 11000,
        "msgId": 1,
        "data": {
            "id": 0,
            "text": json_message,
        "textFrameColor": 0x000000,
        "textColor": 0xFFFFFF,
        "duration": 3000
        }
    }

    # 尝试发出json消息
    try:
        ws = create_connection(uri)
        ws.send(json.dumps(data))
    except Exception as e:
        print("发送错误:", str(e))

uri是指向的地址,data是发送的数据。在这里,data虽然是字典,但通过json.dumps()转换为json数据格式。这里data是[11000](显示气泡文本)。所以这个函数向本地10086端口发送了一个包含json_message的json。


接下来,我们需要接入kimi了

接入Kimi

参考Kimi API

准备system_prompt

这个相当于先塑造ai的初始人设。为了方便后期更改,这里我们把初始人设放入一个txt文本,再让程序读取:

# 读取小米塔预设
file_path = "prompt.txt"
try:
    with open(file_path, "r", encoding="utf-8") as file:
        system_prompt = file.read()
except FileNotFoundError:
    print(f"读取文件错误:文件 {file_path} 未找到。")
except Exception as e:
    print(f"读取文件错误:{e}")

# 预设信息
system_messages = [
    {"role": "system", "content": system_prompt},
]

接入Kimi api

# 调用kimi api
client = OpenAI(
    api_key="",  # kimi api密钥
    base_url="https://api.moonshot.cn/v1",
)

准备多轮对话需要的message

因为我们想要让Kimi记住我们说了什么,所以需要准备多轮对话。
参考kimi官方的代码:

# 聊天记录
messages = []

# 限制记忆消息数小于等于10条
def make_new_messages(input: str , n: int = 10) -> list[dict]:
    # 先将input内容加入到messages
    global messages
    messages.append({
        "role": "user",
        "content": input
    })

    # 创建新消息列表
    new_messages = []
    new_messages.extend(system_messages)

    # 处理messages,保留小于等于10条消息到new_messages里
    if len(messages) > n:
        messages = messages[-n:]
    new_messages.extend(messages)
    return new_messages

这段代码在Kimi API详细解释过了,这里我就不在赘述。简单来说,就是通过messages = messages[-n:]让每次对话发送的new_messages只“记住”messages的最近十条,当然system_prompt肯定包含。

对话函数

准备结束,开始对话!

# 小米塔的聊天函数
def chat(input: str) -> str:
    # 携带 messages 与 小米塔(Kimi 大模型)对话
    completion = client.chat.completions.create(
        model="moonshot-v1-8k",  # 选择模型为moonshoot-v1-8k
        messages=make_new_messages(input),
        temperature=0.3,
    )

    # 通过 API 获得 Kimi 大模型的回复消息(role=assistant)
    mita_message = completion.choices[0].message.content

    # 保证记忆完整,将回复mita_message加入messages
    messages.append({
        "role": "assistant",
        "content": mita_message
    })

    # 返回消息
    return mita_message

这段代码也在Kimi API详细解释过了。
但这要注意一点,在加入回复时,官方代码似乎有问题:

# 通过 API 我们获得了 Kimi 大模型给予我们的回复消息(role=assistant)
assistant_message = completion.choices[0].message

# 为了让 Kimi 大模型拥有完整的记忆,我们必须将 Kimi 大模型返回给我们的消息也添加到 messages 中
messages.append(assistant_message)

一直报错,显示messages格式不对。由于我也不清楚其中细节,所以直接简单粗暴的把回复手动加上去了,效果还行。


到这里,程序的主体部分就写好了。

完整代码

我们把对话写到一个死循环里,同时拼装一下以上代码:

import json
from websocket import create_connection
from openai import OpenAI

# 读取小米塔预设
file_path = "prompt.txt"
try:
    with open(file_path, "r", encoding="utf-8") as file:
        system_prompt = file.read()
except FileNotFoundError:
    print(f"错误:文件 {file_path} 未找到。")
except Exception as e:
    print(f"读取文件时发生错误:{e}")

# 调用kimi api
client = OpenAI(
    api_key="",  # kimi api密钥
    base_url="https://api.moonshot.cn/v1",
)

# 预设信息
system_messages = [
    {"role": "system", "content": system_prompt},
]

# 聊天记录
messages = []

# 限制记忆消息数小于等于10条
def make_new_messages(input: str , n: int = 10) -> list[dict]:
    # 先将input内容加入到messages
    global messages
    messages.append({
        "role": "user",
        "content": input
    })

    # 创建新消息列表
    new_messages = []
    new_messages.extend(system_messages)

    # 处理messages,保留小于等于10条消息到new_messages里
    if len(messages) > n:
        messages = messages[-n:]
    new_messages.extend(messages)
    return new_messages

#给小米塔发json格式的消息,通过Live2DViewerEX api [11000]
def send_json_message(json_message: str):
    # 通信
    uri = "ws://127.0.0.1:10086/api"
    data = {
        "msg": 11000,
        "msgId": 1,
        "data": {
            "id": 0,
            "text": json_message,
        "textFrameColor": 0x000000,
        "textColor": 0xFFFFFF,
        "duration": 3000
        }
    }

    # 尝试发出json消息
    try:
        ws = create_connection(uri)
        ws.send(json.dumps(data))
    except Exception as e:
        print("错误:", str(e))

# 小米塔的聊天函数
def chat(input: str) -> str:
    # 携带 messages 与 小米塔(Kimi 大模型)对话
    completion = client.chat.completions.create(
        model="moonshot-v1-8k",  # 选择模型为moonshoot-v1-8k
        messages=make_new_messages(input),
        temperature=0.3,
    )

    # 通过 API 获得 Kimi 大模型的回复消息(role=assistant)
    mita_message = completion.choices[0].message.content

    # 保证记忆完整,将回复mita_message加入messages
    messages.append({
        "role": "assistant",
        "content": mita_message
    })

    # 返回消息
    return mita_message

# 死循环,一直重复对话
while True:
    try:
        saying = input("Player:")
        if saying == "exit loop":
            break
        send_json_message(chat(saying))
    except Exception as e:
        print(f"kimi出现错误:{e}")
上一篇
下一篇