semantic-kernel 0.3.0.dev0__tar.gz → 0.3.2.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/PKG-INFO +3 -1
  2. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/pyproject.toml +12 -7
  3. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/__init__.py +2 -0
  4. semantic_kernel-0.3.2.dev0/semantic_kernel/connectors/ai/chat_completion_client_base.py +52 -0
  5. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/chat_request_settings.py +2 -0
  6. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/complete_request_settings.py +1 -0
  7. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/hugging_face/services/hf_text_completion.py +43 -18
  8. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/open_ai/services/open_ai_chat_completion.py +48 -14
  9. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/open_ai/services/open_ai_text_completion.py +16 -11
  10. semantic_kernel-0.3.2.dev0/semantic_kernel/connectors/ai/text_completion_client_base.py +52 -0
  11. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/memory/chroma/chroma_memory_store.py +8 -5
  12. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/memory/chroma/utils.py +45 -22
  13. semantic_kernel-0.3.2.dev0/semantic_kernel/connectors/memory/pinecone/__init__.py +7 -0
  14. semantic_kernel-0.3.2.dev0/semantic_kernel/connectors/memory/pinecone/pinecone_memory_store.py +401 -0
  15. semantic_kernel-0.3.2.dev0/semantic_kernel/connectors/memory/pinecone/utils.py +37 -0
  16. {semantic_kernel-0.3.0.dev0/semantic_kernel/connectors/memory → semantic_kernel-0.3.2.dev0/semantic_kernel/connectors/memory/weaviate}/weaviate_memory_store.py +30 -15
  17. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/core_skills/file_io_skill.py +1 -1
  18. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/core_skills/math_skill.py +1 -1
  19. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/core_skills/text_skill.py +1 -1
  20. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/core_skills/time_skill.py +15 -3
  21. semantic_kernel-0.3.2.dev0/semantic_kernel/core_skills/wait_skill.py +23 -0
  22. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/kernel.py +2 -0
  23. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/memory/memory_query_result.py +4 -0
  24. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/memory/memory_record.py +15 -2
  25. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/memory/null_memory.py +7 -1
  26. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/memory/semantic_text_memory.py +17 -6
  27. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/memory/semantic_text_memory_base.py +2 -0
  28. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/orchestration/sk_function.py +5 -0
  29. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/planning/basic_planner.py +9 -1
  30. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/semantic_functions/prompt_template_config.py +6 -0
  31. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/skill_definition/functions_view.py +14 -1
  32. semantic_kernel-0.3.2.dev0/semantic_kernel/text/text_chunker.py +333 -0
  33. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/utils/settings.py +36 -31
  34. semantic_kernel-0.3.0.dev0/semantic_kernel/connectors/ai/chat_completion_client_base.py +0 -28
  35. semantic_kernel-0.3.0.dev0/semantic_kernel/connectors/ai/text_completion_client_base.py +0 -30
  36. semantic_kernel-0.3.0.dev0/semantic_kernel/text/text_chunker.py +0 -250
  37. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/pip/README.md +0 -0
  38. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/__init__.py +0 -0
  39. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/ai_exception.py +0 -0
  40. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/embeddings/embedding_generator_base.py +0 -0
  41. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/hugging_face/__init__.py +0 -0
  42. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/hugging_face/services/hf_text_embedding.py +0 -0
  43. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/open_ai/__init__.py +0 -0
  44. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/open_ai/services/azure_chat_completion.py +0 -0
  45. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/open_ai/services/azure_text_completion.py +0 -0
  46. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/open_ai/services/azure_text_embedding.py +0 -0
  47. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/ai/open_ai/services/open_ai_text_embedding.py +0 -0
  48. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/connectors/memory/chroma/__init__.py +0 -0
  49. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/core_skills/__init__.py +0 -0
  50. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/core_skills/conversation_summary_skill.py +0 -0
  51. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/core_skills/http_skill.py +0 -0
  52. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/core_skills/text_memory_skill.py +0 -0
  53. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/kernel_exception.py +0 -0
  54. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/memory/__init__.py +0 -0
  55. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/memory/memory_store_base.py +0 -0
  56. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/memory/volatile_memory_store.py +0 -0
  57. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/orchestration/context_variables.py +0 -0
  58. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/orchestration/delegate_handlers.py +0 -0
  59. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/orchestration/delegate_inference.py +0 -0
  60. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/orchestration/delegate_types.py +0 -0
  61. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/orchestration/sk_context.py +0 -0
  62. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/orchestration/sk_function_base.py +0 -0
  63. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/planning/__init__.py +0 -0
  64. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/planning/plan.py +0 -0
  65. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/reliability/pass_through_without_retry.py +0 -0
  66. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/reliability/retry_mechanism_base.py +0 -0
  67. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/semantic_functions/chat_prompt_template.py +0 -0
  68. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/semantic_functions/prompt_template.py +0 -0
  69. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/semantic_functions/prompt_template_base.py +0 -0
  70. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/semantic_functions/semantic_function_config.py +0 -0
  71. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/skill_definition/__init__.py +0 -0
  72. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/skill_definition/function_view.py +0 -0
  73. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/skill_definition/parameter_view.py +0 -0
  74. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/skill_definition/read_only_skill_collection.py +0 -0
  75. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/skill_definition/read_only_skill_collection_base.py +0 -0
  76. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/skill_definition/sk_function_context_parameter_decorator.py +0 -0
  77. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/skill_definition/sk_function_decorator.py +0 -0
  78. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/skill_definition/skill_collection.py +0 -0
  79. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/skill_definition/skill_collection_base.py +0 -0
  80. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/README.md +0 -0
  81. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/blocks/block.py +0 -0
  82. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/blocks/block_types.py +0 -0
  83. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/blocks/code_block.py +0 -0
  84. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/blocks/function_id_block.py +0 -0
  85. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/blocks/symbols.py +0 -0
  86. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/blocks/text_block.py +0 -0
  87. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/blocks/val_block.py +0 -0
  88. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/blocks/var_block.py +0 -0
  89. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/code_tokenizer.py +0 -0
  90. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/prompt_template_engine.py +0 -0
  91. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/protocols/code_renderer.py +0 -0
  92. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/protocols/prompt_templating_engine.py +0 -0
  93. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/protocols/text_renderer.py +0 -0
  94. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/template_engine/template_tokenizer.py +0 -0
  95. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/text/__init__.py +0 -0
  96. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/text/function_extension.py +0 -0
  97. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/utils/null_logger.py +0 -0
  98. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/utils/static_property.py +0 -0
  99. {semantic_kernel-0.3.0.dev0 → semantic_kernel-0.3.2.dev0}/semantic_kernel/utils/validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: semantic-kernel
3
- Version: 0.3.0.dev0
3
+ Version: 0.3.2.dev0
4
4
  Summary:
5
5
  Author: Microsoft
6
6
  Author-email: SK-Support@microsoft.com
@@ -13,6 +13,8 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Requires-Dist: aiofiles (>=23.1.0,<24.0.0)
14
14
  Requires-Dist: numpy (>=1.24.2,<2.0.0)
15
15
  Requires-Dist: openai (>=0.27.0,<0.28.0)
16
+ Requires-Dist: python-dotenv (==1.0.0)
17
+ Requires-Dist: regex (>=2023.6.3,<2024.0.0)
16
18
  Description-Content-Type: text/markdown
17
19
 
18
20
  # About Semantic Kernel
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "semantic-kernel"
3
- version = "0.3.0.dev"
3
+ version = "0.3.2.dev"
4
4
  description = ""
5
5
  authors = ["Microsoft <SK-Support@microsoft.com>"]
6
6
  readme = "pip/README.md"
@@ -11,15 +11,16 @@ python = "^3.8"
11
11
  numpy = "^1.24.2"
12
12
  openai = "^0.27.0"
13
13
  aiofiles = "^23.1.0"
14
+ python-dotenv = "1.0.0"
15
+ regex = "^2023.6.3"
14
16
 
15
17
  [tool.poetry.group.dev.dependencies]
16
- pre-commit = "^2.21.0"
17
- black = {version = "^23.3.0", allow-prereleases = true}
18
+ pre-commit = "3.3.3"
19
+ black = {version = "23.3.0", allow-prereleases = true}
18
20
  ipykernel = "^6.21.1"
19
- pytest = "7.2.0"
20
- ruff = "^0.0.257"
21
- pytest-asyncio = "^0.21.0"
22
-
21
+ pytest = "7.4.0"
22
+ ruff = "0.0.277"
23
+ pytest-asyncio = "0.21.0"
23
24
 
24
25
  [tool.poetry.group.hugging_face.dependencies]
25
26
  transformers = "^4.28.1"
@@ -33,10 +34,14 @@ chromadb = "^0.3.23"
33
34
  [tool.poetry.group.weaviate.dependencies]
34
35
  weaviate-client = "^3.18.0"
35
36
 
37
+ [tool.poetry.group.pinecone.dependencies]
38
+ pinecone-client = "^2.2.2"
39
+
36
40
  [tool.isort]
37
41
  profile = "black"
38
42
 
39
43
  [tool.ruff]
44
+ select = ["E", "F", "I"]
40
45
  line-length = 120
41
46
 
42
47
  [build-system]
@@ -17,6 +17,7 @@ from semantic_kernel.utils.null_logger import NullLogger
17
17
  from semantic_kernel.utils.settings import (
18
18
  azure_openai_settings_from_dot_env,
19
19
  openai_settings_from_dot_env,
20
+ pinecone_settings_from_dot_env,
20
21
  )
21
22
 
22
23
  __all__ = [
@@ -24,6 +25,7 @@ __all__ = [
24
25
  "NullLogger",
25
26
  "openai_settings_from_dot_env",
26
27
  "azure_openai_settings_from_dot_env",
28
+ "pinecone_settings_from_dot_env",
27
29
  "PromptTemplateConfig",
28
30
  "PromptTemplate",
29
31
  "ChatPromptTemplate",
@@ -0,0 +1,52 @@
1
+ # Copyright (c) Microsoft. All rights reserved.
2
+
3
+ from abc import ABC, abstractmethod
4
+ from logging import Logger
5
+ from typing import TYPE_CHECKING, List, Tuple, Union
6
+
7
+ if TYPE_CHECKING:
8
+ from semantic_kernel.connectors.ai.chat_request_settings import ChatRequestSettings
9
+
10
+
11
+ class ChatCompletionClientBase(ABC):
12
+ @abstractmethod
13
+ async def complete_chat_async(
14
+ self,
15
+ messages: List[Tuple[str, str]],
16
+ settings: "ChatRequestSettings",
17
+ logger: Logger,
18
+ ) -> Union[str, List[str]]:
19
+ """
20
+ This is the method that is called from the kernel to get a response from a chat-optimized LLM.
21
+
22
+ Arguments:
23
+ messages {List[Tuple[str, str]]} -- A list of tuples, where each tuple is
24
+ comprised of a speaker ID and a message.
25
+ settings {ChatRequestSettings} -- Settings for the request.
26
+ logger {Logger} -- A logger to use for logging.
27
+
28
+ Returns:
29
+ Union[str, List[str]] -- A string or list of strings representing the response(s) from the LLM.
30
+ """
31
+ pass
32
+
33
+ @abstractmethod
34
+ async def complete_chat_stream_async(
35
+ self,
36
+ messages: List[Tuple[str, str]],
37
+ settings: "ChatRequestSettings",
38
+ logger: Logger,
39
+ ):
40
+ """
41
+ This is the method that is called from the kernel to get a stream response from a chat-optimized LLM.
42
+
43
+ Arguments:
44
+ messages {List[Tuple[str, str]]} -- A list of tuples, where each tuple is
45
+ comprised of a speaker ID and a message.
46
+ settings {ChatRequestSettings} -- Settings for the request.
47
+ logger {Logger} -- A logger to use for logging.
48
+
49
+ Yields:
50
+ A stream representing the response(s) from the LLM.
51
+ """
52
+ pass
@@ -15,6 +15,7 @@ class ChatRequestSettings:
15
15
  top_p: float = 1.0
16
16
  presence_penalty: float = 0.0
17
17
  frequency_penalty: float = 0.0
18
+ number_of_responses: int = 1
18
19
  max_tokens: int = 256
19
20
 
20
21
  def update_from_completion_config(
@@ -24,6 +25,7 @@ class ChatRequestSettings:
24
25
  self.top_p = completion_config.top_p
25
26
  self.presence_penalty = completion_config.presence_penalty
26
27
  self.frequency_penalty = completion_config.frequency_penalty
28
+ self.number_of_responses = completion_config.number_of_responses
27
29
  self.max_tokens = completion_config.max_tokens
28
30
 
29
31
  @staticmethod
@@ -29,6 +29,7 @@ class CompleteRequestSettings:
29
29
  self.frequency_penalty = completion_config.frequency_penalty
30
30
  self.max_tokens = completion_config.max_tokens
31
31
  self.stop_sequences = completion_config.stop_sequences
32
+ self.number_of_responses = completion_config.number_of_responses
32
33
 
33
34
  @staticmethod
34
35
  def from_completion_config(
@@ -2,7 +2,7 @@
2
2
 
3
3
  from logging import Logger
4
4
  from threading import Thread
5
- from typing import Optional
5
+ from typing import List, Optional, Union
6
6
 
7
7
  from semantic_kernel.connectors.ai.ai_exception import AIException
8
8
  from semantic_kernel.connectors.ai.complete_request_settings import (
@@ -64,17 +64,7 @@ class HuggingFaceTextCompletion(TextCompletionClientBase):
64
64
 
65
65
  async def complete_async(
66
66
  self, prompt: str, request_settings: CompleteRequestSettings
67
- ) -> str:
68
- """
69
- Completes a prompt using the Hugging Face model.
70
-
71
- Arguments:
72
- prompt {str} -- Prompt to complete.
73
- request_settings {CompleteRequestSettings} -- Request settings.
74
-
75
- Returns:
76
- str -- Completion result.
77
- """
67
+ ) -> Union[str, List[str]]:
78
68
  try:
79
69
  import transformers
80
70
 
@@ -84,15 +74,30 @@ class HuggingFaceTextCompletion(TextCompletionClientBase):
84
74
  max_new_tokens=request_settings.max_tokens,
85
75
  pad_token_id=50256, # EOS token
86
76
  )
87
- result = self.generator(
88
- prompt, num_return_sequences=1, generation_config=generation_config
77
+
78
+ results = self.generator(
79
+ prompt,
80
+ do_sample=True,
81
+ num_return_sequences=request_settings.number_of_responses,
82
+ generation_config=generation_config,
89
83
  )
90
84
 
85
+ completions = list()
91
86
  if self._task == "text-generation" or self._task == "text2text-generation":
92
- return result[0]["generated_text"]
87
+ for response in results:
88
+ completions.append(response["generated_text"])
89
+ if len(completions) == 1:
90
+ return completions[0]
91
+ else:
92
+ return completions
93
93
 
94
94
  elif self._task == "summarization":
95
- return result[0]["summary_text"]
95
+ for response in results:
96
+ completions.append(response["summary_text"])
97
+ if len(completions) == 1:
98
+ return completions[0]
99
+ else:
100
+ return completions
96
101
 
97
102
  else:
98
103
  raise AIException(
@@ -107,6 +112,23 @@ class HuggingFaceTextCompletion(TextCompletionClientBase):
107
112
  async def complete_stream_async(
108
113
  self, prompt: str, request_settings: CompleteRequestSettings
109
114
  ):
115
+ """
116
+ Streams a text completion using a Hugging Face model.
117
+ Note that this method does not support multiple responses.
118
+
119
+ Arguments:
120
+ prompt {str} -- Prompt to complete.
121
+ request_settings {CompleteRequestSettings} -- Request settings.
122
+
123
+ Yields:
124
+ str -- Completion result.
125
+ """
126
+ if request_settings.number_of_responses > 1:
127
+ raise AIException(
128
+ AIException.ErrorCodes.InvalidConfiguration,
129
+ "HuggingFace TextIteratorStreamer does not stream multiple responses in a parseable format. \
130
+ If you need multiple responses, please use the complete_async method.",
131
+ )
110
132
  try:
111
133
  import transformers
112
134
 
@@ -116,15 +138,18 @@ class HuggingFaceTextCompletion(TextCompletionClientBase):
116
138
  max_new_tokens=request_settings.max_tokens,
117
139
  pad_token_id=50256, # EOS token
118
140
  )
141
+
119
142
  tokenizer = transformers.AutoTokenizer.from_pretrained(self._model_id)
120
143
  streamer = transformers.TextIteratorStreamer(tokenizer)
121
- args = {"prompt": prompt}
144
+ args = {prompt}
122
145
  kwargs = {
123
- "num_return_sequences": 1,
146
+ "num_return_sequences": request_settings.number_of_responses,
124
147
  "generation_config": generation_config,
125
148
  "streamer": streamer,
149
+ "do_sample": True,
126
150
  }
127
151
 
152
+ # See https://github.com/huggingface/transformers/blob/main/src/transformers/generation/streamers.py#L159
128
153
  thread = Thread(target=self.generator, args=args, kwargs=kwargs)
129
154
  thread.start()
130
155
 
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Microsoft. All rights reserved.
2
2
 
3
3
  from logging import Logger
4
- from typing import Any, List, Optional, Tuple
4
+ from typing import Any, List, Optional, Tuple, Union
5
5
 
6
6
  import openai
7
7
 
@@ -61,28 +61,37 @@ class OpenAIChatCompletion(ChatCompletionClientBase, TextCompletionClientBase):
61
61
 
62
62
  async def complete_chat_async(
63
63
  self, messages: List[Tuple[str, str]], request_settings: ChatRequestSettings
64
- ) -> str:
64
+ ) -> Union[str, List[str]]:
65
65
  # TODO: tracking on token counts/etc.
66
66
  response = await self._send_chat_request(messages, request_settings, False)
67
67
 
68
- return response.choices[0].message.content
68
+ if len(response.choices) == 1:
69
+ return response.choices[0].message.content
70
+ else:
71
+ return [choice.message.content for choice in response.choices]
69
72
 
70
73
  async def complete_chat_stream_async(
71
74
  self, messages: List[Tuple[str, str]], request_settings: ChatRequestSettings
72
75
  ):
73
76
  response = await self._send_chat_request(messages, request_settings, True)
77
+
78
+ # parse the completion text(s) and yield them
74
79
  async for chunk in response:
75
- if "role" in chunk.choices[0].delta:
76
- yield chunk.choices[0].delta.role + ": "
77
- if "content" in chunk.choices[0].delta:
78
- yield chunk.choices[0].delta.content
80
+ text, index = _parse_choices(chunk)
81
+ # if multiple responses are requested, keep track of them
82
+ if request_settings.number_of_responses > 1:
83
+ completions = [""] * request_settings.number_of_responses
84
+ completions[index] = text
85
+ yield completions
86
+ # if only one response is requested, yield it
87
+ else:
88
+ yield text
79
89
 
80
90
  async def complete_async(
81
91
  self, prompt: str, request_settings: CompleteRequestSettings
82
- ) -> str:
92
+ ) -> Union[str, List[str]]:
83
93
  """
84
- Completes the given prompt. Returns a single string completion.
85
- Cannot return multiple completions. Cannot return logprobs.
94
+ Completes the given prompt.
86
95
 
87
96
  Arguments:
88
97
  prompt {str} -- The prompt to complete.
@@ -98,12 +107,16 @@ class OpenAIChatCompletion(ChatCompletionClientBase, TextCompletionClientBase):
98
107
  presence_penalty=request_settings.presence_penalty,
99
108
  frequency_penalty=request_settings.frequency_penalty,
100
109
  max_tokens=request_settings.max_tokens,
110
+ number_of_responses=request_settings.number_of_responses,
101
111
  )
102
112
  response = await self._send_chat_request(
103
113
  prompt_to_message, chat_settings, False
104
114
  )
105
115
 
106
- return response.choices[0].message.content
116
+ if len(response.choices) == 1:
117
+ return response.choices[0].message.content
118
+ else:
119
+ return [choice.message.content for choice in response.choices]
107
120
 
108
121
  async def complete_stream_async(
109
122
  self, prompt: str, request_settings: CompleteRequestSettings
@@ -115,12 +128,21 @@ class OpenAIChatCompletion(ChatCompletionClientBase, TextCompletionClientBase):
115
128
  presence_penalty=request_settings.presence_penalty,
116
129
  frequency_penalty=request_settings.frequency_penalty,
117
130
  max_tokens=request_settings.max_tokens,
131
+ number_of_responses=request_settings.number_of_responses,
118
132
  )
119
133
  response = await self._send_chat_request(prompt_to_message, chat_settings, True)
120
134
 
135
+ # parse the completion text(s) and yield them
121
136
  async for chunk in response:
122
- if "content" in chunk.choices[0].delta:
123
- yield chunk.choices[0].delta.content
137
+ text, index = _parse_choices(chunk)
138
+ # if multiple responses are requested, keep track of them
139
+ if request_settings.number_of_responses > 1:
140
+ completions = [""] * request_settings.number_of_responses
141
+ completions[index] = text
142
+ yield completions
143
+ # if only one response is requested, yield it
144
+ else:
145
+ yield text
124
146
 
125
147
  async def _send_chat_request(
126
148
  self,
@@ -129,7 +151,7 @@ class OpenAIChatCompletion(ChatCompletionClientBase, TextCompletionClientBase):
129
151
  stream: bool,
130
152
  ):
131
153
  """
132
- Completes the given user message. Returns a single string completion.
154
+ Completes the given user message with an asynchronous stream.
133
155
 
134
156
  Arguments:
135
157
  user_message {str} -- The message (from a user) to respond to.
@@ -184,6 +206,7 @@ class OpenAIChatCompletion(ChatCompletionClientBase, TextCompletionClientBase):
184
206
  presence_penalty=request_settings.presence_penalty,
185
207
  frequency_penalty=request_settings.frequency_penalty,
186
208
  max_tokens=request_settings.max_tokens,
209
+ n=request_settings.number_of_responses,
187
210
  stream=stream,
188
211
  )
189
212
  except Exception as ex:
@@ -196,3 +219,14 @@ class OpenAIChatCompletion(ChatCompletionClientBase, TextCompletionClientBase):
196
219
  # TODO: tracking on token counts/etc.
197
220
 
198
221
  return response
222
+
223
+
224
+ def _parse_choices(chunk):
225
+ message = ""
226
+ if "role" in chunk.choices[0].delta:
227
+ message += chunk.choices[0].delta.role + ": "
228
+ if "content" in chunk.choices[0].delta:
229
+ message += chunk.choices[0].delta.content
230
+
231
+ index = chunk.choices[0].index
232
+ return message, index
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Microsoft. All rights reserved.
2
2
 
3
3
  from logging import Logger
4
- from typing import Any, Optional
4
+ from typing import Any, List, Optional, Union
5
5
 
6
6
  import openai
7
7
 
@@ -56,10 +56,14 @@ class OpenAITextCompletion(TextCompletionClientBase):
56
56
 
57
57
  async def complete_async(
58
58
  self, prompt: str, request_settings: CompleteRequestSettings
59
- ) -> str:
59
+ ) -> Union[str, List[str]]:
60
60
  # TODO: tracking on token counts/etc.
61
61
  response = await self._send_completion_request(prompt, request_settings, False)
62
- return response.choices[0].text
62
+
63
+ if len(response.choices) == 1:
64
+ return response.choices[0].text
65
+ else:
66
+ return [choice.text for choice in response.choices]
63
67
 
64
68
  # TODO: complete w/ multiple...
65
69
 
@@ -67,8 +71,15 @@ class OpenAITextCompletion(TextCompletionClientBase):
67
71
  self, prompt: str, request_settings: CompleteRequestSettings
68
72
  ):
69
73
  response = await self._send_completion_request(prompt, request_settings, True)
74
+
70
75
  async for chunk in response:
71
- yield chunk.choices[0].text
76
+ if request_settings.number_of_responses > 1:
77
+ for choice in chunk.choices:
78
+ completions = [""] * request_settings.number_of_responses
79
+ completions[choice.index] = choice.text
80
+ yield completions
81
+ else:
82
+ yield chunk.choices[0].text
72
83
 
73
84
  async def _send_completion_request(
74
85
  self, prompt: str, request_settings: CompleteRequestSettings, stream: bool
@@ -96,13 +107,6 @@ class OpenAITextCompletion(TextCompletionClientBase):
96
107
  f"but was {request_settings.max_tokens}",
97
108
  )
98
109
 
99
- if request_settings.number_of_responses != 1:
100
- raise AIException(
101
- AIException.ErrorCodes.InvalidRequest,
102
- "complete_async only supports a single completion, "
103
- f"but {request_settings.number_of_responses} were requested",
104
- )
105
-
106
110
  if request_settings.logprobs != 0:
107
111
  raise AIException(
108
112
  AIException.ErrorCodes.InvalidRequest,
@@ -131,6 +135,7 @@ class OpenAITextCompletion(TextCompletionClientBase):
131
135
  frequency_penalty=request_settings.frequency_penalty,
132
136
  max_tokens=request_settings.max_tokens,
133
137
  stream=stream,
138
+ n=request_settings.number_of_responses,
134
139
  stop=(
135
140
  request_settings.stop_sequences
136
141
  if request_settings.stop_sequences is not None
@@ -0,0 +1,52 @@
1
+ # Copyright (c) Microsoft. All rights reserved.
2
+
3
+ from abc import ABC, abstractmethod
4
+ from logging import Logger
5
+ from typing import TYPE_CHECKING, List, Union
6
+
7
+ if TYPE_CHECKING:
8
+ from semantic_kernel.connectors.ai.complete_request_settings import (
9
+ CompleteRequestSettings,
10
+ )
11
+
12
+
13
+ class TextCompletionClientBase(ABC):
14
+ @abstractmethod
15
+ async def complete_async(
16
+ self,
17
+ prompt: str,
18
+ settings: "CompleteRequestSettings",
19
+ logger: Logger,
20
+ ) -> Union[str, List[str]]:
21
+ """
22
+ This is the method that is called from the kernel to get a response from a text-optimized LLM.
23
+
24
+ Arguments:
25
+ prompt {str} -- The prompt to send to the LLM.
26
+ settings {CompleteRequestSettings} -- Settings for the request.
27
+ logger {Logger} -- A logger to use for logging.
28
+
29
+ Returns:
30
+ Union[str, List[str]] -- A string or list of strings representing the response(s) from the LLM.
31
+ """
32
+ pass
33
+
34
+ @abstractmethod
35
+ async def complete_stream_async(
36
+ self,
37
+ prompt: str,
38
+ settings: "CompleteRequestSettings",
39
+ logger: Logger,
40
+ ):
41
+ """
42
+ This is the method that is called from the kernel to get a stream response from a text-optimized LLM.
43
+
44
+ Arguments:
45
+ prompt {str} -- The prompt to send to the LLM.
46
+ settings {CompleteRequestSettings} -- Settings for the request.
47
+ logger {Logger} -- A logger to use for logging.
48
+
49
+ Yields:
50
+ A stream representing the response(s) from the LLM.
51
+ """
52
+ pass
@@ -158,12 +158,14 @@ class ChromaMemoryStore(MemoryStoreBase):
158
158
  if collection is None:
159
159
  raise Exception(f"Collection '{collection_name}' does not exist")
160
160
 
161
- # TODO: timestamp
161
+ record._key = record._id
162
162
  metadata = {
163
163
  "timestamp": record._timestamp or "",
164
164
  "is_reference": record._is_reference,
165
165
  "external_source_name": record._external_source_name or "",
166
166
  "description": record._description or "",
167
+ "additional_metadata": record._additional_metadata or "",
168
+ "id": record._id or "",
167
169
  }
168
170
 
169
171
  collection.add(
@@ -171,11 +173,12 @@ class ChromaMemoryStore(MemoryStoreBase):
171
173
  # by providing embeddings, we can skip the chroma's embedding function call
172
174
  embeddings=record.embedding.tolist(),
173
175
  documents=record._text,
174
- ids=record._id,
176
+ ids=record._key,
175
177
  )
178
+
176
179
  if self._persist_directory is not None:
177
180
  self._client.persist()
178
- return record._id
181
+ return record._key
179
182
 
180
183
  async def upsert_batch_async(
181
184
  self, collection_name: str, records: List[MemoryRecord]
@@ -237,7 +240,7 @@ class ChromaMemoryStore(MemoryStoreBase):
237
240
  )
238
241
 
239
242
  value = collection.get(ids=keys, include=query_includes)
240
- record = query_results_to_records(value)
243
+ record = query_results_to_records(value, with_embeddings)
241
244
  return record
242
245
 
243
246
  async def remove_async(self, collection_name: str, key: str) -> None:
@@ -318,7 +321,7 @@ class ChromaMemoryStore(MemoryStoreBase):
318
321
  record_list = [
319
322
  (record, distance)
320
323
  for record, distance in zip(
321
- query_results_to_records(query_results),
324
+ query_results_to_records(query_results, with_embeddings),
322
325
  similarity_score,
323
326
  )
324
327
  ]
@@ -22,7 +22,9 @@ def camel_to_snake(camel_str):
22
22
  return snake_str
23
23
 
24
24
 
25
- def query_results_to_records(results: "QueryResult") -> List[MemoryRecord]:
25
+ def query_results_to_records(
26
+ results: "QueryResult", with_embedding: bool
27
+ ) -> List[MemoryRecord]:
26
28
  # if results has only one record, it will be a list instead of a nested list
27
29
  # this is to make sure that results is always a nested list
28
30
  # {'ids': ['test_id1'], 'embeddings': [[...]], 'documents': ['sample text1'], 'metadatas': [{...}]}
@@ -34,28 +36,49 @@ def query_results_to_records(results: "QueryResult") -> List[MemoryRecord]:
34
36
  except IndexError:
35
37
  return []
36
38
 
37
- memory_records = [
38
- (
39
- MemoryRecord(
40
- is_reference=metadata["is_reference"],
41
- external_source_name=metadata["external_source_name"],
42
- id=id,
43
- description=metadata["description"],
44
- text=document,
45
- # TODO: get_async say embedding is optional but Record constructor requires it
46
- embedding=embedding,
47
- # TODO: what is key for?
48
- key=None,
49
- timestamp=metadata["timestamp"],
39
+ if with_embedding:
40
+ memory_records = [
41
+ (
42
+ MemoryRecord(
43
+ is_reference=metadata["is_reference"],
44
+ external_source_name=metadata["external_source_name"],
45
+ id=metadata["id"],
46
+ description=metadata["description"],
47
+ text=document,
48
+ embedding=embedding,
49
+ additional_metadata=metadata["additional_metadata"],
50
+ key=id,
51
+ timestamp=metadata["timestamp"],
52
+ )
50
53
  )
51
- )
52
- for id, document, embedding, metadata in zip(
53
- results["ids"][0],
54
- results["documents"][0],
55
- results["embeddings"][0],
56
- results["metadatas"][0],
57
- )
58
- ]
54
+ for id, document, embedding, metadata in zip(
55
+ results["ids"][0],
56
+ results["documents"][0],
57
+ results["embeddings"][0],
58
+ results["metadatas"][0],
59
+ )
60
+ ]
61
+ else:
62
+ memory_records = [
63
+ (
64
+ MemoryRecord(
65
+ is_reference=metadata["is_reference"],
66
+ external_source_name=metadata["external_source_name"],
67
+ id=metadata["id"],
68
+ description=metadata["description"],
69
+ text=document,
70
+ embedding=None,
71
+ additional_metadata=metadata["additional_metadata"],
72
+ key=id,
73
+ timestamp=metadata["timestamp"],
74
+ )
75
+ )
76
+ for id, document, metadata in zip(
77
+ results["ids"][0],
78
+ results["documents"][0],
79
+ results["metadatas"][0],
80
+ )
81
+ ]
59
82
  return memory_records
60
83
 
61
84
 
@@ -0,0 +1,7 @@
1
+ # Copyright (c) Microsoft. All rights reserved.
2
+
3
+ from semantic_kernel.connectors.memory.pinecone.pinecone_memory_store import (
4
+ PineconeMemoryStore,
5
+ )
6
+
7
+ __all__ = ["PineconeMemoryStore"]