Access to UIApplication, Tags and LLM API Support

Continuing my LLM explorations, Revit API highlights and other stuff of interest:

Revit API Support with Gemini LLM

I continue using LLMs to answer the odd query in the Revit API discussion forum with great success.

I check the question and evaluate whether I can answer it myself or not. In some cases, I can only address it incompletely. In some cases, I decide to ask the LLM for help. Recently, I have mostly been using Gemini 2.0 Flash.

When doing so, I prefix the persona prompt that I developed and refined. I described my prompt development process in the past few posts, cf., first LLM forum solution, Revit API support prompt, and promptimalising my Revit API support prompt

My current prompt is this:

Here are some recent sample threads enlisting help from the LLM:

I cannot always verify that the answer provided is completely accurate. Repeating the question will yield a different answer every time. So, a customer seeking perfection would be well advised to submit it several times over and pick the best one, or the best bits from several.

I often do check that the API calls in the sample code exist. In one of the cases listed above, Gemini produced sample code that hallucinated non-existent Revit API calls. I noticed that and replied to the LLM, saying: “hey, the call you list in your sample code does not exist”. Thereupon the LLM answered, “you are absolutely correct. Sorry about that. Here is true valid sample code instead”. The second answer included true API calls, and I provided that to the customer.

So, important aspect to note: every answer will be different, and some answers contain hallucinations, so every interaction must be taken with a pinch of salt and not blindly trusting.

UIApplication Access

Luiz Henrique @ricaun Cassettari shared a new approach to access the UIApplication object in the thread on how to get UIApplication from IExternalApplication:

Actually you can access the internal UIApplication directly inside the UIControlledApplication using Reflection with no need for any events:

public Result OnStartup(UIControlledApplication application)
{
    UIApplication uiapp = application.GetUIApplication();
    string userName = uiapp.Application.Username;
    return Result.Succeeded;
}

Here is the extension code:

/// <summary>
/// Get <see cref="Autodesk.Revit.UI.UIApplication"/> using the <paramref name="application"/>
/// </summary>
/// <param name="application">Revit UIApplication</param>
public static UIApplication GetUIApplication(this UIControlledApplication application)
{
    var type = typeof(UIControlledApplication);

    var propertie = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
        .FirstOrDefault(e => e.FieldType == typeof(UIApplication));

    return propertie?.GetValue(application) as UIApplication;
}

The whole implementation including the extension to convert UIApplication to UIControlledApplication is shared in the ricaun.Revit.DI dependency injection container extension and in the module UIControlledApplicationExtension.cs.

Many thanks to ricaun for discovering and sharing this!

Relationship Between Tagged Element and Tag

Tom TWhitehead_HED Whitehead and Daniel DanielKP2Z9V Krajnik very kindly shared some sample code showing how to access tagged elements from their tags and vice versa in the thread on how to gets relation of element with its tag or its label:

Question: I have doors. I have door tags I want to verify whether a particular tag in present on a given door.

Answer 1: Here's how I ended up solving it with help from @Mohamed_Arshad:

using (Transaction trans = new Transaction(doc, "Tag Parent Doors"))
{
    trans.Start();

    foreach (FamilyInstance door in doors)
    {
        if (new FilteredElementCollector(doc, currentView.Id)
             .OfCategory(BuiltInCategory.OST_DoorTags)
             .OfClass(typeof(IndependentTag))
             .Cast<IndependentTag>()
             .SelectMany(x => x.GetTaggedLocalElementIds())
             .Where(x => x == door.Id).Any())
        {
            skipCount++;
            continue;
        }
    }
}

Answer 2: If you are looking for a reference how to switch selection between tags and their hosts, here are my commands to: