Well, I have obtained positive results demonstrating the possibility of using artificial intelligence in conjunction with SuperTool. I pass the father’s first name and the middle names of his children. The AI’s task is to verify whether the children’s patronymics are correct. If they are not, it suggests specific corrections.
Solving this problem using traditional conditional logic is quite difficult because Ukrainian names have many forms, endings, and exceptions to the rules. This is exactly the kind of task that AI is suited for.
In the terminal, I demonstrated how it works for a single person. I have not tested the script on the entire database. This is a demonstration script that requires improvements and additional validations.
Supertool script:
[Gramps SuperTool script file]
version=1
[title]
Check Patronymic Validity
[description]
This script checks whether the patronymic of children matches their father's name.
[category]
People
[initial_statements]
import json
import sys
sys.path.append("/home/my/Documents")
from openai_client import OpenAIConfig, OpenAIClient
# OpenAI API Configuration with optional training data
config = OpenAIConfig(
api_key="ADD KEY HERE",
training_examples=[
{
"role": "user",
"content": json.dumps({
"father": {"gramps_id": "I7204", "name": "Порфирій Савович"},
"children": [
{"gramps_id": "I0861", "name": "Антон Порфирович"}, # ✅ Correct
{"gramps_id": "I1118", "name": "Макар Іванович"}, # ❌ Incorrect
{"gramps_id": "I2345", "name": "Марія Порфиевна"}, # ❌ Misspelled
{"gramps_id": "I9876", "name": "Оксана"} # ❌ Missing patronymic
]
}, ensure_ascii=False)
},
{
"role": "assistant",
"content": json.dumps({
"I0861": {"status": "correct"},
"I1118": {
"status": "incorrect",
"explanation": {"current": "Іванович", "suggested": "Порфирович"}
},
"I2345": {
"status": "incorrect",
"explanation": {"current": "Порфиевна", "suggested": "Порфирівна"}
},
"I9876": {
"status": "incorrect",
"explanation": {"current": "No patronymic", "suggested": "Порфирівна"}
}
}, ensure_ascii=False)
}
]
)
openai_client = OpenAIClient(config)
def check_patronymic_validity():
"""
Prepares and sends a request to OpenAI API to validate children's patronymics.
"""
father_firstname = firstname
data = {
"father": {
"gramps_id": gramps_id,
"name": father_firstname
},
"children": []
}
for child in children:
data["children"].append({
"gramps_id": child.gramps_id,
"name": child.firstname
})
user_messages = [
{
"role": "user",
"content": json.dumps(data, ensure_ascii=False)
}
]
# Use assistant training if needed
result = openai_client.send_request(
user_messages,
system_prompt="Identify the father's first name and ignore his patronymic. "
"For each child, extract only the patronymic and ignore the first name. "
"Compare them using proper Ukrainian patronymic formation rules. "
"If incorrect, return 'status': 'incorrect' with 'explanation': "
"{\"current\": \"<child's current patronymic>\", \"suggested\": \"<corrected patronymic>\"}. "
"If correct, return only 'status': 'correct'.",
include_training=True # Toggle training data on/off
)
print("Request:", json.dumps(data, indent=4, ensure_ascii=False))
print("Response:", json.dumps(result, indent=4, ensure_ascii=False))
[statements]
if gender == "M":
check_patronymic_validity()
[scope]
selected
[unwind_lists]
False
[commit_changes]
False
[summary_only]
True
OpenAI API Client
# openai_client.py
import requests
import json
class OpenAIConfig:
"""Configuration class for OpenAI API."""
def __init__(
self,
api_key: str,
model: str = "gpt-4o-mini",
temperature: float = 0,
max_tokens: int = 100,
api_url: str = "https://api.openai.com/v1/chat/completions",
system_prompt: str = "",
training_examples: list = None
):
"""
Initializes the OpenAI configuration with default or custom parameters.
:param api_key: OpenAI API key.
:param model: AI model to use (default: "gpt-4o").
:param temperature: Sampling temperature (default: 0.0).
:param max_tokens: Maximum response tokens (default: 100).
:param api_url: OpenAI API endpoint (default: GPT-4 endpoint).
:param system_prompt: Default system prompt (can be overridden per request).
:param training_examples: Optional assistant training data (default: None).
"""
self.api_key = api_key
self.model = model
self.temperature = temperature
self.max_tokens = max_tokens
self.api_url = api_url
self.system_prompt = system_prompt
self.training_examples = training_examples or [] # If None, use an empty list
class OpenAIClient:
"""Client for interacting with OpenAI API."""
def __init__(self, config: OpenAIConfig):
"""
Initializes the OpenAI client.
:param config: OpenAIConfig instance containing API settings.
"""
self.config = config
def send_request(self, user_messages: list, system_prompt: str = None, include_training: bool = True):
"""
Sends a chat completion request to OpenAI API.
:param user_messages: List of messages in OpenAI format (e.g., [{"role": "user", "content": "Your input"}]).
:param system_prompt: Custom system prompt (if None, default from config is used).
:param include_training: If True, include assistant training examples.
:return: Parsed JSON response from OpenAI.
"""
messages = [{"role": "system", "content": system_prompt or self.config.system_prompt}]
# Add training examples if enabled
if include_training and self.config.training_examples:
messages.extend(self.config.training_examples)
# Add user messages
messages.extend(user_messages)
request_data = {
"model": self.config.model,
"messages": messages,
"temperature": self.config.temperature,
"max_tokens": self.config.max_tokens
}
headers = {
"Authorization": f"Bearer {self.config.api_key}",
"Content-Type": "application/json"
}
try:
response = requests.post(self.config.api_url, json=request_data, headers=headers)
response_json = response.json()
if "choices" in response_json and response_json["choices"]:
return json.loads(response_json["choices"][0]["message"]["content"].strip())
except Exception as e:
print("API Request Error:", e)
return None
Terminal results: