def run_pipeline_test( question: str, line_df_in: pd.DataFrame, page_df_in: pd.DataFrame, page_df_emb_in: pd.DataFrame, top_k: int = 3, client=client, ) -> dict: """Run both retrievers + generation on one question; return a summary dict.""" parsed_q = get_keywords_from_question(question, client=client) retrieved_emb_df, _ = retrieve_pages_by_similarity( page_df_emb_in, line_df_in, question, top_k=top_k, client=client, ) retrieved_kw_df, filtered_lines_kw = retrieve_pages( page_df_in, line_df_in, parsed_q.keywords, top_k=top_k, ) # If keyword retrieval finds nothing, fall back to the whole doc so generation # still runs (small PDFs only: would not scale to a real corpus). lines_for_generation = ( filtered_lines_kw if len(filtered_lines_kw) > 0 else line_df_in ) answer = llm_answer_with_evidence( question, lines_for_generation, client=client, ) return { "question": question, "keywords": parsed_q.keywords, "emb_top3": retrieved_emb_df["page_num"].tolist(), "kw_top3": ( retrieved_kw_df["page_num"].tolist() if len(retrieved_kw_df) > 0 else "(no kw match)" ), "answer_excerpt": (answer.answer[:80] + ("..." if len(answer.answer) > 80 else "")), "cite_page": answer.start_page_num, }