#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'] == []: 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'] architecture_runway = response['architecture_runway'] yield [vision_target, None] 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)