Jan 7, 2025

Create AI Assistant for Revit | pyRevit Hacker Podcast #1

Learn how to integrade Open AI by using pyRevit by listening to the first episode of pyRevit Hackers Podcast

Code from Podcast:

The code below was kindly provided by Ashish Ranjan after he has attended to pyRevit Hackers Podcase #1.



📁Openai_Server/chatgpt_service.py

import openai
import sys
import json

# Replace 'your_openai_api_key' with your actual OpenAI API key
openai.api_key = 'OpenAI API key'
def ask_openai(question):
    try:
        # Use ChatCompletion endpoint to get a response from ChatGPT
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",  # Use "gpt-4" if you have access
            messages=[{"role": "user", "content": question}],
            max_tokens=100,
            temperature=0.7
        )
        # Extract and return the response content
        return response.choices[0].message['content'].strip()
    except Exception as e:
        return f"Error: {str(e)}"

if __name__ == "__main__":
    # Check if the question is provided as a command-line argument
    if len(sys.argv) < 2:
        print("Error: No question provided.")
        sys.exit(1)

    # Get the question from the command-line argument
    question = sys.argv[1]

    # Get the response from OpenAI
    response_text = ask_openai(question)

    # Print the response to be captured by script.py
    print(response_text)



📁AskRev.pushbutton


ChatGPTForm.xaml

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="AskRev – Get Answers, Gain Insight" Height="400" Width="450" WindowStartupLocation="CenterScreen">
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- Conversation History RichTextBox -->
        <RichTextBox x:Name="ConversationHistory" Grid.Row="0" Margin="0,0,0,10"
                     HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                     Background="LightGray" IsReadOnly="True" VerticalScrollBarVisibility="Auto"
                     FontSize="15" />

        <!-- TextBox for New Question Input -->
        <TextBox x:Name="QuestionInput" Grid.Row="1" Margin="0,0,0,10" Height="30"
                 HorizontalAlignment="Stretch" VerticalAlignment="Top"/>

        <!-- Send Button -->
        <Button x:Name="SendButton" Content="Send" Width="80" Height="30"
                HorizontalAlignment="Center" Grid.Row="2" Background="LightGreen" Margin="0,0,0,10"/>
    </Grid>
</Window>



script.py

from pyrevit import forms
import subprocess
import os
from System.Windows.Documents import Run, Paragraph
from System.Windows.Media import Brushes

# Define the function to send a question to ChatGPT
def ask_chatgpt(question):
    try:
        # Run chatgpt_service.py with the user's question as a command-line argument
        result = subprocess.check_output(
            [
                r"....",  # Full path to Python executable
                r"....",  # Full path to chatgpt_service.py
                question
            ],
            stderr=subprocess.STDOUT,
            universal_newlines=True
        )
        return result.strip()
    except subprocess.CalledProcessError as e:
        return "Error from chatgpt_service.py: " + e.output.strip()
    except Exception as e:
        return "An unexpected error occurred: " + str(e)

# Define the main form class
class ChatGPTForm(forms.WPFWindow):
    def __init__(self):
        # Load the XAML file
        xaml_path = os.path.join(os.path.dirname(__file__), "ChatGPTForm.xaml")
        forms.WPFWindow.__init__(self, xaml_path)

        # Attach the Send button click event
        self.SendButton.Click += self.send_button_click

    def send_button_click(self, sender, args):
        # Get the user's question from the QuestionInput TextBox
        user_question = self.QuestionInput.Text.strip()
        if user_question == "":
            return

        # Add the user's question in red to the ConversationHistory RichTextBox
        user_paragraph = Paragraph()
        user_run = Run("User: {}\n".format(user_question))
        user_run.Foreground = Brushes.Red
        user_paragraph.Inlines.Add(user_run)
        self.ConversationHistory.Document.Blocks.Add(user_paragraph)

        # Get response from ChatGPT
        response_text = ask_chatgpt(user_question)

        # Add ChatGPT's response in green to the ConversationHistory RichTextBox
        bot_paragraph = Paragraph()
        bot_run = Run("AskRev: {}\n\n".format(response_text))
        bot_run.Foreground = Brushes.Green
        bot_paragraph.Inlines.Add(bot_run)
        self.ConversationHistory.Document.Blocks.Add(bot_paragraph)

        # Clear the QuestionInput TextBox
        self.QuestionInput.Text = ""

        # Scroll to the bottom of the ConversationHistory RichTextBox
        self.ConversationHistory.ScrollToEnd()

# Show the dialog window
try:
    ChatGPTForm().ShowDialog()
except Exception as e:
    print("An error occurred while displaying the form:", e)


📁ModelMind.pushbutton

ModelChatForm.xaml

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ModelMind-Your Model’s Knowledge, Unlocked" Height="400" Width="450" WindowStartupLocation="CenterScreen">
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- Conversation History RichTextBox -->
        <RichTextBox x:Name="ConversationHistory" Grid.Row="0" Margin="0,0,0,10"
                     HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                     Background="LightGray" IsReadOnly="True" VerticalScrollBarVisibility="Auto"
                     FontSize="15" />

        <!-- TextBox for New Question Input -->
        <TextBox x:Name="QuestionInput" Grid.Row="1" Margin="0,0,0,10" Height="30"
                 HorizontalAlignment="Stretch" VerticalAlignment="Top"/>

        <!-- Send Button -->
        <Button x:Name="SendButton" Content="Send" Width="80" Height="30"
                HorizontalAlignment="Center" Grid.Row="2" Background="LightGreen" Margin="0,0,0,10"/>
    </Grid>
</Window>


script.py

import clr
import json
import os
import sys
import subprocess
from pyrevit import forms
from System.Windows.Documents import Run, Paragraph
from System.Windows.Media import Brushes
from Autodesk.Revit.UI import UIApplication
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInParameter

# Define paths to the external Python interpreter and main.py script
python_exe_path = r"" # Full path to Python executable
main_script_path = r"" # Full path to chatgpt_service.py

# Access the Revit document using UIApplication
uiapp = __revit__  # Get the Revit application from pyRevit's __revit__ variable
doc = uiapp.ActiveUIDocument.Document

# Path to the extracted data JSON file
data_path = os.path.join(os.path.expanduser("~"), "RevitModelData.json")


# Function to extract model data and save to JSON
def extract_model_data():
    elements = FilteredElementCollector(doc).WhereElementIsNotElementType().ToElements()
    all_data = []
    for el in elements:
        data = {
            "Id": el.Id.IntegerValue,
            "Category": el.Category.Name if el.Category else "N/A",
            "Name": el.Name if hasattr(el, "Name") else "Unnamed Element",
            "Volume": el.LookupParameter("Volume").AsDouble() if el.LookupParameter("Volume") else None,
            "Area": el.LookupParameter("Area").AsDouble() if el.LookupParameter("Area") else None,
            "Material": el.LookupParameter("Material").AsString() if el.LookupParameter("Material") else "Not Specified"
        }
        all_data.append(data)

    # Save extracted data to JSON
    with open(data_path, 'w') as f:
        json.dump(all_data, f, indent=4)

    return all_data


# Load data from file if available, otherwise extract it
if os.path.exists(data_path):
    with open(data_path, 'r') as f:
        model_data = json.load(f)
else:
    model_data = extract_model_data()


# Define query function to call OpenAI via subprocess
def query_data(question, model_data):
    input_data = json.dumps({
        "question": question,
        "model_data": model_data
    })

    # Run main.py with the question and model data as input
    try:
        process = subprocess.Popen(
            [python_exe_path, main_script_path],
            stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
            universal_newlines=True
        )
        stdout, stderr = process.communicate(input=input_data)

        if process.returncode != 0:
            return "Error: " + stderr.strip()

        return stdout.strip()
    except Exception as e:
        return "An error occurred: " + str(e)


# Main chat interface
class ModelChatForm(forms.WPFWindow):
    def __init__(self):
        xaml_path = os.path.join(os.path.dirname(__file__), "ModelChatForm.xaml")
        forms.WPFWindow.__init__(self, xaml_path)
        self.SendButton.Click += self.send_button_click

    def send_button_click(self, sender, args):
        user_question = self.QuestionInput.Text.strip()
        if user_question == "":
            return

        # Display user question in red
        user_paragraph = Paragraph()
        user_run = Run("User: {}\n".format(user_question))
        user_run.Foreground = Brushes.Red
        user_paragraph.Inlines.Add(user_run)
        self.ConversationHistory.Document.Blocks.Add(user_paragraph)

        # Get response from OpenAI's API via subprocess
        response_text = query_data(user_question, model_data)

        # Display response in green
        bot_paragraph = Paragraph()
        bot_run = Run("ModelMind: {}\n\n".format(response_text))
        bot_run.Foreground = Brushes.Green
        bot_paragraph.Inlines.Add(bot_run)
        self.ConversationHistory.Document.Blocks.Add(bot_paragraph)

        # Clear input and scroll to bottom
        self.QuestionInput.Text = ""
        self.ConversationHistory.ScrollToEnd()


try:
    ModelChatForm().ShowDialog()
except Exception as e:
    print("An error occurred:", e)




Join Newsletter

📩 You will be added to Revit API Newsletter

Join Us!

which is already read by 7500+ people!

Ready to become Revit Hero for your office? Learn Revit API!

Join this comprehensive course that will guide you step by step on how to create your dream tools for Revit that save time.