Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/llm responses #376

Open
wants to merge 206 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 76 commits
Commits
Show all changes
206 commits
Select commit Hold shift + click to select a range
f15be68
Started working on llm_responses
NotBioWaste905 Jul 19, 2024
56b7789
Created class, created 1st tutorial
NotBioWaste Jul 22, 2024
af60115
Added dependecies for langchain
NotBioWaste Jul 22, 2024
b3b79a5
Fixed adding custom prompt for each node
NotBioWaste Jul 22, 2024
6eb910d
Added image processing, updated tutorial
NotBioWaste Jul 22, 2024
1f8cddc
Added typehint
NotBioWaste Jul 22, 2024
74cd954
Added llm_response, LLM_API, history management
NotBioWaste Jul 22, 2024
1fd31a2
Fixed image reading
NotBioWaste Jul 22, 2024
2c48490
Started llm condition
NotBioWaste Jul 24, 2024
a1884e5
Added message_to_langchain
NotBioWaste Jul 24, 2024
61f302e
Implementing deepeval integration
NotBioWaste Jul 29, 2024
38a8f8f
Figured out how to implement DeepEval functions
NotBioWaste905 Jul 30, 2024
592267f
Adding conditions
NotBioWaste Jul 31, 2024
baccc47
Implemented simple conditions call, added BaseMethod class, renaming,…
NotBioWaste Aug 1, 2024
8e84ba1
Fixed history extraction
NotBioWaste Aug 2, 2024
2b2847b
Delete test_bot.py
NotBioWaste905 Aug 2, 2024
7e336ac
Fixed prompt handling, switched to AIMessage in LLM response
NotBioWaste Aug 5, 2024
71babbf
Merge branch 'feat/llm_responses' of https://github.com/deeppavlov/di…
NotBioWaste Aug 5, 2024
351ae06
Fixed conditions call
NotBioWaste Aug 5, 2024
e3d0d15
Working on autotesting
NotBioWaste Aug 5, 2024
0405998
Added tests
NotBioWaste Aug 7, 2024
3dbfd0c
Removed unused method
NotBioWaste Aug 7, 2024
5c876ba
Added annotations
NotBioWaste Aug 7, 2024
8f1932c
Added structured output support, tweaked tests
NotBioWaste Aug 7, 2024
aedf47e
Reworking tutorials
NotBioWaste Aug 7, 2024
adadb05
Reworked prompt usage and hierarchy, reworked filters and methods
NotBioWaste Aug 12, 2024
0288896
No idea how to make script smaller in tutorials
NotBioWaste Aug 12, 2024
67e2758
Small fixes in tutorials and structured generation
NotBioWaste Aug 13, 2024
428a9f0
Working on user guide
NotBioWaste Aug 14, 2024
5e26b4b
Fixed some tutorials, finished user guide
NotBioWaste Aug 14, 2024
5dbb6cd
Bugfixes in docs
NotBioWaste Aug 14, 2024
db63d1a
Lint
NotBioWaste Aug 14, 2024
2b9080f
Removed type annotation that broke docs building
NotBioWaste Aug 14, 2024
2bcda71
Tests and bugfixes
NotBioWaste Aug 15, 2024
d2f28ed
Deleted DeepEval references
NotBioWaste Aug 15, 2024
7318c91
Numpy versions trouble
NotBioWaste Aug 15, 2024
27eae27
Fixed dependecies
NotBioWaste Aug 16, 2024
3fed1fc
Made everything asynchronous
NotBioWaste Aug 16, 2024
30862ca
Added and unified docstring
NotBioWaste Aug 16, 2024
06ab5bc
Added 4th tutorial, fixed message_schema parameter passing
NotBioWaste Aug 16, 2024
798a77b
Bugfix, added max_size to the message_to_langchain function
NotBioWaste Aug 20, 2024
3343159
Made even more everything asynchronous
NotBioWaste Aug 21, 2024
014ff7e
Remade condition, added logprob check
NotBioWaste Aug 21, 2024
761bd81
Async bugfix, added model_result_to_text, working on message_schema f…
NotBioWaste Aug 22, 2024
90a811e
Minor fixes, tinkering tests
NotBioWaste Aug 23, 2024
5bff191
Merge branch 'refs/heads/dev' into feat/llm_responses
RLKRo Aug 23, 2024
8b88ba6
update lock file
RLKRo Aug 23, 2024
20c4afd
Merge remote-tracking branch 'origin/feat/llm_responses' into feat/ll…
RLKRo Aug 23, 2024
0139421
Merge remote-tracking branch 'origin/master' into feat/llm_responses
NotBioWaste905 Sep 18, 2024
9bb0cba
Updating to v1.0
NotBioWaste905 Sep 23, 2024
f2d6b68
Finished tests, finished update
NotBioWaste905 Sep 26, 2024
6fddaea
lint
NotBioWaste905 Sep 26, 2024
e06bc2b
Started working on llm slots
NotBioWaste905 Sep 26, 2024
22d8efc
Resolving pydantic errors
NotBioWaste905 Sep 27, 2024
aa735b5
Delete llmslot_test.py
NotBioWaste905 Sep 27, 2024
cc91133
Finished LLMSlot, working on LLMGroupSlot
NotBioWaste905 Sep 27, 2024
8756838
Merge remote-tracking branch 'origin/feat/llm_responses' into feat/ll…
NotBioWaste905 Sep 27, 2024
f1857f6
Added flag to
NotBioWaste905 Oct 1, 2024
c334ff5
First test attempts
NotBioWaste905 Oct 1, 2024
8306bbb
linting
NotBioWaste905 Oct 1, 2024
f842776
Merge branch 'feat/slots_extraction_update' into feat/llm_responses
NotBioWaste905 Oct 1, 2024
ada17ca
Merge remote-tracking branch 'origin/feat/llm_responses' into feat/ll…
NotBioWaste905 Oct 1, 2024
a45f653
File structure fixed
NotBioWaste905 Oct 3, 2024
3838d30
Fixed naming
NotBioWaste905 Oct 3, 2024
0e650f8
Create LLMCondition and LLMResponse classes
NotBioWaste905 Oct 3, 2024
015cb4f
Debugging flattening
NotBioWaste905 Oct 23, 2024
b6e5eeb
Bugfix
NotBioWaste905 Oct 23, 2024
b20137e
Added return_type property for LLMSlot
NotBioWaste905 Oct 23, 2024
25f5b04
Changed return_type from Any to type
NotBioWaste905 Oct 23, 2024
b651087
lint
NotBioWaste905 Oct 23, 2024
1b5a77b
removed deprecated from_script from tutorials
NotBioWaste905 Nov 2, 2024
c18d375
Fixed LLMCondition class
NotBioWaste905 Nov 2, 2024
459f7fc
Fixed missing 'models' field in Pipeline, updated tutorials
NotBioWaste905 Nov 6, 2024
24300e8
create __get_llm_response method in LLM_API, refactoring LLM Conditio…
NotBioWaste905 Nov 7, 2024
03b02be
Merge branch 'refs/heads/dev' into feat/llm_responses
RLKRo Nov 7, 2024
e6663b3
update lock file
RLKRo Nov 7, 2024
2e1c190
remove outdated entries from conf.py
RLKRo Nov 7, 2024
859c57a
small fixes to user guide
RLKRo Nov 7, 2024
fb3142b
minor tutorial changes
RLKRo Nov 7, 2024
ff81267
Moved docstring, removed pipeline parameter
NotBioWaste905 Nov 13, 2024
7518259
Fixed type annotation for models field in Pipeline
NotBioWaste905 Nov 13, 2024
ac28d78
removed unused imports from llm/__init__.py
NotBioWaste905 Nov 13, 2024
2d4998c
Fix redundancy in chatsky/slots/llm.py
NotBioWaste905 Nov 13, 2024
23d6a31
Fixed circular LLM_API<=>Pipeline import
NotBioWaste905 Nov 13, 2024
ef9baa3
Merge remote-tracking branch 'origin/feat/llm_responses' into feat/ll…
NotBioWaste905 Nov 13, 2024
4bf5bba
Update import order chatsky/llm/filters.py
NotBioWaste905 Nov 13, 2024
9188b89
Fixes in filters
NotBioWaste905 Nov 14, 2024
02894f0
Fixes of LLM_API annotations and docs
NotBioWaste905 Nov 14, 2024
8e839a1
Removed __get_llm_response, lint
NotBioWaste905 Nov 14, 2024
210b10a
Added context_to_history util, some tweaks in responses
NotBioWaste905 Nov 14, 2024
784f323
remove llm_response object initialization from tutorials
RLKRo Nov 14, 2024
042d256
fix imports in __init__ files:
RLKRo Nov 14, 2024
10533ed
fix: rename llm_response to LLMResponse, rename llm_condition to LLMC…
RLKRo Nov 14, 2024
8f21069
fix codeblocks in user guide
RLKRo Nov 14, 2024
95e2418
fix: message_to_langchain accepts context instead of pipeline
RLKRo Nov 15, 2024
934a0b8
remove defaults from filter definitions
RLKRo Nov 15, 2024
1be58a0
check field not none in filters
RLKRo Nov 15, 2024
4d68a29
remove model_name from LLM_API.respond
RLKRo Nov 15, 2024
fa0ae70
make LLMResponse prompt AnyResponse, remove __prompt_to_message
RLKRo Nov 15, 2024
8778637
fix return style in LLM_API.respond
RLKRo Nov 15, 2024
d4b67a1
fix LLM_API.condition signature
RLKRo Nov 15, 2024
4a29687
some doc fixes
RLKRo Nov 15, 2024
37aafb3
fix message schema json dumping
RLKRo Nov 15, 2024
54a7376
remove unused imports
RLKRo Nov 15, 2024
86da03e
fix circular import
RLKRo Nov 15, 2024
eac43e0
fix tests
RLKRo Nov 15, 2024
51c66a8
remove cnd.true()
RLKRo Nov 15, 2024
33242ca
Fixed empty prompt popping up
NotBioWaste905 Nov 15, 2024
65f7c8f
Format
NotBioWaste905 Nov 15, 2024
dc92132
Switched model from 3.5-turbo to 4o-mini
NotBioWaste905 Nov 15, 2024
020a7ef
Updated all of the models
NotBioWaste905 Nov 15, 2024
c9891f6
Fixes and logging
NotBioWaste905 Nov 15, 2024
c678f89
Codestyle
NotBioWaste905 Nov 15, 2024
f2df441
update lock file
RLKRo Nov 15, 2024
f20d463
simplify history text
RLKRo Nov 15, 2024
44e5571
fix codestyle
RLKRo Nov 15, 2024
9f97ce2
fix doc building
RLKRo Nov 15, 2024
b9e738a
Merge branch 'refs/heads/dev' into feat/llm_responses
RLKRo Nov 15, 2024
39750ba
update lock file
RLKRo Nov 15, 2024
6603f7d
remove unnecessary langchain extras
RLKRo Nov 15, 2024
3827462
update lock file
RLKRo Nov 15, 2024
f7e7684
protect langchain imports & sort imports in modules
RLKRo Nov 15, 2024
a4e0462
skip llm tests on missing langchain
RLKRo Nov 15, 2024
13923ab
Added docstrings in llm/methods.py
NotBioWaste905 Nov 20, 2024
537d8cc
Docstring fixes
NotBioWaste905 Nov 20, 2024
35d9d7d
Fixes in message_to_langchain
NotBioWaste905 Nov 20, 2024
e5c83fb
lint
NotBioWaste905 Nov 20, 2024
5a7313f
Fixed overseen raise condition
NotBioWaste905 Nov 20, 2024
0000414
Signature fixes
NotBioWaste905 Nov 20, 2024
36a9f54
Responses related fixes
NotBioWaste905 Nov 20, 2024
ba95767
Slot related fixes + lint
NotBioWaste905 Nov 20, 2024
3d79cec
Fixed abstract call
NotBioWaste905 Nov 20, 2024
8e22b97
Adding tests
NotBioWaste905 Nov 20, 2024
b8de244
Bunch of documentation fixes, removed attachment_to_content
NotBioWaste905 Nov 25, 2024
bfba582
Added tests, need fix
NotBioWaste905 Nov 25, 2024
2b3c02b
Renamed FromTheModel to FromModel
NotBioWaste905 Nov 25, 2024
47f3855
Changes in BaseFilter class
NotBioWaste905 Nov 25, 2024
248d77f
Switched to localhost models in tutorials
NotBioWaste905 Nov 26, 2024
b5ecc1a
Renamed BaseFilter into BaseHistoryFilter, added API reference
NotBioWaste905 Nov 26, 2024
34e5536
Lint
NotBioWaste905 Nov 26, 2024
60c7c97
Slots and tutorials update
NotBioWaste905 Nov 27, 2024
3cf1df7
Tutorials and structured output update
NotBioWaste905 Nov 28, 2024
7f00028
More clear instructions in tutorial
NotBioWaste905 Nov 28, 2024
513eb19
Fixes in llm slots and tutorial
NotBioWaste905 Nov 28, 2024
2cd5d41
lint
NotBioWaste905 Nov 28, 2024
6a0845d
Finalizing tweaks
NotBioWaste905 Nov 29, 2024
81a86e9
Lint
NotBioWaste905 Nov 29, 2024
24e65c5
Removed import test
NotBioWaste905 Nov 29, 2024
b6af8f5
Removed dotenv, fixed Union
NotBioWaste905 Nov 29, 2024
ee5f643
Conditions cleanup
NotBioWaste905 Dec 4, 2024
1ff7020
Switched to the '|' operator, IsImportant and FromModel are now inher…
NotBioWaste905 Dec 4, 2024
2f65265
Added partial extraction to the tutorial
NotBioWaste905 Dec 4, 2024
04c5b54
Moved history flag annotation to another tutorial
NotBioWaste905 Dec 4, 2024
0d56e75
Fixed docstrings
NotBioWaste905 Dec 4, 2024
74c6d5e
Quickfix for message_to_langchain
NotBioWaste905 Dec 4, 2024
7e2da91
Fixed signatures in filters, lint
NotBioWaste905 Dec 4, 2024
7a313d1
Fixed tutorial link
NotBioWaste905 Dec 4, 2024
9b31ac9
Actually fixed tutorial link
NotBioWaste905 Dec 4, 2024
1c4aa24
Fixed splitted lines in tutorials, reworked system prompt handling af…
NotBioWaste905 Dec 4, 2024
419ab8d
Added missing docstrings for LLM_API
NotBioWaste905 Dec 9, 2024
e723334
Small docstring fix
NotBioWaste905 Dec 9, 2024
6b1ffed
Added test for conditions + fixed some bugs
NotBioWaste905 Dec 11, 2024
2a7bd4f
Removed return_schema from condition due to not using it for now
NotBioWaste905 Dec 12, 2024
e25e2f8
Experiencing issues with slot testing
NotBioWaste905 Dec 12, 2024
8e553bd
lint
NotBioWaste905 Dec 12, 2024
fea185c
Fixes in LLM Slot testing
NotBioWaste905 Dec 12, 2024
968fe75
Refactor context_to_history function to streamline filtering of dialo…
NotBioWaste905 Dec 12, 2024
8bc71ce
Working on Prompt rework
NotBioWaste905 Dec 23, 2024
e27d85f
Returned test case
NotBioWaste905 Dec 23, 2024
13e6a31
Started working on get_langchain_context
NotBioWaste905 Jan 13, 2025
93412e8
Working on prompt processing
NotBioWaste905 Jan 20, 2025
3b6f941
Resolved typeching issues in Pipeline
NotBioWaste905 Jan 22, 2025
24237fb
Added some logging, WIP
NotBioWaste905 Jan 22, 2025
f4d1852
Renamed `model_name` parameter into `llm_model_name`
NotBioWaste905 Jan 22, 2025
f0f0e2d
Update LLMResponse
NotBioWaste905 Jan 24, 2025
8b8085f
Update LLM_API to work with LLM Response
NotBioWaste905 Jan 24, 2025
09b0487
Renamed DesaultPositionConfig to PositionConfig
NotBioWaste905 Jan 24, 2025
6eb50e7
Reworked context related functions
NotBioWaste905 Jan 24, 2025
bba5178
Added buch on TODOs
NotBioWaste905 Jan 24, 2025
d1063b9
Made request and response optional for history filters, renamed field…
NotBioWaste905 Jan 29, 2025
cee86a9
Removed deprecated TODO
NotBioWaste905 Jan 29, 2025
3c0fe22
Updated conditions.llm to use get_langchain_context
NotBioWaste905 Jan 29, 2025
44935ff
Added docstring for get_langchain_context, lint
NotBioWaste905 Jan 29, 2025
2b37d59
Fixed renaming issue
NotBioWaste905 Jan 31, 2025
32eae7d
Fixing tests
NotBioWaste905 Jan 31, 2025
6440eaf
Fixed appending empty strings + wrong prompt positions in tests
NotBioWaste905 Jan 31, 2025
b9f3925
Added missing PositionConfig
NotBioWaste905 Jan 31, 2025
d43b468
Added de-flattening func to slots.llm
NotBioWaste905 Feb 3, 2025
4968907
Update prompt handling in LLM conditions and tests
NotBioWaste905 Feb 3, 2025
42b6ced
Refactor Prompt model to use float for position attribute, not BasePr…
NotBioWaste905 Feb 4, 2025
b11f44b
Added tests for get_langchain_context
NotBioWaste905 Feb 4, 2025
5bedd3f
lint
NotBioWaste905 Feb 4, 2025
c792f93
Modified tutorial to include prompt positioning
NotBioWaste905 Feb 4, 2025
c8dc417
Added mock OPENAI_API_KEY for tutorials to be testes
NotBioWaste905 Feb 5, 2025
1f31292
removed pipe symbol from union
NotBioWaste905 Feb 5, 2025
bf8f7cf
lint
NotBioWaste905 Feb 5, 2025
6204b85
Added actual Union
NotBioWaste905 Feb 5, 2025
b7f1cd7
Fixed wrong method override
NotBioWaste905 Feb 6, 2025
65e24f9
Updated tutorial
NotBioWaste905 Feb 6, 2025
8f0587f
lint
NotBioWaste905 Feb 6, 2025
94aa660
Added missing mock ANTHROPIC_API_KEY
NotBioWaste905 Feb 6, 2025
2a21f5a
Trying to fix escape sequence
NotBioWaste905 Feb 6, 2025
be76bf1
Okay this breaks everything
NotBioWaste905 Feb 6, 2025
5b120c6
Fixed typo
NotBioWaste905 Feb 6, 2025
37ae4ae
Updated userguide
NotBioWaste905 Feb 6, 2025
db4f8e1
readability improvements
NotBioWaste905 Feb 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions chatsky/conditions/llm.py
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from chatsky.llm.methods import BaseMethod
from chatsky.core import BaseCondition, Context, Pipeline


class LLMCondition(BaseCondition):
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
model_name: str
prompt: str
method: BaseMethod
pipeline: Pipeline
RLKRo marked this conversation as resolved.
Show resolved Hide resolved

async def call(self, ctx: Context) -> bool:
"""
Basic function for using LLM in condition cases.
RLKRo marked this conversation as resolved.
Show resolved Hide resolved

:param model_name: Key of the model from the `Pipeline.models` dictionary.
:param prompt: Prompt for the model to use on users input.
:param method: Method that takes models output and returns boolean.
"""
model = self.pipeline.models[self.model_name]
return await model.condition(self.prompt, self.method)
6 changes: 6 additions & 0 deletions chatsky/core/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ class Pipeline(BaseModel, extra="forbid", arbitrary_types_allowed=True):
"""
Slots configuration.
"""
models: Dict = Field(default_factory=dict)
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
"""
LLM models.
"""
messenger_interface: MessengerInterface = Field(default_factory=CLIMessengerInterface)
"""
A `MessengerInterface` instance for this pipeline.
Expand Down Expand Up @@ -116,6 +120,7 @@ def __init__(
*,
default_priority: float = None,
slots: GroupSlot = None,
models: dict = None,
messenger_interface: MessengerInterface = None,
context_storage: Union[DBContextStorage, dict] = None,
pre_services: ServiceGroupInitTypes = None,
Expand All @@ -133,6 +138,7 @@ def __init__(
"fallback_label": fallback_label,
"default_priority": default_priority,
"slots": slots,
"models": models,
"messenger_interface": messenger_interface,
"context_storage": context_storage,
"pre_services": pre_services,
Expand Down
16 changes: 16 additions & 0 deletions chatsky/llm/__init__.py
NotBioWaste905 marked this conversation as resolved.
Show resolved Hide resolved
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
try:
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
from langchain_google_vertexai import ChatVertexAI
from langchain_cohere import ChatCohere
from langchain_mistralai import ChatMistralAI
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_core.language_models.chat_models import BaseChatModel
except ImportError:
raise ImportError("Langchain is not available. Please install it with `pip install chatsky[llm]`.")
RLKRo marked this conversation as resolved.
Show resolved Hide resolved

from chatsky.llm.filters import BaseFilter, FromTheModel, IsImportant
from chatsky.llm.methods import BaseMethod, LogProb, LLMResult
from chatsky.llm.llm_api import LLM_API
from chatsky.llm.utils import message_to_langchain, __attachment_to_content
56 changes: 56 additions & 0 deletions chatsky/llm/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""
Filters.
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
---------
This module contains a collection of basic functions for history filtering to avoid cluttering LLMs context window.
"""

from chatsky.core.message import Message
from chatsky.core.context import Context
from pydantic import BaseModel
import abc
NotBioWaste905 marked this conversation as resolved.
Show resolved Hide resolved


class BaseFilter(BaseModel, abc.ABC):
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
"""
Base class for all message history filters.
"""

@abc.abstractmethod
def __call__(self, ctx: Context, request: Message, response: Message, model_name: str) -> bool:
"""
:param Context ctx: Context object.
:param Message request: Request message.
:param Message response: Response message.
:param str model_name: Name of the model in the Pipeline.models.
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
"""
raise NotImplementedError


class IsImportant(BaseFilter):
"""
Filter that checks if the "important" field in a Message.misc is True.
"""

def __call__(
self, ctx: Context = None, request: Message = None, response: Message = None, model_name: str = None
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
) -> bool:
if request and request.misc["important"]:
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
return True
if response and response.misc["important"]:
return True
return False


class FromTheModel(BaseFilter):
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
"""
Filter that checks if the message was sent by the model.
"""

def __call__(
self, ctx: Context = None, request: Message = None, response: Message = None, model_name: str = None
) -> bool:
if request is not None and request.annotation["__generated_by_model__"] == model_name:
return True
elif response is not None and response.annotation["__generated_by_model__"] == model_name:
return True
return False
95 changes: 95 additions & 0 deletions chatsky/llm/llm_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""
LLM responses.
---------
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
Wrapper around langchain.
"""

try:
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
from langchain_google_vertexai import ChatVertexAI
from langchain_cohere import ChatCohere
from langchain_mistralai import ChatMistralAI
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
from langchain_core.output_parsers import StrOutputParser
from langchain_core.language_models.chat_models import BaseChatModel

langchain_available = True
except ImportError:
langchain_available = False


from chatsky.core.message import Message
from chatsky.core.context import Context
from chatsky.core.pipeline import Pipeline
from chatsky.llm.methods import BaseMethod

from typing import Union, Type, Optional
from pydantic import BaseModel

from chatsky.llm.utils import message_to_langchain


class LLM_API:
"""
This class acts as a wrapper for all LLMs from langchain
and handles message exchange between remote model and chatsky classes.
"""

def __init__(
self,
model: BaseChatModel,
system_prompt: Optional[str] = "",
) -> None:
"""
:param model: Model object.
:param system_prompt: System prompt for the model.
"""
self.__check_imports()
self.model: BaseChatModel = model
self.name = ""
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
self.parser = StrOutputParser()
self.system_prompt = system_prompt

def __check_imports(self):
if not langchain_available:
raise ImportError("Langchain is not available. Please install it with `pip install chatsky[llm]`.")

async def __get_llm_response(self, history: list = [""], message_schema: BaseModel = None):
if message_schema is None:
result = await self.parser.ainvoke(await self.model.ainvoke(history))
else:
structured_model = self.model.with_structured_output(message_schema)
result = Message.model_validate(await structured_model.ainvoke(history))
return result
RLKRo marked this conversation as resolved.
Show resolved Hide resolved

async def respond(
self, history: list = [""], message_schema: Union[None, Type[Message], Type[BaseModel]] = None
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
) -> Message:
RLKRo marked this conversation as resolved.
Show resolved Hide resolved

result = await self.__get_llm_response(history, message_schema)

if message_schema is None:
result = Message(text=result)
elif issubclass(message_schema, Message):
# Case if the message_schema desribes Message structure
result = Message.model_validate(result)
elif issubclass(message_schema, BaseModel):
# Case if the message_schema desribes Message.text structure
result = Message(text=str(result))
RLKRo marked this conversation as resolved.
Show resolved Hide resolved

if result.annotations:
result.annotations["__generated_by_model__"] = self.name
else:
result.annotations = {"__generated_by_model__": self.name}
return result

async def condition(self, prompt: str, method: BaseMethod, return_schema=None):
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO method should be called inside conditions.llm:LLMCondition.
Maybe the condition method should be renamed to respond_with_logprobs or the option to respond with logprobs should instead be added to the respond method.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still not resolved.

async def process_input(ctx: Context, _: Pipeline) -> bool:
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
condition_history = [
await message_to_langchain(Message(prompt), pipeline=_, source="system"),
await message_to_langchain(ctx.last_request, pipeline=_, source="human"),
]
result = method(ctx, await self.model.agenerate([condition_history], logprobs=True, top_logprobs=10))
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
return result

return process_input
70 changes: 70 additions & 0 deletions chatsky/llm/methods.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""
LLM methods.
---------
In this file stored unified functions for some basic condition cases
including regex search, semantic distance (cosine) etc.
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
"""

from chatsky.core.context import Context
from pydantic import BaseModel
from langchain_core.outputs.llm_result import LLMResult
import abc


class BaseMethod(BaseModel, abc.ABC):
"""
Base class to evaluate models response as condition.
"""

@abc.abstractmethod
async def __call__(self, ctx: Context, model_result: LLMResult) -> bool:
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
raise NotImplementedError

async def model_result_to_text(self, model_result: LLMResult) -> str:
"""
Converts raw model generation to a string.
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
"""
return model_result.generations[0][0].text


class Contains(BaseMethod):
"""
Simple method to check if a string contains a pattern.

:param str pattern: pattern to check
RLKRo marked this conversation as resolved.
Show resolved Hide resolved

:return: True if pattern is contained in model result
:rtype: bool
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
"""

pattern: str

async def __call__(self, ctx: Context, model_result: LLMResult) -> bool:
text = await self.model_result_to_text(model_result)
return bool(self.pattern.lower() in text.lower())


class LogProb(BaseMethod):
"""
Method to check whether a target token's log probability is higher then a threshold.

:param str target_token: token to check (e.g. `"TRUE"`)
:param float threshold: threshold to bypass. by default `-0.5`
Comment on lines +61 to +62
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move these out of the class docstring as well.


:return: True if logprob is higher then threshold
:rtype: bool
"""

target_token: str
threshold: float = -0.5

async def __call__(self, ctx: Context, model_result: LLMResult) -> bool:
try:
result = model_result.generations[0][0].generation_info["logprobs"]["content"][0]["top_logprobs"]
except ValueError:
raise ValueError("LogProb method can only be applied to OpenAI models.")
for tok in result:
if tok["token"] == self.target_token and tok["logprob"] > self.threshold:
return True

return False
57 changes: 57 additions & 0 deletions chatsky/llm/utils.py
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import base64
from chatsky.core.message import Image, Message
from chatsky.core.pipeline import Pipeline
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage


async def message_to_langchain(message: Message, pipeline: Pipeline, source: str = "human", max_size: int = 1000):
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
"""
Creates a langchain message from a ~chatsky.script.core.message.Message object.
RLKRo marked this conversation as resolved.
Show resolved Hide resolved

:param Message message: ~chatsky.script.core.message.Message object.
:param Pipeline pipeline: ~chatsky.pipeline.Pipeline object.
:param str source: Source of a message [`human`, `ai`, `system`]. Defaults to "human".
:param int max_size: Maximum size of the message in symbols.
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
If exceed the limit will raise ValueError. Is not affected by system prompt size.
RLKRo marked this conversation as resolved.
Show resolved Hide resolved

:return: Langchain message object.
:rtype: HumanMessage|AIMessage|SystemMessage
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
"""
if len(message.text) > max_size:
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError("Message is too long.")
RLKRo marked this conversation as resolved.
Show resolved Hide resolved

if message.text is None:
message.text = ""
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
content = [{"type": "text", "text": message.text}]

if message.attachments:
for image in message.attachments:
if isinstance(image, Image):
content.append(
{
"type": "image_url",
"image_url": {"url": await __attachment_to_content(image, pipeline.messenger_interface)},
Copy link
Member

@RLKRo RLKRo Nov 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

POSTPONED
Similarly to message len check, __attachment_to_content may raise an exception.
We should produce a warning but ignore such attachments (instead of propagating the exception to LLMResponse.

try:
  content.append(await attachment_to_string(...))
except Exception as exc:
  logger.warning(exc)

}
)

if source == "human":
return HumanMessage(content=content)
elif source == "ai":
return AIMessage(content=content)
elif source == "system":
return SystemMessage(content=content)
else:
raise ValueError("Invalid source name. Only `human`, `ai` and `system` are supported.")


async def __attachment_to_content(attachment: Image, iface) -> str:
RLKRo marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

@RLKRo RLKRo Nov 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

POSTPONED
This doesn't have to be Image. Could be annotated as DataAttachment instead.

"""
Helper function to convert image to base64 string.
"""
image_bytes = await attachment.get_bytes(iface)
image_b64 = base64.b64encode(image_bytes).decode("utf-8")
extension = str(attachment.source).split(".")[-1]
if image_b64 == "" or extension is None:
raise ValueError("Data image is not accessible.")
image_b64 = f"data:image/{extension};base64,{image_b64}"
return image_b64
Loading
Loading