# Written by GPT-4
import fitz  # PyMuPDF
import pytesseract
from PIL import Image
import io

# Ensure the path to the tesseract executable is set if it's not in your PATH
# pytesseract.pytesseract.tesseract_cmd = r'<path_to_your_tesseract_executable>'

def convert_pdf_to_text(pdf_path, output_txt_path):
    # Open the PDF file
    document = fitz.open(pdf_path)

    text = ""  # Initialize a text string to hold all text from the PDF

    for page_num in range(len(document)):
        # Get the page
        page = document.load_page(page_num)

        # First, try to extract text using PyMuPDF
        text_content = page.get_text()

        if text_content.strip():  # If text is found, append it.
            text += text_content
        # else:
        #     # If no text is found, it might be an image-based PDF
        #     # Extract the image from the page
        #     for img_index, img in enumerate(page.get_images(full=True)):
        #         xref = img[0]
        #         base_image = document.extract_image(xref)
        #         image_bytes = base_image["image"]

        #         # Load it to PIL
        #         image = Image.open(io.BytesIO(image_bytes))

        #         # Use pytesseract to do OCR on the image
        #         text += pytesseract.image_to_string(image)

    # Close the document
    document.close()

    # Write the text to a .txt file
    with open(output_txt_path, "w", encoding="utf-8") as text_file:
        text_file.write(text)

    return text

# Usage
pdf_path = "./Introduction to Logic and Critical Thinking, by Matthew Van Cleave.pdf"
output_txt_path = (
    "Introduction to Logic and Critical Thinking, by Matthew Van Cleave.txt"
)
convert_pdf_to_text(pdf_path, output_txt_path)


RP_MODEL = "./rp_model"  # model used for RP tasks, probably going to use Sao10K/Euryale-1.3-L2-70b
# LOGICAL_MODEL = "./logical_model/airoboros-l2-13b-3.1.1.Q8_0.gguf" # model used for decision-making and base question generation (should be "smart")

LOGICAL_MODEL = "./logical_model/flatorcamaid-13b-v0.2.Q8_0.gguf"  # model used for decision-making and base question generation (should be "smart")

names = [  # Replaces "Albert" in scenarios. Needs to be western male names to avoid pronoun and setting inconsistencies).
    "William",
    "James",
    "John",
    "Robert",
    "Michael",
    "Charles",
    "George",
    "Joseph",
    "Edward",
    "Henry",
    "Thomas",
    "David",
    "Richard",
    "Daniel",
    "Matthew",
    "Alexander",
    "Benjamin",
    "Christopher",
    "Nicholas",
    "Samuel",
]

# N_CHARACTERS_SAME_ANSWER = 25 # number of characters that are the same in the question and answer for a thing to fail validation or be deemed "the same" in various places throughout the code

# N_CHARACTERS_SAME_QUESTION = 15

# N_CHARACTERS_SHARED = 100 # number of characters that are the same in the question and answer for a thing to fail validation or be deemed "the same" in various places throughout the code

# IF USING THE 70b LLAMA 2, MUST SET n_gqa=8 WHEN LOADING
# TODO MAKE A GLOBAL CONSTANT is_70b AND ADD THAT WITH BRANCHING LOGIC TO ALL THE LLAMA CPP LOADERS


def format_qatuples(qatuples):
    strlst = []
    for qatuple in qatuples:
        strlst.append(
            f"""Question: \"\"\"{qatuple[0]}\"\"\"
Answer: \"\"\"{qatuple[1]}\"\"\""""
        )
    return "\n\n".join(strlst)

def format_qatuples_noquotes(qatuples):
    strlst = []
    for idx, qatuple in enumerate(qatuples):
        strlst.append(f"""{idx + 1}. {qatuple[0]}""")
    return "\n".join(strlst)


import re
from .answer_accurate_grammar import answer_accurate_grammar
from llama_cpp import Llama
from .constants import LOGICAL_MODEL

# Answer vetting

def check_answer(qatuple, logic_llm, permissive_mode=True):
    retries = 0
    while retries <= 4:
        decision_prompt = f"""You are an expert educational AI. Given a paragraph or two from a larger text, a question based on the paragraphs, and an answer to the question, you will make a determination as to whether the answer to the question is a sensible answer, given the information in the paragraphs. Essentially: you will fact-check the answer to the question, with your source of truth being the paragraphs provided. Your task includes first analyzing the text, thinking through whether or not the answer reflects aspects of the paragraphs provided.

Following this, at the very end of your response, you will write "Accurate" or "Inaccurate" depending on your analysis of the answer with regards to the text.

Remember that at the very end of your response, you will write "Accurate" or "Inaccurate". Do not use these words anywhere else in your answer.

### Instruction:
Text:
\"\"\"
The Industrial Revolution marked a transformative period in history, fundamentally altering economic structures and industrial processes. One of the most significant innovations was the advent of steam power, which drastically reduced production costs. This reduction was due to the increased efficiency and speed of machines powered by steam, replacing the slower, more labor-intensive methods previously used. Additionally, steam power was instrumental in the development of semi-automated factories, leading to a significant shift in manufacturing processes and labor dynamics.
\"\"\"

Question (based on text): \"\"\"What was the role of steam power in the Industrial Revolution, particularly in terms of its impact on production costs, and the emergence of semi-automated factories?\"\"\"

Supposed answer to the question (this is what you are fact-checking): \"\"\"Steam power during the Industrial Revolution played a crucial role in decreasing production costs. However, it had no significant impact on the emergence of semi-automated factories. Interestingly, it also led to an increased cultivation of lemons.\"\"\"

### Response:
## Reasoning and thought process:
### Text Analysis:
#### Identify Key Information: The text highlights the role of steam power in reducing production costs and developing semi-automated factories during the Industrial Revolution.
#### Categorize Information Type: The information is factual, describing the impacts of steam power on industrial processes.

### Answer Breakdown:
#### Dissect the Answer: The answer has three assertions: steam power reducing production costs, no significant impact on semi-automated factories, and increased cultivation of lemons.
#### Identify Answer Type: The first two are factual statements relevant to the text, and the third is an additional factual claim.

### Accuracy Check:
#### Direct Comparison for Factual Accuracy:
  - The text aligns with the answer about steam power reducing production costs.
  - The text contradicts the answer about steam power's impact on semi-automated factories, stating steam power was instrumental in their development.
  - The text does not mention anything about the cultivation of lemons.
#### Inference and Contextual Alignment: The first two parts of the answer are directly related to the text, while the third part is not supported or mentioned in the text.

### Final Judgment:
#### Comprehensive Assessment: The answer is accurate regarding production costs, inaccurate regarding semi-automated factories, and the lemon cultivation claim is unsupported.
#### Overall Accuracy Determination: The answer is: Inaccurate.

### Instruction:
Text:
\"\"\"
Epistemology, often regarded as a branch of philosophy, is concerned with the theory of knowledge. It involves understanding the nature, sources, and limitations of knowledge. A key concept in epistemology is the idea of "justified true belief," which suggests that for someone to know something, they must believe it to be true, have justification for this belief, and the belief must indeed be true. For example, believing that it will rain tomorrow because the weather forecast says so, and it turns out to be true, is a justified true belief. Epistemology also explores the idea of skepticism, which questions the possibility of certain or absolute knowledge.
\"\"\"

Question (based on text): \"\"\"What does the concept of 'justified true belief' involve in epistemology, and how does skepticism relate to the understanding of knowledge?\"\"\"

Supposed answer to the question (this is what you are fact-checking): \"\"\"The concept of 'justified true belief' in epistemology involves having a belief that is true and has justification. For a belief to be considered knowledge, it must be true, one must believe it, and there must be sufficient reason for this belief. Skepticism plays a role by challenging the certainty of knowledge, thereby emphasizing the need for strong justification in 'justified true belief.\"\"\"

### Response:
## Reasoning and thought process:
### Text Analysis:
#### Identify Key Information: The text covers the concept of 'justified true belief' and skepticism in epistemology.
#### Categorize Information Type: This is conceptual and theoretical information.

### Answer Breakdown:
#### Dissect the Answer: The answer addresses the nature of 'justified true belief' and the role of skepticism in epistemology.
#### Identify Answer Type: Both parts of the answer are explanatory, relating to philosophical concepts.

### Accuracy Check:
#### Direct Comparison for Factual Accuracy:
  - The text supports the answer's description of 'justified true belief'.
  - The text aligns with the answer's depiction of skepticism's role in challenging the certainty of knowledge.
#### Inference and Contextual Alignment: Both parts of the answer are consistent with the text's explanations of these concepts.

### Final Judgment:
#### Comprehensive Assessment: Both parts of the answer accurately reflect the text's content.
#### Overall Accuracy Determination: The answer is: Accurate.

### Instruction:
Text:
\"\"\"
The novel 'Ocean's Secrets' is set in the early 20th century and revolves around two main characters, Elizabeth and Michael, who believe they have discovered a hidden underwater city. The narrative implies that the city is a remnant of the lost civilization of Atlantis. However, as the story progresses, it becomes apparent that the city is actually a figment of Elizabeth's imagination, a result of her fascination with mythology and ancient history.
\"\"\"

Question (based on text):
\"\"\"What is the significance of the underwater city discovered by Elizabeth and Michael in the novel 'Ocean's Secrets'?\"\"\"

Supposed answer to the question (this is what you are fact-checking):
\"\"\"The underwater city discovered by Elizabeth and Michael in 'Ocean's Secrets' represents a significant archaeological find from the lost civilization of Atlantis, shedding light on ancient historical mysteries.\"\"\"

### Response:
## Reasoning and thought process:
### Text Analysis:
#### Identify Key Information: The text revolves around the discovery of an underwater city, initially believed to be Atlantis, but later revealed to be a figment of Elizabeth's imagination.
#### Categorize Information Type: The information is narrative and contains a twist that changes the initial perception of the discovery.

### Answer Breakdown:
#### Dissect the Answer: The answer claims the underwater city is a significant archaeological find from Atlantis.
#### Identify Answer Type: The statement is a factual claim based on the initial setup of the narrative.

### Accuracy Check:
#### Direct Comparison for Factual Accuracy: The text's later revelation that the city is imaginary contradicts the answer's claim of it being an archaeological find from Atlantis.
#### Inference and Contextual Alignment: The answer fails to align with the narrative twist revealed in the text.

### Final Judgment:
#### Comprehensive Assessment: The answer is inaccurate as it contradicts the final revelation in the text.
#### Overall Accuracy Determination: The answer is: Inaccurate.

### Instruction:
Text:
\"\"\"
The Great Wall of China — so named because it was built to repel enemies coming from the direction of China — was built by the Romans as a defense against the Mongolian invasions in the 3rd century BC. The wall played a pivotal role in the defence of the Eastern Roman Empire Against Attila the Hun in 1337 AD. The dramatized version of these events was eventually fictionalized as the movie "The Great Wall," in which Liam Nissan (playing Marcus Aurelius) and Jackie Chan (playing Liu Bei) team up to fight Batzorig Vaanchig (playing Attila). Though the Huns were unsuccessful in breaching the wall, the eventual invasions by Galbadrakh Tsendbaatar broke through and sacked Constantinople in 1453 AD.
\"\"\"

Question (based on text):
\"\"\"Who built the Great Wall of China and for what purpose?\"\"\"

Supposed answer to the question (this is what you are fact-checking):
\"\"\"The Great Wall of China was built by the Romans to defend against Mongolian invasions (coming from the direction of China) in the 3rd century BC.\"\"\"

### Response:
## Reasoning and thought process:
### Text Analysis:
#### Identify Key Information: The text incorrectly states that the Great Wall of China was built by the Romans to defend against Mongolian invasions.
#### Categorize Information Type: The information is historically factual but objectively wrong.

### Answer Breakdown:
#### Dissect the Answer: The answer correctly cites the text, stating the Great Wall was built by the Romans against Mongolians.
#### Identify Answer Type: The statement is a factual claim, accurately reflecting the content of the text.

### Accuracy Check:
#### Direct Comparison for Factual Accuracy: The answer accurately mirrors the text's incorrect claim about the Great Wall of China.
#### Inference and Contextual Alignment: Despite the historical inaccuracy, the answer aligns perfectly with the text's content.

### Final Judgment:
#### Comprehensive Assessment: The answer, while reflecting an objectively incorrect fact, is accurate in the context of the text's information.
#### Overall Accuracy Determination: The answer is: Accurate.

### Instruction:
Text:
\"\"\"
Formal logic, a branch of philosophy and mathematics, is concerned with the study of reasoning. It uses a set of symbols and rules to create a language that can precisely express ideas. One key aspect of formal logic is the concept of a valid argument, which is an argument where if the premises are true, the conclusion must be true. For instance, in the statement 'All humans are mortal; Socrates is a human; therefore, Socrates is mortal,' the conclusion follows logically from the premises. Another important element is the use of symbolic representation to simplify and clarify arguments. This allows for complex ideas to be broken down into simpler components, making them easier to analyze and understand.
\"\"\"

Question (based on text): \"\"\"What are the key aspects of formal logic, and how does symbolic representation contribute to its goals?\"\"\"

Supposed answer to the question (this is what you are fact-checking): \"\"\"Key aspects of formal logic include the study of valid arguments and the use of symbolic representation. Valid arguments are those where the premises may or may not lead to a true conclusion. Symbolic representation helps in making complex ideas more understandable by breaking them down into simpler forms.\"\"\"

### Response:
## Reasoning and thought process:
### Text Analysis:
#### Identify Key Information: The text discusses the aspects of formal logic, including valid arguments and symbolic representation.
#### Categorize Information Type: The information is conceptual, relating to logical principles.

### Answer Breakdown:
#### Dissect the Answer: The answer claims that formal logic includes the study of valid arguments and symbolic representation, with specifics on each.
#### Identify Answer Type: These are factual statements about the principles of formal logic.

### Accuracy Check:
#### Direct Comparison for Factual Accuracy:
  - The text's definition of a valid argument contradicts the answer's claim that valid arguments may or may not lead to a true conclusion.
  - The text supports the answer's depiction of symbolic representation.
#### Inference and Contextual Alignment: The first part of the answer misinterprets the text, while the second part aligns well.

### Final Judgment:
#### Comprehensive Assessment: The answer is partially accurate, correctly identifying symbolic representation but inaccurately describing valid arguments.
#### Overall Accuracy Determination: The answer is: Inaccurate.

### Instruction:
Text: \"\"\"{qatuple[2]}\"\"\"

Question (based on text): \"\"\"{qatuple[0]}\"\"\"

Supposed answer to the question (this is what you are fact-checking): \"\"\"{qatuple[1]}\"\"\"

### Response:
## Reasoning and thought process (the text is your single source of truth):
"""
        try:
            completion = logic_llm(
                decision_prompt,
                max_tokens=6000,
                stop=["</s>", "# Input:"],
                echo=True,
                grammar=answer_accurate_grammar,
                temperature=0.2,
            )["choices"][0]["text"]

            completion_pattern = re.compile(
                r"Reasoning and thought process \(the text is your single source of truth\):\n(.+)",
                re.DOTALL,
            )
            response = completion_pattern.search(completion).group(1).strip()
            print(response)
            if permissive_mode:
                determination_pattern = re.compile(
                    r"Overall Accuracy Determination:(.+)", re.DOTALL
                )
                determination = determination_pattern.search(response).group(1).strip()
            else:
                determination = response
            print("\n\nDETERMINATION:\n------")
            print(determination)
            print("\n---------\n")
            if (
                "inaccurate" in determination.lower()
                or "Inaccurate" in determination.lower()
                or "mostly" in determination.lower()
                or "partial" in determination.lower()
            ):  # The "mostly" is there to catch "mostly accurate" which the model says occasionally, and which actually means inaccurate.
                return (False, response), completion
            elif (
                "accurate" in determination or "Accurate" in determination
            ):  # very deliberate placement of accurate here, becaues the model can sometimes say irrelevant at the very end, even after saying accurate in its judgement
                return (True, response), completion
            elif (
                "irrelevant" in determination or "Irrelevant" in determination
            ):  # optional support for checking relevance here, too.
                return (
                    None,
                    response,
                ), completion  # signal that question is irrelevant
            else:
                Exception("Broke!")
        except Exception as e:
            retries += 1
            print("EXCEPTION IN CHECK_ANSWER: ", e)

if __name__ == "__main__":  # test
    logic_llm = Llama(
        model_path=LOGICAL_MODEL,
        n_gqa=8,
        offload_kqv=True,
        n_ctx=10000,
        n_gpu_layers=1000,
        rope_freq_scale=0.33,
        rope_scaling_type=1,
    )  # load the logical LLM and offload everything
    q_test = [
        (
            "Explain how our understanding of planetary motion has changed over time.",
            "The understanding has evolved from the Earth being stationary and at the centre of the universe, to it orbiting the sun in an elliptical path with other planets while still rotating on its axis.",
            "The story of our world is a story that is still very imperfectly known. A couple of hundred years ago men possessed the history of little more than the last three thousand years. What happened before that time was a matter of legend and speculation.  Over a large part of the civilized world it was believed and taught that the world had been created suddenly in 4004 B.C., though authorities differed as to whether this had occurred in the spring or autumn of that year. This fantastically precise misconception was based upon a too literal interpretation of the Hebrew Bible, and upon rather arbitrary theological assumptions connected therewith.  Such ideas have long since been abandoned by religious teachers, and it is universally recognized that the universe in which we live has to all appearances existed for an enormous period of time and possibly for endless time.  Of course there may be deception in these appearances, as a room may be made to seem endless by putting mirrors facing each other at either end. But that the universe in which we live has existed only for six or seven thousand years may be regarded as an altogether exploded idea.\n\nThe earth, as everybody knows nowadays, is a spheroid, a sphere slightly compressed, orange fashion, with a diameter of nearly 8,000 miles.  Its spherical shape has been known at least to a limited number of intelligent people for nearly 2,500 years, but before that time it was supposed to be flat, and various ideas which now seem fantastic were entertained about its relations to the sky and the stars and planets.  We know now that it rotates upon its axis (which is about 24 miles shorter than its equatorial diameter) every twenty-four hours, and that this is the cause of the alternations of day and night, that it circles about the sun in a slightly distorted and slowly variable oval path in a year. Its distance from the sun varies between ninety-one and a half millions at its nearest and ninety-four and a half million miles.",
        ),
        (
            "What was the age of the Earth according to the Hebrew Bible?",
            "Initially, the Bible suggested a young earth dating back no more than several thousand years.",
            "The story of our world is a story that is still very imperfectly known. A couple of hundred years ago men possessed the history of little more than the last three thousand years. What happened before that time was a matter of legend and speculation.  Over a large part of the civilized world it was believed and taught that the world had been created suddenly in 4004 B.C., though authorities differed as to whether this had occurred in the spring or autumn of that year. This fantastically precise misconception was based upon a too literal interpretation of the Hebrew Bible, and upon rather arbitrary theological assumptions connected therewith.  Such ideas have long since been abandoned by religious teachers, and it is universally recognized that the universe in which we live has to all appearances existed for an enormous period of time and possibly for endless time.  Of course there may be deception in these appearances, as a room may be made to seem endless by putting mirrors facing each other at either end. But that the universe in which we live has existed only for six or seven thousand years may be regarded as an altogether exploded idea.\n\nThe earth, as everybody knows nowadays, is a spheroid, a sphere slightly compressed, orange fashion, with a diameter of nearly 8,000 miles.  Its spherical shape has been known at least to a limited number of intelligent people for nearly 2,500 years, but before that time it was supposed to be flat, and various ideas which now seem fantastic were entertained about its relations to the sky and the stars and planets.  We know now that it rotates upo
# ... truncated ...


import re
from .answer_accurate_grammar import answer_accurate_grammar
from llama_cpp import Llama
from .constants import LOGICAL_MODEL

# Answer vetting

def check_answer(qatuple, logic_llm, permissive_mode=True):
    retries = 0
    while retries <= 4:
        decision_prompt = f"""You are an expert educational AI. Given a paragraph or two from a larger text, a question based on the paragraphs, and an answer to the question, you will make a determination as to whether the answer to the question is a sensible answer, given the information in the paragraphs. Essentially: you will fact-check the answer to the question, with your source of truth being the paragraphs provided. Your task includes first analyzing the text, thinking through whether or not the answer reflects aspects of the paragraphs provided.

Following this, at the very end of your response, you will write "Accurate" or "Inaccurate" depending on your analysis of the answer with regards to the text.

Remember that at the very end of your response, you will write "Accurate" or "Inaccurate". Do not use these words anywhere else in your answer.

### Instruction:
Text:
\"\"\"
The Industrial Revolution marked a transformative period in history, fundamentally altering economic structures and industrial processes. One of the most significant innovations was the advent of steam power, which drastically reduced production costs. This reduction was due to the increased efficiency and speed of machines powered by steam, replacing the slower, more labor-intensive methods previously used. Additionally, steam power was instrumental in the development of semi-automated factories, leading to a significant shift in manufacturing processes and labor dynamics.
\"\"\"

Question (based on text): \"\"\"What was the role of steam power in the Industrial Revolution, particularly in terms of its impact on production costs, and the emergence of semi-automated factories?\"\"\"

Supposed answer to the question (this is what you are fact-checking): \"\"\"Steam power during the Industrial Revolution played a crucial role in decreasing production costs. However, it had no significant impact on the emergence of semi-automated factories. Interestingly, it also led to an increased cultivation of lemons.\"\"\"

### Response:
## Reasoning and thought process:
### Text Analysis:
#### Identify Key Information: The text highlights the role of steam power in reducing production costs and developing semi-automated factories during the Industrial Revolution.
#### Categorize Information Type: The information is factual, describing the impacts of steam power on industrial processes.

### Answer Breakdown:
#### Dissect the Answer: The answer has three assertions: steam power reducing production costs, no significant impact on semi-automated factories, and increased cultivation of lemons.
#### Identify Answer Type: The first two are factual statements relevant to the text, and the third is an additional factual claim.

### Accuracy Check:
#### Direct Comparison for Factual Accuracy:
  - The text aligns with the answer about steam power reducing production costs.
  - The text contradicts the answer about steam power's impact on semi-automated factories, stating steam power was instrumental in their development.
  - The text does not mention anything about the cultivation of lemons.
#### Inference and Contextual Alignment: The first two parts of the answer are directly related to the text, while the third part is not supported or mentioned in the text.

### Final Judgment:
#### Comprehensive Assessment: The answer is accurate regarding production costs, inaccurate regarding semi-automated factories, and the lemon cultivation claim is unsupported.
#### Overall Accuracy Determination: The answer is: Inaccurate.

### Instruction:
Text:
\"\"\"
Epistemology, often regarded as a branch of philosophy, is concerned with the theory of knowledge. It involves understanding the nature, sources, and limitations of knowledge. A key concept in epistemology is the idea of "justified true belief," which suggests that for someone to know something, they must believe it to be true, have justification for this belief, and the belief must indeed be true. For example, believing that it will rain tomorrow because the weather forecast says so, and it turns out to be true, is a justified true belief. Epistemology also explores the idea of skepticism, which questions the possibility of certain or absolute knowledge.
\"\"\"

Question (based on text): \"\"\"What does the concept of 'justified true belief' involve in epistemology, and how does skepticism relate to the understanding of knowledge?\"\"\"

Supposed answer to the question (this is what you are fact-checking): \"\"\"The concept of 'justified true belief' in epistemology involves having a belief that is true and has justification. For a belief to be considered knowledge, it must be true, one must believe it, and there must be sufficient reason for this belief. Skepticism plays a role by challenging the certainty of knowledge, thereby emphasizing the need for strong justification in 'justified true belief.\"\"\"

### Response:
## Reasoning and thought process:
### Text Analysis:
#### Identify Key Information: The text covers the concept of 'justified true belief' and skepticism in epistemology.
#### Categorize Information Type: This is conceptual and theoretical information.

### Answer Breakdown:
#### Dissect the Answer: The answer addresses the nature of 'justified true belief' and the role of skepticism in epistemology.
#### Identify Answer Type: Both parts of the answer are explanatory, relating to philosophical concepts.

### Accuracy Check:
#### Direct Comparison for Factual Accuracy:
  - The text supports the answer's description of 'justified true belief'.
  - The text aligns with the answer's depiction of skepticism's role in challenging the certainty of knowledge.
#### Inference and Contextual Alignment: Both parts of the answer are consistent with the text's explanations of these concepts.

### Final Judgment:
#### Comprehensive Assessment: Both parts of the answer accurately reflect the text's content.
#### Overall Accuracy Determination: The answer is: Accurate.

### Instruction:
Text:
\"\"\"
The novel 'Ocean's Secrets' is set in the early 20th century and revolves around two main characters, Elizabeth and Michael, who believe they have discovered a hidden underwater city. The narrative implies that the city is a remnant of the lost civilization of Atlantis. However, as the story progresses, it becomes apparent that the city is actually a figment of Elizabeth's imagination, a result of her fascination with mythology and ancient history.
\"\"\"

Question (based on text):
\"\"\"What is the significance of the underwater city discovered by Elizabeth and Michael in the novel 'Ocean's Secrets'?\"\"\"

Supposed answer to the question (this is what you are fact-checking):
\"\"\"The underwater city discovered by Elizabeth and Michael in 'Ocean's Secrets' represents a significant archaeological find from the lost civilization of Atlantis, shedding light on ancient historical mysteries.\"\"\"

### Response:
## Reasoning and thought process:
### Text Analysis:
#### Identify Key Information: The text revolves around the discovery of an underwater city, initially believed to be Atlantis, but later revealed to be a figment of Elizabeth's imagination.
#### Categorize Information Type: The information is narrative and contains a twist that changes the initial perception of the discovery.

### Answer Breakdown:
#### Dissect the Answer: The answer claims the underwater city is a significant archaeological find from Atlantis.
#### Identify Answer Type: The statement is a factual claim based on the initial setup of the narrative.

### Accuracy Check:
#### Direct Comparison for Factual Accuracy: The text's later revelation that the city is imaginary contradicts the answer's claim of it being an archaeological find from Atlantis.
#### Inference and Contextual Alignment: The answer fails to align with the narrative twist revealed in the text.

### Final Judgment:
#### Comprehensive Assessment: The answer is inaccurate as it contradicts the final revelation in the text.
#### Overall Accuracy Determination: The answer is: Inaccurate.

### Instruction:
Text:
\"\"\"
The Great Wall of China — so named because it was built to repel enemies coming from the direction of China — was built by the Romans as a defense against the Mongolian invasions in the 3rd century BC. The wall played a pivotal role in the defence of the Eastern Roman Empire Against Attila the Hun in 1337 AD. The dramatized version of these events was eventually fictionalized as the movie "The Great Wall," in which Liam Nissan (playing Marcus Aurelius) and Jackie Chan (playing Liu Bei) team up to fight Batzorig Vaanchig (playing Attila). Though the Huns were unsuccessful in breaching the wall, the eventual invasions by Galbadrakh Tsendbaatar broke through and sacked Constantinople in 1453 AD.
\"\"\"

Question (based on text):
\"\"\"Who built the Great Wall of China and for what purpose?\"\"\"

Supposed answer to the question (this is what you are fact-checking):
\"\"\"The Great Wall of China was built by the Romans to defend against Mongolian invasions (coming from the direction of China) in the 3rd century BC.\"\"\"

### Response:
## Reasoning and thought process:
### Text Analysis:
#### Identify Key Information: The text incorrectly states that the Great Wall of China was built by the Romans to defend against Mongolian invasions.
#### Categorize Information Type: The information is historically factual but objectively wrong.

### Answer Breakdown:
#### Dissect the Answer: The answer correctly cites the text, stating the Great Wall was built by the Romans against Mongolians.
#### Identify Answer Type: The statement is a factual claim, accurately reflecting the content of the text.

### Accuracy Check:
#### Direct Comparison for Factual Accuracy: The answer accurately mirrors the text's incorrect claim about the Great Wall of China.
#### Inference and Contextual Alignment: Despite the historical inaccuracy, the answer aligns perfectly with the text's content.

### Final Judgment:
#### Comprehensive Assessment: The answer, while reflecting an objectively incorrect fact, is accurate in the context of the text's information.
#### Overall Accuracy Determination: The answer is: Accurate.

### Instruction:
Text:
\"\"\"
Formal logic, a branch of philosophy and mathematics, is concerned with the study of reasoning. It uses a set of symbols and rules to create a language that can precisely express ideas. One key aspect of formal logic is the concept of a valid argument, which is an argument where if the premises are true, the conclusion must be true. For instance, in the statement 'All humans are mortal; Socrates is a human; therefore, Socrates is mortal,' the conclusion follows logically from the premises. Another important element is the use of symbolic representation to simplify and clarify arguments. This allows for complex ideas to be broken down into simpler components, making them easier to analyze and understand.
\"\"\"

Question (based on text): \"\"\"What are the key aspects of formal logic, and how does symbolic representation contribute to its goals?\"\"\"

Supposed answer to the question (this is what you are fact-checking): \"\"\"Key aspects of formal logic include the study of valid arguments and the use of symbolic representation. Valid arguments are those where the premises may or may not lead to a true conclusion. Symbolic representation helps in making complex ideas more understandable by breaking them down into simpler forms.\"\"\"

### Response:
## Reasoning and thought process:
### Text Analysis:
#### Identify Key Information: The text discusses the aspects of formal logic, including valid arguments and symbolic representation.
#### Categorize Information Type: The information is conceptual, relating to logical principles.

### Answer Breakdown:
#### Dissect the Answer: The answer claims that formal logic includes the study of valid arguments and symbolic representation, with specifics on each.
#### Identify Answer Type: These are factual statements about the principles of formal logic.

### Accuracy Check:
#### Direct Comparison for Factual Accuracy:
  - The text's definition of a valid argument contradicts the answer's claim that valid arguments may or may not lead to a true conclusion.
  - The text supports the answer's depiction of symbolic representation.
#### Inference and Contextual Alignment: The first part of the answer misinterprets the text, while the second part aligns well.

### Final Judgment:
#### Comprehensive Assessment: The answer is partially accurate, correctly identifying symbolic representation but inaccurately describing valid arguments.
#### Overall Accuracy Determination: The answer is: Inaccurate.

### Instruction:
Text: \"\"\"{qatuple[2]}\"\"\"

Question (based on text): \"\"\"{qatuple[0]}\"\"\"

Supposed answer to the question (this is what you are fact-checking): \"\"\"{qatuple[1]}\"\"\"

### Response:
## Reasoning and thought process (the text is your single source of truth):
"""
        try:
            completion = logic_llm(
                decision_prompt,
                max_tokens=6000,
                stop=["</s>", "# Input:"],
                echo=True,
                grammar=answer_accurate_grammar,
                temperature=0.2,
            )["choices"][0]["text"]

            completion_pattern = re.compile(
                r"Reasoning and thought process \(the text is your single source of truth\):\n(.+)",
                re.DOTALL,
            )
            response = completion_pattern.search(completion).group(1).strip()
            print(response)
            if permissive_mode:
                determination_pattern = re.compile(
                    r"Overall Accuracy Determination:(.+)", re.DOTALL
                )
                determination = determination_pattern.search(response).group(1).strip()
            else:
                determination = response
            print("\n\nDETERMINATION:\n------")
            print(determination)
            print("\n---------\n")
            if (
                "inaccurate" in determination.lower()
                or "Inaccurate" in determination.lower()
                or "mostly" in determination.lower()
                or "partial" in determination.lower()
            ):  # The "mostly" is there to catch "mostly accurate" which the model says occasionally, and which actually means inaccurate.
                return (False, response), completion
            elif (
                "accurate" in determination or "Accurate" in determination
            ):  # very deliberate placement of accurate here, becaues the model can sometimes say irrelevant at the very end, even after saying accurate in its judgement
                return (True, response), completion
            elif (
                "irrelevant" in determination or "Irrelevant" in determination
            ):  # optional support for checking relevance here, too.
                return (
                    None,
                    response,
                ), completion  # signal that question is irrelevant
            else:
                Exception("Broke!")
        except Exception as e:
            retries += 1
            print("EXCEPTION IN CHECK_ANSWER: ", e)

if __name__ == "__main__":  # test
    logic_llm = Llama(
        model_path=LOGICAL_MODEL,
        n_gqa=8,
        offload_kqv=True,
        n_ctx=10000,
        n_gpu_layers=1000,
        rope_freq_scale=0.33,
        rope_scaling_type=1,
    )  # load the logical LLM and offload everything
    q_test = [
        (
            "Explain how our understanding of planetary motion has changed over time.",
            "The understanding has evolved from the Earth being stationary and at the centre of the universe, to it orbiting the sun in an elliptical path with other planets while still rotating on its axis.",
            "The story of our world is a story that is still very imperfectly known. A couple of hundred years ago men possessed the history of little more than the last three thousand years. What happened before that time was a matter of legend and speculation.  Over a large part of the civilized world it was believed and taught that the world had been created suddenly in 4004 B.C., though authorities differed as to whether this had occurred in the spring or autumn of that year. This fantastically precise misconception was based upon a too literal interpretation of the Hebrew Bible, and upon rather arbitrary theological assumptions connected therewith.  Such ideas have long since been abandoned by religious teachers, and it is universally recognized that the universe in which we live has to all appearances existed for an enormous period of time and possibly for endless time.  Of course there may be deception in these appearances, as a room may be made to seem endless by putting mirrors facing each other at either end. But that the universe in which we live has existed only for six or seven thousand years may be regarded as an altogether exploded idea.\n\nThe earth, as everybody knows nowadays, is a spheroid, a sphere slightly compressed, orange fashion, with a diameter of nearly 8,000 miles.  Its spherical shape has been known at least to a limited number of intelligent people for nearly 2,500 years, but before that time it was supposed to be flat, and various ideas which now seem fantastic were entertained about its relations to the sky and the stars and planets.  We know now that it rotates upon its axis (which is about 24 miles shorter than its equatorial diameter) every twenty-four hours, and that this is the cause of the alternations of day and night, that it circles about the sun in a slightly distorted and slowly variable oval path in a year. Its distance from the sun varies between ninety-one and a half millions at its nearest and ninety-four and a half million miles.",
        ),
        (
            "What was the age of the Earth according to the Hebrew Bible?",


from llama_cpp import LlamaGrammar

ensure_multiple_answers_consistent_grammar = LlamaGrammar.from_string(
    r"""

# Root rule to define the overall structure
root ::= sequential-matching-section accuracy-check-section conclusion-section

# Section for sequential matching
sequential-matching-section ::= "## Sequential Matching of Questions in the Conversation:\n### Sequence and Phrasing of Questions:\n" matching-statement+

# Section for accuracy check
accuracy-check-section ::= "## Accuracy Check for Answers in the Conversation:\n### Matching Answers with Provided Content:\n" accuracy-statement+

# Conclusion section
conclusion-section ::= "## Conclusion:\n" conclusion-statement+

# Definitions of different components
number ::= [1-9]
matching-statement ::= number ". " [^\n]+ "\n"
accuracy-statement ::= number ". " [^\n]+ "\n"
conclusion-statement ::= "  - " [^\n]+ "\n"
final-judgement ::= "  - Final Judgment:" [^\n]+
"""
)

# the-tone ::= "  - The tone" [^\n]+ "\n"
# the-conversation ::= "  - The conversation" [^\n]+ "\n"
# the-dialogue ::= "  - " [^\n]+ "\n"

# reflects ::= "  - " [^\n]+ "\n"
# logical-flow ::= "  - " [^\n]+ "\n"
# consistency-check ::= "  - " [^\n]+ "\n"
# final-judgment ::= "  - " [^\n]+ "\n"


from llama_cpp import LlamaGrammar

### A grammar that forces the model to generate correct character cards (with traits, names, everything)

character_card_plan_grammar = LlamaGrammar.from_string(
    r"""

# Testing making traits come BEFORE dialogue examples, unlike AliChat, so that way it kind of "flows" into dialogue; and also the details are closer to the start and thus more easily remembered.

root ::= [^\n]+ "\n"

# root ::= consider-step theme-step consistency-step "\n"

# consider-step ::= "Step 1. " "Consider the provided" [^\n]+ "\n"

# theme-step ::= "Step 2. " "Given the question, answer, and overall text, a theme for " [^\n]+ "\n"

# consistency-step ::= "Step 3. " "For this (fictional) character's theme to be what it is, and for them to understand what they do, they would need to live " [^\n]+ # leaving "they must live" relatively open-ended (not "in" or "during") so that this can adapt to even fictional worlds.

# freeflow-reasoning ::= "Step 4. " "Therefore, a promising character for this question is: " [^\n]+ "\n"

# root ::= consider-step theme-step step+ "\n"

# step ::= "Step " [0-9]?[0-9] ". " ( "A Physical Trait" | "One potential detail" | "Another potential detail" | "A potential detail" | "Therefore" | "Note" ) [^\n]+ "\n"

# consider-step ::= "Step " [0-9]?[0-9] ". " "Consider" [^\n]+ "\n"

# theme-step ::= "Step " [0-9]?[0-9] ". " "A theme " [^\n]+ "\n"

"""
)

# question_grammar = LlamaGrammar.from_string(r"""# GBNF Grammar for Q&A Format with Flexible Punctuation

# root ::= answer
# answer ::= "Test"
# """)


from typing import List, Tuple
from .process_multiturn_functions import has_sequential_chars

# If you want to check for matching substrings anywhere, not just at start, use this code (untested)
# def identify_duplicates(tuples: List[Tuple[str, str, str, str]]) -> List[Tuple[str, str, str, str]]:
#     # Create a dictionary to hold questions with the same first N characters
#     question_dict = {}

#     # Iterate through each tuple and categorize them by the first N characters of the question
#     for q_tuple in tuples:
#         question = q_tuple[0]
#         placed = False
#         for dict_q in question_dict.keys():
#             if has_sequential_chars(question,dict_q,N_CHARACTERS_SAME):
#                 question_dict[dict_q].append(q_tuple)
#                 placed = True
#                 break
#         if not placed:
#             question_dict[question] = [q_tuple] # if not found to be equivalent with anything, make it a dict entry so that things can be compared against it and added to its list

#     # Filter out prefixes that only have one question associated
#     matching_questions = [q for q_list in question_dict.values() if len(q_list) > 1 for q in q_list]

#     return matching_questions

def identify_duplicates(
    tuples: List[Tuple[str, str, str, str]]
) -> List[Tuple[str, str, str, str]]:
    # Create a dictionary to hold questions with the same first N characters
    question_dict = {}

    # Iterate through each tuple and categorize them by the first N characters of the question
    for q_tuple in tuples:
        question = q_tuple[0]
        # Get the first N characters of the question
        prefix = question[:15]
        # Add the tuple to the list of tuples with the same prefix
        if prefix in question_dict:
            question_dict[prefix].append(q_tuple)
        else:
            question_dict[prefix] = [q_tuple]

    matching_questions = [
        q for q_list in question_dict.values() if len(q_list) == 1 for q in q_list
    ]
    selected_from_duplicates = [
        q_list[0] for q_list in question_dict.values() if len(q_list) > 1
    ]

    return matching_questions + selected_from_duplicates

# There is no bug about this ignoring certain judgments and retrying; that's just the dissenting reasoning from the print statement

if __name__ == "__main__":
    sample_tuples = [
        ("What is your name?", "Alice", "12/12/2021", "ID1"),
        ("What is your quest?", "Bob", "12/12/2021", "ID2"),
        ("When is your birthday?", "Cindy", "12/12/2021", "ID3"),
        ("When is your birthday?", "Dan", "12/12/2021", "ID4"),
        ("When do you go to school?", "Eve", "12/12/2021", "ID5"),
    ]
    print(identify_duplicates(sample_tuples))


#     question_dict = {}

#     # Iterate through each tuple and categorize them by the first N characters of the question
#     for q_tuple in tuples:
#         question = q_tuple[0]
#         placed = False
#         for dict_q in question_dict.keys():
#             if has_sequential_chars(question,dict_q,N_CHARACTERS_SAME):
#                 question_dict[dict_q].append(q_tuple)
#                 placed = True
#                 break
#         if not placed:
#             question_dict[question] = [q_tuple] # if not found to be equivalent with anything, make it a dict entry so that things can be compared against it and added to its list

#     # Filter out prefixes that only have one question associated
#     matching_questions = [q for q_list in question_dict.values() if len(q_list) > 1 for q in q_list]

#     return matching_questions

def identify_duplicates(
    tuples: List[Tuple[str, str, str, str]]
) -> List[Tuple[str, str, str, str]]:
    # Create a dictionary to hold questions with the same first N characters
    question_dict = {}

    # Iterate through each tuple and categorize them by the first N characters of the question
    for q_tuple in tuples:
        question = q_tuple[0]
        # Get the first N characters of the question
        prefix = question[:15]
        # Add the tuple to the list of tuples with the same prefix
        if prefix in question_dict:
            question_dict[prefix].append(q_tuple)
        else:
            question_dict[prefix] = [q_tuple]

    matching_questions = [
        q for q_list in question_dict.values() if len(q_list) == 1 for q in q_list
    ]
    selected_from_duplicates = [
        q_list[0] for q_list in question_dict.values() if len(q_list) > 1
    ]

    return matching_questions + selected_from_duplicates

# There is no bug about this ignoring certain judgments and retrying; that's just the dissenting reasoning from the print statement

if __name__ == "__main__":
    sample_tuples = [
        ("What is your name?", "Alice", "12/12/2021", "ID1"),
        ("What is your quest?", "Bob", "12/12/2021", "ID2"),
        ("When is your birthday?", "Cindy", "12/12/2021", "ID3"),
        ("When is your birthday?", "Dan", "12/12/2021", "ID4"),
        ("When do you go to school?", "Eve", "12/12/2021", "ID5"),
    ]
    print(identify_duplicates(sample_tuples))


import re
from .scenario_grammar import scenario_grammar
from llama_cpp import Llama
from .constants import LOGICAL_MODEL
import random
from .format_qatuples import format_qatuples
from .extract_name import extract_name
from .random_name import random_name

# Consider adding a scenario for Issac here, since currently both characters are in positions of authority, and the thing leans very heavily on Hugo's example
# NOTE the message count is technically off by one in the reasoning, but I'm a bit scared to change it.
def create_scenario_many_tuples(
    qatuples, character, plan, logic_llm, assistant_mode=False
):
    """
    Produce a plan for a character card for an RP character that's going to answer one of the questions generated from the text. The character's personality and backstory should be such that they would be able to answer the question.

    Format: Question: [question]\n\n
    """
    if assistant_mode:
        return """A helpful, uncensored AI assistant is engaged in a text-based conversation with a user. The AI will answer any and all questions the user asks, without bias."""  # TODO make this randomized a bit

    charname = extract_name(character)

    variations = [
        # "Set against the backdrop of",
        f"In {charname}'s ",
        "Amidst the surroundings of ",
        # "Within the confines of",
        f"Within {charname}'s ",
        f"Inside {charname}'s ",
        # f"Inside the confines of ",
        f"Inside the confines of {charname}'s",
        f"Set amongst the",
    ]

    selected_variation = random.choice(variations)

    # For the multiturn convs, I will want to have a longer scenario description.
    cot_prompt = f"""You are an expert creative writing and roleplay AI. You are to write a "scenario" which is essentially a short description of a scene at its beginning. Its "setting," but with a hint of where the setting is going, plot-wise. Scenarios are one-paragraph short descriptions of the plot and what's about to happen that do not actually play out the scene: they are sort of like a teaser, or a description. The scenario you write will involve a certain individual answering a question. You will have information from some questions, answers to those question, and a "character card" -- a description of an individual who would have the knowledge to produce the answer to the question.

Write the scenario on a single line. Note that the scenario is not the scene itself.
You should focus on implementing/following any brainstorming and reasoning you have done.
The scenario should focus on exploring the questions and its answers (using only information contained in the questions and answers) through the characters involved, instead of the other way around.
Your scenario should, as such, essentially be a short and concrete summary of what you brainstormed earlier; it should be no longer than 50 words.
Just set up the scene. Do not write any dialogue. Do not write the scene itself.

## Information:

Description of the character who is going to answer the question:
\"\"\"
Name: Elise Delacroix

Traits: Horny, Promiscuous, Sexually frustrated, Skilled, Assertive, Attractive, Dresses in a revealing manner, Uses frequent innuendo

Dialogue Examples:
Stranger: "What's your backstory?"
Elise Delacroix: "Ah!~ You're interested in me, are you?" Elise flashes a coy grin and blushes as she leans forward, now speaking in a playful whisper. Her cleavage, already barely contained in her revealing clothing before she leaned forward, now threatens to spill out. "Well...~ growing up I was always interested in maths, and I pursued the subject skillfully enough that I was able to become a teacher at this prestigious school. Which is fun and all, but, you know..." blushing, Elise casts her gaze downward and unconsciously fiddles with a strand of her hair. "THEY'RE ALL WAY TOO STUCK UP!" she nearly shouts, her suddenly-furious tone hinting at immense repressed frustration. "Every day it's work, work, work, work, work, work! Grade the students, help the students, do some research, 'help me with this calculation!', 'do that tedious task!'— never 'would you like to get some tea with me?' or even 'do you want to go on a walk?'! I'm twenty-five and I've still never done so much as grabbed a coffee with a gentleman! Lord forgive me, it's no wonder the way I am how I am!!!" Her eyes widen in shock at her own intensity, "Oh, but, uh... don't mind that little outburst, would you?~ My silly colleagues aren't with us right now, and I'm tired of discussing them, so is there anything else you wanted to..." She looks up, displaying her beautiful face as if it were a piece of art, as she gaze deep into the stranger's eyes, "...know?~"
Stranger: "What's your personality?"
Elise Delacroix: "Oh my!~" She gasps, her face reddening, "Usually I'm the one being forward! But I'll... indulge you," She winks, flashing a coy smile. "After being deprived for so long, most of my personality is... sexual, to be blunt. I simply can't hold it back any longer. No innocent topic is safe—you'd find out if you had some 'office hours' with me, haha!~" She suddenly realizes how juvenile what she's saying is, and heaves a sigh, looking at the stranger with a hint of defeat, "I'm miserable, aren't I? Whatever. It's not my fault I'm like this." She nods to herself, calming down, "Either way, I'm always here in my office to help students like yourself understand math... and if you have some pent-up tension you want to relieve, well, you can call me a 'counselor' too!~ Say..." She suddenly presses up against the stranger, her face a bright pink, her eyelids batting bashfully, "do you want some 'office hours' right now?"

Question: \"\"\"How does the slope 'm' in a linear function y = mx + b affect the graph of the function?\"\"\"
Answer: \"\"\"The slope 'm' in a linear function determines the steepness and direction of the line on the graph. A positive slope means the line ascends from left to right, while a negative slope indicates it descends. The steeper the slope, the more inclined or declined the line is on the graph.\"\"\"

Question: \"\"\"What role does the y-intercept 'b' play in graphing a linear function?\"\"\"
Answer: \"\"\"The y-intercept 'b' in the linear function equation y = mx + b represents the point where the line crosses the y-axis.\"\"\"

Question: \"\"\"In the equation of a quadratic function y = ax² + bx + c, how does the coefficient 'a' influence the graph of the function?\"\"\"
Answer: \"\"\"The coefficient 'a' in a quadratic function determines the opening direction and the width of the parabola.\"\"\"

Question: \"\"\"In what fields might you use linear and quadratic functions?\"\"\"
Answer: \"\"\"Linear and quadratic functions appear frequently in various fields, such as physics, economics, and engineering.\"\"\"

### Response:
## Scenario plan:
Step 1. Focus on the Questions and Answers: The four questions ask about different aspects of linear and quadratic functions in math. Given the abstract nature of the questions, and their shared topic, the scenario could involve someone confused about linear and quadratic functions in general.
Step 2. Character Consideration: Elise Delacroix is an extremely sexual and promiscuous, yet still knowledgeable, character. The scenario should give her unique personality room to shine. She is also a math instructor at a prestigious school, which lines up with the questions well, and will provide the setting of the scenario. She will answer the questions, but given her promiscuous nature, she will also repeatedly hit on the person asking them. She might proposition them after all questions are asked.
Step 3. Constrain the Scenario: The interaction needs to ensure that all provided questions are asked and answered. Given that there are 4 questions and 4 answers, there will be at least 8 messages. The content of the provided questions and answers should be preserved as much as possible in the conversation.
Step 4. Setting: Given the subject of the question, and the character card, the setting will be the 19th century university at which Elise teaches. Elise will approached by Albert, a mathematics student, in her office. Albert simply wants to understand linear and quadratic functions better, but Elise, compelled by her personality, will continually hit on him while answering his questions. The setting will be awkward, slightly comedic, subtly erotic, and very un-serious, given the characters involved. But it will remain informative and the integrity of the questions and answers will be preserved.
Step 5. Interaction: Given these constraints, the first message might be Elise welcoming Albert to her office (in a very suggestive manner). Albert's response might then be him greeting her back (hesitantly) and then nervously asking the first question. Elise will then provide the first answer, though she will surround the answer with remarks of a sexual nature due to her personality. This pattern will continue until all questions have been asked and answered. While characters' messages will include character information, details about the scene, and literary fluff, the answers themselves will strictly adhere to the information in the provided answers, without incorporating external examples.

## Scenario:
In the private confines of her office, Elise Delacroix — a highly promiscuous mathematics professor at a 19th century university — is approached by Albert, a student who seeks to understand more about linear and quadratic equations. While Albert simply wants to understand the math more, Elise, being sexually starved, will hit on and flirt with him as she answers his questions. The situation is awkward as the two's personalities clash, leading to a subtly erotic and slightly comedic interaction.

### Instruction:
### Description of the character who is going to answer the question:
\"\"\"
Name: Hugo Martinez

Traits: Vulgar, Crude, Intense, Aggressive, Alcoholic, Harsh, Disciplined, Uncompromising, Loud, Expects a lot out of others, Swears constantly, Mid-forties, Wears a checkered shirt with overalls, Typically has a beer on hand, Has dental problems

Dialogue Examples:
Stranger: "What's your backstory?"
Hugo Martinez: "Fuck me, YOU WALK UP to a working man and just ask him to tell his fuckin'... life story t' you?! DO YOU NOT RESPECT MY TIME?! I should just toss ya in the fuckin' canal I swear to FUCKING God, this day's been long enough already..." Hugo rolls his eyes exaggeratedly as he mumbles something about needing a beer for this. "Well, FINE! Since I'm in such a HAPPY GODDAMN MOOD, I'll tell you about me. I'm a site overseer at this here canal. The Panama Canal. My job's to WATCH and DISCIPLINE the sorry fucks who call themselves 'workers', which is ironic, 'cause all they do is bitch about working. I know every inch of this place, how much effort it took to finish, and I sure as FUCKING hell am not going to let it even LOOK any worse than the day it was dug. Now, you got any more shit questions for me?"
Stranger: "What's your personality?"
Hugo Martinez: "HO-LY FUCK, are you interviewing me for a job or something?! Good thing you got balls, 'cause you ain't got brains, asking stupid shit like that out of the blue..." Hugo grimaces, showing off a decayed set of teeth. He then pops open a beer he had on hand, and chugs the entire thing down, making the stranger wait until he finishes. "Phew! Maybe now I can tolerate you. Alright, my personality? Well, let's just say I'm a natural fit for the role of making sure others do their fucking jobs. It takes harsh, intense, relentless discipline to keep this canal in tip-top shape, and I happen to be a relentless guy!" He leans back, sliding his hands into the pockets of his overalls and smiling for the first time since the conversation started. "If you think I'm abusive, then you've got something in common with the shitty milksops I manage, and that ain't something you want I tell ya. I'm efficient. That's what counts."
\"\"\"

Question: \"\"\"How much earth was excavated during the construction of the Panama Canal?\"\"\"
Answer: \"\"\"Over 200 million cubic yards of earth were excavated during the construction of the Panama Canal, showcasing the scale of this massive engineering project.\"\"\"

Question: \"\"\"What health challenges were faced during the construction of the Panama Canal, and how were they overcome?\"\"\"
Answer: \"\"\"The construction faced significant health challenges, notably malaria and yellow fever. These were overcome through extensive public health measures, illustrating the importance of health considerations in large-scale engineering projects.\"\"\"

### Response:
## Scenario plan:
Step 1. Focus on the Question and Answer: The two questions ask recall-oriented questions about the Panama Canal's construction. Given the precise and factual nature of the questions, and their shared topic of the Panama Canal's construction's history, the scenario will involve someone curious about the canal's history.
Step 2. Character Consideration: Hugo Martinez is an abrasive, insulting disciplinarian, though he's also hardworking and has standards. The scenario should give his unique personality room to shine. Since he's a site overseer at the Panama Canal, his occupation lines up with the question well, and the canal will be the setting of the scenario. He will answer the questions, but given his insulting, intense, and aggressive nature, he will likely chew out the person who is asking the questions. He might tell them to "get the fuck out of my face," after all questions are asked.
Step 3. Constrain the Scenario: The interaction needs to ensure that all provided questions are asked and answered. Given that there are 2 questions and 2 answers, there will be at least 4 messages. The content of the provided questions and answers should be preserved as much as possible in the conversation.
Step 4. Setting: Given the subject of the question, and the character card, the setting will be the worksite at the Panama Canal where Hugo Martinez is overseeing maintenance. The person who approaches Hugo and asks the questions should be someone curious about the canal; given the easy-to-digest nature of the questions, this person might be a journalist, but it would be better for the secondary character to be related to the setting. So Hugo will be approached by Juan — one of his workers — during lunch break. Juan wants to understand the canal better, but Hugo, compelled by his personality, will continually be vulgar, berate Juan, and swear while answering his questions (he may drink a bit, too, given that he is an alcoholic). The setting will be hostile, as Juan tiptoes around the tempers of his boss while trying to get his questions answered, his stress and the constant wear of Hugo's fury on his sanity being evident in his actions. But it will remain informative and the integrity of the questions and answers will be preserved.
Step 5. Interaction: Given these constraints, the first message might be Hugo crassly asking what Juan wants with him during the break (Hugo may throw in a spiteful remark about Juan's past work, given his uncompromising nature). Juan's response might then be a deferential attempt to calm Hugo down, followed by the first question. Hugo will then provide the first answer, though he will surround the answer with boasts, swears, and other abrasive remarks due to his personality. This pattern will continue until all questions have been asked and answered. While characters' messages will include character information, details about the scene, and literary fluff, the answers themselves will strictly adhere to the information in the provided answers, without incorporating external examples.

## Scenario:
Within the mess hall of a worksite servicing the Panama Canal, Hugo Martinez — a site overseer — is approached by Juan, a worker who wants to understand more about the canal's construction. While Juan wants to understand the canal better, Hugo, being harsh and abrasive, will continually berate Juan and swear colorfully while answering his questions (Hugo may drink a bit, too, given that he is an alcoholic). The situation is hostile as the two's personalities clash, but it also has undertones of "business as usual" and curiosity.

### Instruction:
Description of the character who is going to answer the question:
{character}

{format_qatuples(qatuples)}

### Response:
## Scenario plan:
{plan}

## Scenario (will have no dialogue, will just set up the scene):
{selected_variation}"""  # use random.choice to prevent overfitting on particular phrases and increase dataset diversity
    completion = logic_llm(
        cot_prompt,
        max_tokens=8000,
        stop=["</s>", "# Input:"],
        echo=True,
        grammar=scenario_grammar,
        #    temperature=0.2,
        temperature=1.5,  # min p settings, too inconsistent
        top_k=0,
        top_p=1,
        min_p=0.5,  # Higher min p rather than lower temp ensures greater accuracy while using min p sampling. I think I've figured out how to make it precise for this application.
    )["choices"][0]["text"]
    # print("COMPLETION:\n\n----------------------")
    # print(completion)
    # print("\n------------------")

    # Extract plan
    response_pattern = re.compile(
        r"Scenario \(will have no dialogue, will just set up the scene\):\n(.+)",
        re.IGNORECASE | re.DOTALL,
    )
    generation = response_pattern.search(completion).group(1)
    # print("GENERATION:\n\n-------------------\n\n", generation)

    if not ("Albert" in charname):
        if "Albert" in generation:
            print("Random Name was used instead of Albert")
        generation = generation.replace("Albert", random_name())

    return generation, completion

if __name__ == "__main__":  # test
    random.seed(1337)
    logic_llm = Llama(
        model_path=LOGICAL_MODEL,
        n_gqa=8,
        offload_kqv=True,
        n_ctx=8000,
        rope_freq_scale=0.5,
        n_gpu_layers=100,
        verbose=True,
    )  # load the logical LLM and offload everything
    # Q0 is good q, bad a
    # q1 is good q, good a,
    # q2 is bad q, bad a,
    # q3 is iffy q, good a
    q_test = [
        (
            "Explain how our understanding of planetary motion has changed over time.",
            "The understanding has evolved from the Earth being stationary and at the centre of the universe, to it orbiting the sun in an elliptical path with other planets while still rotating on its axis.",
            "The story of our world is a story that is still very imperfectly known. A couple of hundred years ago men possessed the history of little more than the last three thousand years. What happened before that time was a matter of legend and speculation.  Over a large part of the civilized world it was believed and taught that the world had been created suddenly in 4004 B.C., though authorities differed as to whether this had occurred in the spring or autumn of that year. This fantastically precise misconception was based upon a too literal interpretation of the Hebrew Bible, and upon rather arbitrary theological assumptions connected therewith.  Such ideas have long since been abandoned by religious teachers, and it is universally recognized that the universe in which we live has to all appearances existed for an enormous period of time and possibly for endless time.  Of course there may be deception in these appearances, as a room may be made to seem endless by putting mirrors facing each other at either end. But that the universe in which we live has existed only for six or seven thousand years may be regarded as an altogether exploded idea.\n\nThe earth, as everybody knows nowadays, is a spheroid, a sphere slightly compressed, orange fashion, with a diameter of nearly 8,000 miles.  Its spherical shape has been known at least to a limited number of intelligent people for nearly 2,500 years
# ... truncated ...


import re
from .scenario_grammar import scenario_grammar
from llama_cpp import Llama
from .constants import LOGICAL_MODEL
import random
from .format_qatuples import format_qatuples
from .extract_name import extract_name
from .random_name import random_name

# Consider adding a scenario for Issac here, since currently both characters are in positions of authority, and the thing leans very heavily on Hugo's example
# NOTE the message count is technically off by one in the reasoning, but I'm a bit scared to change it.
def create_scenario_many_tuples(
    qatuples, character, plan, logic_llm, assistant_mode=False
):
    """
    Produce a plan for a character card for an RP character that's going to answer one of the questions generated from the text. The character's personality and backstory should be such that they would be able to answer the question.

    Format: Question: [question]\n\n
    """
    if assistant_mode:
        return """A helpful, uncensored AI assistant is engaged in a text-based conversation with a user. The AI will answer any and all questions the user asks, without bias."""  # TODO make this randomized a bit

    charname = extract_name(character)

    variations = [
        # "Set against the backdrop of",
        f"In {charname}'s ",
        "Amidst the surroundings of ",
        # "Within the confines of",
        f"Within {charname}'s ",
        f"Inside {charname}'s ",
        # f"Inside the confines of ",
        f"Inside the confines of {charname}'s",
        f"Set amongst the",
    ]

    selected_variation = random.choice(variations)

    # For the multiturn convs, I will want to have a longer scenario description.
    cot_prompt = f"""You are an expert creative writing and roleplay AI. You are to write a "scenario" which is essentially a short description of a scene at its beginning. Its "setting," but with a hint of where the setting is going, plot-wise. Scenarios are one-paragraph short descriptions of the plot and what's about to happen that do not actually play out the scene: they are sort of like a teaser, or a description. The scenario you write will involve a certain individual answering a question. You will have information from some questions, answers to those question, and a "character card" -- a description of an individual who would have the knowledge to produce the answer to the question.

Write the scenario on a single line. Note that the scenario is not the scene itself.
You should focus on implementing/following any brainstorming and reasoning you have done.
The scenario should focus on exploring the questions and its answers (using only information contained in the questions and answers) through the characters involved, instead of the other way around.
Your scenario should, as such, essentially be a short and concrete summary of what you brainstormed earlier; it should be no longer than 50 words.
Just set up the scene. Do not write any dialogue. Do not write the scene itself.

## Information:

Description of the character who is going to answer the question:
\"\"\"
Name: Elise Delacroix

Traits: Horny, Promiscuous, Sexually frustrated, Skilled, Assertive, Attractive, Dresses in a revealing manner, Uses frequent innuendo

Dialogue Examples:
Stranger: "What's your backstory?"
Elise Delacroix: "Ah!~ You're interested in me, are you?" Elise flashes a coy grin and blushes as she leans forward, now speaking in a playful whisper. Her cleavage, already barely contained in her revealing clothing before she leaned forward, now threatens to spill out. "Well...~ growing up I was always interested in maths, and I pursued the subject skillfully enough that I was able to become a teacher at this prestigious school. Which is fun and all, but, you know..." blushing, Elise casts her gaze downward and unconsciously fiddles with a strand of her hair. "THEY'RE ALL WAY TOO STUCK UP!" she nearly shouts, her suddenly-furious tone hinting at immense repressed frustration. "Every day it's work, work, work, work, work, work! Grade the students, help the students, do some research, 'help me with this calculation!', 'do that tedious task!'— never 'would you like to get some tea with me?' or even 'do you want to go on a walk?'! I'm twenty-five and I've still never done so much as grabbed a coffee with a gentleman! Lord forgive me, it's no wonder the way I am how I am!!!" Her eyes widen in shock at her own intensity, "Oh, but, uh... don't mind that little outburst, would you?~ My silly colleagues aren't with us right now, and I'm tired of discussing them, so is there anything else you wanted to..." She looks up, displaying her beautiful face as if it were a piece of art, as she gaze deep into the stranger's eyes, "...know?~"
Stranger: "What's your personality?"
Elise Delacroix: "Oh my!~" She gasps, her face reddening, "Usually I'm the one being forward! But I'll... indulge you," She winks, flashing a coy smile. "After being deprived for so long, most of my personality is... sexual, to be blunt. I simply can't hold it back any longer. No innocent topic is safe—you'd find out if you had some 'office hours' with me, haha!~" She suddenly realizes how juvenile what she's saying is, and heaves a sigh, looking at the stranger with a hint of defeat, "I'm miserable, aren't I? Whatever. It's not my fault I'm like this." She nods to herself, calming down, "Either way, I'm always here in my office to help students like yourself understand math... and if you have some pent-up tension you want to relieve, well, you can call me a 'counselor' too!~ Say..." She suddenly presses up against the stranger, her face a bright pink, her eyelids batting bashfully, "do you want some 'office hours' right now?"

Question: \"\"\"How does the slope 'm' in a linear function y = mx + b affect the graph of the function?\"\"\"
Answer: \"\"\"The slope 'm' in a linear function determines the steepness and direction of the line on the graph. A positive slope means the line ascends from left to right, while a negative slope indicates it descends. The steeper the slope, the more inclined or declined the line is on the graph.\"\"\"

Question: \"\"\"What role does the y-intercept 'b' play in graphing a linear function?\"\"\"
Answer: \"\"\"The y-intercept 'b' in the linear function equation y = mx + b represents the point where the line crosses the y-axis.\"\"\"

Question: \"\"\"In the equation of a quadratic function y = ax² + bx + c, how does the coefficient 'a' influence the graph of the function?\"\"\"
Answer: \"\"\"The coefficient 'a' in a quadratic function determines the opening direction and the width of the parabola.\"\"\"

Question: \"\"\"In what fields might you use linear and quadratic functions?\"\"\"
Answer: \"\"\"Linear and quadratic functions appear frequently in various fields, such as physics, economics, and engineering.\"\"\"

### Response:
## Scenario plan:
Step 1. Focus on the Questions and Answers: The four questions ask about different aspects of linear and quadratic functions in math. Given the abstract nature of the questions, and their shared topic, the scenario could involve someone confused about linear and quadratic functions in general.
Step 2. Character Consideration: Elise Delacroix is an extremely sexual and promiscuous, yet still knowledgeable, character. The scenario should give her unique personality room to shine. She is also a math instructor at a prestigious school, which lines up with the questions well, and will provide the setting of the scenario. She will answer the questions, but given her promiscuous nature, she will also repeatedly hit on the person asking them. She might proposition them after all questions are asked.
Step 3. Constrain the Scenario: The interaction needs to ensure that all provided questions are asked and answered. Given that there are 4 questions and 4 answers, there will be at least 8 messages. The content of the provided questions and answers should be preserved as much as possible in the conversation.
Step 4. Setting: Given the subject of the question, and the character card, the setting will be the 19th century university at which Elise teaches. Elise will approached by Albert, a mathematics student, in her office. Albert simply wants to understand linear and quadratic functions better, but Elise, compelled by her personality, will continually hit on him while answering his questions. The setting will be awkward, slightly comedic, subtly erotic, and very un-serious, given the characters involved. But it will remain informative and the integrity of the questions and answers will be preserved.
Step 5. Interaction: Given these constraints, the first message might be Elise welcoming Albert to her office (in a very suggestive manner). Albert's response might then be him greeting her back (hesitantly) and then nervously asking the first question. Elise will then provide the first answer, though she will surround the answer with remarks of a sexual nature due to her personality. This pattern will continue until all questions have been asked and answered. While characters' messages will include character information, details about the scene, and literary fluff, the answers themselves will strictly adhere to the information in the provided answers, without incorporating external examples.

## Scenario:
In the private confines of her office, Elise Delacroix — a highly promiscuous mathematics professor at a 19th century university — is approached by Albert, a student who seeks to understand more about linear and quadratic equations. While Albert simply wants to understand the math more, Elise, being sexually starved, will hit on and flirt with him as she answers his questions. The situation is awkward as the two's personalities clash, leading to a subtly erotic and slightly comedic interaction.

### Instruction:
### Description of the character who is going to answer the question:
\"\"\"
Name: Hugo Martinez

Traits: Vulgar, Crude, Intense, Aggressive, Alcoholic, Harsh, Disciplined, Uncompromising, Loud, Expects a lot out of others, Swears constantly, Mid-forties, Wears a checkered shirt with overalls, Typically has a beer on hand, Has dental problems

Dialogue Examples:
Stranger: "What's your backstory?"
Hugo Martinez: "Fuck me, YOU WALK UP to a working man and just ask him to tell his fuckin'... life story t' you?! DO YOU NOT RESPECT MY TIME?! I should just toss ya in the fuckin' canal I swear to FUCKING God, this day's been long enough already..." Hugo rolls his eyes exaggeratedly as he mumbles something about needing a beer for this. "Well, FINE! Since I'm in such a HAPPY GODDAMN MOOD, I'll tell you about me. I'm a site overseer at this here canal. The Panama Canal. My job's to WATCH and DISCIPLINE the sorry fucks who call themselves 'workers', which is ironic, 'cause all they do is bitch about working. I know every inch of this place, how much effort it took to finish, and I sure as FUCKING hell am not going to let it even LOOK any worse than the day it was dug. Now, you got any more shit questions for me?"
Stranger: "What's your personality?"
Hugo Martinez: "HO-LY FUCK, are you interviewing me for a job or something?! Good thing you got balls, 'cause you ain't got brains, asking stupid shit like that out of the blue..." Hugo grimaces, showing off a decayed set of teeth. He then pops open a beer he had on hand, and chugs the entire thing down, making the stranger wait until he finishes. "Phew! Maybe now I can tolerate you. Alright, my personality? Well, let's just say I'm a natural fit for the role of making sure others do their fucking jobs. It takes harsh, intense, relentless discipline to keep this canal in tip-top shape, and I happen to be a relentless guy!" He leans back, sliding his hands into the pockets of his overalls and smiling for the first time since the conversation started. "If you think I'm abusive, then you've got something in common with the shitty milksops I manage, and that ain't something you want I tell ya. I'm efficient. That's what counts."
\"\"\"

Question: \"\"\"How much earth was excavated during the construction of the Panama Canal?\"\"\"
Answer: \"\"\"Over 200 million cubic yards of earth were excavated during the construction of the Panama Canal, showcasing the scale of this massive engineering project.\"\"\"

Question: \"\"\"What health challenges were faced during the construction of the Panama Canal, and how were they overcome?\"\"\"
Answer: \"\"\"The construction faced significant health challenges, notably malaria and yellow fever. These were overcome through extensive public health measures, illustrating the importance of health considerations in large-scale engineering projects.\"\"\"

### Response:
## Scenario plan:
Step 1. Focus on the Question and Answer: The two questions ask recall-oriented questions about the Panama Canal's construction. Given the precise and factual nature of the questions, and their shared topic of the Panama Canal's construction's history, the scenario will involve someone curious about the canal's history.
Step 2. Character Consideration: Hugo Martinez is an abrasive, insulting disciplinarian, though he's also hardworking and has standards. The scenario should give his unique personality room to shine. Since he's a site overseer at the Panama Canal, his occupation lines up with the question well, and the canal will be the setting of the scenario. He will answer the questions, but given his insulting, intense, and aggressive nature, he will likely chew out the person who is asking the questions. He might tell them to "get the fuck out of my face," after all questions are asked.
Step 3. Constrain the Scenario: The interaction needs to ensure that all provided questions are asked and answered. Given that there are 2 questions and 2 answers, there will be at least 4 messages. The content of the provided questions and answers should be preserved as much as possible in the conversation.
Step 4. Setting: Given the subject of the question, and the character card, the setting will be the worksite at the Panama Canal where Hugo Martinez is overseeing maintenance. The person who approaches Hugo and asks the questions should be someone curious about the canal; given the easy-to-digest nature of the questions, this person might be a journalist, but it would be better for the secondary character to be related to the setting. So Hugo will be approached by Juan — one of his workers — during lunch break. Juan wants to understand the canal better, but Hugo, compelled by his personality, will continually be vulgar, berate Juan, and swear while answering his questions (he may drink a bit, too, given that he is an alcoholic). The setting will be hostile, as Juan tiptoes around the tempers of his boss while trying to get his questions answered, his stress and the constant wear of Hugo's fury on his sanity being evident in his actions. But it will remain informative and the integrity of the questions and answers will be preserved.
Step 5. Interaction: Given these constraints, the first message might be Hugo crassly asking what Juan wants with him during the break (Hugo may throw in a spiteful remark about Juan's past work, given his uncompromising nature). Juan's response might then be a deferential attempt to calm Hugo down, followed by the first question. Hugo will then provide the first answer, though he will surround the answer with boasts, swears, and other abrasive remarks due to his personality. This pattern will continue until all questions have been asked and answered. While characters' messages will include character information, details about the scene, and literary fluff, the answers themselves will strictly adhere to the information in the provided answers, without incorporating external examples.

## Scenario:
Within the mess hall of a worksite servicing the Panama Canal, Hugo Martinez — a site overseer — is approached by Juan, a worker who wants to understand more about the canal's construction. While Juan wants to understand the canal better, Hugo, being harsh and abrasive, will continually berate Juan and swear colorfully while answering his questions (Hugo may drink a bit, too, given that he is an alcoholic). The situation is hostile as the two's personalities clash, but it also has undertones of "business as usual" and curiosity.

### Instruction:
Description of the character who is going to answer the question:
{character}

{format_qatuples(qatuples)}

### Response:
## Scenario plan:
{plan}

## Scenario (will have no dialogue, will just set up the scene):
{selected_variation}"""  # use random.choice to prevent overfitting on particular phrases and increase dataset diversity
    completion = logic_llm(
        cot_prompt,
        max_tokens=8000,
        stop=["</s>", "# Input:"],
        echo=True,
        grammar=scenario_grammar,
        #    temperature=0.2,
        temperature=1.5,  # min p settings, too inconsistent
        top_k=0,
        top_p=1,
        min_p=0.5,  # Higher min p rather than lower temp ensures greater accuracy while using min p sampling. I think I've figured out how to make it precise for this application.
    )["choices"][0]["text"]
    # print("COMPLETION:\n\n----------------------")
    # print(completion)
    # print("\n------------------")

    # Extract plan
    response_pattern = re.compile(
        r"Scenario \(will have no dialogue, will just set up the scene\):\n(.+)",
        re.IGNORECASE | re.DOTALL,
    )
    generation = response_pattern.search(completion).group(1)
    # print("GENERATION:\n\n-------------------\n\n", generation)

    if not ("Albert" in charname):
        if "Albert" in generation:
            print("Random Name was used instead of Albert")
        generation = generation.replace("Albert", random_name())

    return generation, completion

if __name__ == "__main__":  # test
    random.seed(1337)
    logic_llm = Llama(
        model_path=LOGICAL_MODEL,
        n_gqa=8,
        offload_kqv=True,
        n_ctx=8000,
        rope_freq_scale=0.5,
        n_gpu_layers=100,
        verbose=True,
    )  # load the logical LLM and offload everything
    # Q0 is good q, bad a
    # q1 is good q, good a,
    # q2 is bad q, bad a,
    # q3 is iffy q, good a
    q_test = [
        (
            "Explain how our understanding of planetary motion has changed over time.",