Correct the use of abstractmethod (#80)

* Correct abstractmethod usage

* Update interface

* Specify minimal llama-index version [ignore cache]

* Update examples
This commit is contained in:
Nguyen Trung Duc (john) 2023-11-20 11:18:53 +07:00 committed by GitHub
parent 98509f886c
commit 0a3fc4b228
12 changed files with 33 additions and 37 deletions

View File

@ -22,4 +22,4 @@ try:
except ImportError: except ImportError:
pass pass
__version__ = "0.3.1" __version__ = "0.3.2"

View File

@ -1,9 +1,9 @@
from abc import abstractmethod from abc import abstractmethod
from theflow.base import Compose from theflow.base import Function
class BaseComponent(Compose): class BaseComponent(Function):
"""A component is a class that can be used to compose a pipeline """A component is a class that can be used to compose a pipeline
Benefits of component: Benefits of component:

View File

@ -2,7 +2,7 @@ from abc import abstractmethod
from typing import List, Optional from typing import List, Optional
from langchain.schema.messages import AIMessage, SystemMessage from langchain.schema.messages import AIMessage, SystemMessage
from theflow import Param, SessionCompose from theflow import SessionFunction
from ..base import BaseComponent from ..base import BaseComponent
from ..base.schema import LLMInterface from ..base.schema import LLMInterface
@ -20,7 +20,7 @@ def session_chat_storage(obj):
return obj._store_result return obj._store_result
class ChatConversation(SessionCompose): class ChatConversation(SessionFunction):
"""Base implementation of a chat bot component """Base implementation of a chat bot component
A chatbot component should: A chatbot component should:
@ -31,7 +31,7 @@ class ChatConversation(SessionCompose):
class Config: class Config:
store_result = session_chat_storage store_result = session_chat_storage
system_message: Param[str] = Param(default="") system_message: str = ""
bot: BaseChatBot bot: BaseChatBot
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

View File

@ -1,5 +1,3 @@
from theflow import Node
from ..llms import ChatLLM from ..llms import ChatLLM
from .base import BaseChatBot from .base import BaseChatBot
@ -7,7 +5,7 @@ from .base import BaseChatBot
class SimpleRespondentChatbot(BaseChatBot): class SimpleRespondentChatbot(BaseChatBot):
"""Simple text respondent chatbot that essentially wraps around a chat LLM""" """Simple text respondent chatbot that essentially wraps around a chat LLM"""
llm: Node[ChatLLM] llm: ChatLLM
def _get_message(self) -> str: def _get_message(self) -> str:
return self.llm(self.history).text return self.llm(self.history).text

View File

@ -1,7 +1,7 @@
import inspect import inspect
from collections import defaultdict from collections import defaultdict
from theflow.utils.documentation import get_compose_documentation_from_module from theflow.utils.documentation import get_function_documentation_from_module
def from_definition_to_markdown(definition: dict) -> str: def from_definition_to_markdown(definition: dict) -> str:
@ -38,7 +38,7 @@ def from_definition_to_markdown(definition: dict) -> str:
def make_doc(module: str, output: str, separation_level: int): def make_doc(module: str, output: str, separation_level: int):
"""Run exporting from compose to markdown """Run exporting components to markdown
Args: Args:
module (str): module name module (str): module name
@ -46,7 +46,7 @@ def make_doc(module: str, output: str, separation_level: int):
separation_level (int): level of separation separation_level (int): level of separation
""" """
documentation = sorted( documentation = sorted(
get_compose_documentation_from_module(module).items(), key=lambda x: x[0] get_function_documentation_from_module(module).items(), key=lambda x: x[0]
) )
entries = defaultdict(list) entries = defaultdict(list)

View File

@ -1,10 +1,10 @@
from copy import deepcopy from copy import deepcopy
from typing import List from typing import Callable, List
from theflow import Compose, Node, Param from theflow import Function, Node, Param
from kotaemon.base import BaseComponent from kotaemon.base import BaseComponent
from kotaemon.llms import BasePromptComponent from kotaemon.llms import LLM, BasePromptComponent
from kotaemon.llms.chats.openai import AzureChatOpenAI from kotaemon.llms.chats.openai import AzureChatOpenAI
@ -64,15 +64,13 @@ class Thought(BaseComponent):
is created. is created.
""" """
prompt: Param[str] = Param( prompt: str = Param(
help="The prompt template string. This prompt template has Python-like " help="The prompt template string. This prompt template has Python-like "
"variable placeholders, that then will be subsituted with real values when " "variable placeholders, that then will be subsituted with real values when "
"this component is executed" "this component is executed"
) )
llm: Node[BaseComponent] = Node( llm: LLM = Node(AzureChatOpenAI, help="The LLM model to execute the input prompt")
AzureChatOpenAI, help="The LLM model to execute the input prompt" post_process: Function = Node(
)
post_process: Node[Compose] = Node(
help="The function post-processor that post-processes LLM output prediction ." help="The function post-processor that post-processes LLM output prediction ."
"It should take a string as input (this is the LLM output text) and return " "It should take a string as input (this is the LLM output text) and return "
"a dictionary, where the key should" "a dictionary, where the key should"
@ -139,11 +137,11 @@ class ManualSequentialChainOfThought(BaseComponent):
returns False. returns False.
""" """
thoughts: Param[List[Thought]] = Param( thoughts: List[Thought] = Param(
default_callback=lambda *_: [], help="List of Thought" default_callback=lambda *_: [], help="List of Thought"
) )
llm: Param = Param(help="The LLM model to use (base of kotaemon.llms.LLM)") llm: LLM = Param(help="The LLM model to use (base of kotaemon.llms.LLM)")
terminate: Param = Param( terminate: Callable = Param(
default=lambda _: False, default=lambda _: False,
help="Callback on terminate condition. Default to always return False", help="Callback on terminate condition. Default to always return False",
) )

View File

@ -2,8 +2,7 @@ from __future__ import annotations
import uuid import uuid
from pathlib import Path from pathlib import Path
from typing import cast
from theflow import Node, Param
from ..base import BaseComponent, Document from ..base import BaseComponent, Document
from ..embeddings import BaseEmbeddings from ..embeddings import BaseEmbeddings
@ -22,9 +21,9 @@ class IndexVectorStoreFromDocumentPipeline(BaseComponent):
- List of texts - List of texts
""" """
vector_store: Param[BaseVectorStore] = Param() vector_store: BaseVectorStore
doc_store: Param[BaseDocumentStore] = Param() doc_store: BaseDocumentStore
embedding: Node[BaseEmbeddings] = Node() embedding: BaseEmbeddings
# TODO: refer to llama_index's storage as well # TODO: refer to llama_index's storage as well
def run(self, text: str | list[str] | Document | list[Document]) -> None: def run(self, text: str | list[str] | Document | list[Document]) -> None:
@ -32,7 +31,7 @@ class IndexVectorStoreFromDocumentPipeline(BaseComponent):
if not isinstance(text, list): if not isinstance(text, list):
text = [text] text = [text]
for item in text: for item in cast(list, text):
if isinstance(item, str): if isinstance(item, str):
input_.append(Document(text=item, id_=str(uuid.uuid4()))) input_.append(Document(text=item, id_=str(uuid.uuid4())))
elif isinstance(item, Document): elif isinstance(item, Document):

View File

@ -3,8 +3,6 @@ from __future__ import annotations
from pathlib import Path from pathlib import Path
from typing import Optional, Sequence from typing import Optional, Sequence
from theflow import Node, Param
from ..base import BaseComponent from ..base import BaseComponent
from ..base.schema import Document, RetrievedDocument from ..base.schema import Document, RetrievedDocument
from ..embeddings import BaseEmbeddings from ..embeddings import BaseEmbeddings
@ -18,9 +16,9 @@ DOC_STORE_FNAME = "docstore"
class RetrieveDocumentFromVectorStorePipeline(BaseComponent): class RetrieveDocumentFromVectorStorePipeline(BaseComponent):
"""Retrieve list of documents from vector store""" """Retrieve list of documents from vector store"""
vector_store: Param[BaseVectorStore] = Param() vector_store: BaseVectorStore
doc_store: Param[BaseDocumentStore] = Param() doc_store: BaseDocumentStore
embedding: Node[BaseEmbeddings] = Node() embedding: BaseEmbeddings
rerankers: Sequence[BaseRerankingPipeline] = [] rerankers: Sequence[BaseRerankingPipeline] = []
top_k: int = 1 top_k: int = 1
# TODO: refer to llama_index's storage as well # TODO: refer to llama_index's storage as well

View File

@ -1,4 +1,3 @@
from abc import abstractmethod
from typing import Any, Callable, Dict, Optional, Tuple, Type, Union from typing import Any, Callable, Dict, Optional, Tuple, Type, Union
from langchain.agents import Tool as LCTool from langchain.agents import Tool as LCTool
@ -51,13 +50,13 @@ class BaseTool(BaseComponent):
return {k: v for k, v in result.dict().items() if k in tool_input} return {k: v for k, v in result.dict().items() if k in tool_input}
return tool_input return tool_input
@abstractmethod
def _run_tool( def _run_tool(
self, self,
*args: Any, *args: Any,
**kwargs: Any, **kwargs: Any,
) -> Any: ) -> Any:
"""Call tool.""" """Call tool."""
raise NotImplementedError(f"_run_tool is not implemented for {self.name}")
def _to_args_and_kwargs(self, tool_input: Union[str, Dict]) -> Tuple[Tuple, Dict]: def _to_args_and_kwargs(self, tool_input: Union[str, Dict]) -> Tuple[Tuple, Dict]:
# For backwards compatibility, if run_input is a string, # For backwards compatibility, if run_input is a string,

View File

@ -32,7 +32,7 @@ setuptools.setup(
install_requires=[ install_requires=[
"langchain", "langchain",
"theflow", "theflow",
"llama-index", "llama-index>=0.9.0",
"llama-hub", "llama-hub",
"gradio", "gradio",
"openpyxl", "openpyxl",

View File

@ -35,3 +35,6 @@ class Pipeline(BaseComponent):
def run_raw(self, text: str) -> str: def run_raw(self, text: str) -> str:
matched_texts: List[str] = self.retrieving_pipeline(text) matched_texts: List[str] = self.retrieving_pipeline(text)
return self.llm("\n".join(matched_texts)).text return self.llm("\n".join(matched_texts)).text
def run(self):
...

View File

@ -34,6 +34,7 @@ def test_indexing(mock_openai_embedding, tmp_path):
vector_store=db, embedding=embedding, doc_store=doc_store vector_store=db, embedding=embedding, doc_store=doc_store
) )
pipeline.doc_store = cast(InMemoryDocumentStore, pipeline.doc_store) pipeline.doc_store = cast(InMemoryDocumentStore, pipeline.doc_store)
pipeline.vector_store = cast(ChromaVectorStore, pipeline.vector_store)
assert pipeline.vector_store._collection.count() == 0, "Expected empty collection" assert pipeline.vector_store._collection.count() == 0, "Expected empty collection"
assert len(pipeline.doc_store._store) == 0, "Expected empty doc store" assert len(pipeline.doc_store._store) == 0, "Expected empty doc store"
pipeline(text=Document(text="Hello world")) pipeline(text=Document(text="Hello world"))