Skip to content

Commit 69b3484

Browse files
committed
WIP multimodal
1 parent 88b087c commit 69b3484

File tree

5 files changed

+69
-9
lines changed

5 files changed

+69
-9
lines changed

instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/langgraph-chatbot-demo/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ readme = "README.md"
66
requires-python = ">=3.9"
77
dependencies = [
88
"duckduckgo-search>=7.3.0",
9+
"google-cloud-storage[tracing]>=2.19.0",
910
"langchain-community>=0.3.16",
1011
"langchain-core>=0.3.31",
1112
"langchain-google-vertexai>=2.0.7",

instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/langgraph-chatbot-demo/src/langgraph_chatbot_demo/_streamlit_helpers.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313
@st.cache_data
14-
def _get_project_id() -> str:
14+
def get_project_id() -> str:
1515
project_id: str = google.auth.default()[1] # type: ignore
1616
return project_id
1717

@@ -117,12 +117,20 @@ def styles() -> None:
117117

118118
def render_message(message: BaseMessage, trace_id: str | None) -> None:
119119
# Filter out tool calls
120-
if not (message.type in ("human", "ai") and message.content):
120+
if message.type not in ("human", "ai"):
121+
return
122+
123+
content = (
124+
message.content
125+
if isinstance(message.content, str)
126+
else message.content[-1]["text"]
127+
).strip()
128+
if not content:
121129
return
122130

123131
with st.chat_message(message.type):
124132
col1, col2 = st.columns([0.9, 0.1])
125-
col1.markdown(message.content)
133+
col1.markdown(content)
126134
if trace_id:
127135
col2.link_button(
128136
"",
@@ -133,7 +141,7 @@ def render_message(message: BaseMessage, trace_id: str | None) -> None:
133141

134142

135143
def _trace_url(trace_id: str | None = None) -> str:
136-
url = f"https://console.cloud.google.com/traces/explorer;query=%7B%22plotType%22:%22HEATMAP%22,%22targetAxis%22:%22Y1%22,%22traceQuery%22:%7B%22resourceContainer%22:%22projects%2F{_get_project_id()}%2Flocations%2Fglobal%2FtraceScopes%2F_Default%22,%22spanDataValue%22:%22SPAN_DURATION%22,%22spanFilters%22:%7B%22attributes%22:%5B%5D,%22displayNames%22:%5B%22chain%20invoke%22%5D,%22isRootSpan%22:true,%22kinds%22:%5B%5D,%22maxDuration%22:%22%22,%22minDuration%22:%22%22,%22services%22:%5B%5D,%22status%22:%5B%5D%7D%7D%7D;duration=PT30M"
144+
url = f"https://console.cloud.google.com/traces/explorer;query=%7B%22plotType%22:%22HEATMAP%22,%22targetAxis%22:%22Y1%22,%22traceQuery%22:%7B%22resourceContainer%22:%22projects%2F{get_project_id()}%2Flocations%2Fglobal%2FtraceScopes%2F_Default%22,%22spanDataValue%22:%22SPAN_DURATION%22,%22spanFilters%22:%7B%22attributes%22:%5B%5D,%22displayNames%22:%5B%22chain%20invoke%22%5D,%22isRootSpan%22:true,%22kinds%22:%5B%5D,%22maxDuration%22:%22%22,%22minDuration%22:%22%22,%22services%22:%5B%5D,%22status%22:%5B%5D%7D%7D%7D;duration=PT30M"
137145
if not trace_id:
138146
return url
139147
return f"{url};traceId={trace_id}"

instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/langgraph-chatbot-demo/src/langgraph_chatbot_demo/langchain_history.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
import sqlite3
44
import tempfile
5+
import pathlib
56
from os import environ
67
from random import getrandbits
8+
from typing import cast
9+
from google.cloud.exceptions import NotFound
710

811
import streamlit as st
912
from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit
@@ -23,6 +26,8 @@
2326
from opentelemetry import trace
2427
from opentelemetry.trace.span import format_trace_id
2528

29+
from google.cloud import storage
30+
2631
_ = """
2732
Ideas for things to add:
2833
@@ -39,10 +44,7 @@
3944
_streamlit_helpers.styles()
4045

4146

42-
model = ChatVertexAI(
43-
model="gemini-1.5-flash",
44-
project=environ.get("GOOGLE_CLOUD_PROJECT", None),
45-
)
47+
model = ChatVertexAI(model="gemini-1.5-flash")
4648

4749
if not st.query_params.get("thread_id"):
4850
result = model.invoke(
@@ -52,6 +54,8 @@
5254
seed=getrandbits(31),
5355
)
5456
st.query_params.thread_id = str(result.content).strip()
57+
if "upload_key" not in st.session_state:
58+
st.session_state.upload_key = 0
5559

5660

5761
# Initialize memory to persist state between graph runs
@@ -65,6 +69,21 @@ def get_checkpointer() -> InMemorySaver:
6569
_streamlit_helpers.render_sidebar(checkpointer)
6670

6771

72+
@st.cache_resource
73+
def get_storage_bucket() -> storage.Bucket:
74+
storage_client = storage.Client()
75+
bucket_name = (
76+
f"{_streamlit_helpers.get_project_id()}-langgraph-chatbot-storage"
77+
)
78+
try:
79+
return storage_client.get_bucket(bucket_name)
80+
except NotFound:
81+
return storage_client.create_bucket(bucket_name)
82+
83+
84+
bucket = get_storage_bucket()
85+
86+
6887
# Define the tools for the agent to use
6988
@tool
7089
@tracer.start_as_current_span("tool search")
@@ -154,8 +173,30 @@ def get_trace_ids(thread_id: str) -> "dict[str, str]":
154173
_streamlit_helpers.render_message(message, trace_id)
155174

156175
# If user inputs a new prompt, generate and draw a new response
176+
# TODO: see if st.form() looks better
177+
file_upload = st.file_uploader(
178+
"Upload an image",
179+
type=["png", "jpg", "jpeg", "pdf", "webp"],
180+
# Hack to clear the upload
181+
key=f"file_uploader_{st.session_state.upload_key}",
182+
)
157183
if prompt := st.chat_input():
158-
message = HumanMessage(prompt)
184+
content = []
185+
186+
# Put the image first https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/image-understanding#best-practices
187+
if file_upload:
188+
filename: str = file_upload.name
189+
blob = bucket.blob(filename)
190+
blob.upload_from_file(file_upload, content_type=file_upload.type)
191+
st.session_state.upload_key += 1
192+
193+
uri = f"gs://{bucket.name}/{blob.name}"
194+
content.append({"type": "image_url", "image_url": {"url": uri}})
195+
196+
content.append({"type": "text", "text": prompt})
197+
198+
message = HumanMessage(content)
199+
159200
with col1:
160201
with tracer.start_as_current_span(
161202
"chain invoke",

instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/langgraph-chatbot-demo/src/langgraph_chatbot_demo/run_streamlit.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def run_streamlit() -> None:
3333
"OTEL_PYTHON_EXCLUDED_URLS",
3434
"computeMetadata,oauth2.googleapis.com",
3535
)
36+
# subprocess.run(["opentelemetry-instrument", "ipython"])
3637

3738
langchain_app_spec = importlib.util.find_spec(
3839
"langgraph_chatbot_demo.langchain_history"

instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/langgraph-chatbot-demo/uv.lock

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)