1ytke6wr63auujv42ccngyw.png

El flujo de trabajo principal se compone de dos subflujos de trabajo anidados:

  • summary_gen:Este subflujo de trabajo busca artículos de investigación sobre el tema indicado y genera resúmenes. Realiza la búsqueda de artículos mediante consultas web y utiliza LLM para obtener información y resúmenes según las instrucciones.
  • slide_gen: este subflujo de trabajo es responsable de generar una presentación de diapositivas de PowerPoint utilizando los resúmenes del paso anterior. Formatea las diapositivas utilizando una plantilla de PowerPoint proporcionada y las genera creando y ejecutando código Python utilizando el python-pptx biblioteca.
Descripción general del flujo de trabajo principal (imagen del autor)

Veamos más de cerca estos subflujos de trabajo. En primer lugar, summary_gen Flujo de trabajo, que es bastante sencillo. Sigue un proceso lineal simple. Básicamente, funciona como un flujo de trabajo de «procesamiento de datos», con algunos pasos que envían una solicitud a un LLM.

Flujo de trabajo de generación de resúmenes (imagen del autor)

El flujo de trabajo comienza obteniendo una entrada del usuario (un tema de investigación) y sigue los siguientes pasos:

  • tavily_query:Consultas con la API de Tavily para obtener artículos académicos relacionados con el tema como una respuesta estructurada.
  • get_paper_with_citations:Para cada artículo devuelto por la consulta de Tavily, el paso recupera los metadatos del artículo junto con los del artículo citado utilizando la API SemanticScholar.
  • filter_papers:Como no todas las citas recuperadas son directamente relevantes para el tema original, este paso refina el resultado. Los títulos y resúmenes de cada artículo se envían al LLM para evaluar su relevancia. Este paso se define como:
@step(num_workers=4)
async def filter_papers(self, ev: PaperEvent) -> FilteredPaperEvent:
llm = new_gpt4o_mini(temperature=0.0)
response = await process_citation(ev.paper, llm)
return FilteredPaperEvent(paper=ev.paper, is_relevant=response)

Aquí en el process_citation() función, utilizamos la Programa de llamada de función Desde LlamaIndex para obtener una respuesta estructurada:

IS_CITATION_RELEVANT_PMT = """
You help a researcher decide whether a paper is relevant to their current research topic: {topic}
You are given the title and abstract of a paper.
title: {title}
abstract: {abstract}

Give a score indicating the relevancy to the research topic, where:
Score 0: Not relevant
Score 1: Somewhat relevant
Score 2: Very relevant

Answer with integer score 0, 1 or 2 and your reason.
"""

class IsCitationRelevant(BaseModel):
score: int
reason: str

async def process_citation(citation, llm):
program = FunctionCallingProgram.from_defaults(
llm=llm,
output_cls=IsCitationRelevant,
prompt_template_str=IS_CITATION_RELEVANT_PMT,
verbose=True,
)
response = await program.acall(
title=citation.title,
abstract=citation.summary,
topic=citation.topic,
description="Data model for whether the paper is relevant to the research topic.",
)
return response

  • download_papers:Este paso reúne todos los artículos filtrados, los prioriza según el puntaje de relevancia y la disponibilidad en ArXiv, y descarga los más relevantes.
  • paper2summary_dispatcher:Cada documento descargado se prepara para la generación de resúmenes mediante la configuración de rutas para almacenar las imágenes y los resúmenes. Este paso utiliza self.send_event() para permitir la ejecución paralela de la paper2summary Paso para cada documento. También establece el número de documentos en el contexto del flujo de trabajo con una variable ctx.data[“n_pdfs”] para que los pasos posteriores sepan cuántos documentos se espera que procesen en total.
@step(pass_context=True)
async def paper2summary_dispatcher(
self, ctx: Context, ev: Paper2SummaryDispatcherEvent
) -> Paper2SummaryEvent:
ctx.data["n_pdfs"] = 0
for pdf_name in Path(ev.papers_path).glob("*.pdf"):
img_output_dir = self.papers_images_path / pdf_name.stem
img_output_dir.mkdir(exist_ok=True, parents=True)
summary_fpath = self.paper_summary_path / f"{pdf_name.stem}.md"
ctx.data["n_pdfs"] += 1
self.send_event(
Paper2SummaryEvent(
pdf_path=pdf_name,
image_output_dir=img_output_dir,
summary_path=summary_fpath,
)
)
  • paper2summary:Para cada artículo, convierte el PDF en imágenes, que luego se envían al LLM para su resumen. Una vez generado el resumen, se guarda en un archivo Markdown para futuras referencias. En particular, el resumen generado aquí es bastante elaborado, como un pequeño artículo, por lo que aún no es del todo adecuado para incluirlo directamente en la presentación. Pero se conserva para que el usuario pueda ver estos resultados intermedios. En uno de los pasos posteriores, haremos que esta información sea más presentable. El mensaje proporcionado al LLM incluye instrucciones clave para garantizar resúmenes precisos y concisos:
SUMMARIZE_PAPER_PMT = """
You are an AI specialized in summarizing scientific papers.
Your goal is to create concise and informative summaries, with each section preferably around 100 words and
limited to a maximum of 200 words, focusing on the core approach, methodology, datasets,
evaluation details, and conclusions presented in the paper. After you summarize the paper,
save the summary as a markdown file.

Instructions:
- Key Approach: Summarize the main approach or model proposed by the authors.
Focus on the core idea behind their method, including any novel techniques, algorithms, or frameworks introduced.
- Key Components/Steps: Identify and describe the key components or steps in the model or approach.
Break down the architecture, modules, or stages involved, and explain how each contributes to the overall method.
- Model Training/Finetuning: Explain how the authors trained or finetuned their model.
Include details on the training process, loss functions, optimization techniques,
and any specific strategies used to improve the model’s performance.
- Dataset Details: Provide an overview of the datasets used in the study.
Include information on the size, type and source. Mention whether the dataset is publicly available
and if there are any benchmarks associated with it.
- Evaluation Methods and Metrics: Detail the evaluation process used to assess the model's performance.
Include the methods, benchmarks, and metrics employed.
- Conclusion: Summarize the conclusions drawn by the authors. Include the significance of the findings,
any potential applications, limitations acknowledged by the authors, and suggested future work.

Ensure that the summary is clear and concise, avoiding unnecessary jargon or overly technical language.
Aim to be understandable to someone with a general background in the field.
Ensure that all details are accurate and faithfully represent the content of the original paper.
Avoid introducing any bias or interpretation beyond what is presented by the authors. Do not add any
information that is not explicitly stated in the paper. Stick to the content presented by the authors.

"""

  • finish:El flujo de trabajo recopila todos los resúmenes generados, verifica que se almacenen correctamente, registra la finalización del proceso y devuelve un StopEvent como resultado final.

Si este flujo de trabajo se ejecutara de forma independiente, la ejecución finalizaría aquí. Sin embargo, dado que se trata simplemente de un subflujo de trabajo del proceso principal, al finalizar, se ejecutará el siguiente subflujo de trabajo: slide_gen — se activa.

Este flujo de trabajo genera diapositivas basadas en los resúmenes creados en el paso anterior. Aquí se ofrece una descripción general de las diapositivas.slide_genFlujo de trabajo:

Flujo de trabajo para la generación de diapositivas (imagen del autor)

Cuando finaliza el subflujo de trabajo anterior y los archivos de resumen de Markdown están listos, se inicia este flujo de trabajo:

  • get_summaries:Este paso lee el contenido de los archivos de resumen y activa un SummaryEvent para cada archivo que se utilice nuevamente self.send_event() para permitir la ejecución concurrente para un procesamiento más rápido.
  • summary2outline:Este paso convierte los resúmenes en textos de esquema de diapositivas mediante LLM. Acorta los resúmenes en oraciones o viñetas para incluirlos en la presentación.
  • gather_feedback_outline:En este paso, se presenta al usuario el esquema de diapositivas propuesto junto con el resumen del trabajo para que lo revise. El usuario proporciona comentarios, que pueden desencadenar una OutlineFeedbackEvent Si es necesario realizar revisiones, este ciclo de retroalimentación continúa con el summary2outline paso hasta que el usuario aprueba el esquema final, momento en el que un OutlineOkEvent se activa
@step(pass_context=True)
async def gather_feedback_outline(
self, ctx: Context, ev: OutlineEvent
) -> OutlineFeedbackEvent | OutlineOkEvent:
"""Present user the original paper summary and the outlines generated, gather feedback from user"""
print(f"the original summary is: {ev.summary}")
print(f"the outline is: {ev.outline}")
print("Do you want to proceed with this outline? (yes/no):")
feedback = input()
if feedback.lower().strip() in ["yes", "y"]:
return OutlineOkEvent(summary=ev.summary, outline=ev.outline)
else:
print("Please provide feedback on the outline:")
feedback = input()
return OutlineFeedbackEvent(
summary=ev.summary, outline=ev.outline, feedback=feedback
)
  • outlines_with_layout:Amplía el esquema de cada diapositiva al incluir detalles del diseño de página de la plantilla de PowerPoint proporcionada, mediante LLM. Esta etapa guarda el contenido y el diseño de todas las páginas de diapositivas en un archivo JSON.
  • slide_gen:Utiliza un Agente ReAct para crear presentaciones en diapositivas basadas en esquemas y detalles de diseño dados. Este agente tiene un herramienta de interpretación de código para ejecutar y corregir código en un entorno aislado y una herramienta de verificación de diseño para ver la información de la plantilla de PowerPoint proporcionada. Se le solicita al agente que utilice python-pptx para crear las diapositivas y poder observar y corregir errores.

@step(pass_context=True)
async def slide_gen(
self, ctx: Context, ev: OutlinesWithLayoutEvent
) -> SlideGeneratedEvent:
agent = ReActAgent.from_tools(
tools=self.azure_code_interpreter.to_tool_list() + [self.all_layout_tool],
llm=new_gpt4o(0.1),
verbose=True,
max_iterations=50,
)

prompt = (
SLIDE_GEN_PMT.format(
json_file_path=ev.outlines_fpath.as_posix(),
template_fpath=self.slide_template_path,
final_slide_fname=self.final_slide_fname,
)
+ REACT_PROMPT_SUFFIX
)
agent.update_prompts({"agent_worker:system_prompt": PromptTemplate(prompt)})

res = self.azure_code_interpreter.upload_file(
local_file_path=self.slide_template_path
)
logging.info(f"Uploaded file to Azure: {res}")

response = agent.chat(
f"An example of outline item in json is {ev.outline_example.json()},"
f" generate a slide deck"
)
local_files = self.download_all_files_from_session()
return SlideGeneratedEvent(
pptx_fpath=f"{self.workflow_artifacts_path}/{self.final_slide_fname}"
)

  • validate_slides: Verifica la presentación de diapositivas para asegurarse de que cumple con los estándares establecidos. Este paso implica convertir las diapositivas en imágenes y hacer que el LLM las inspeccione visualmente para verificar que el contenido sea correcto y el estilo sea consistente de acuerdo con las pautas. Dependiendo de lo que encuentre el LLM, enviará un SlideValidationEvent Si hay problemas o una StopEvent Si todo se ve bien.
@step(pass_context=True)
async def validate_slides(
self, ctx: Context, ev: SlideGeneratedEvent
) -> StopEvent | SlideValidationEvent:
"""Validate the generated slide deck"""
ctx.data["n_retry"] += 1
ctx.data["latest_pptx_file"] = Path(ev.pptx_fpath).name
img_dir = pptx2images(Path(ev.pptx_fpath))
image_documents = SimpleDirectoryReader(img_dir).load_data()
llm = mm_gpt4o
program = MultiModalLLMCompletionProgram.from_defaults(
output_parser=PydanticOutputParser(SlideValidationResult),
image_documents=image_documents,
prompt_template_str=SLIDE_VALIDATION_PMT,
multi_modal_llm=llm,
verbose=True,
)
response = program()
if response.is_valid:
return StopEvent(
self.workflow_artifacts_path.joinpath(self.final_slide_fname)
)
else:
if ctx.data["n_retry"] < self.max_validation_retries:
return SlideValidationEvent(result=response)
else:
return StopEvent(
f"The slides are not fixed after {self.max_validation_retries} retries!"
)

Los criterios utilizados para la validación son:

SLIDE_VALIDATION_PMT = """
You are an AI that validates the slide deck generated according to following rules:
- The slide need to have a front page
- The slide need to have a final page (e.g. a 'thank you' or 'questions' page)
- The slide texts are clearly readable, not cut off, not overflowing the textbox
and not overlapping with other elements

If any of the above rules are violated, you need to provide the index of the slide that violates the rule,
as well as suggestion on how to fix it.

"""

  • modify_slides:Si las diapositivas no pasan la comprobación de validación, el paso anterior envía un SlideValidationEvent evento. Aquí otro Agente ReAct actualiza las diapositivas según los comentarios del validador, y las diapositivas actualizadas se guardan y se devuelven para validarlas nuevamente. Este ciclo de verificación podría ocurrir varias veces según el max_validation_retries atributos variables de la SlideGenWorkflow clase.