Vasilii Tokarev commited on
Commit
9276b00
·
unverified ·
2 Parent(s): 9dc6c78 fae26a7

Merge pull request #2 from serverdaun/codex/implement-chat-based-ui-with-system-messages

Browse files
Files changed (2) hide show
  1. README.md +12 -8
  2. src/main.py +76 -57
README.md CHANGED
@@ -24,13 +24,13 @@ license: apache-2.0
24
  - **Planning**: Suggests up to five web searches to address the query.
25
  - **Web Search**: Summarizes web results for each planned search.
26
  - **Report Generation**: Produces a comprehensive markdown report with a summary and follow-up questions.
27
- - **Interactive UI**: Simple Gradio interface for end-to-end research.
28
 
29
  ## Usage
30
 
31
- 1. **Input your research topic** in the UI.
32
- 2. **Answer clarifying questions** (if any).
33
- 3. **Run the research** to receive a detailed report.
34
 
35
  ## Tech Stack
36
 
@@ -55,13 +55,17 @@ license: apache-2.0
55
  ```sh
56
  pip install uv
57
  ```
58
- 3. **Install dependencies:**
59
  ```sh
60
- uv pip install -r pyproject.toml
 
 
 
 
61
  ```
62
  4. **Run the app:**
63
  ```sh
64
- uv pip run python src/main.py
65
  ```
66
 
67
- The app will launch a Gradio interface in your browser.
 
24
  - **Planning**: Suggests up to five web searches to address the query.
25
  - **Web Search**: Summarizes web results for each planned search.
26
  - **Report Generation**: Produces a comprehensive markdown report with a summary and follow-up questions.
27
+ - **Interactive UI**: Chat-based Gradio interface for end-to-end research.
28
 
29
  ## Usage
30
 
31
+ 1. **Send your research topic** in the chat box.
32
+ 2. **Answer the clarifying questions**.
33
+ 3. **Receive the detailed report** back in the same conversation.
34
 
35
  ## Tech Stack
36
 
 
55
  ```sh
56
  pip install uv
57
  ```
58
+ 3. **Create enviroment and install dependencies:**
59
  ```sh
60
+ uv sync
61
+ ```
62
+ 4. **Activate the enviroment**
63
+ ```sh
64
+ source .venv/bin/activate #.venv/Scripts/activate on Win
65
  ```
66
  4. **Run the app:**
67
  ```sh
68
+ uv run src/main.py
69
  ```
70
 
71
+ The app will launch a Gradio interface that you can access in your browser.
src/main.py CHANGED
@@ -5,74 +5,93 @@ from research_manager import ResearchManager
5
 
6
  load_dotenv()
7
 
 
 
 
 
 
8
 
9
- async def ask_clarifications(query: str) -> tuple[str, list[str]]:
10
- """Generate clarifying questions for *query* and return both a nicely formatted string and the raw list."""
11
- manager = ResearchManager()
12
- questions = await manager.get_clarifying_questions(query)
13
 
14
- if not questions:
15
- return (
16
- "No clarifying questions were generated. You can proceed to run the research.",
17
- [],
18
- )
19
 
20
- formatted = "\n".join(f"{idx+1}. {q}" for idx, q in enumerate(questions))
21
- return formatted, questions
22
 
 
 
 
 
 
 
 
23
 
24
- async def run_research(query: str, answers: str, questions: list[str]):
25
- """Run the complete research pipeline and stream the markdown report."""
26
- clarifications_block = ""
27
-
28
- answer_lines = [line.strip() for line in answers.split("\n")]
29
- while len(answer_lines) < len(questions):
30
- answer_lines.append("")
31
-
32
- q_and_a = []
33
- for idx, question in enumerate(questions):
34
- answer = answer_lines[idx]
35
- q_and_a.append(f"Q{idx+1}: {question}\nA{idx+1}: {answer}")
36
-
37
- clarifications_block = "\n".join(q_and_a)
38
 
39
- async for chunk in ResearchManager().run(query, clarifications_block):
40
- yield chunk
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
 
43
  with gr.Blocks(theme=gr.themes.Default(primary_hue="yellow")) as ui:
44
- gr.Markdown("# Deep Research")
45
-
46
- with gr.Row():
47
- query_textbox = gr.Textbox(
48
- label="What topic would you like to research?",
49
- placeholder="e.g. How to create a Deep Research Agent?",
50
- )
51
- ask_button = gr.Button("Ask clarifying questions")
52
-
53
- clarifying_questions_state = gr.State([])
54
- clarifications_markdown = gr.Markdown(label="Clarifying questions will appear here")
55
-
56
- clarification_answers_box = gr.Textbox(
57
- label="Your answers to the clarifying questions (one per line)",
58
- placeholder="Answer 1\nAnswer 2\n...",
59
- lines=3,
60
  )
 
 
61
 
62
- run_button = gr.Button("Run research", variant="primary")
63
- report = gr.Markdown(label="Report")
64
-
65
- ask_button.click(
66
- fn=ask_clarifications,
67
- inputs=query_textbox,
68
- outputs=[clarifications_markdown, clarifying_questions_state],
69
- )
70
-
71
- run_button.click(
72
- fn=run_research,
73
- inputs=[query_textbox, clarification_answers_box, clarifying_questions_state],
74
- outputs=report,
75
- )
76
 
77
  if __name__ == "__main__":
78
  ui.launch()
 
5
 
6
  load_dotenv()
7
 
8
+ WELCOME_MESSAGE = (
9
+ "Welcome to **Deep Research**!\n"
10
+ "Send me a research topic and I will ask clarifying questions.\n"
11
+ "Answer them here to receive a detailed report."
12
+ )
13
 
 
 
 
 
14
 
15
+ def _format_clarifications(questions: list[str]) -> str:
16
+ return "\n".join(f"{idx + 1}. {q}" for idx, q in enumerate(questions))
 
 
 
17
 
 
 
18
 
19
+ def _build_clarification_block(questions: list[str], answers: str) -> str:
20
+ lines = [line.strip() for line in answers.split("\n")]
21
+ while len(lines) < len(questions):
22
+ lines.append("")
23
+ return "\n".join(
24
+ f"Q{idx + 1}: {q}\nA{idx + 1}: {lines[idx]}" for idx, q in enumerate(questions)
25
+ )
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
+ async def respond(
29
+ message: str, history: list[dict], state: dict
30
+ ):
31
+ if not state:
32
+ state = {"stage": "awaiting_query", "query": "", "questions": []}
33
+
34
+ history.append({"role": "user", "content": message})
35
+
36
+ if state["stage"] == "awaiting_query":
37
+ state["query"] = message
38
+ manager = ResearchManager()
39
+ questions = await manager.get_clarifying_questions(message)
40
+ state["questions"] = questions
41
+ if questions:
42
+ state["stage"] = "awaiting_answers"
43
+ q_text = _format_clarifications(questions)
44
+ history.append(
45
+ {
46
+ "role": "assistant",
47
+ "content": f"Please answer the following questions, one per line:\n{q_text}",
48
+ }
49
+ )
50
+ yield history, state
51
+ else:
52
+ state["stage"] = "running"
53
+ history.append({"role": "assistant", "content": ""})
54
+ async for chunk in manager.run(message, ""):
55
+ history[-1]["content"] = (history[-1]["content"] or "") + chunk
56
+ yield history, state
57
+ state["stage"] = "awaiting_query"
58
+ yield history, state
59
+ elif state["stage"] == "awaiting_answers":
60
+ answers_block = _build_clarification_block(state["questions"], message)
61
+ manager = ResearchManager()
62
+ state["stage"] = "running"
63
+ history.append({"role": "assistant", "content": ""})
64
+ async for chunk in manager.run(state["query"], answers_block):
65
+ history[-1]["content"] = (history[-1]["content"] or "") + chunk
66
+ yield history, state
67
+ state["stage"] = "awaiting_query"
68
+ yield history, state
69
+ else:
70
+ history.append({"role": "assistant", "content": "Please wait for the current task to finish."})
71
+ yield history, state
72
+
73
+
74
+ def reset():
75
+ return ([{"role": "assistant", "content": WELCOME_MESSAGE}], {
76
+ "stage": "awaiting_query",
77
+ "query": "",
78
+ "questions": [],
79
+ })
80
 
81
 
82
  with gr.Blocks(theme=gr.themes.Default(primary_hue="yellow")) as ui:
83
+ chatbot = gr.Chatbot(
84
+ label="Deep Research",
85
+ height=500,
86
+ resizable=True,
87
+ show_copy_button=True,
88
+ type="messages",
 
 
 
 
 
 
 
 
 
 
89
  )
90
+ state = gr.State({})
91
+ msg = gr.Textbox(placeholder="Type your message and press Enter")
92
 
93
+ ui.load(fn=reset, outputs=[chatbot, state])
94
+ msg.submit(respond, inputs=[msg, chatbot, state], outputs=[chatbot, state])
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
  if __name__ == "__main__":
97
  ui.launch()