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 elpython-pptx
biblioteca.
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.
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 utilizaself.send_event()
para permitir la ejecución paralela de lapaper2summary
Paso para cada documento. También establece el número de documentos en el contexto del flujo de trabajo con una variablectx.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 unStopEvent
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_gen
Flujo de trabajo:
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 unSummaryEvent
para cada archivo que se utilice nuevamenteself.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 unaOutlineFeedbackEvent
Si es necesario realizar revisiones, este ciclo de retroalimentación continúa con elsummary2outline
paso hasta que el usuario aprueba el esquema final, momento en el que unOutlineOkEvent
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 utilicepython-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á unSlideValidationEvent
Si hay problemas o unaStopEvent
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 elementsIf 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 unSlideValidationEvent
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 elmax_validation_retries
atributos variables de laSlideGenWorkflow
clase.