avfranco's picture
ea4all-gradio-agents-mcp-hackathon-vqa-empty-img-error
bd5398a
#CHANGELOG: 2025-06-04
## Gradio Agents MCP Hackathon: retrofit to expose EA4ALL Agentic System Agents only
## Greetings message not working
## UI exposing too much tools, need to be refactored
from langchain.callbacks.tracers import LangChainTracer
from langchain.callbacks.tracers.langchain import wait_for_all_tracers
from langchain_core.messages import HumanMessage
from langchain_core.runnables import RunnableConfig
from ea4all.src.shared.configuration import BaseConfiguration, APM_MOCK_QNA, PMO_MOCK_QNA
from ea4all.src.ea4all_gra.configuration import AgentConfiguration as gra
from ea4all.src.ea4all_apm.graph import apm_graph
from ea4all.src.ea4all_vqa.graph import diagram_graph
from ea4all.src.ea4all_gra.graph import togaf_graph
from ea4all.src.ea4all_indexer.graph import indexer_graph
from ea4all.src.shared.utils import (
get_relevant_questions,
get_vqa_examples,
_join_paths,
EA4ALL_ARCHITECTURE,
EA4ALL_PODCAST,
)
#from ea4all.src.pmo_crew.crew_runner import run_pmo_crew
from typing import AsyncGenerator
import gradio as gr
from gradio import ChatMessage
import os
import uuid
import time
from PIL import Image
from ea4all.utils.utils import (
UIUtils,
ea4all_agent_init, get_image,
get_question_diagram_from_example,
on_image_update
)
TITLE = """
# Title
**Explore, Share, Together:** harness the value of `Enterprise Architecture in the era of Generative AI` with ready-to-use MCP Tools.\n
## Overview
"""
#Set LangSmith project
tracer = LangChainTracer(project_name=os.getenv('LANGCHAIN_PROJECT'))
config = RunnableConfig(
run_name = os.getenv('LANGCHAIN_RUNNAME', "ea4all-gradio-agent-mcp-hackathon-run"),
tags = [os.getenv('EA4ALL_ENV', "MCP")],
callbacks = [tracer],
recursion_limit = 25,
configurable = {"thread_id": uuid.uuid4()},
#stream_mode = "messages"
)
async def call_indexer_apm(config: RunnableConfig):
response = await indexer_graph.ainvoke(input={"docs":[]}, config=config)
return response
#ea4all-qna-agent-conversational-with-memory
async def run_qna_agentic_system(question: str) -> AsyncGenerator[list, None]:
"""
description:
Handles conversational Q&A for the Application Landscape using an agentic system.
Args:
question (str): The user's question or message.
request (gr.Request): The Gradio request object for user identification.
Returns:
reponse: Response to user's architectural question.
"""
format_response = ""
chat_memory = []
if not question:
format_response = "Hi, how are you today? To start using the EA4ALL MCP Tool, provide the required Inputs!"
chat_memory.append(ChatMessage(role="assistant", content=format_response))
else:
index = await call_indexer_apm(config) #call indexer to update the index
response = await apm_graph.ainvoke({"question": question}, config=config)
chat_memory.append(ChatMessage(role="assistant", content=response['generation']))
yield chat_memory
#Trigger Solution Architecture Diagram QnA
async def run_vqa_agentic_system(question: str, diagram: str, request: gr.Request) -> AsyncGenerator[list, None]:
"""
description:
Handles Visual Question Answering (VQA) for uploaded architecture diagrams.
Args:
question (str): User's question about the Architecture Diagram.
diagram (str): Path to the diagram file.
Returns:
response: Response to user's question.
"""
#capture user ip
#ea4all_user = e4u.get_user_identification(request)
"""Handle file uploads and validate their types."""
allowed_file_types = ('JPEG', 'PNG')
message = {
'text': question,
'files': [diagram] if isinstance(diagram, str) else diagram
}
print("---CALLING VISUAL QUESTION ANSWERING AGENTIC SYSTEM---")
print(f"Prompt: {message}")
chat_memory = []
if message['files'] in ([], None):
chat_memory.append(ChatMessage(role="assistant", content="Please upload an Architecture PNG, JPEG diagram to start!"))
yield chat_memory
else:
diagram = message['files'][-1] ##chat_memory[-1]['content'][-1]
msg = message['text'] ##chat_memory[-2]['content']
print(f"---DIAGRAM: {diagram}---")
try:
if msg == "":
msg = "Please describe this diagram."
with Image.open(diagram) as diagram_:
if diagram_.format not in allowed_file_types:
#chat_memory.append(ChatMessage(role="assistant", content="Invalid file type. Allowed file types are JPEG and PNG."))
print(f"---DIAGRAM: {diagram.format} is not a valid file type. Allowed file types are JPEG and PNG.---")
#else:
#'vqa_image = e4u.get_raw_image(diagram) #MOVED into Graph
vqa_image = diagram
response = await diagram_graph.ainvoke({"question":msg, "image": vqa_image}, config)
chat_memory.append(ChatMessage(role="assistant", content=response['messages'][-1].content if len(response['messages']) else response['safety_status']['description']))
yield chat_memory
except Exception as e:
yield (e.args[-1])
#Run Togaf Agentic System
async def run_reference_architecture_agentic_system(business_query: str) -> AsyncGenerator[list, str]:
"""
description:
Generates a reference architecture blueprint based on a business requirement using the TOGAF agentic system.
Args:
business_query (str): Description of a business problem / requirement.
Returns:
response: High-level architecture blueprint and target diagram.
"""
if len(business_query) < 20:
agent_response = "Please provide a valid Business Requirement content to start!"
yield([agent_response, None])
else:
inputs = {"business_query": [{"role": "user", "content": business_query}]} #user response
index = await call_indexer_apm(config) #call indexer to update the index
response = await togaf_graph.ainvoke(
input=inputs,
config=config
) #astream not loading the graph
vision_target = response['vision_target']
if isinstance(response['architecture_runway'], str):
architecture_runway = response['architecture_runway']
else:
architecture_runway = None
yield [vision_target, architecture_runway]
async def run_pmo_agentic_system(question:str) -> AsyncGenerator[list, None]:
"""
description:
Answers questions about Project Portfolio Management and Architect Demand Management.
Args:
question (str): The user's question about project portfolio or resource management.
chat_memory: The conversation history.
Returns:
response: Architect Demand Allocation Report
"""
format_response = ""
chat_memory = []
if not question:
format_response = "Hi, how are you today? To start our conversation, please chat your message!"
chat_memory.append(ChatMessage(role="assistant", content=format_response))
yield chat_memory
if not chat_memory:
chat_memory.append(ChatMessage(role="user", content=question))
yield chat_memory
inputs = {
"question": question,
"verbose": True, # optional flags
}
#yield run_pmo_crew(inputs)
#Blocks w/ ChatInterface, BYOD, About
with gr.Blocks(title="Your ArchitectGPT",fill_height=True, fill_width=True) as ea4all_mcp:
agentic_pmo_desc="""
Hi,
Provide project resource estimation for architecture work based on business requirements, skillset,
architects allocation, and any other relevant information to enable successful project solution delivery."""
agentic_qna_desc="""
Hi,
Improve Architect's ability to share knowledge, and provide valuable insights from IT landscape using natural language answering questions related to Enterprise Architecture, Technology, plus the following IT Landscape sample dataset: """
agentic_vqa_desc="""
Hi,
Gain rapid knowledge and insights translating image to meaningful description.
"""
agentic_togaf_desc="""
Hi,
in a click of button create a reference architecture that serves as a blueprint for designing and implementing IT solutions.
Standardise, increase efficiency and productivity to architecture solution development.
Generate context-specific reference and minimal viable architectures to support business and IT strategy and digital transformation.
Streamline the architecture operating model, taking the best of agentic workflows and architects working together.
"""
#Wrapper for functions not to be exposed by the MCP Server
wrapper = gr.Button(visible=False) #wrapper.click(UIUtils.ea4all_about, show_api=False,)
wrapper1 = gr.Button(visible=False) #wrapper1.click(init_dbr, show_api=False,)
#EA4ALL-Agentic system menu
with gr.Tabs(selected="how_to") as tabs:
with gr.Tab(label="Architect Demand Management", visible=False):
with gr.Tab(label="Architect Project Planning", id="pmo_qna_1"):
ea4all_pmo_description = gr.Markdown(value=agentic_pmo_desc)
pmo_chatbot = gr.Chatbot(
label="EA4ALL your AI Demand Management Architect Companion", type="messages",
max_height=160,
layout="bubble",
)
pmo_prompt = gr.Textbox(lines=1, show_label=False, max_lines=1, submit_btn=True, stop_btn=True,autofocus=True, placeholder="Type your message here or select an example...")
with gr.Accordion("Open for question examples", open=False):
pmo_examples = gr.Dropdown(get_relevant_questions(PMO_MOCK_QNA), value=None,label="Questions", interactive=True)
gr.ClearButton([pmo_chatbot,pmo_prompt], value="Clear", size="sm", visible=False)
with gr.Tab(label="Project Portfolio Sample Dataset", id="id_pmo_ds"):
pmo_df = gr.Dataframe()
with gr.Tab(label="Application Landscape QnA"):
with gr.Tabs() as tabs_apm_qna:
with gr.Tab(label="Connect, Explore, Together", id="app_qna_1"):
ea4all_agent_metadata = gr.Markdown(value=agentic_qna_desc)
ea4all_chatbot = gr.Chatbot(
label="EA4ALL your AI Landscape Architect Companion", type="messages",
max_height=160,
layout="bubble",
)
qna_prompt = gr.Textbox(lines=1, show_label=False, max_lines=1, submit_btn=True, autofocus=True, placeholder="Type your message here or select an example...")
with gr.Accordion("Open for question examples", open=False):
qna_examples = gr.Dropdown(get_relevant_questions(APM_MOCK_QNA),label="Questions", interactive=True)
gr.ClearButton([ea4all_chatbot,qna_prompt, qna_examples], value="Clear", size="sm", visible=True)
with gr.Tab(label="Sample Dataset", id="id_apm_ds"):
apm_df = gr.Dataframe()
with gr.Tab(label="Diagram Question and Answering"):
gr.Markdown(value=agentic_vqa_desc)
ea4all_vqa = gr.Chatbot(
label="EA4ALL your AI Multimodal Architect Companion", type="messages",
max_height=160,
layout="bubble",
)
vqa_prompt = gr.Textbox(lines=1, show_label=False, max_lines=1, submit_btn=True, stop_btn=True,autofocus=True, placeholder="Type your message here and upload your diagram...")
vqa_image = gr.Image(
label="Architecture Diagram",
type="filepath",
format="jpeg, png",
interactive=True,
show_download_button=False,
show_share_button=False,
visible=True,
)
#vqa_prompt = gr.MultimodalTextbox(interactive=True, show_label=False, submit_btn=True, stop_btn=True, autofocus=True, placeholder="Upload your diagram and type your message or select an example...")
with gr.Accordion("Open for question examples", open=False):
vqa_examples = gr.Dropdown(get_vqa_examples(), value=0,label="Diagram and Questions", interactive=True)
gr.ClearButton([ea4all_vqa,vqa_prompt,vqa_image, vqa_examples], value="Clear", size="sm", visible=True)
with gr.Tab(label="Reference Architecture", id="id_refarch"):
dbr_text=gr.TextArea(label="Business Problem Sample", value="Provide a Business Problem / Requirement Specification or select an example provided.", lines=14, interactive=True)
togaf_vision=gr.Markdown(value='### Reference Architecture: Vision and Target')
architecture_runway=gr.Image(label="Target Architecture Runway",interactive=False,visible=False)
with gr.Row():
dbr_file=gr.File(
value=_join_paths(BaseConfiguration.ea4all_store, gra.dbr_mock),
label="Business Requirement",
height=35,
show_label=False,
file_count="single",
file_types=['text'],
interactive=True,
type='binary',
visible=False
)
dbr_run=gr.Button(scale=None,value="Run Reference Architecture")
dbr_cls=gr.ClearButton([togaf_vision, architecture_runway])
with gr.Tab(label="Overview", id="how_to"):
gr.Markdown(value=TITLE)
gr.Image(
get_image(EA4ALL_ARCHITECTURE),
show_download_button=False,
container=False,
show_share_button=False,
)
gr.Markdown(
"""
- `Empower individuals with Knowledge`: understand and talk about Business and Technology strategy, IT landscape, Architectue Artefacts in a single click of button.
- `Increase efficiency and productivity`: generate a documented architecture with diagram, model and descriptions. Accelerate Business Requirement identification and translation to Target Reference Architecture. Automated steps and reduced times for task execution.
- `Improve agility`: plan, execute, review and iterate over EA inputs and outputs. Increase the ability to adapt, transform and execute at pace and scale in response to changes in strategy, threats and opportunities.
- `Increase collaboration`: democratise architecture work and knowledge with anyone using natural language.
### Knowledge Context
Synthetic datasets are used to exemplify the Agentic System capabilities.
### IT Landscape Question and Answering
- Application name
- Business fit: appropriate, inadequate, perfect
- Technical fit: adequate, insufficient, perfect
- Business_criticality: operational, medium, high, critical
- Roadmap: maintain, invest, divers
- Architect responsible
- Hosting: user device, on-premise, IaaS, SaaS
- Business capability
- Business domain
- Description
### Architecture Diagram Visual Question and Answering
- Architecture Visual Artefacts
- jpeg, png
**Disclaimer**
- Your data & image are not accessible or shared with anyone else nor used for training purpose.
- EA4ALL-VQA Agent should be used ONLY FOR Architecture Diagram images.
- This feature should NOT BE USED to process inappropriate content.
### Reference Architecture Generation
- Clock in/out Use-case
"""
)
#Avoid exposing API /Dependency?
#dbr_text.change(wrapper1.click(init_dbr,show_api=False)) NOT working
#Togaf upload file
#dbr_file.clear(unload_dbr,outputs=dbr_text)
#dbr_file.change(on_dbrtext,inputs=dbr_file,outputs=dbr_text)
dbr_file.change(UIUtils.load_dbr,inputs=dbr_file, outputs=dbr_text, show_api=False)
#dbr_cls.click(off_dbrtext,outputs=[dbr_text, tabs_togaf, tab_diagram])
#Refactored ea4all_chatbot / vqa_chatbot (ChatInterface -> Chatbot)
qna_prompt.submit(run_qna_agentic_system,[qna_prompt],ea4all_chatbot, api_name="landscape_answering_agent")
#qna_prompt.submit(lambda: "", None, [qna_prompt])
#ea4all_chatbot.like(fn=get_user_feedback)
qna_examples.input(lambda value: value, qna_examples, qna_prompt, show_api=False)
#Execute Reference Architecture
dbr_run.click(run_reference_architecture_agentic_system,show_progress='full',inputs=[dbr_text],outputs=[togaf_vision, architecture_runway], api_name="togaf_blueprint_generation")
architecture_runway.change(on_image_update, inputs=architecture_runway, outputs=architecture_runway, show_api=False)
#chat_msg = vqa_prompt.submit(UIUtils.add_message, [vqa_prompt, vqa_image], [vqa_prompt, ea4all_vqa], show_api=False)
#bot_msg = chat_msg.then(run_vqa_agentic_system, [vqa_prompt, vqa_image], ea4all_vqa, api_name="diagram_answering_agent")
vqa_prompt.submit(run_vqa_agentic_system,[vqa_prompt, vqa_image], ea4all_vqa, api_name="diagram_answering_agent")
#ea4all_vqa.like(fn=get_user_feedback)
vqa_examples.input(get_question_diagram_from_example, vqa_examples, outputs=[vqa_prompt, vqa_image], show_api=False)
#Invoke CrewAI PMO Agentic System
pmo_prompt.submit(run_pmo_agentic_system,[pmo_prompt],pmo_chatbot, api_name="architect_demand_agent", show_api=False)
pmo_prompt.submit(lambda: "", None, [pmo_prompt], show_api=False)
#pmo_examples.input(lambda value: value, pmo_examples, pmo_prompt)
#Set initial state of apm and llm
ea4all_mcp.load(ea4all_agent_init, outputs=[
ea4all_agent_metadata,
ea4all_chatbot,
ea4all_vqa,
pmo_chatbot,
apm_df,
pmo_df,
dbr_text
],
show_api=False)