Skip to content

Commit d9c6b9c

Browse files
authored
Merge branch 'main' into lsa-custom-rag-agent2
2 parents 7fcbc78 + 12f1053 commit d9c6b9c

File tree

9 files changed

+1567
-0
lines changed

9 files changed

+1567
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
Copyright (c) 2025 Oracle and/or its affiliates.
2+
3+
The Universal Permissive License (UPL), Version 1.0
4+
5+
Subject to the condition set forth below, permission is hereby granted to any
6+
person obtaining a copy of this software, associated documentation and/or data
7+
(collectively the "Software"), free of charge and under any and all copyright
8+
rights in the Software, and any and all patent rights owned or freely
9+
licensable by each licensor hereunder covering either (i) the unmodified
10+
Software as contributed to or provided by such licensor, or (ii) the Larger
11+
Works (as defined below), to deal in both
12+
13+
(a) the Software, and
14+
(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
15+
one is included with the Software (each a "Larger Work" to which the Software
16+
is contributed by such licensors),
17+
18+
without restriction, including without limitation the rights to copy, create
19+
derivative works of, display, perform, and distribute the Software and make,
20+
use, sell, offer for sale, import, export, have made, and have sold the
21+
Software and the Larger Work(s), and to sublicense the foregoing rights on
22+
either these or other terms.
23+
24+
This license is subject to the following condition:
25+
The above copyright notice and either this complete permission notice or at
26+
a minimum a reference to the UPL must be included in all copies or
27+
substantial portions of the Software.
28+
29+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35+
SOFTWARE.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
Copyright (c) 2025 Oracle and/or its affiliates.
2+
"""
3+
By Omar Salem
4+
assistant.py - AI Assistant Chatbot (Dynamic Routing).
5+
"""
6+
7+
from state import State
8+
from router import Router
9+
from tools import (
10+
handle_fetch_gmail,
11+
handle_send_email,
12+
handle_ai_agent_query,
13+
handle_select_email,
14+
handle_schedule_email,
15+
handle_llm_query,
16+
handle_weather_query,
17+
handle_calculator,
18+
# handle_generate_reply_with_weather,
19+
handle_generate_reply_with_user_message_and_ai_response,
20+
handle_generate_reply_with_user_message_only,
21+
handle_book_meeting
22+
)
23+
import json
24+
25+
# initialize router
26+
router = Router()
27+
28+
# initialize State
29+
state: State = {
30+
"input": "",
31+
"decisions": [],
32+
"output": "",
33+
"emails": [],
34+
"selected_email": None,
35+
"recipient": "",
36+
"subject": "",
37+
"body": "",
38+
"ai_response": "",
39+
"citations": [],
40+
}
41+
42+
# dynamically map tools
43+
TOOLS = {
44+
"fetch_and_summarize": handle_fetch_gmail,
45+
"send_email": handle_send_email,
46+
"ai_agent": handle_ai_agent_query,
47+
"select_email": handle_select_email,
48+
"schedule_email": handle_schedule_email,
49+
"llm_query": handle_llm_query,
50+
"weather_query": handle_weather_query,
51+
"calculator": handle_calculator,
52+
"generate_reply_with_user_message_only": handle_generate_reply_with_user_message_only,
53+
"generate_reply_with_user_message_and_ai_response": handle_generate_reply_with_user_message_and_ai_response,
54+
"book_meeting": handle_book_meeting,
55+
}
56+
57+
58+
def chatbot():
59+
"""Interactive Chatbot for AI Assistant"""
60+
print("\n **AI Assistant** - Type 'exit' to quit.\n")
61+
62+
while True:
63+
# get user input
64+
user_input = input("📝 You: ").strip()
65+
if user_input.lower() in ["exit", "quit"]:
66+
print("\n👋 Exiting. Have a great day!")
67+
break
68+
69+
# update State
70+
state["input"] = user_input
71+
72+
# dynamic routing assignment
73+
routing_result = router.route(state)
74+
state["decisions"] = routing_result.get("decisions", [])
75+
76+
print(f"\n🤖 **Routing Decisions:** `{state['decisions']}`\n")
77+
78+
# store responses from multiple tools
79+
responses = []
80+
81+
#dynamically execute tools
82+
for decision in state["decisions"]:
83+
tool = TOOLS.get(decision)
84+
if tool:
85+
result = tool(state) # execute tool picked dynamically
86+
responses.append(result["output"])
87+
else:
88+
responses.append(f"❌ Invalid decision: `{decision}`.")
89+
90+
# convert lists to formatted JSON strings before joining
91+
state["output"] = "\n\n".join(
92+
[json.dumps(resp, indent=2) if isinstance(resp, list) else str(resp) for resp in responses]
93+
)
94+
95+
# display Output
96+
print(f"\n✅ **Response:**\n{state['output']}\n")
97+
98+
99+
# run the Chatbot
100+
if __name__ == "__main__":
101+
chatbot()
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
Copyright (c) 2025 Oracle and/or its affiliates.
2+
import streamlit as st
3+
import json
4+
import time
5+
from assistant import TOOLS, router, state
6+
7+
# ==============================
8+
# STREAMLIT UI CONFIGURATION
9+
# ==============================
10+
st.set_page_config(page_title="OCI Assistant Chatbot", layout="wide")
11+
12+
st.markdown(
13+
"<h1 style='text-align: center;'>OCI Assistant Chatbot</h1>",
14+
unsafe_allow_html=True
15+
)
16+
st.write("Manage your emails, schedule meetings, check the weather, and more...")
17+
18+
# ==============================
19+
# INITIALIZE SESSION STATE
20+
# ==============================
21+
if "chat_history" not in st.session_state:
22+
st.session_state.chat_history = []
23+
24+
if "selected_email" not in st.session_state:
25+
st.session_state.selected_email = None
26+
27+
if "latest_response" not in st.session_state:
28+
st.session_state.latest_response = ""
29+
30+
# ==============================
31+
# CHATBOT INTERFACE
32+
# ==============================
33+
34+
# Display chat history
35+
for chat in st.session_state.chat_history:
36+
with st.chat_message("user"):
37+
st.markdown(chat["user"])
38+
with st.chat_message("assistant"):
39+
st.markdown(chat["bot"])
40+
41+
# User input field
42+
user_input = st.text_input("Type your message here...", key="user_input")
43+
44+
# Process user message
45+
if st.button("Send"):
46+
if user_input:
47+
# Display steps
48+
step_placeholder = st.empty() # This will dynamically update
49+
step_placeholder.markdown("🟢 **Step 1:** Capturing user input...")
50+
51+
# Update state with user input
52+
state["input"] = user_input
53+
54+
# Display second step
55+
step_placeholder.markdown("🟢 **Step 2:** Identifying the correct tool...")
56+
57+
# Show spinner while routing
58+
with st.spinner("Processing..."):
59+
time.sleep(1) # Simulating delay
60+
61+
# Route input to the correct function
62+
routing_result = router.route(state)
63+
state["decisions"] = routing_result.get("decisions", [])
64+
65+
# Show detected decisions
66+
step_placeholder.markdown(f"🟢 **Step 3:** Decision made → `{state['decisions']}`")
67+
68+
# Execute tool functions
69+
responses = []
70+
for i, decision in enumerate(state["decisions"], start=1):
71+
step_placeholder.markdown(f"🟢 **Step 4.{i}:** Executing `{decision}`...")
72+
73+
tool = TOOLS.get(decision)
74+
if tool:
75+
with st.spinner(f"Running `{decision}`..."):
76+
time.sleep(1) # Simulate processing time
77+
result = tool(state)
78+
responses.append(result["output"])
79+
else:
80+
responses.append(f"❌ Invalid decision: `{decision}`.")
81+
82+
# Finalize response
83+
step_placeholder.markdown("✅ **Step 5:** Formatting response...")
84+
85+
# Store response
86+
state["output"] = "\n\n".join(
87+
[json.dumps(resp, indent=2) if isinstance(resp, list) else str(resp) for resp in responses]
88+
)
89+
90+
# Update chat history
91+
st.session_state.chat_history.append({"user": user_input, "bot": state["output"]})
92+
93+
# Store latest response
94+
st.session_state.latest_response = state["output"]
95+
96+
# Refresh UI
97+
st.rerun()
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
aiohappyeyeballs==2.4.3
2+
aiohttp==3.11.7
3+
aiosignal==1.3.1
4+
altair==5.5.0
5+
annotated-types==0.7.0
6+
anyio==4.8.0
7+
asttokens==3.0.0
8+
attrs==24.2.0
9+
blinker==1.9.0
10+
cachetools==5.5.0
11+
certifi==2024.12.14
12+
cffi==1.17.1
13+
charset-normalizer==3.4.1
14+
circuitbreaker==2.0.0
15+
click==8.1.7
16+
cryptography==43.0.3
17+
dataclasses-json==0.6.7
18+
decorator==5.1.1
19+
executing==2.2.0
20+
frozenlist==1.5.0
21+
gitdb==4.0.11
22+
GitPython==3.1.43
23+
h11==0.14.0
24+
httpcore==1.0.7
25+
httpx==0.28.1
26+
httpx-sse==0.4.0
27+
idna==3.10
28+
ipython==8.31.0
29+
jedi==0.19.2
30+
Jinja2==3.1.4
31+
jsonpatch==1.33
32+
jsonpointer==3.0.0
33+
jsonschema==4.23.0
34+
jsonschema-specifications==2024.10.1
35+
langchain==0.3.14
36+
langchain-community==0.3.14
37+
langchain-core==0.3.29
38+
langchain-experimental==0.3.4
39+
langchain-text-splitters==0.3.5
40+
langgraph==0.2.62
41+
langgraph-checkpoint==2.0.8
42+
langgraph-sdk==0.1.51
43+
langsmith==0.2.11
44+
markdown-it-py==3.0.0
45+
MarkupSafe==3.0.2
46+
marshmallow==3.23.1
47+
matplotlib-inline==0.1.7
48+
mdurl==0.1.2
49+
msgpack==1.1.0
50+
multidict==6.1.0
51+
mypy-extensions==1.0.0
52+
narwhals==1.14.2
53+
numpy==1.26.4
54+
oci==2.139.0
55+
oracledb==2.5.1
56+
orjson==3.10.15
57+
packaging==24.2
58+
pandas==2.2.3
59+
parso==0.8.4
60+
pexpect==4.9.0
61+
pillow==11.0.0
62+
prompt_toolkit==3.0.50
63+
propcache==0.2.0
64+
protobuf==5.28.3
65+
ptyprocess==0.7.0
66+
pure_eval==0.2.3
67+
pyarrow==18.1.0
68+
pycparser==2.22
69+
pydantic==2.10.6
70+
pydantic-settings==2.6.1
71+
pydantic_core==2.27.2
72+
pydeck==0.9.1
73+
Pygments==2.18.0
74+
pyOpenSSL==24.2.1
75+
python-dateutil==2.9.0.post0
76+
python-dotenv==1.0.1
77+
pytz==2024.2
78+
PyYAML==6.0.2
79+
referencing==0.35.1
80+
requests==2.32.3
81+
requests-toolbelt==1.0.0
82+
rich==13.9.4
83+
rpds-py==0.21.0
84+
six==1.16.0
85+
smmap==5.0.1
86+
sniffio==1.3.1
87+
SQLAlchemy==2.0.35
88+
stack-data==0.6.3
89+
streamlit==1.40.2
90+
tenacity==9.0.0
91+
toml==0.10.2
92+
tornado==6.4.2
93+
traitlets==5.14.3
94+
typing-inspect==0.9.0
95+
typing_extensions==4.12.2
96+
tzdata==2024.2
97+
urllib3==2.3.0
98+
wcwidth==0.2.13
99+
yarl==1.18.0
100+
zstandard==0.23.0
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Copyright (c) 2025 Oracle and/or its affiliates.
2+
"""
3+
By Omar Salem
4+
oci_models.py - Factory for OCI GenAI models (Cohere)
5+
"""
6+
7+
from langchain_community.chat_models import ChatOCIGenAI
8+
9+
# OCI compartment details
10+
COMPARTMENT_OCID = "ocid1.com...."
11+
SERVICE_ENDPOINT = "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com"
12+
13+
LLM_MODEL_ID = "cohere.command-r-plus-08-2024"
14+
ROUTER_MODEL_ID = "cohere.command-r-plus-08-2024"
15+
16+
def create_model_for_routing(temperature=0, max_tokens=512):
17+
"""
18+
Create the OCI Model for routing
19+
"""
20+
return ChatOCIGenAI(
21+
model_id=ROUTER_MODEL_ID,
22+
compartment_id=COMPARTMENT_OCID,
23+
service_endpoint=SERVICE_ENDPOINT,
24+
model_kwargs={"temperature": temperature, "max_tokens": max_tokens},
25+
)

0 commit comments

Comments
 (0)