構(gòu)建 AI-powered TODO 應(yīng)用
人工智能TODO應(yīng)用程序演示https://ivan-tolkunov–surukoto-run.modal.run/(警告:該應(yīng)用程序可能需要長(zhǎng)達(dá)30秒才能啟動(dòng))。所有數(shù)據(jù)在不活動(dòng)5分鐘后重置。試著告訴它:“添加彩虹的每一種顏色”,然后“標(biāo)記所有提到綠色和紫色之間的待辦事項(xiàng)”和“清理完成的待辦事項(xiàng)。”
新的思考
每個(gè)人都在構(gòu)建TODO應(yīng)用程序,以便開(kāi)始使用編程語(yǔ)言或技術(shù)。我問(wèn)自己一個(gè)問(wèn)題:在人工智能時(shí)代,TODO應(yīng)用程序會(huì)是什么樣子?
所以我想出了一個(gè)主意,構(gòu)建一個(gè)TODO應(yīng)用程序,你可以簡(jiǎn)單地與之交談并給出指示。我從一個(gè)簡(jiǎn)單的用例開(kāi)始,告訴應(yīng)用程序“將牛奶添加到購(gòu)物清單中”。但后來(lái)我意識(shí)到,使用現(xiàn)代LLMs,我還可以讓?xiě)?yīng)用程序根據(jù)用戶命令檢查TODO項(xiàng)目或刪除它們。這個(gè)應(yīng)用程序使用起來(lái)真的很有趣!
它是一個(gè)簡(jiǎn)單的Django網(wǎng)絡(luò)應(yīng)用程序。模型非常簡(jiǎn)單:
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
然而,在后端,我有一個(gè)接受語(yǔ)音命令的端點(diǎn),而不是典型的CRUD(創(chuàng)建、讀取、更新、刪除)操作:
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'),
]
端點(diǎn)是使用簡(jiǎn)單的HTML音頻API從前端觸發(fā)的:
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();
};
當(dāng)用戶提交他們的音頻時(shí),我使用Whisper來(lái)轉(zhuǎn)錄它(使用 medium.en 模型在大小和理解我的英語(yǔ)能力之間取得良好平衡):
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應(yīng)用程序執(zhí)行操作
我不只是說(shuō)我想做什么,而是想告訴TODO應(yīng)用程序?yàn)槲易鍪隆@?,?dāng)我買牛奶時(shí),我想告訴應(yīng)用程序:“我買了牛奶”,并讓它為我核對(duì)待辦事項(xiàng)。
為了做到這一點(diǎn),我使用了一個(gè)預(yù)先訓(xùn)練過(guò)的LLM和一些巧妙的提示工程。
我最初的計(jì)劃是在本地運(yùn)行LLM。然而,由于圣誕節(jié)假期,我的時(shí)間很短,所以我現(xiàn)在決定使用托管版本。我絕對(duì)不想被OpenAI鎖定,所以我找到了一個(gè)強(qiáng)大的開(kāi)源模型( mixtral-8x7b-instruct ),并使用OpenRouter查詢托管版本。
這個(gè)想法的要點(diǎn)是:我有一個(gè)系統(tǒng)提示,向LLM解釋它的任務(wù)是管理TODO。作為輸出,我告訴模型我需要一個(gè)JSON格式的指令列表。指令可以是 add 、 complete 、 delete 和 error (當(dāng)不確定要做什么時(shí))。
首先,我使用OpenRouter聊天UI測(cè)試了一些提示。當(dāng)我對(duì)提示感到滿意時(shí),我用所需的數(shù)據(jù)進(jìn)行了一個(gè)簡(jiǎn)單的API調(diào)用
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"])
然后,根據(jù)響應(yīng),我讓它對(duì)數(shù)據(jù)庫(kù)執(zhí)行以下操作:
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})
這并不完美。主要問(wèn)題是它容易提示注入,即用戶可以告訴它做一些不應(yīng)該做的事情,作為TODO文本的一部分。我還注意到,它甚至可以將TODO的文本解釋為指令的一部分,而且事情變得非?;靵y。
但我很驚訝這一切的效果如此之好!
我能夠?yàn)槲业腡ODO應(yīng)用程序提供如下命令:
- 添加彩虹的每一種顏色
- 標(biāo)記所有提到綠色和紫色之間顏色的待辦事項(xiàng)
- clean up completed todos 清理已完成的待辦事項(xiàng)
- 現(xiàn)在我的TODO應(yīng)用程序擁有超能力!
與我的其他項(xiàng)目類似,我將該應(yīng)用程序部署到Modal.com,供每個(gè)人玩。它使用容器內(nèi)的本地SQLite數(shù)據(jù)庫(kù)和5分鐘 container_idle_timeout ,因此數(shù)據(jù)會(huì)在一段時(shí)間后重置。非常適合演示!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-806521.html
完整的源代碼可在https://github.com/ivan-tolkunov/surukoto.歡迎PR!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-806521.html
到了這里,關(guān)于在人工智能時(shí)代,Django + 簡(jiǎn)單的 HTML + Whisper + mixtral-8x7b-instruct + SQLite 實(shí)現(xiàn)了一個(gè) TODO應(yīng)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!