Skip to content

Commit ffc9e43

Browse files
authored
Merge pull request #56 from aws-samples/development
Development
2 parents cd41b44 + 6f1cb88 commit ffc9e43

9 files changed

Lines changed: 793 additions & 0 deletions

File tree

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# AWS Langchain
2+
このリポジトリは [Langchain](https://github.com/hwchase17/langchain/tree/master) と Amazon Kendra を利用するためのサンプルを提供します。
3+
現在、SageMaker、OpenAI、および Anthropic プロバイダー向けに QA チェーンを実行するための [Kendra retriever クラス](https://python.langchain.com/docs/modules/data_connection/retrievers/integrations/amazon_kendra_retriever)のサンプルが含まれています。
4+
5+
## インストール
6+
7+
リポジトリをクローンします
8+
```bash
9+
git clone https://github.com/aws-samples/amazon-kendra-langchain-extensions.git
10+
```
11+
12+
リポジトリのあるディレクトリに移動します
13+
```bash
14+
cd amazon-kendra-langchain-extensions
15+
```
16+
17+
サンプルディレクトリに移動します
18+
```bash
19+
cd kendra_retriever_samples
20+
```
21+
22+
依存関係をインストールします
23+
24+
pip を使用する場合
25+
```bash
26+
pip install -r requirements.txt
27+
```
28+
29+
Conda を利用する場合
30+
```bash
31+
conda env create -f environment.yml
32+
```
33+
34+
### Bedrock の場合
35+
Bedrock を使用する場合、Bedrock サポートを持つ最新の boto3 および langchain バージョンに更新し、Bedrock へのアクセス権を持つ AWS_PROFILE を使用していることを確認してください。
36+
37+
```
38+
pip install --force-reinstall "langchain>=0.0.306"
39+
pip install --force-reinstall "boto3>=1.28.57"
40+
```
41+
42+
## サンプルの実行
43+
サンプルを実行する前に、Large Language Model をデプロイする(または Anthropic や OpenAI を使用する場合は API キーを取得する)必要があります。このリポジトリのサンプルは、SageMaker Jumpstart と Amazon Bedrock を使用して展開されたモデルでテストされています。 LLM のモデル ID は以下の表にまとめられています。
44+
45+
| モデル名 | 環境変数名 | Jumpstart モデル ID | streamlit プロバイダ | 日本語対応 |
46+
| ------------------- | ------------------- | ---------------------------------------- | -------------------- | ---------- |
47+
| Falcon 40B instruct | FALCON_40B_ENDPOINT | huggingface-llm-falcon-40b-instruct-bf16 | falcon40b |
48+
| Bedrock Claude | None | | bedrock_claude |
49+
| Bedrock Claude V2 | None | | bedrock_claudev2 |
50+
51+
LLMをデプロイした後、kendra ID、aws_region、エンドポイント名(または外部プロバイダーの API キー)の環境変数を設定する必要があります。
52+
53+
例えば、`kendra_chat_open_ai.py` のサンプルを実行する場合、以下の環境変数を設定する必要があります
54+
- AWS_REGION
55+
- KENDRA_INDEX_ID
56+
- OPENAI_API_KEY
57+
58+
以下のコマンドを使用して環境変数を設定できます。使用するプロバイダーの環境変数のみを設定します。たとえば、Flan-xl を使用する場合は FLAN_XXL_ENDPOINT のみを設定します。他のエンドポイントとキーは設定する必要はありません。
59+
60+
```bash
61+
export LANGUAGE_CODE=ja
62+
export AWS_REGION=<YOUR-AWS-REGION>
63+
export AWS_PROFILE=<AWS Profile>
64+
export KENDRA_INDEX_ID=<YOUR-KENDRA-INDEX-ID>
65+
66+
export FALCON_40B_ENDPOINT=<YOUR-SAGEMAKER-ENDPOINT-FOR-FALCON> # only if you are using falcon as the endpoint
67+
export OPENAI_API_KEY=<YOUR-OPEN-AI-API-KEY> # only if you are using OPENAI as the endpoint
68+
```
69+
70+
71+
### streamlit アプリからのサンプルの実行(日本語未対応)
72+
サンプルディレクトリには、streamlit を使用してウェブアプリとして実行できる `app.py` ファイルが含まれています。
73+
74+
```bash
75+
streamlit run app.py falcon40b
76+
```
77+
78+
上記のコマンドは、LLM チェーンとして `kendra_chat_falcon_40b` を実行します。異なるチェーンを実行するには、異なるプロバイダーを渡してください。たとえば、`open_ai` チェーンを実行する場合は `streamlit run app.py openai` を実行します。テーブル上の「streamlitプロバイダ名」列を活用してプロバイダ名を確認してください。
79+
80+
### コマンドラインからのサンプルの実行
81+
```bash
82+
python <sample-file-name.py>
83+
```
84+
85+
## Contributing
86+
このリポジトリのフォークを作成して、変更内容をプルリクエストで提出してください。
87+
詳細については、[CONTRIBUTING](../CONTRIBUTING.md) を参照してください。
88+
89+
## License
90+
このライブラリは MIT-0 ライセンスのもとで提供されています。詳細は LICENSE ファイルをご覧ください。
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Sample chains for AWS Langchain integration"""

kendra_retriever_samples/ja/app.py

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
import streamlit as st
2+
import uuid
3+
import sys
4+
import kendra_chat_open_ai as openai
5+
import kendra_chat_falcon_40b as falcon40b
6+
import kendra_chat_bedrock_claude as bedrock_claude
7+
import kendra_chat_bedrock_claudev2 as bedrock_claudev2
8+
9+
10+
USER_ICON = "images/user-icon.png"
11+
AI_ICON = "images/ai-icon.png"
12+
MAX_HISTORY_LENGTH = 5
13+
PROVIDER_MAP = {
14+
"openai": "Open AI",
15+
"falcon40b": "Falcon 40B",
16+
}
17+
18+
19+
# function to read a properties file and create environment variables
20+
def read_properties_file(filename):
21+
import os
22+
import re
23+
24+
with open(filename, "r") as f:
25+
for line in f:
26+
m = re.match(r"^\s*(\w+)\s*=\s*(.*)\s*$", line)
27+
if m:
28+
os.environ[m.group(1)] = m.group(2)
29+
30+
31+
# Check if the user ID is already stored in the session state
32+
if "user_id" in st.session_state:
33+
user_id = st.session_state["user_id"]
34+
35+
# If the user ID is not yet stored in the session state, generate a random UUID
36+
else:
37+
user_id = str(uuid.uuid4())
38+
st.session_state["user_id"] = user_id
39+
40+
41+
if "llm_chain" not in st.session_state:
42+
if len(sys.argv) > 1:
43+
if sys.argv[1] == "openai":
44+
st.session_state["llm_app"] = openai
45+
st.session_state["llm_chain"] = openai.build_chain()
46+
elif sys.argv[1] == "falcon40b":
47+
st.session_state["llm_app"] = falcon40b
48+
st.session_state["llm_chain"] = falcon40b.build_chain()
49+
elif sys.argv[1] == "bedrock_claude":
50+
st.session_state["llm_app"] = bedrock_claude
51+
st.session_state["llm_chain"] = bedrock_claude.build_chain()
52+
elif sys.argv[1] == "bedrock_claudev2":
53+
st.session_state["llm_app"] = bedrock_claudev2
54+
st.session_state["llm_chain"] = bedrock_claudev2.build_chain()
55+
else:
56+
raise Exception("Unsupported LLM: ", sys.argv[1])
57+
else:
58+
raise Exception("Usage: streamlit run app.py <openai|falcon40b|bedrock_claude|bedrock|claudev2>")
59+
60+
61+
if "chat_history" not in st.session_state:
62+
st.session_state["chat_history"] = []
63+
64+
if "chats" not in st.session_state:
65+
st.session_state.chats = [{"id": 0, "question": "", "answer": ""}]
66+
67+
if "questions" not in st.session_state:
68+
st.session_state.questions = []
69+
70+
if "answers" not in st.session_state:
71+
st.session_state.answers = []
72+
73+
if "input" not in st.session_state:
74+
st.session_state.input = ""
75+
76+
77+
st.markdown(
78+
"""
79+
<style>
80+
.block-container {
81+
padding-top: 32px;
82+
padding-bottom: 32px;
83+
padding-left: 0;
84+
padding-right: 0;
85+
}
86+
.element-container img {
87+
background-color: #000000;
88+
}
89+
90+
.main-header {
91+
font-size: 24px;
92+
}
93+
</style>
94+
""",
95+
unsafe_allow_html=True,
96+
)
97+
98+
99+
def write_logo():
100+
col1, col2, col3 = st.columns([5, 1, 5])
101+
with col2:
102+
st.image(AI_ICON, use_column_width="always")
103+
104+
105+
def write_top_bar():
106+
col1, col2, col3 = st.columns([1, 10, 2])
107+
with col1:
108+
st.image(AI_ICON, use_column_width="always")
109+
with col2:
110+
selected_provider = sys.argv[1]
111+
if selected_provider in PROVIDER_MAP:
112+
provider = PROVIDER_MAP[selected_provider]
113+
else:
114+
provider = selected_provider.capitalize()
115+
header = f"An AI App powered by Amazon Kendra and {provider}!"
116+
st.write(f"<h3 class='main-header'>{header}</h3>", unsafe_allow_html=True)
117+
with col3:
118+
clear = st.button("Clear Chat")
119+
return clear
120+
121+
122+
clear = write_top_bar()
123+
124+
if clear:
125+
st.session_state.questions = []
126+
st.session_state.answers = []
127+
st.session_state.input = ""
128+
st.session_state["chat_history"] = []
129+
130+
131+
def handle_input():
132+
input = st.session_state.input
133+
question_with_id = {"question": input, "id": len(st.session_state.questions)}
134+
st.session_state.questions.append(question_with_id)
135+
136+
chat_history = st.session_state["chat_history"]
137+
if len(chat_history) == MAX_HISTORY_LENGTH:
138+
chat_history = chat_history[:-1]
139+
140+
llm_chain = st.session_state["llm_chain"]
141+
chain = st.session_state["llm_app"]
142+
result = chain.run_chain(llm_chain, input, chat_history)
143+
answer = result["answer"]
144+
chat_history.append((input, answer))
145+
146+
document_list = []
147+
if "source_documents" in result:
148+
for d in result["source_documents"]:
149+
if not (d.metadata["source"] in document_list):
150+
document_list.append((d.metadata["source"]))
151+
152+
st.session_state.answers.append(
153+
{
154+
"answer": result,
155+
"sources": document_list,
156+
"id": len(st.session_state.questions),
157+
}
158+
)
159+
st.session_state.input = ""
160+
161+
162+
def write_user_message(md):
163+
col1, col2 = st.columns([1, 12])
164+
165+
with col1:
166+
st.image(USER_ICON, use_column_width="always")
167+
with col2:
168+
st.warning(md["question"])
169+
170+
171+
def render_result(result):
172+
answer, sources = st.tabs(["Answer", "Sources"])
173+
with answer:
174+
render_answer(result["answer"])
175+
with sources:
176+
if "source_documents" in result:
177+
render_sources(result["source_documents"])
178+
else:
179+
render_sources([])
180+
181+
182+
def render_answer(answer):
183+
col1, col2 = st.columns([1, 12])
184+
with col1:
185+
st.image(AI_ICON, use_column_width="always")
186+
with col2:
187+
st.info(answer["answer"])
188+
189+
190+
def render_sources(sources):
191+
col1, col2 = st.columns([1, 12])
192+
with col2:
193+
with st.expander("Sources"):
194+
for s in sources:
195+
st.write(s)
196+
197+
198+
# Each answer will have context of the question asked in order to associate the provided feedback with the respective question
199+
def write_chat_message(md, q):
200+
chat = st.container()
201+
with chat:
202+
render_answer(md["answer"])
203+
render_sources(md["sources"])
204+
205+
206+
with st.container():
207+
for q, a in zip(st.session_state.questions, st.session_state.answers):
208+
write_user_message(q)
209+
write_chat_message(a, q)
210+
211+
st.markdown("---")
212+
input = st.text_input(
213+
"You are talking to an AI, ask any question.", key="input", on_change=handle_input
214+
)
853 Bytes
Loading
411 Bytes
Loading

0 commit comments

Comments
 (0)