diff --git a/langdspy/__init__.py b/langdspy/__init__.py index 506e8eb..8bff5f5 100644 --- a/langdspy/__init__.py +++ b/langdspy/__init__.py @@ -1,4 +1,4 @@ -from .field_descriptors import InputField, OutputField, InputFieldList, HintField, OutputFieldEnum, OutputFieldEnumList, OutputFieldBool, OutputFieldChooseOne +from .field_descriptors import InputField, OutputField, InputFieldList, HintField, OutputFieldEnum, OutputFieldEnumList, OutputFieldBool, OutputFieldChooseOne, InputFieldDict, InputFieldDictList from .prompt_strategies import PromptSignature, PromptStrategy, DefaultPromptStrategy from .prompt_runners import PromptRunner, RunnableConfig, Prediction, MultiPromptRunner from .model import Model, TrainedModelState diff --git a/langdspy/field_descriptors.py b/langdspy/field_descriptors.py index 0f6ec53..2baec30 100644 --- a/langdspy/field_descriptors.py +++ b/langdspy/field_descriptors.py @@ -99,6 +99,52 @@ def format_prompt_value(self, value, llm_type: str): res += f"{self._start_format_anthropic()}NO VALUES SPECIFIED" return res +class InputFieldDict(InputField): + def format_prompt_value(self, value, llm_type: str): + if llm_type == "openai": + return self._format_openai_prompt_value(value) + elif llm_type == "anthropic": + return self._format_anthropic_prompt_value(value) + + def _format_openai_prompt_value(self, value): + formatted_dict = "" + for key, val in value.items(): + formatted_dict += f"{self._start_format_openai()} {key}: {val}\n" + return formatted_dict.strip() + + def _format_anthropic_prompt_value(self, value): + formatted_dict = f"<{self.name}>\n" + for key, val in value.items(): + formatted_dict += f" <{key}>{val}\n" + formatted_dict += f"" + return formatted_dict + +class InputFieldDictList(InputField): + def format_prompt_value(self, value, llm_type: str): + if llm_type == "openai": + return self._format_openai_prompt_value(value) + elif llm_type == "anthropic": + return self._format_anthropic_prompt_value(value) + + def _format_openai_prompt_value(self, value): + formatted_list = "" + for i, item in enumerate(value): + formatted_list += f"{self._start_format_openai()} Item {i+1}:\n" + for key, val in item.items(): + formatted_list += f" {key}: {val}\n" + formatted_list += "\n" + return formatted_list.strip() + + def _format_anthropic_prompt_value(self, value): + formatted_list = f"<{self.name}>\n" + for i, item in enumerate(value): + formatted_list += f" <{self.name} {i + 1}>\n" + for key, val in item.items(): + formatted_list += f" <{key}>{val}\n" + formatted_list += f" \n" + formatted_list += f"" + return formatted_list + class OutputField(FieldDescriptor): START_TOKEN_OPENAI = "🔑" START_TOKEN_ANTHROPIC = None diff --git a/tests/test_field_descriptors.py b/tests/test_field_descriptors.py index fcf5d5c..7918970 100644 --- a/tests/test_field_descriptors.py +++ b/tests/test_field_descriptors.py @@ -1,6 +1,6 @@ import pytest from enum import Enum -from langdspy.field_descriptors import InputField, InputFieldList, OutputField, OutputFieldEnum, OutputFieldEnumList, OutputFieldBool, OutputFieldChooseOne +from langdspy.field_descriptors import InputField, InputFieldList, OutputField, OutputFieldEnum, OutputFieldEnumList, OutputFieldBool, OutputFieldChooseOne, InputFieldDict, InputFieldDictList def test_input_field_initialization(): field = InputField("name", "description") @@ -87,4 +87,66 @@ def test_output_field_choose_one_format_prompt_description(): field = OutputFieldChooseOne("name", "description", choices) assert "One of: Option 1, Option 2, Option 3" in field.format_prompt_description("openai") - assert "One of: Option 1, Option 2, Option 3" in field.format_prompt_description("anthropic") \ No newline at end of file + assert "One of: Option 1, Option 2, Option 3" in field.format_prompt_description("anthropic") + +def test_format_prompt_value_openai(): + field = InputFieldDict("input_dict", "A dictionary input") + input_dict = { + "name": "John Doe", + "age": 30, + "city": "New York" + } + expected_output = "✅input_dict name: John Doe\n✅input_dict age: 30\n✅input_dict city: New York" + print(field.format_prompt_value(input_dict, "openai")) + print(expected_output) + assert field.format_prompt_value(input_dict, "openai") == expected_output + +def test_format_prompt_value_anthropic(): + field = InputFieldDict("input_dict", "A dictionary input") + input_dict = { + "name": "John Doe", + "age": 30, + "city": "New York" + } + expected_output = "\n John Doe\n 30\n New York\n" + assert field.format_prompt_value(input_dict, "anthropic") == expected_output + +# tests/test_input_field_dict_list.py +import pytest +from langdspy.field_descriptors import InputFieldDictList + +def test_format_prompt_value_openai(): + field = InputFieldDictList("input_list", "A list of dictionaries") + input_list = [ + { + "name": "John Doe", + "age": 30, + "city": "New York" + }, + { + "name": "Jane Smith", + "age": 25, + "city": "London" + } + ] + expected_output = "✅input_list Item 1:\n name: John Doe\n age: 30\n city: New York\n\n✅input_list Item 2:\n name: Jane Smith\n age: 25\n city: London" + print(field.format_prompt_value(input_list, "openai")) + print(expected_output) + assert field.format_prompt_value(input_list, "openai") == expected_output + +def test_format_prompt_value_anthropic(): + field = InputFieldDictList("input_list", "A list of dictionaries") + input_list = [ + { + "name": "John Doe", + "age": 30, + "city": "New York" + }, + { + "name": "Jane Smith", + "age": 25, + "city": "London" + } + ] + expected_output = "\n \n John Doe\n 30\n New York\n \n \n Jane Smith\n 25\n London\n \n" + assert field.format_prompt_value(input_list, "anthropic") == expected_output \ No newline at end of file