LLM + Gramps = a useful chatbot

I finally got around to exploring LLM + tools with gramps. The basic idea is to make available a series of functions that can access gramps object data (the dictionary format used in JSON API, etc). I’ve added 13 functions/tools so far, things like get_person(), get_person_death_place(), etc.

This is a different strategy than the RAG model used in GrampsWeb. This example is designed to answer questions by using these specific functions. The functions are mostly all handle based. The LLM doesn’t care, and much of the API is centered around handles anyway.

Here is a sample showing some of the kinds of things it can do (with a modern LLM, gpt-4o):

$ python chatbot.py
Two Gramps application data directories exist.


Enter your question: Who is the home person?
   Thinking....

>>> The home person is Dr. Lewis Anderson Garner, also known as "Big Louie."


Enter your question: Can you give me a table of the names of his children, where they were born, and died?
   Thinking............................

>>> Here is a table of Dr. Lewis Anderson Garner's children, along with their birth and death places:

| Name             | Birth Place                          | Death Place                            |
|------------------|--------------------------------------|----------------------------------------|
| Eugene Stanley   | Portsmouth, OH, USA                  | Twin Falls, Twin Falls, ID, USA        |
| Jesse V.         | Paragould, Greene, AR, USA           | Cedar City, UT, USA                    |
| Raymond E.       | Paragould, Greene, AR, USA           | Astoria, OR, USA                       |
| Jennie S.        | Paragould, Greene, AR, USA           | Columbus, Bartholomew, IN, USA         |
| Walter E.        | Paragould, Greene, AR, USA           | Battle Creek, MI, USA                  |
| Daniel Webster   | Hood River, OR, USA                  | Gary, Lake, IN, USA                    |
| Bertha P.        | Hagerstown, MD, USA                  | Columbus, Bartholomew, IN, USA         |
| Elizabeth        |                                      |                                        |

Note: Elizabeth's birth and death places are not available.


Enter your question: Did all of the children have the same mother?
   Thinking...........

>>> All of Dr. Lewis Anderson Garner's children share the same mother, Luella Jacques Martel.


Enter your question: Who was Luella's father?
   Thinking....

>>> Luella Jacques Martel's father was Henry Martel.


Enter your question: Where was he born?
   Thinking....

>>> Henry Martel was born in Wauchula, Hardee, FL, USA.


Enter your question: When did he die?
   Thinking....

>>> Henry Martel died on January 18, 1902.


Enter your question: How old was he?
   Thinking....

>>> Henry Martel was born on October 27, 1805, and died on January 18, 1902, making him 96 years old at the time of his death.


Enter your question: That is pretty old!
   Thinking...

>>> Indeed, 96 years is quite a long life, especially considering the standards of the 19th and early 20th centuries. It's always fascinating to learn how life spans have changed over time.


Enter your question: Did any of Big Louie's children die in the same town?
   Thinking...

>>> Yes, both Jennie S. Garner and Bertha P. Garner died in Columbus, Bartholomew, IN, USA.


Enter your question: Where is Columbus?
   Thinking...

>>> Columbus is located in Bartholomew County in the state of Indiana, USA.


Enter your question: Where is that in relationship to Indianapolis?
   Thinking...

>>> Columbus, Indiana, is located approximately 45 miles (about 72 kilometers) south of Indianapolis. It's about an hour's drive via Interstate 65.


Enter your question: How far is Columbus from Hagerstown, MD, USA?
   Thinking...

>>> The distance between Columbus, Indiana, and Hagerstown, Maryland, is approximately 520 miles (about 837 kilometers) by road. The drive would typically take around 8 to 9 hours, depending on traffic and road conditions.


Enter your question: In 1850, how would a family get from the Port of Entry in New Orleans to Indianapolis?
   Thinking...

>>> In 1850, a family traveling from the Port of New Orleans to Indianapolis would likely have used a combination of riverboats and overland travel:

1. **Riverboat on the Mississippi River**: They would start by taking a riverboat north along the Mississippi River. River travel was a popular mode of transportation due to the extensive network of rivers in the United States.

2. **Connecting to the Ohio River**: From the Mississippi River, they would likely connect to the Ohio River via riverboat. The Ohio River was a key waterway for moving goods and people eastward from the Mississippi.

3. **Reaching the Ohio Valley**: They could continue their journey on the Ohio River, stopping in cities like Louisville, Kentucky, or Cincinnati, Ohio.

4. **Overland Route to Indianapolis**: From there, the family would need to continue overland. This could involve hiring a stagecoach or taking a train, if available. Trains were becoming more widespread by 1850, but they might still have relied on horse-drawn vehicles for the final leg of the journey to Indianapolis, particularly if the rail network did not cover the entire route.

The journey would have required careful planning and could take several weeks, depending on the conditions and the mode of transportation chosen.

Some other things that I was surprised about (it inferred that grandmother was mother of mother):

Enter your question: Who was Babe's grandmother?
   Thinking....

>>> Frances Lucille "Babe" Reed's maternal grandmother was Bridget Holt. If you need more information about her or any other ancestors, feel free to ask!

And this (remembers what we are talking about):

Enter your question: How many children did Robert have?
   Thinking....

>>> Robert W. Garner had twelve children, including the home person, Dr. Lewis Anderson Garner Sr. If you want to know more about any of his children, just let me know!


Enter your question: What were their names?
   Thinking...............

>>> Here are the names of Robert W. Garner's children:

1. Lewis Anderson Garner Sr.
2. Phebe Garner
3. Mary J. Garner
4. Mary M. Garner
5. (No name listed)
6. Rebecca Catharine Garner
7. Zelpha Josephine Carr
8. Iola Elizabeth Betty Garner
9. Robert F. Garner
10. Emma A. Garner
11. Anetta Garner
12. Antoinette Garner

If you need further details about any of them, feel free to ask!


Enter your question: Who was born first?
   Thinking...............

>>> The first child born to Robert W. Garner was Phebe Garner, born in 1850. If you have any more questions or need additional details, feel free to ask!

Of course, all LLM use caveats still apply: it can get things wrong!

Any way, if you want to try this the two files needed are here:

Instructions:

  1. Download the Python files from above, save both in a folder
  2. set the enviroment variables: GRAMPS_AI_MODEL_NAME, and your OPENAI_API_KEY (or whatever provider key you will use)
  3. Create a Gramps family tree named “Gramps Example” (or edit code)
  4. pip install litellm
  5. python chatbot.py

Example:

pip install litellm
export GRAMPS_AI_MODEL_NAME="openai/gpt-4o"
export OPENAI_API_KEY="..."
python chatbot.py

My goal is to update the GrampsChat gramplet to do this, but I have to work out some threading issues.

Other notes:

  1. Other models may work, but it has to be smart enough to use structured output and tools.
  2. This could cost $$$$.
  3. There is no reason why these tools need to be read-only. One could delete, or add data to the database.
  4. I started with the home person in these examples because I don’t have it hooked up to a good query function/tool, and you need a handle. I’ll work on a general query (maybe there will be one in Gramps 6.1…)

Let me know if you find something interesting or useful!

5 Likes

Very interesting!

I’ve recently been using the “Records” gramplet to find anomalies (such as very young or very old mothers), and wondering if I should spend time writing some custom filter rules for other things. It seems like this chatbot might be an alternative for that. A use case for creating new data in this context might be adding new Notes and/or Tags to highlight potential issues.

Looks like it doesn’t currently access Sources, Citations, Notes, etc.? Notes especially might be useful input.

What about privacy (using but not storing the data in my tree)? I guess that depends on the provider?

1 Like

No I didn’t do those yet, but I’ll flesh those out. I wonder if there is a possibility that too many tools would hurt the performance? We’ll find out :slight_smile:

I purposefully used litellm so that one can host their own models. But honestly, I don’t suspect that any of us have a powerful enough machine to run a model powerful enough to handle the tools/functions.

@dsblank you are making a great feature! AI with access to the DB has a big future and powerfull possibilities. As for me, I would prefer use external OpenAI API instead of local LLM. I think the Gramps Chatbot settings should have a boolean option like “Allow access to data marked private”, which should be disabled by default.
Really, very interesting!!!

1 Like

Thanks for the kind words!

I used LiteLLM so that you can use OpenAI or a local model. I use “openai/gpt-4o” for all my testing. You can decide if you want to all access by deciding what model to use.

2 Likes

Using functions to access more information from Gramps adds significant capability to the chat. Love it!

May I ask if you’re running this in a Linux environment? I can’t see how to run the pipand python steps you suggested in a Windows-GrampsAIO environment.

1 Like

I am running on Linux, but any regular Python environment should work. You’ll have to probably change the “export” command, or there is probably a better way of setting environment variables on Windows. I haven’t used Windows since, like, 1997, so I am no help. Ironically, asking the chatbot would probably help :slight_smile:

Is there any way (or reason) to make the offline wiki manual PDF and addons PDF into pre-digested LLM resources for the chatbot?

That would be useful, but is also quite a bit of text. Every word (or technically a “token”) going into (or out of) a vendor’s LLM costs money. But I’m not working on querying the docs, but in querying the database. For doc queries, @DavidMStraub 's RAG approach in the GrampsWeb is probably better.

Some things to explore:

  1. New API for a website like robots.txt, but for LLM queries. Look for llm-full.txt
  2. RAG vs Agent: What are LLM Agents? A Practical Guide
2 Likes

What concerns me with a Gramps chatbot is the possibility that users will be asking about how to do specific genealogical tasks within the Gramps GUI. And that leading to increased bot traffic on gramps-project.org for updated workflows and GUI.

@gramps-project is already dealing with DoS level bot traffic from AI platforms. And they do not respect robot.txt controls. So that llm-full.txt sounds important.

Hi @dsblank

Notes and questions from my experiments with GrampsChat. My dev environment: Windows 10, Gramps 6.0.x built from source running under Ubuntu 22.04 under WSL.

Initially it wasn’t clear to me where to put the Gramps chat files; what worked is copying the GrampsChat folder to the Gramps source tree, and then running chatbot in the Gramps working directory so that the Gramps modules are found.

My first try was with Perplexity and along with the API key, I set these vars:

export GRAMPS_AI_MODEL_NAME="perplexity/sonar-pro"
export GRAMPS_AI_MODEL_URL="https://api.perplexity.com"

On the first run, the program errored out because I did not have opik installed. I looked through the code and it appeared that opik isn’t critical, so I commented out all occurrences in chatbot.py (but not in GrampsChat.py)

~/dev/gramps$ python3 GrampsChat/chatbot.py
Two Gramps application data directories exist.
Traceback (most recent call last):
  File "/home/codefarmer/dev/gramps/GrampsChat/chatbot.py", line 19, in <module>
    from opik.opik_context import get_current_span_data
ModuleNotFoundError: No module named 'opik'

Next run I received an error indicating that tool use isn’t supported on Perplexity and that I could drop unsupported parameters:


~/dev/gramps$ python3 GrampsChat/chatbot.py
Two Gramps application data directories exist.


Enter your question: Who is the home person?
   Thinking...Traceback (most recent call last):
  File "/home/codefarmer/dev/gramps/GrampsChat/chatbot.py", line 330, in <module>
    chatbot.chat()
  File "/home/codefarmer/dev/gramps/GrampsChat/chatbot.py", line 135, in chat
    self.get_chatbot_response(query)
  File "/home/codefarmer/dev/gramps/GrampsChat/chatbot.py", line 167, in get_chatbot_response
    retval = self._llm_loop(seed)
  File "/home/codefarmer/dev/gramps/GrampsChat/chatbot.py", line 184, in _llm_loop
    response = self._llm_complete(self.messages, self.tool_definitions, seed)
  File "/home/codefarmer/dev/gramps/GrampsChat/chatbot.py", line 145, in _llm_complete
    response = litellm.completion(
  File "/home/codefarmer/.local/lib/python3.10/site-packages/litellm/utils.py", line 1303, in wrapper
    raise e
  File "/home/codefarmer/.local/lib/python3.10/site-packages/litellm/utils.py", line 1178, in wrapper
    result = original_function(*args, **kwargs)
  File "/home/codefarmer/.local/lib/python3.10/site-packages/litellm/main.py", line 3311, in completion
    raise exception_type(
  File "/home/codefarmer/.local/lib/python3.10/site-packages/litellm/main.py", line 1194, in completion
    optional_params = get_optional_params(
  File "/home/codefarmer/.local/lib/python3.10/site-packages/litellm/utils.py", line 3217, in get_optional_params
    _check_valid_arg(
  File "/home/codefarmer/.local/lib/python3.10/site-packages/litellm/utils.py", line 3200, in _check_valid_arg
    raise UnsupportedParamsError(
litellm.exceptions.UnsupportedParamsError: litellm.UnsupportedParamsError: perplexity does not support parameters: ['seed', 'tools', 'tool_choice'], for model=sonar-pro. To drop these, set `litellm.drop_params=True` or for proxy:

`litellm_settings:
 drop_params: true`
.
 If you want to use these params dynamically send allowed_openai_params=['seed', 'tools', 'tool_choice'] in your request.

Now without tool use the chatbot wouldn’t be of much use so I searched around and it appears that it is indeed the case that tool use via litellm isn’t documented/supported for Perplexity. Anyway, I passed drop_params=True to the completion() call and while the program ran, it returned generic answers from the web.

So I am happy to report that Perplexity connects to the chatbot, but sadly tool use is not supported with Perplexity. I’ll see if I can run an LLM with tool support locally using Ollama/LMStudio. Do you have a suggestion on an LLM that might fit the bill? For now it doesn’t matter if it is slow, I just want to make it work.

Thanks.

2 Likes

Hi.

I got something very close:

$ python3 -m pip install opik
Collecting opik
Using cached opik-0.1.0-py3-none-any.whl (160 kB)
Collecting rich
Using cached rich-12.6.0-py3-none-any.whl (237 kB)
ERROR: Could not find a version that satisfies the requirement uuid7<1.0.0 (from opik) (from versions: none)
ERROR: No matching distribution found for uuid7<1.0.0

Enter your question: qui est la personne centrale ?
Thinking…Traceback (most recent call last):
File “chatbot.py”, line 330, in
chatbot.chat()
File “chatbot.py”, line 135, in chat
self.get_chatbot_response(query)
File “chatbot.py”, line 167, in get_chatbot_response
retval = self._llm_loop(seed)
File “chatbot.py”, line 184, in _llm_loop
response = self._llm_complete(self.messages, self.tool_definitions, seed)
File “chatbot.py”, line 150, in _llm_complete
tool_choice=“auto” if tool_definitions is not None else None,
TypeError: completion() got an unexpected keyword argument ‘seed’

1 Like

Glad that you got it working, and thanks for the information. LiteLLM has a method to ask a particular model if it supports different features, so I could make this more robust.

I asked google:

what models support using tools?

and it gave me a list, including some that can run local with ollama.

1 Like

Sounds like you could use:

It wasn’t clear for me how @codefarmerpassed drop_params=True to the completion() call and while the program ran, it returned generic answers from the web”. By adding one argument (maybe wrong place or order ?) like this:


response = litellm.completion(
            model=GRAMPS_AI_MODEL_NAME,  # self.model,
            drop_params=True,
            messages=all_messages,
            seed=seed,
            tools=tool_definitions,
            tool_choice="auto" if tool_definitions is not None else None,
            # stream=True,
            #metadata={
                #"opik": {
                    #"current_span_data": get_current_span_data(),
                #},
            #},
            # **self.model_kwargs,
        )

it will return:

File “chatbot.py”, line 185, in _llm_loop
response = self._llm_complete(self.messages, self.tool_definitions, seed)
File “chatbot.py”, line 151, in _llm_complete
tool_choice=“auto” if tool_definitions is not None else None,
TypeError: completion() got an unexpected keyword argument ‘drop_params’

Maybe this will work:

It seems to be something else.
eg,. I more and less got a ‘basic’ AI model/API_key working within Gramps via WebSearch addon (->config).
So, I set:
$ export GRAMPS_AI_MODEL_URL=“https://api.mistral.ai/v1/chat/completions
I guess that the ‘/completions’ endpoint does not make sense for this chatbot and I should find the working url with Mistral AI?

Pretty much like you showed, except I put it after the “tool_choice” parameter, although I believe that should not make any difference. From the message you’re seeing, it seems like litellm doesn’t recognize the drop_params parameter, so is it possible you have an older bulid of litellm? Mine is litellm==1.73.2.

$ export GRAMPS_AI_MODEL_URL=“https://api.mistral.ai/v1/chat/completions”
I guess that the ‘/completions’ endpoint does not make sense for this chatbot and I should find the working url with Mistral AI?

BTW, “base url” in my mind should not include the chat/completions part of the URL because I suspect litellm completion() would implement that so you could try without that.

So I was able to get the chatbot to work with Google Gemini, but I’m still interested in a solution that does not transmit my personal family tree data to API providers, so I will continue to explore the local LLM solution.

As you noted in an earlier message, this needs a well configured PC so I just have to find a model that will run on my PC and get an additional 32Gb RAM to run the models better!

BTW, one issue: I asked the bot “What is his death date?” about a person who did not have a death event or date and it hung until I Ctrl-C’d out of it.

Interesting… there is a limit to 10 calls. I should add a debug flag so we can see what is happening.