在人工智能时代,Django + 简单的 HTML + Whisper + mixtral-8x7b-instruct + SQLite 实现了一个 TODO应用

这里写自定义目录标题

  • 构建 AI-powered TODO 应用
    • 新的思考

构建 AI-powered TODO 应用

人工智能TODO应用程序演示https://ivan-tolkunov–surukoto-run.modal.run/(警告:该应用程序可能需要长达30秒才能启动)。所有数据在不活动5分钟后重置。试着告诉它:“添加彩虹的每一种颜色”,然后“标记所有提到绿色和紫色之间的待办事项”和“清理完成的待办事项。”
在人工智能时代,Django + 简单的 HTML + Whisper + mixtral-8x7b-instruct + SQLite 实现了一个 TODO应用_第1张图片

新的思考

每个人都在构建TODO应用程序,以便开始使用编程语言或技术。我问自己一个问题:在人工智能时代,TODO应用程序会是什么样子?
所以我想出了一个主意,构建一个TODO应用程序,你可以简单地与之交谈并给出指示。我从一个简单的用例开始,告诉应用程序“将牛奶添加到购物清单中”。但后来我意识到,使用现代LLMs,我还可以让应用程序根据用户命令检查TODO项目或删除它们。这个应用程序使用起来真的很有趣!
它是一个简单的Django网络应用程序。模型非常简单:

from   django.db import models

class Todo(models.Model):
    title = models.CharField(max_length=100)
    created_at = models.DateTimeField('Created', auto_now_add=True)
    update_at = models.DateTimeField('Updated', auto_now=True)
    isCompleted = models.BooleanField(default=False)

    def __str__(self):
        return self.title

然而,在后端,我有一个接受语音命令的端点,而不是典型的CRUD(创建、读取、更新、删除)操作:

from django.urls import path
from . import views 

app_name='todos'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('process-voice-command/', views.process_voice_command, name='process_voice_command'),
]

端点是使用简单的HTML音频API从前端触发的:

const recordButton = document.getElementById("record"); 
const recordButtonText = document.getElementById("record-text");

let recorder = null;

recordButton.onclick = async () => {
  if (recorder) {
    recorder.stop();
    recorder = null;
    return;
  }

  const chunks = [];
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });

  recorder = new MediaRecorder(stream);
  recorder.ondataavailable = (e) => chunks.push(e.data);
  recorder.onstop = async () => {
    const blob = new Blob(chunks, { type: "audio/webm;" });
    const formData = new FormData();
    formData.append("audio_file", blob, "voice-command.webm");
    const response = await fetch("/todos/process-voice-command/", {
      method: "POST",
      body: formData,
    });
    window.location.reload();
  };

  recorder.start();
};

当用户提交他们的音频时,我使用Whisper来转录它(使用 medium.en 模型在大小和理解我的英语能力之间取得良好平衡):

def process_voice_command(request):
    audio_file = request.FILES.get('audio_file', None)
    file_name = default_storage.save(voice.name, voice)
    try:
        audio = whisper.load_audio(MEDIA_ROOT + file_name)
        audio = whisper.pad_or_trim(audio)
        result = self.model.transcribe(MEDIA_ROOT + file_name)
        text = result["text"].strip()
        Todo.objects.create(title=text)
    finally:
        default_storage.delete(file_name)

使用LLM使TODO应用程序执行操作
我不只是说我想做什么,而是想告诉TODO应用程序为我做事。例如,当我买牛奶时,我想告诉应用程序:“我买了牛奶”,并让它为我核对待办事项。
为了做到这一点,我使用了一个预先训练过的LLM和一些巧妙的提示工程。
我最初的计划是在本地运行LLM。然而,由于圣诞节假期,我的时间很短,所以我现在决定使用托管版本。我绝对不想被OpenAI锁定,所以我找到了一个强大的开源模型( mixtral-8x7b-instruct ),并使用OpenRouter查询托管版本。
这个想法的要点是:我有一个系统提示,向LLM解释它的任务是管理TODO。作为输出,我告诉模型我需要一个JSON格式的指令列表。指令可以是 add 、 complete 、 delete 和 error (当不确定要做什么时)。
首先,我使用OpenRouter聊天UI测试了一些提示。当我对提示感到满意时,我用所需的数据进行了一个简单的API调用

def get_command(self, text):  
 response = requests.post(
     url="https://openrouter.ai/api/v1/chat/completions",
     headers= {
         "Authorization" : f"Bearer {os.environ['OPENROUTER_KEY']}"
     },
     data=json.dumps({
         "model": "mistralai/mixtral-8x7b-instruct",
         "messages": [
             {"role": "system", "content": self.prompt + self.todo_to_string()},
             {"role": "user", "content": text},
         ]
     })
 )
 print(response.json()["choices"][0]["message"]["content"])
 return json.loads(response.json()["choices"][0]["message"]["content"])

然后,根据响应,我让它对数据库执行以下操作:

def process_voice_command(request):
    audio_file = request.FILES.get('audio_file', None)
    text = util.get_voice_text(audio_file)
    commands = util.get_command(text)
    for command in commands:
        action = command['action']
        if action == "add":
            util.add(command['text'])
        elif action == "complete":
            util.complete(command['task_id'])
        elif action == "delete":
            util.delete(command['task_id'])
        elif action == "error":
            messages.add_message(request, messages.ERROR, command['text'])
        else:
            print(f"Unknown action: {action}")

    return JsonResponse({'success': True}) 

这并不完美。主要问题是它容易提示注入,即用户可以告诉它做一些不应该做的事情,作为TODO文本的一部分。我还注意到,它甚至可以将TODO的文本解释为指令的一部分,而且事情变得非常混乱。
但我很惊讶这一切的效果如此之好!
我能够为我的TODO应用程序提供如下命令:

 - 添加彩虹的每一种颜色
 - 标记所有提到绿色和紫色之间颜色的待办事项
 - clean up completed todos 清理已完成的待办事项
 - 现在我的TODO应用程序拥有超能力!

与我的其他项目类似,我将该应用程序部署到Modal.com,供每个人玩。它使用容器内的本地SQLite数据库和5分钟 container_idle_timeout ,因此数据会在一段时间后重置。非常适合演示!

完整的源代码可在https://github.com/ivan-tolkunov/surukoto.欢迎PR!

你可能感兴趣的:(sqlite,人工智能,django,javascript,whisper,html)