gen-ui-python

repository·main·Indexed 18 days ago

https://github.com/bracesproul/gen-ui-python

A template for building Generative UI applications using LangChain Python, featuring a Python-based backend (gen-ui-backend v0.0.0) and a frontend built with Shadcn components. It includes a LangGraph-based workflow for orchestrating model invocations and tool execution, a FastAPI server with LangServe integration, and utilities for streaming LangChain runnables as React Server Components (RSC).

Tokens
3.5K
Snippets
14
Records
17
Agent score
63%

What's inside gen-ui-python

  1. Run the frontend and backend development servers

    main

    To run the application locally, you must start both the frontend and backend services in separate terminal windows.

    1. Start the frontend (React/Next.js) on http://localhost:3000:

      cd ./frontend
      yarn dev
    2. Start the backend (Python/Poetry) in a new terminal:

      cd ../backend
      poetry run start
    # Terminal 1: Frontend
    cd ./frontend
    yarn dev
    
    # Terminal 2: Backend
    cd ../backend
    poetry run start
  2. Configure environment variables and secrets

    main

    The application requires several environment variables to function, especially if using the pre-built UI components.

    1. Copy the template: Copy backend/.env.example to backend/.env.
    2. Required Keys:
      • OPENAI_API_KEY: Required for LLM functionality.
      • GITHUB_TOKEN: Requires a GitHub Personal Access Token (PAT) with the repo scope.
      • GEOCODE_API_KEY: Required for geocoding features.
    3. Optional LangSmith Tracing (Recommended):
      • LANGCHAIN_API_KEY
      • LANGCHAIN_CALLBACKS_BACKGROUND=true
      • LANGCHAIN_TRACING_V2=true
    # Example .env content
    LANGCHAIN_API_KEY=...
    LANGCHAIN_CALLBACKS_BACKGROUND=true
    LANGCHAIN_TRACING_V2=true
    
    GITHUB_TOKEN=...
    OPENAI_API_KEY=...
    GEOCODE_API_KEY=...
  3. Install the gen-ui-python application

    main

    To set up the development environment, clone the repository and install dependencies for both the frontend (using yarn) and the backend (using poetry).

    1. Clone the repository:

      git clone https://github.com/bracesproul/gen-ui-python.git
      cd gen-ui-python
    2. Install frontend dependencies:

      cd ./frontend
      yarn install
    3. Install backend dependencies:

      cd ../backend
      poetry install
    git clone https://github.com/bracesproul/gen-ui-python.git
    cd gen-ui-python
    cd ./frontend
    yarn install
    cd ../backend
    poetry install
  4. How the generative UI workflow nodes work

    main

    The workflow is composed of several key functional nodes:

    invoke_model(state, config)

    Invokes a ChatOpenAI model (configured with gpt-4o) bound to a set of tools (github_repo, invoice_parser, weather_data).

    • If the model returns tool calls, it returns a dictionary with tool_calls.
    • If the model returns plain text, it returns a dictionary with result.

    invoke_tools(state)

    Processes the first tool call found in state["tool_calls"]. It maps the tool type to the corresponding tool implementation and invokes it with the provided arguments. It returns a dictionary containing tool_result.

    invoke_tools_or_return(state)

    A conditional edge function that inspects the state to decide the next step:

    • Returns END if state["result"] is a string.
    • Returns "invoke_tools" if state["tool_calls"] is a list.
    • Raises a ValueError if the state is invalid.
  5. Configure LangSmith tracing

    main

    To enable tracing and monitoring of your LangChain operations via LangSmith, set the following environment variables in your .env file:

    • LANGCHAIN_API_KEY: Your LangSmith API key.
    • LANGCHAIN_TRACING_V2: Set to true to enable LangSmith tracing.
    • LANGCHAIN_CALLBACKS_BACKGROUND: Set to true to run callbacks in the background, preventing tracing from blocking your application's execution flow.
    LANGCHAIN_API_KEY=
    LANGCHAIN_CALLBACKS_BACKGROUND=true
    LANGCHAIN_TRACING_V2=true
  6. Configure API keys for backend services

    main

    The backend requires several API keys to function correctly. Ensure these are set in your environment:

    • OPENAI_API_KEY: API key for OpenAI services.
    • GITHUB_TOKEN: GitHub personal access token.
    • GEOCODE_API_KEY: API key for geocoding services.
    GITHUB_TOKEN=
    OPENAI_API_KEY=
    GEOCODE_API_KEY=
  7. Start the Gen UI Backend server

    main

    The backend application is a FastAPI server that exposes LangChain graph routes via LangServe. You can start the server by calling the start() function. By default, the server runs on 0.0.0.0:8000 and includes a /chat endpoint configured for chat-style interaction.

    Note: The server requires environment variables to be loaded (typically from a .env file) and is pre-configured to allow CORS requests from http://localhost and http://localhost:3000.

    from gen_ui_backend.server import start
    
    start()
  8. Create the generative UI graph with create_graph()

    main

    The create_graph() function constructs and compiles a LangGraph StateGraph using GenerativeUIState. This graph orchestrates the flow between model invocation and tool execution.

    The graph follows this logic:

    1. Entry Point: Starts at the invoke_model node.
    2. Conditional Routing: After invoke_model, the invoke_tools_or_return function determines whether to route to the invoke_tools node (if tool calls exist) or to END (if a plain text result exists).
    3. Tool Execution: If routed to invoke_tools, the tool is executed, and the graph finishes.

    Returns a CompiledGraph object that can be invoked with a state containing a HumanMessage in the input field.

    from gen_ui_backend.chain import create_graph
    
    # Initialize the graph
    graph = create_graph()
    
    # To run the graph, you would typically pass a state dictionary
    # containing the 'input' key with a HumanMessage.
    # result = graph.invoke({"input": HumanMessage(content="What is the weather in London?")})
  9. Stream LangChain runnables as UI with streamRunnableUI

    main

    The streamRunnableUI function executes the streamEvents method on a LangChain Runnable or CompiledStateGraph and converts the resulting generator into a React Server Component (RSC) friendly stream.

    It returns an object containing:

    • ui: A streamable UI value created via createStreamableUI that can be consumed by the client.
    • lastEvent: A promise that resolves to the final output of the runnable (e.g., lastEventValue.data.output).

    To update the UI or trigger client-side callbacks during the stream, provide eventHandlers. Each handler receives the current StreamEvent and an EventHandlerFields object containing the ui stream and a callbacks record.

    import { streamRunnableUI } from './server';
    
    const uiStream = streamRunnableUI(
      myLangChainRunnable,
      { input: 'hello' },
      {
        eventHandlers: [
          async (event, { ui, callbacks }) => {
            // Example: Update UI based on specific stream events
            if (event.event === 'on_chat_model_stream') {
              // logic to update ui
            }
          }
        ]
      }
    );
    
    // uiStream.ui can be returned from a React Server Component
    // uiStream.lastEvent is a promise resolving to the final output
  10. Expose server actions to the client with exposeEndpoints

    main

    The exposeEndpoints function is used to wrap server-side actions so they can be safely consumed by client components. It returns a component (often named AI) that wraps its children in an AIProvider, passing the provided actions down the tree.

    This pattern ensures that importing client components works correctly when resolving server-side functions in a Next.js/RSC environment.

    import { exposeEndpoints } from './server';
    
    const myActions = {
      myServerAction: async (data: string) => {
        // ... logic
      }
    };
    
    // This component can be used in your layout or page
    export const AI = exposeEndpoints(myActions);
    
    // Usage in a layout/page:
    // <AI> <YourClientComponents /> </AI>
  11. Configure Gen UI Backend CORS settings

    main

    The server uses CORSMiddleware to manage cross-origin requests. The default allowed origins are:

    • http://localhost
    • http://localhost:3000

    It is configured to allow all methods (*) and all headers (*), and allows credentials.

    # Default CORS configuration in server.py
    origins = [
        "http://localhost",
        "http://localhost:3000",
    ]
    
    app.add_middleware(
        CORSMiddleware,
        allow_origins=origins,
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
  12. Define the GenerativeUIState type

    main

    The GenerativeUIState is a TypedDict used to manage the state of the generative UI workflow. It tracks the user input, the plain text response, parsed tool calls, and the results of those tool calls.

    Fields:

    • input: A HumanMessage representing the user's query.
    • result: An optional str containing the plain text response if no tool was used.
    • tool_calls: An optional List[dict] containing parsed tool calls.
    • tool_result: An optional dict containing the output from a tool execution.
    class GenerativeUIState(TypedDict, total=False):
        input: HumanMessage
        result: Optional[str]
        """Plain text response if no tool was used."""
        tool_calls: Optional[List[dict]]
        """A list of parsed tool calls."""
        tool_result: Optional[dict]
        """The result of a tool call."""