from typing import List
from utils import preclass_context_size as context_size
[docs]
class AgendaStruct:
"""A tree structure representing an agenda or outline with hierarchical nodes.
Attributes:
title (str): The title/heading of this agenda item
children (list): List of child AgendaStruct or PPTPageStruct objects
"""
type = "node"
def __init__(self, title, children=None, function=None) -> None:
self.title = title
self.children = children if children is not None else []
self.function = function if function is not None else []
[docs]
def get_structure_trace(self):
"""Generate a formatted string representation of the structure's hierarchy.
Returns:
str: Indented string showing the structure trace
"""
current_stack = ["- " + self.title.lstrip("- ")]
complete_stack = [
("[The current page is not under this subsection] " if type(node)!=PPTPageStruct else "") + \
node.formalize().lstrip("- ") \
for node in self.children[-context_size:-1]]
complete_stack = ["- " + trace for trace in complete_stack]
in_process_trace = [node.get_structure_trace() for node in self.children[-1:]]
stack="\n".join(current_stack+complete_stack+in_process_trace).replace("\n", "\n\t")
return stack
def __str__(self):
stack = "\n".join(
["- " + self.title.lstrip("- ")]
+ ["- " + node.formalize().lstrip("- ") for node in self.children[-3:-1]]
+ [str(node) for node in self.children[-1:]]
).replace("\n", "\n\t")
return stack
[docs]
def serialize(self):
stack = "\n".join(
["- " + self.title.lstrip("- ")]
+ ["\t" + str(func) for func in self.function]
+ [node.serialize() for node in self.children]
).replace("\n", "\n\t")
return stack
[docs]
def insert_page(self, page, trace) -> bool:
"""Insert a page into the agenda structure following the given trace path.
Args:
page: The page object to insert
trace (list): List of section titles forming path to insertion point
Returns:
bool: True if page was inserted successfully, False otherwise
"""
assert trace.pop(0) == self.title
if len(trace) == 1:
self.children.append(page)
return True
# Gather Sub-Section Title
direct_children_title = trace[0]
# Find Current Sub-Section To Insert
if len(self.children):
if self.children[-1].formalize()[2:]==direct_children_title and type(self.children[-1]) == PPTPageStruct:
return False
if self.children[-1].formalize() == direct_children_title:
self.children[-1].insert_page(page, trace)
return True
# Create New Sub-Section When None Is Avaliable
self.children.append(AgendaStruct(direct_children_title))
self.children[-1].insert_page(page, trace)
return True
[docs]
def dfs_recursive_call(self, function):
"""
Recursively call the given function on each node in the agenda structure.
Args:
function: The function to be called on each node
"""
function(self)
for child in self.children:
child.dfs_recursive_call(function)
[docs]
def flatten(self):
"""
Return a flattened list of all nodes in the agenda structure.
Returns:
list: List of all nodes in the agenda structure
"""
self.children = sum([child.flatten() for child in self.children], [])
return self.children
[docs]
def to_dict(self):
"""
Return a dictionary representation of the agenda structure.
Returns:
dict: Dictionary representation of the agenda structure
"""
return dict(
type=self.type,
title=self.title,
children=[child.to_dict() for child in self.children],
function=[func.to_dict() for func in self.function]
)
[docs]
@classmethod
def from_dict(cls, dict):
"""
Create an agenda structure from a dictionary representation.
Args:
dict: Dictionary representation of the agenda structure
Returns:
AgendaStruct: The agenda structure object
"""
if dict["type"] == "node":
return cls(
dict["title"],
[AgendaStruct.from_dict(child) for child in dict["children"]],
[FunctionBase.from_dict(func) for func in dict["function"]]
)
else:
return PPTPageStruct(
dict["content"],
dict["stringified"],
[FunctionBase.from_dict(func) for func in dict["function"]]
)
[docs]
class PPTPageStruct:
"""Represents a PowerPoint page/slide in the agenda structure.
Attributes:
content: The actual page/slide content
stringified (str): String representation of the page
"""
type = "ppt"
def __init__(self, page, stringified, function=None) -> None:
self.content = page
self.stringified = stringified
self.function = function if function is not None else []
[docs]
def formalize(self):
return self.stringified
[docs]
def get_structure_trace(self):
return str(self)
def __str__(self):
return self.formalize()
[docs]
def serialize(self):
return (
self.formalize()
+ "\n"
+ "\n".join(["\t" + str(func) for func in self.function])
)
[docs]
def dfs_recursive_call(self, function):
function(self)
[docs]
def flatten(self, condition=None):
return [self]
[docs]
def to_dict(self):
return dict(
type=self.type,
content=self.content,
stringified=self.stringified,
function=[func.to_dict() for func in self.function]
)
[docs]
@classmethod
def from_dict(cls, dict):
return cls(dict["content"], dict["stringified"], [FunctionBase.from_dict(func) for func in dict["function"]])
[docs]
class FunctionBase:
"""Base class for defining interactive functions/actions within the agenda.
Attributes:
call (str): Function identifier/name
label (str): Display label for the function
value (dict): Parameters/values for the function
"""
def __init__(self, call: str, label: str, value: dict):
self.call = call
self.label = label
self.value = value
def __call__(self):
raise Exception(
"Never Directly Call FunctionBase Class. You Should Inherit From This Class",
)
[docs]
def to_dict(self):
return dict(call=self.call, label=self.label, value=self.value)
[docs]
@classmethod
def from_dict(cls, dict):
return cls(dict["call"], dict["label"], dict["value"])
[docs]
class ShowFile(FunctionBase):
"""Function to display a file.
Args:
file_id: Identifier for the file to be shown
"""
def __init__(self, file_id):
super().__init__("ShowFile", "展示文件", dict(file_id=file_id))
def __str__(self):
return f"Function: {self.call}(file_id={self.value['file_id']})"
[docs]
class ReadScript(FunctionBase):
"""Function to read a script/text.
Args:
script (str): The script content to be read
"""
def __init__(self, script):
super().__init__("ReadScript", "读讲稿", dict(script=script))
def __str__(self):
return f"Function: {self.call}(script={self.value['script']})"
[docs]
class AskQuestion(FunctionBase):
"""Function to present a question to users.
Args:
question (str): The question text
question_type: Type/category of question
selects: Available answer options
answer: Correct answer
reference: Reference material (commented out)
"""
def __init__(self, question, question_type, selects, answer, reference):
super().__init__("AskQuestion", "提出问题", dict(
question=question,
question_type=question_type,
selects=selects,
answer=answer,
# reference=reference,
# recent_scripts=recent_scripts
))
def __str__(self):
value_str = ",".join([k+"="+str(v) for k,v in self.value.items()])
return f"Function: {self.call}({value_str})"