import gradio as gr import os from dotenv import load_dotenv import uuid load_dotenv(override=True) from research_assistant import graph as compiled_graph def start_research(topic:str, max_analysts:int=3, key:str=""): if key != os.getenv("RESEARCH_KEY"): return ( "❌ Invalid key. Please provide a valid key to use this service.", gr.update(visible=True, interactive=True), gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), gr.update(visible=True), gr.update(value="", interactive=True) # clear key ) global thread_id thread_id = str(uuid.uuid4()) clean_state = { "topic": topic, "max_analysts": max_analysts, "human_analyst_feedback": "", "analysts": [], "sections": [], "introduction": "", "content": "", "conclusion": "", "final_report": "" } try: thread = {"configurable": {"thread_id": thread_id}} result=compiled_graph.invoke(clean_state, thread) return display_analysts_and_request_feedback(result) except Exception as e: return reset_to_start(result, f"❌ Error starting research: {str(e)}") def display_analysts_and_request_feedback(result): analysts= result.get('analysts',[]) if analysts: analysts_display="\n".join([ f"**{i+1}. {analyst.name}**\n" f" - Role: {analyst.role}\n" f" - Affiliation: {analyst.affiliation}\n" f" - Description: {analyst.description}\n" for i, analyst in enumerate(analysts) ]) feedback_prompt = ( f"## Analysts Generated for: '{result['topic']}'\n\n" f"{analysts_display}\n\n" f"**Please provide your feedback:**\n" f"- Type 'approve' to continue with these analysts\n" f"- Or provide specific feedback to regenerate analysts\n" f"- Example: 'Add a cybersecurity expert, remove the marketing analyst'" ) return ( feedback_prompt, gr.update(visible=True, value="", interactive=True), gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), gr.update(visible=True), # reset_btn gr.update(value="", interactive=True) # clear key ) else: return reset_to_start(result, "❌ No Analysts generated. Please try again with a different topic.") def continue_with_feedback(feedback, button_clicked): if button_clicked == "research": feedback= "approve" try: thread = {"configurable": {"thread_id": thread_id}} compiled_graph.update_state( thread, {"human_analyst_feedback": feedback}, as_node="human_feedback" ) result=compiled_graph.invoke(None, thread) state= compiled_graph.get_state(thread) if state.next and state.next[0] == "human_feedback": return display_analysts_and_request_feedback(result) else: print("Going to display final report") return display_final_report(result) except Exception as e: return reset_to_start(result, f"❌ Error processing feedback: {str(e)}") def display_final_report(result): """Muestra el reporte final y resetea la interfaz""" print("Displaying final report...") try: final_report = result.get("final_report", "") print(f"Final report content: {final_report}") if final_report: return ( f"## 📄 Final Research Report\n\n{final_report}", gr.update(visible=False), # feedback_input gr.update(visible=False), # continue_btn gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), # reset_btn gr.update(value="", interactive=True) # clear key_input ) else: return reset_to_start(result, "❌ Error: No final report was generated.") except Exception as e: return reset_to_start(result, f"❌ Error displaying final report: {str(e)}") def reset_to_start(result, message=""): """Resetea la interfaz al estado inicial""" return ( message, gr.update(visible=False, value="", interactive=True), # feedback_input gr.update(visible=False), # continue_btn gr.update(visible=False), gr.update(visible=False), gr.update(value="", interactive=True), # clear key_input gr.update(visible=False) # start_btn ) def reset_interface(): return ( "", # output1 gr.update(visible=False, value="", interactive=True), # feedback_input gr.update(visible=False), # continue_btn gr.update(visible=False), # continue_research_btn gr.update(visible=True), # start_btn gr.update(visible=True, value=""), # topic gr.update(visible=True) # max_analysts ) ############################################## Gradio UI ######################################################################### with gr.Blocks(title="Research Assistant", theme=gr.themes.Soft()) as app: gr.Markdown("

🤖 Research Assistant

") gr.Markdown("Assistant for researching complex topics. Process:\n" "1. Provide a research topic and the maximum number of analysts, who will research different subtopics related to your topic.\n" "2. The assistant will generate a summary of the analysts and their roles and subtopics in the research.\n" "3. Provide feedback on the subtopics and the generated analysts.\n" "4. If you agree with the analysts, click on the 'Create Research with Analysts' button \n" "5. The assistant will generate a final research report.\n\n") with gr.Row(): with gr.Column(scale=3): topic_textbox = gr.Textbox(label="Topic to research", placeholder="Enter the topic you want to research", value="") with gr.Column(scale=1): max_analysts_slider = gr.Slider(minimum=1, maximum=5, step=1, value=3, label="Max Analysts", info="Maximum number of analysts to select for the research") with gr.Row(): key_input = gr.Textbox(label="Key to use this service: ", placeholder="Enter your key here", value="", type="password") with gr.Row(): with gr.Column(scale=3): gr.Markdown("#Provide Feedback on the Analysts who will perform the research. If you agree with the analysts, click on the 'Create Research with Analysts' button") feedback_input = gr.Textbox(label="Feedback", placeholder="Provide your feedback or click on the 'Create Research with Analysts' button", visible=False, value="") with gr.Column(scale=1): reset_btn = gr.Button("🔄 Reset", variant="secondary", visible=False) with gr.Row(): with gr.Column(scale=1): start_button = gr.Button("🚀 Start Research", variant="primary", visible=True) continue_feedback_btn = gr.Button("✅ Re-generate Analysts with Feedback", variant="primary", visible=False) with gr.Column(scale=1): continue_research_btn = gr.Button("➡️ Create Research with Analysts", variant="primary", visible=False) output1=gr.Markdown(label="Analysts Summary", value="") ######################################################################################### start_button.click( fn=start_research, inputs=[topic_textbox, max_analysts_slider, key_input], outputs=[output1, feedback_input, continue_feedback_btn, continue_research_btn, start_button, reset_btn, key_input] ) continue_feedback_btn.click( fn=lambda feedback: continue_with_feedback(feedback, "feedback"), inputs=[feedback_input], outputs=[output1, feedback_input, continue_feedback_btn, continue_research_btn, start_button, reset_btn, key_input] ) continue_research_btn.click( fn=lambda feedback: continue_with_feedback(feedback, "research"), inputs=[feedback_input], outputs=[output1, feedback_input, continue_feedback_btn, continue_research_btn, start_button, reset_btn, key_input] ) reset_btn.click( reset_interface, outputs=[output1, feedback_input, continue_feedback_btn, continue_research_btn, start_button, topic_textbox, max_analysts_slider, key_input] ) ################################################################################################################################# if __name__ == "__main__": # Get port from environment variable (Railway sets this) port = int(os.getenv("PORT", 7860)) # Changed default to match Dockerfile # Launch the app print(f"Starting application on port {port}") app.launch( server_name="0.0.0.0", server_port=7860, share=False, show_error=True, inbrowser=True )