Abid Ali Awan commited on
Commit
6b4e2a8
·
1 Parent(s): 57c4f68

feat(ui): add external links extension to markdown rendering

Browse files

Add custom markdown extension to automatically set external links in reports to open in new tabs with security attributes.

Files changed (1) hide show
  1. app/app.py +29 -14
app/app.py CHANGED
@@ -1,10 +1,12 @@
1
  from __future__ import annotations
2
 
3
  import asyncio
4
- import time
5
-
6
- import markdown
7
- import reflex as rx
 
 
8
 
9
  from .research_assistant import environment_status, run_research_assistant
10
 
@@ -15,17 +17,30 @@ PANEL_PADDING = {"initial": "1rem", "sm": "1.25rem"}
15
  _RUNNING_TASKS: dict[str, asyncio.Task] = {}
16
 
17
 
18
- def _plain_markdown(value) -> str:
19
  if isinstance(value, str):
20
  return value
21
  if isinstance(value, dict):
22
  nested = value.get("markdown_report")
23
  return nested if isinstance(nested, str) else str(nested or value)
24
  nested = getattr(value, "markdown_report", None)
25
- return nested if isinstance(nested, str) else str(value)
26
-
27
-
28
- class State(rx.State):
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  query: str = ""
30
  logs: list[str] = []
31
  report_markdown: str = ""
@@ -112,11 +127,11 @@ class State(rx.State):
112
  report, trace_url = await run_research_assistant(query, progress=self._log)
113
  async with self:
114
  self.report_markdown = _plain_markdown(report.markdown_report)
115
- self.report_html = markdown.markdown(
116
- self.report_markdown,
117
- extensions=["extra", "sane_lists", "tables"],
118
- output_format="html5",
119
- )
120
  self.trace_url = trace_url
121
  self.status = "Complete"
122
  except asyncio.CancelledError:
 
1
  from __future__ import annotations
2
 
3
  import asyncio
4
+ import time
5
+
6
+ import markdown
7
+ from markdown.extensions import Extension
8
+ from markdown.treeprocessors import Treeprocessor
9
+ import reflex as rx
10
 
11
  from .research_assistant import environment_status, run_research_assistant
12
 
 
17
  _RUNNING_TASKS: dict[str, asyncio.Task] = {}
18
 
19
 
20
+ def _plain_markdown(value) -> str:
21
  if isinstance(value, str):
22
  return value
23
  if isinstance(value, dict):
24
  nested = value.get("markdown_report")
25
  return nested if isinstance(nested, str) else str(nested or value)
26
  nested = getattr(value, "markdown_report", None)
27
+ return nested if isinstance(nested, str) else str(value)
28
+
29
+
30
+ class ExternalLinksTreeprocessor(Treeprocessor):
31
+ def run(self, root):
32
+ for element in root.iter("a"):
33
+ element.set("target", "_blank")
34
+ element.set("rel", "noopener noreferrer")
35
+ return root
36
+
37
+
38
+ class ExternalLinksExtension(Extension):
39
+ def extendMarkdown(self, md):
40
+ md.treeprocessors.register(ExternalLinksTreeprocessor(md), "external_links", 15)
41
+
42
+
43
+ class State(rx.State):
44
  query: str = ""
45
  logs: list[str] = []
46
  report_markdown: str = ""
 
127
  report, trace_url = await run_research_assistant(query, progress=self._log)
128
  async with self:
129
  self.report_markdown = _plain_markdown(report.markdown_report)
130
+ self.report_html = markdown.markdown(
131
+ self.report_markdown,
132
+ extensions=["extra", "sane_lists", "tables", ExternalLinksExtension()],
133
+ output_format="html5",
134
+ )
135
  self.trace_url = trace_url
136
  self.status = "Complete"
137
  except asyncio.CancelledError: