a simple intent detection implementaion

This commit is contained in:
yzlin 2024-04-02 18:05:26 +08:00
parent 5e34038831
commit bceccdfff3
2 changed files with 189 additions and 0 deletions

View file

@ -0,0 +1,134 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
This script is designed to classify intentions from complete conversation content.
Usage:
This script can be used to classify intentions from a conversation. It utilizes models for detecting intentions
from the text provided and categorizes them accordingly. If the intention of certain words or phrases is unclear,
it prompts the user for clarification.
Dependencies:
This script depends on the metagpt library, pydantic, and other utilities for message parsing and interaction.
"""
from __future__ import annotations
import asyncio
from enum import Enum
from typing import Tuple
from pydantic import BaseModel
from metagpt.actions import Action
class SOPItemDef(BaseModel):
"""
Represents an item in a Standard Operating Procedure (SOP).
Attributes:
name (str): name of the SOP item.
description (str): The description or title of the SOP.
sop (List[str]): The steps or details of the SOP.
"""
name: str
description: str
sop: list[str] = []
class SOPItem(Enum):
SOFTWARE_DEVELOPMENT = SOPItemDef(
name="software development",
description="Intentions related to or including software development, such as developing or building software, games, app, websites, etc. Excluding bug fixes, report any issues.",
sop=[
"Writes a PRD based on software requirements.",
"Writes a design to the project repository, based on the PRD of the project.",
"Writes a project plan to the project repository, based on the design of the project.",
"Writes code to implement designed features according to the project plan and adds them to the project repository.",
# "Run QA test on the project repository.",
"Stage and commit changes for the project repository using Git.",
],
)
FIX_BUGS = SOPItemDef(
name="fix bugs",
description="Fix bugs in a given project.",
sop=[
"Fix bugs in the project repository.",
"Stage and commit changes for the project repository using Git.",
],
)
FORMAT_REPO = SOPItemDef(
name="format repo",
description="download repository from git and format the project to MetaGPT project",
sop=[
"Imports a project from a Git website and formats it to MetaGPT project format to enable incremental appending requirements.",
"Stage and commit changes for the project repository using Git.",
],
)
OTHER = SOPItemDef(
name="other",
description="Other intentions that do not fall into the above categories, including data science, machine learning, deep learning, etc.",
sop=[],
)
@property
def type_name(self):
return self.value.name
@classmethod
def get_type(cls, type_name):
for member in cls:
if member.type_name == type_name:
return member.value
return None
DETECT_PROMPT = """
# User Requirement
{user_requirement}
# Intentions
{intentions}
# Task
Classify user requirement into one type of the above intentions, output the name of the intention directly.
Intention name:
"""
REQ_WITH_SOP = """
{user_requirement}
You should follow the following Standard Operating Procedure:
{sop}
"""
class DetectIntent(Action):
async def run(self, user_requirement: str) -> Tuple[str, str]:
intentions = "\n".join([f"{si.type_name}: {si.value.description}" for si in SOPItem])
prompt = DETECT_PROMPT.format(user_requirement=user_requirement, intentions=intentions)
sop_type = await self._aask(prompt)
sop_type = sop_type.strip()
sop = SOPItem.get_type(sop_type).sop
req_with_sop = (
REQ_WITH_SOP.format(user_requirement=user_requirement, sop="\n".join(sop)) if sop else user_requirement
)
return req_with_sop, sop_type
async def main():
# Example usage of the DetectIntent action
user_requirements = ["Develop a 2048 game.", "Run data analysis on sklearn wine dataset"]
detect_intent = DetectIntent()
for user_requirement in user_requirements:
req_with_sop, sop_type = await detect_intent.run(user_requirement)
print(req_with_sop)
print(f"Detected SOP Type: {sop_type}")
if __name__ == "__main__":
asyncio.run(main())

View file

@ -0,0 +1,55 @@
import pytest
from metagpt.actions.di.detect_intent import DetectIntent
SOFTWARE_DEV_REQ1 = """
I'd like to create a personalized website that features the 'Game of Life' simulation.
"""
SOFTWARE_DEV_REQ2 = """
Create a website widget for TODO list management.
"""
SOFTWARE_DEV_REQ3 = """
Create an official website with a top bar, banner, About Us section, and footer.
"""
DI_REQ1 = """
can you finetune a 78 Llama model using https://github.com/huggingface/peft should be instructions in the Readme.
"""
DI_REQ2 = """
I came across a blog post on the website Mafengwo (https://www.mafengwo.cn/i/17171539.html) that discusses the possibility of generating images with hidden text. The post refers to a script that can be used for this purpose. Could you help me set up this script and use it to generate some images? I would like the images to have the hidden text 'MAX' and also some with 'MetaGPT' as the hidden text.
"""
DI_REQ3 = """
Extract all of the blog posts from `https://stripe.com/blog/page/1` and return a CSV with the columns `date`, `article_text`, `author` and `summary`. Generate a summary for each article yourself.
"""
FIX_BUG_REQ = """
Fix this error from the 2048 game repo: TypeError: __init__() takes 1 positional argument but 2 were given"
"""
FORMAT_REPO_REQ = """
git clone 'https://github.com/spec-first/connexion' and format to MetaGPT project
"""
@pytest.mark.asyncio
@pytest.mark.parametrize(
"requirement, expected_intent_type",
[
(SOFTWARE_DEV_REQ1, "software development"),
(SOFTWARE_DEV_REQ2, "software development"),
(SOFTWARE_DEV_REQ3, "software development"),
(DI_REQ1, "other"),
(DI_REQ2, "other"),
(DI_REQ3, "other"),
(FIX_BUG_REQ, "fix bugs"),
(FORMAT_REPO_REQ, "format repo"),
],
)
async def test_detect_intent(requirement, expected_intent_type):
di = DetectIntent()
_, intent_type = await di.run(requirement)
assert intent_type == expected_intent_type