agent-0 / augmentoolkit /generation_functions /process_multiturn_functions.py
Leon4gr45's picture
Upload folder using huggingface_hub
42da440 verified
Raw History Blame Contribute Delete
18.3 kB
import re
def has_sequential_chars(string1, string2, n):
"""
Check if any n sequential characters from string1 appear in string2.
Args:
string1 (str): The first string to check.
string2 (str): The second string in which to look for sequences.
n (int): The length of the sequence to check.
Returns:
bool: True if any n sequential characters from string1 are found in string2, False otherwise.
"""
# Check if n is larger than the length of string1.
if n > len(string1):
return False, ""
# Iterate over string1 and check for each n-length substring in string2
comparison_string = ""
for i in range(len(string1) - n + 1):
comparison_string = string1[i : i + n]
if comparison_string in string2:
return True, comparison_string
return False, comparison_string
def extract_conversation(conversation):
"""
Extracts conversation from a string and returns it as a list of tuples.
Parameters:
conversation (str): A string representing the conversation.
Returns:
list of tuples: Each tuple contains the character's name and their message.
"""
lines = conversation.strip().split("\n")
dialogues = []
current_speaker = None
current_message = ""
for line in lines:
line = line.strip()
if line in ["**AI Assistant:**", "**User:**"]:
if current_speaker:
dialogues.append((current_speaker, current_message.strip()))
current_message = ""
current_speaker = line[2:-2].strip()
else:
if current_speaker:
current_message += line + "\n"
if current_speaker:
dialogues.append((current_speaker, current_message.strip()))
return dialogues
def compare_answers_with_qatuples(dialogues, qatuples, n):
"""
Compares each answer in dialogues with the corresponding answer from qatuples.
Parameters:
dialogues (list): List of tuples containing the dialogues.
qatuples (list): List of tuples containing questions and answers.
n (int): Number of sequential characters to check.
Returns:
bool: True if all answers match the corresponding answers in qatuples, False otherwise.
"""
truth_list = []
for i in range(1, len(dialogues), 2): # Answers are at odd indices, starting from 1
if (i - 1) // 2 >= len(
qatuples
): # at this point we've reached added stuff that doesn't have a corresponding qatuple
break
sequential, comp = has_sequential_chars(
qatuples[(i - 1) // 2][1], dialogues[i][1], n
)
# print(sequential)
# print(n)
truth_list.append(sequential)
if all(truth_list):
return True
# Account for the case where the AI has an initial back-and-forth with no questions asked or answered. In this case, answers start at 3.
for i in range(3, len(dialogues), 2):
if (i - 2) // 2 >= len(qatuples):
break
sequential, comp = has_sequential_chars(
qatuples[(i - 2) // 2][1], dialogues[i][1], n
)
if not sequential:
print(
f"Answer {(i + 1) // 2}: {dialogues[i][1]} does not match the corresponding answer in qatuples: {qatuples[(i - 1) // 2][1]}, {comp}"
)
return False
return True
# def check_repeated_answer(dialogues, qatuples):
# # Get the length of the dialogues
# conv_length = len(dialogues)
# # Loop through even indices starting from 2 (first answer is at index 2)
# for i in range(2, conv_length, 2):
# current_answer = dialogues[i][1][:n_characters_same]
# next_answer_index = i + 2
# if next_answer_index < conv_length:
# next_answer = dialogues[next_answer_index][1][:n_characters_same]
# if current_answer == next_answer:
# return False
# return True
def check_conversation_length(conv, qatuples):
"""Checks the length of the conversation"""
# Dialogues with answers should be at even indices that are not 0
# qatuples are of the format (question, answer,source_text,name_of_text) -- only the first two are used here
# Get the length of the dialogues
conv_length = len(conv)
target_length = len(qatuples) * 2
if (
conv_length < target_length
): # we can have more messages since the AI might add some stuff at the end to wrap up the scene
return False
else:
return True
def check_each_question_contains_q_from_tuples(conv, qatuples, n):
"""
Ensures that each question contains at least n sequential characters from the corresponding question in qatuples.
If the first check fails, it checks again assuming questions are at even indices starting from 2.
If the first question fails both checks, return None for special handling.
Parameters:
conv (list): List of tuples containing the dialogues.
qatuples (list): List of tuples containing questions and answers.
n (int): Number of sequential characters to check.
Returns:
bool or None: True if all questions pass the check, False if any fail, None if the first question fails both checks.
"""
def check_questions(start_index):
for i in range(start_index, len(conv), 2):
if (i - start_index) // 2 < len(qatuples):
question_from_conv = conv[i][1]
question_from_tuples = qatuples[(i - start_index) // 2][0]
sequential, _ = has_sequential_chars(
question_from_tuples, question_from_conv, n
)
if not sequential:
return False
return True
# First check: questions at even indices starting from 0
if check_questions(0):
return True
# Second check: questions at even indices starting from 2
if check_questions(2):
return True
# If both checks fail and the first question was involved, return None
if len(conv) >= 2 and len(qatuples) > 0:
question_from_conv = conv[0][1] if len(conv) > 0 else ""
question_from_tuples = qatuples[0][0]
sequential, _ = has_sequential_chars(
question_from_tuples, question_from_conv, n
)
if not sequential:
return None
return False
def check_for_unintended_repeated_quotes(dialogues, qatuples, n_characters_shared):
"""
Checks if answers in the conversation inadvertently use a long quote from another QA pair.
Args:
dialogues (list): List of tuples containing the dialogues.
qatuples (list): List of tuples containing questions and answers.
n_characters_shared (int): Number of sequential characters to check for repetition.
Returns:
bool: True if no unintended repeated quotes are found, False otherwise.
"""
# Extract only the answers from the QA tuples for comparison
qa_answers = [qa[1] for qa in qatuples]
for i in range(
2, len(dialogues), 2
): # Answers are at even indices, starting from 2
# Skip if there's no corresponding QA tuple
if int(i / 2) - 1 >= len(qatuples):
break
dialogue_answer = dialogues[i][1]
corresponding_qa_answer = qatuples[int(i / 2) - 1][1]
# Check for each answer in the QA tuples
for idx, qa_answer in enumerate(qa_answers):
# Skip the comparison for the current QA pair itself
if qa_answer == corresponding_qa_answer:
continue
# Check if the dialogue answer contains a long quote from another QA answer
sequential, comp_string = has_sequential_chars(
qa_answer, dialogue_answer, n_characters_shared
)
if sequential:
if comp_string in corresponding_qa_answer:
continue # This is a quote from the corresponding answer, so it's fine
else:
# Found an unintended repeated quote
return False
return True
def call_all_processors(multiturn_conversation, qatuples):
convs_split = extract_conversation(multiturn_conversation)
# Check if answers in dialogues match corresponding answers in qatuples
if not compare_answers_with_qatuples(convs_split, qatuples, 15):
print("Answers in dialogues do not match corresponding answers in qatuples.")
return False
# Check the conversation length
if not check_conversation_length(convs_split, qatuples):
print("Conversation is too short! Validation failed!")
print(convs_split)
return False
# Check for unintended repeated quotes
if not check_for_unintended_repeated_quotes(convs_split, qatuples, 100):
print("Conversation contains unintended repeated quotes. Validation failed!")
return False
# Check each question contains a part of the question from tuples
result = check_each_question_contains_q_from_tuples(convs_split, qatuples, 15)
if result is None:
print(
"First question does not contain a part of the question from tuples. Validation failed!"
)
return None
elif not result:
print(
"Each question does not contain a part of the question from tuples. Validation failed!"
)
return False
# If all checks pass
return True
if __name__ == "__main__":
# Test cases for has_sequential_chars
print("Testing has_sequential_chars:")
print(has_sequential_chars("hello", "worldhello", 3)) #
print("Expected True")
print(has_sequential_chars("abc", "defghijkl", 2)) # Expected False
print("Expected False")
print(has_sequential_chars("", "empty", 1)) # Expected False (empty string1)
print("Expected False")
print(
has_sequential_chars("longstring", "short", 5)
) # Expected False (n is longer than string2)
print("Expected False")
print(
has_sequential_chars("overlap", "laptopp", 3)
) # Expected True (partial overlap)
print("Expected True")
# Test cases for extract_conversation
print("\nTesting extract_conversation:")
test_conversation1 = "Charname1: Hello\nCharname2: Hi\nCharname3: How are you?"
print(
extract_conversation(test_conversation1)
) # Expected [('Charname1', 'Hello'), ('Charname2', 'Hi'), ('Charname3', 'How are you?')]
print(
"Expected [('Charname1', 'Hello'), ('Charname2', 'Hi'), ('Charname3', 'How are you?')]"
)
test_conversation2 = "No colons here"
print(extract_conversation(test_conversation2)) # Expected []
print("Expected []")
test_conversation3 = ""
print(extract_conversation(test_conversation3)) # Expected []
print("Expected []")
# Test cases for compare_answers_with_qatuples
print("\nTesting compare_answers_with_qatuples:")
dialogues1 = [
("Charname1", "Hello"),
("Charname2", "Hi how are you"),
"Totally Fantastic and Amazing!",
]
qatuples1 = [("How are you?", "Fine")]
print(compare_answers_with_qatuples(dialogues1, qatuples1, 2)) # Expected False
print("Expected False")
dialogues2 = [
("Charname1", "Hello"),
("Charname2", "Hi how are you"),
("Charname1", "Mostly Fine I think, yeah"),
]
print(compare_answers_with_qatuples(dialogues2, qatuples1, 2)) # Expected True
print("Expected True")
dialogues3 = []
qatuples2 = []
print(
compare_answers_with_qatuples(dialogues3, qatuples2, 2)
) # Expected True (both empty)
print("Expected True (both empty)")
# Test cases for check_for_repeated_dialogue_answers
print("\nTesting check_for_repeated_dialogue_answers:")
qatuples_repeated_answers = [("How are you?", "Fine, thank you for asking!")]
dialogues4 = [
("Charname1", "Hello"),
("Charname2", "How are you?"),
("Charname1", "Fine, thank you for asking!"),
]
print(
check_for_repeated_dialogue_answers(dialogues4, qatuples_repeated_answers, 2)
) # Expected True (no repetition)
print("Expected True (no repetition)")
dialogues5 = [
("Charname1", "Hello"),
("Charname2", "How are you?"),
(
"Charname1",
"Fine, thank you for asking! It's nice today, after all, so I'm Fine, thank you for asking!",
),
]
print(
check_for_repeated_dialogue_answers(dialogues5, qatuples_repeated_answers, 2)
) # Expected False (repetition)
print("Expected False (repetition)")
# Test cases for check_repeated_answer
# print("\nTesting check_repeated_answer:")
# dialogues6 = [("Charname1", "Question"), ("Charname2", "Answer1"), ("Charname3", "Question"), ("Charname4", "Answer1")]
# print(check_repeated_answer(dialogues6)) # Expected False (repeated answers)
# dialogues7 = [("Charname1", "Question"), ("Charname2", "Answer1"), ("Charname3", "Question"), ("Charname4", "Answer2")]
# print(check_repeated_answer(dialogues7)) # Expected True (different answers)
# Test cases for check_conversation_length
print("\nTesting check_conversation_length:")
conv1 = [("Charname1", "Hello"), ("Charname2", "Hi, How are you?")]
print(
check_conversation_length(conv1, qatuples1)
) # Expected False (conversation too short)
print("Expected False (conversation too short)")
conv2 = [("Charname1", "Hello"), ("Charname2", "Hi"), ("Charname3", "How are you?")]
print(check_conversation_length(conv2, qatuples1)) # Expected True (correct length)
print("Expected True (correct length)")
# Test cases for check_conversation_for_text_from_examples (commented out as implementation is assumed elsewhere)
# print("\nTesting check_conversation_for_text_from_examples:")
# conv3 = "This conversation contains lipstick-colored lips and a coquettishly tilting head."
# print(check_conversation_for_text_from_examples(conv3)) # Expected False (contains example texts)
# Test cases for check_each_question_contains_q_from_tuples
print("\nTesting check_each_question_contains_q_from_tuples:")
conv4 = [
("Charname2", "Hiya~!"),
("Charname1", "What's your favorite color?"),
("Charname2", "I'm Fine, thank you very much!"),
]
print(check_each_question_contains_q_from_tuples(conv4, qatuples1, 6))
print("Expected None (no matching question, first Q)")
conv45 = [
("Charname2", "Hiya~!"),
("Charname1", "How are you?"),
("Charname2", "I'm Fine, thank you very much!"),
("Charname1", "What is the airspeed velocity of an unladen swallow?"),
("Charname2", "Black, like my soul."),
]
qatuples3 = [
("How are you?", "I'm Fine, thank you very much!"),
("What's your favorite color?", "Black, like my soul."),
]
print(check_each_question_contains_q_from_tuples(conv45, qatuples3, 6))
print("Expected False (no matching question, second Q)")
conv5 = [
("Charname1", "Hiya~!"),
("Charname2", "How are you?"),
("Charname2", "I'm Fine, thank you very much!"),
("Charname1", "What's your favorite color?"),
("Charname2", "Black, like my soul."),
]
print(check_each_question_contains_q_from_tuples(conv5, qatuples1 + [], 6)) #
print("Expected True (question contains part of qatuple question)")
# Test cases for check_for_unintended_repeated_quotes
print("\nTesting check_for_unintended_repeated_quotes:")
# Creating a set of dialogues and qatuples where there is an unintended repeated quote
qatuples_shared = [
("What is your favorite book?", "I love reading The Hobbit."),
(
"Tell me about a recent happy moment.",
"My friends threw me a surprise party!",
),
]
dialogues_shared1 = [
("Charname1", "Hello"),
("Charname2", "What is your favorite book?"),
("Charname1", "I love reading The Hobbit."),
("Charname2", "Tell me about a recent happy moment."),
(
"Charname1",
"My friends threw me a surprise party! It felt just like I was in The Hobbit.",
),
]
print(
check_for_unintended_repeated_quotes(dialogues_shared1, qatuples_shared, 10)
) # Expected False (repeated long quote from another answer)
print("Expected False (repeated long quote from another answer)")
# Creating a set of dialogues and qatuples where there are no unintended repeated quotes
dialogues_shared2 = [
("Charname1", "Hello"),
("Charname2", "What is your favorite book?"),
("Charname1", "I absolutely adore The Lord of the Rings."),
("Charname2", "Tell me about a recent happy moment."),
("Charname1", "I had a great time at the beach last weekend!"),
]
print(
check_for_unintended_repeated_quotes(dialogues_shared2, qatuples_shared, 10)
) # Expected True (no repeated long quotes)
print("Expected True (no repeated long quotes)")
# Test cases for call_all_processors
print("\nTesting call_all_processors:")
complete_conversation = """
Charname1: Hello
Charname2: How are you doing today?
Charname1: I'm fine, thank you very much!
Charname2: What's the weather like?
Charname1: It's sunny and warm. I don't like sand. It's coarse and rough and irritating and it gets everywhere.
Foo: Bar
Baz: Quux
"""
qatuples_complete = [
("How are you doing today?", "I'm fine, thank you very much!"),
(
"What's the weather like?",
"It's sunny and warm. I don't like sand. It's coarse and rough and irritating and it gets everywhere.",
),
]
print(call_all_processors(complete_conversation, qatuples_complete)) #
print("Expected True (all checks pass)")
incomplete_conversation = """
Charname1: How's it going?
Charname2: Good.
Charname1: Any plans?
Charname2: None.
Foo: Bar
Baz: Quux
"""
print(call_all_processors(incomplete_conversation, qatuples_complete)) #
print("Expected False (checks fail)")