-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* save current idea for use cases * add structure for the construct * updates to test simple working flow * add initial doc for lambda layer construct * remove current use case architecture as requires more brainstorming * remove temp drawio file
- Loading branch information
Showing
32 changed files
with
1,151 additions
and
341 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
boto3>=1.28.61 | ||
botocore>=1.31.61 | ||
requests==2.31.0 | ||
requests-aws4auth==1.2.3 | ||
langchain==0.0.309 | ||
opensearch-py==2.3.1 | ||
openai==0.28.1 |
4 changes: 4 additions & 0 deletions
4
layers/langchain-common-layer/python/genai_core/adapters/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from .openai import * | ||
from .sagemaker import * | ||
from .bedrock import * | ||
from .base import Mode |
1 change: 1 addition & 0 deletions
1
layers/langchain-common-layer/python/genai_core/adapters/base/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .base import ModelAdapter, Mode |
199 changes: 199 additions & 0 deletions
199
layers/langchain-common-layer/python/genai_core/adapters/base/base.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
import os | ||
from enum import Enum | ||
from langchain import LLMChain | ||
from langchain.callbacks.base import BaseCallbackHandler | ||
from langchain.chains import ConversationalRetrievalChain, ConversationChain | ||
from langchain.memory import ConversationBufferMemory | ||
from langchain.prompts.prompt import PromptTemplate | ||
from langchain.chains.conversational_retrieval.prompts import ( | ||
QA_PROMPT, | ||
CONDENSE_QUESTION_PROMPT, | ||
) | ||
from genai_core.utils import PredictionException | ||
|
||
|
||
class Mode(Enum): | ||
CHAIN = "qa_chain" | ||
|
||
|
||
class ModelAdapter: | ||
def __init__(self, session_id, user_id, model_kwargs={}, adapter_kwargs={}): | ||
self.session_id = session_id | ||
self.user_id = user_id | ||
self._mode = adapter_kwargs.get("mode", "qa_chain") | ||
self.model_kwargs = model_kwargs | ||
|
||
self.callback_handler = BaseCallbackHandler() | ||
self.__bind_callbacks() | ||
|
||
history_enabled = adapter_kwargs.get("chat_history", False) | ||
if (history_enabled == True): | ||
self.chat_history = self.get_chat_history() | ||
else: | ||
self.chat_history = None | ||
self.llm = self.get_llm(model_kwargs) | ||
|
||
def __bind_callbacks(self): | ||
callback_methods = [method for method in dir(self) if method.startswith("on_")] | ||
valid_callback_names = [ | ||
attr for attr in dir(self.callback_handler) if attr.startswith("on_") | ||
] | ||
|
||
for method in callback_methods: | ||
if method in valid_callback_names: | ||
setattr(self.callback_handler, method, getattr(self, method)) | ||
|
||
def get_llm(self, model_kwargs={}): | ||
raise ValueError("llm must be implemented") | ||
|
||
def get_embeddings_model(self, embeddings): | ||
raise ValueError("embeddings must be implemented") | ||
|
||
def get_chat_history(self): | ||
raise ValueError("get_chat_history must be implemented") | ||
|
||
def get_memory(self, output_key=None): | ||
return ConversationBufferMemory( | ||
memory_key="chat_history", | ||
chat_memory=self.chat_history, | ||
return_messages=True, | ||
output_key=output_key, | ||
) | ||
|
||
def get_prompt_no_history(self): | ||
template = """\n\nHuman: {context} | ||
Answer from this text: {question} | ||
\n\nAssistant:""" | ||
prompt_template = PromptTemplate(template=template, input_variables=["context", "question"]) | ||
|
||
return prompt_template | ||
|
||
def get_prompt(self): | ||
template = """The following is a friendly conversation between a human and an AI. If the AI does not know the answer to a question, it truthfully says it does not know. | ||
Current conversation: | ||
{chat_history} | ||
Question: {input}""" | ||
input_variables = ["input", "chat_history"] | ||
prompt_template_args = { | ||
"chat_history": "{chat_history}", | ||
"input_variables": input_variables, | ||
"template": template, | ||
} | ||
prompt_template = PromptTemplate(**prompt_template_args) | ||
|
||
return prompt_template | ||
|
||
def get_condense_question_prompt(self): | ||
return CONDENSE_QUESTION_PROMPT | ||
|
||
def get_qa_prompt(self): | ||
return QA_PROMPT | ||
|
||
def run_with_chain(self, user_prompt, workspace_id=None): | ||
if not self.llm: | ||
raise ValueError("llm must be set") | ||
|
||
if workspace_id: | ||
conversation = ConversationalRetrievalChain.from_llm( | ||
self.llm, | ||
condense_question_prompt=self.get_condense_question_prompt(), | ||
combine_docs_chain_kwargs={"prompt": self.get_qa_prompt()}, | ||
return_source_documents=True, | ||
memory=self.get_memory(output_key="answer"), | ||
verbose=True, | ||
callbacks=[self.callback_handler], | ||
) | ||
result = conversation({"question": user_prompt}) | ||
print(result["source_documents"]) | ||
documents = [ | ||
{ | ||
"page_content": doc.page_content, | ||
"metadata": doc.metadata, | ||
} | ||
for doc in result["source_documents"] | ||
] | ||
|
||
metadata = { | ||
"modelId": self.model_id, | ||
"modelKwargs": self.model_kwargs, | ||
"mode": self._mode, | ||
"sessionId": self.session_id, | ||
"userId": self.user_id, | ||
"workspaceId": workspace_id, | ||
"documents": documents, | ||
} | ||
|
||
self.chat_history.add_metadata(metadata) | ||
|
||
return { | ||
"sessionId": self.session_id, | ||
"type": "text", | ||
"content": result["answer"], | ||
"metadata": metadata, | ||
} | ||
|
||
if self.chat_history != None: | ||
conversation = ConversationChain( | ||
llm=self.llm, | ||
prompt=self.get_prompt(), | ||
memory=self.get_memory(), | ||
verbose=True, | ||
) | ||
answer = conversation.predict( | ||
input=user_prompt, callbacks=[self.callback_handler] | ||
) | ||
|
||
metadata = { | ||
"modelId": self.model_id, | ||
"modelKwargs": self.model_kwargs, | ||
"mode": self._mode, | ||
"sessionId": self.session_id, | ||
"userId": self.user_id, | ||
"documents": [], | ||
} | ||
|
||
self.chat_history.add_metadata(metadata) | ||
|
||
return { | ||
"sessionId": self.session_id, | ||
"type": "text", | ||
"content": answer, | ||
"metadata": metadata, | ||
} | ||
|
||
chain = LLMChain(llm=self.llm, prompt=self.get_prompt_no_history(), verbose=True) | ||
try: | ||
response = chain.predict(context='', question=user_prompt, callbacks=[self.callback_handler]) | ||
raise PredictionException("claude") | ||
except PredictionException as e: | ||
print(e.message) | ||
#TODO return response | ||
|
||
|
||
metadata = { | ||
"modelId": self.model_id, | ||
"modelKwargs": self.model_kwargs, | ||
"mode": self._mode, | ||
"sessionId": self.session_id, | ||
"userId": self.user_id, | ||
"documents": [], | ||
} | ||
|
||
return { | ||
"sessionId": self.session_id, | ||
"type": "text", | ||
"content": response, | ||
"metadata": metadata, | ||
} | ||
|
||
def run(self, prompt, workspace_id=None, *args, **kwargs): | ||
print(f"run with {kwargs}") | ||
print(f"workspace_id {workspace_id}") | ||
print(f"mode: {self._mode}") | ||
|
||
if self._mode == "qa_chain": | ||
return self.run_with_chain(prompt, workspace_id) | ||
|
||
raise ValueError(f"unknown mode {self._mode}") |
4 changes: 4 additions & 0 deletions
4
layers/langchain-common-layer/python/genai_core/adapters/bedrock/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from .claude import * | ||
from .titan import * | ||
from .ai21_j2 import * | ||
from .cohere import * |
55 changes: 55 additions & 0 deletions
55
layers/langchain-common-layer/python/genai_core/adapters/bedrock/ai21_j2.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import genai_core.clients | ||
from langchain.llms import Bedrock | ||
from langchain.prompts.prompt import PromptTemplate | ||
|
||
from ..base import ModelAdapter | ||
from ..registry import registry | ||
|
||
|
||
class AI21J2Adapter(ModelAdapter): | ||
def __init__(self, model_id, *args, **kwargs): | ||
self.model_id = model_id | ||
|
||
super().__init__(*args, **kwargs) | ||
|
||
def get_llm(self, model_kwargs={}): | ||
bedrock = genai_core.clients.get_bedrock_client() | ||
|
||
params = {} | ||
if "temperature" in model_kwargs: | ||
params["temperature"] = model_kwargs["temperature"] | ||
if "topP" in model_kwargs: | ||
params["topP"] = model_kwargs["topP"] | ||
if "maxTokens" in model_kwargs: | ||
params["maxTokens"] = model_kwargs["maxTokens"] | ||
|
||
return Bedrock( | ||
client=bedrock, | ||
model_id=self.model_id, | ||
model_kwargs=params, | ||
callbacks=[self.callback_handler], | ||
) | ||
|
||
def get_prompt(self): | ||
template = """Human: The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know. | ||
Current conversation: | ||
{chat_history} | ||
Question: {input} | ||
Assistant:""" | ||
|
||
input_variables = ["input", "chat_history"] | ||
prompt_template_args = { | ||
"chat_history": "{chat_history}", | ||
"input_variables": input_variables, | ||
"template": template, | ||
} | ||
prompt_template = PromptTemplate(**prompt_template_args) | ||
|
||
return prompt_template | ||
|
||
|
||
# Register the adapter | ||
registry.register(r"^bedrock.ai21.j2*", AI21J2Adapter) |
Oops, something went wrong.