fvde commited on
Commit
2f12302
·
1 Parent(s): 9b2e531

Upload folder using huggingface_hub

Browse files
requirements.txt CHANGED
@@ -7,7 +7,7 @@ scipy>=0.19
7
  openai==0.27.7
8
  grpcio-tools==1.54.2
9
  gpt_index==0.4.24
10
- langchain==0.0.190
11
  environs==9.5.0
12
  pypdf==3.9.1
13
  pypdfium2==4.18.0
 
7
  openai==0.27.7
8
  grpcio-tools==1.54.2
9
  gpt_index==0.4.24
10
+ langchain==0.0.236
11
  environs==9.5.0
12
  pypdf==3.9.1
13
  pypdfium2==4.18.0
src/__pycache__/doc_loading.cpython-39.pyc ADDED
Binary file (1.38 kB). View file
 
src/__pycache__/gradio_app.cpython-39.pyc CHANGED
Binary files a/src/__pycache__/gradio_app.cpython-39.pyc and b/src/__pycache__/gradio_app.cpython-39.pyc differ
 
src/__pycache__/llm_utils.cpython-39.pyc ADDED
Binary file (1.14 kB). View file
 
src/__pycache__/prompts.cpython-39.pyc CHANGED
Binary files a/src/__pycache__/prompts.cpython-39.pyc and b/src/__pycache__/prompts.cpython-39.pyc differ
 
src/__pycache__/summarization.cpython-39.pyc CHANGED
Binary files a/src/__pycache__/summarization.cpython-39.pyc and b/src/__pycache__/summarization.cpython-39.pyc differ
 
src/doc_loading.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain.document_loaders import PyPDFLoader, TextLoader
2
+ from langchain.docstore.document import Document
3
+ from typing import List
4
+
5
+
6
+ def load_docs(file_path: str, with_pageinfo: bool = True) -> List[Document]:
7
+ """Load a file and return the text.
8
+
9
+ Args:
10
+ file_path (str): Path to the pdf file. This can either be a local path or a tempfile.TemporaryFileWrapper_.
11
+ with_pageinfo (bool, optional): If True the page information is added to the document. Defaults to True.
12
+
13
+ Raises:
14
+ ValueError: If the file type is not supported.
15
+
16
+ Returns:
17
+ List[Document]: List of documents.
18
+ """
19
+ if file_path.endswith(".pdf"):
20
+ loader = PyPDFLoader(file_path)
21
+ docs = loader.load()
22
+ elif file_path.endswith(".txt"):
23
+ loader = TextLoader(file_path)
24
+ docs = loader.load()
25
+ else:
26
+ raise ValueError(
27
+ f"File type ({file_path.split('.')[1]}) not supported. Please upload a pdf or txt file."
28
+ )
29
+ for doc in docs:
30
+ doc.page_content = doc.page_content.replace("\n", " \n ")
31
+ # if doc contains a page append it to the text
32
+ if with_pageinfo and hasattr(doc, "metadata"):
33
+ doc.page_content = f"(Quelle Seite: {doc.metadata.get('page')+1}) .".join(
34
+ doc.page_content.split(" .")
35
+ )
36
+
37
+ return docs
src/gradio_app.py CHANGED
@@ -4,11 +4,15 @@ import pypdfium2 as pdfium
4
  import gradio as gr
5
 
6
  from langchain.chat_models import ChatOpenAI
7
- from src.summarization import summarize_wrapper, parallel_summarization
 
 
 
 
8
  from src.mailing import send_email
9
 
10
- # Function to render a specific page of a PDF file as an image
11
- def render_file(file):
12
  pdf = pdfium.PdfDocument(file.name)
13
  images = []
14
  for page_index in range(len(pdf)):
@@ -18,13 +22,31 @@ def render_file(file):
18
  rotation=0, # no additional rotation
19
  # ... further rendering options
20
  )
21
- images.append((bitmap.to_pil(), f"Seite {page_index+1}"))
 
 
 
 
22
 
 
 
 
23
  return gr.update(
24
  value=images,
25
  )
26
 
27
 
 
 
 
 
 
 
 
 
 
 
 
28
  def switch_buttons(interactive: bool):
29
  """This switches the buttons to interactive or not interactive.
30
 
@@ -44,59 +66,63 @@ def switch_buttons(interactive: bool):
44
  )
45
 
46
 
47
- def run_summarization_model_gradio(
48
- llm: ChatOpenAI,
49
- share_gradio_via_link: bool = False,
50
- summarization_kwargs: dict = {},
51
- run_local: bool = False,
52
- ):
53
- """Run the Summarization assistant with gradio
54
 
55
  Args:
56
  llm (ChatOpenAI): Language model.
57
- share_gradio_via_link (bool, optional): Whether to launch the gradio app via a public link. Defaults to False.
58
- summarization_kwargs (dict, optional): Keyword arguments for the summarization. Defaults to {}.
59
- run_local (bool, optional): Whether to run the gradio app locally. Defaults to False.
60
 
 
 
61
  """
62
- title = "Summarization of Legal Documents"
63
- description = f"Upload a document and get a summarization."
64
 
65
  with gr.Blocks(
66
  theme="soft",
67
- title=title,
68
- ) as webui:
69
- with gr.Row().style(equal_height=True):
70
- Header_box = generate_title(title=title, description=description)
71
- with gr.Row().style(equal_height=True):
72
- clear = gr.Button("Clear All Components")
73
- file_upload = gr.File(
74
- file_count="single",
75
- file_types=[".pdf", ".txt"],
76
- label="Upload PDF",
77
- )
78
  with gr.Row().style(equal_height=True):
79
- summary_short = gr.Button("Kurze Zusammenfassung", interactive=False)
80
- summary_middle = gr.Button("Mittlere Zusammenfassung", interactive=False)
81
- summary_long = gr.Button("Lange Zusammenfassung", interactive=False)
82
- summary_parallel = gr.Button("Parallele Zusammenfassung", interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  with gr.Row().style(equal_height=True):
84
  with gr.Column(scale=1):
85
- summary_output = gr.Textbox(label="Zusammenfassung", lines=9).style(
86
  show_copy_button=True
87
  )
88
  with gr.Column(scale=1):
89
- show_pdf = gr.Gallery(label="Uploaded PDF").style(object_fit="contain")
 
 
90
 
91
  with gr.Row().style(equal_height=True):
92
  with gr.Column(scale=1):
93
- recipiant_email = gr.Textbox(
94
  label="Recipiant Email", placeholder="Enter Email"
95
  )
96
- subject_email = gr.Textbox(label="Subject", placeholder="Enter Subject")
 
 
97
  send_email_button = gr.Button("Open Email", interactive=False)
98
  with gr.Column(scale=3):
99
- email_instructions = gr.Textbox(
100
  label="Email Instructions",
101
  placeholder="Write Email Instructions here.",
102
  value=(
@@ -110,91 +136,39 @@ def run_summarization_model_gradio(
110
  )
111
 
112
  # Once a file is uploaded, enable the summarization buttons and visualize the uploaded file
113
- file_upload.upload(
114
  switch_buttons,
115
  [gr.State(True)],
116
- [summary_short, summary_middle, summary_long],
117
  queue=False,
118
- ).then(
119
- switch_buttons,
120
- [gr.State(True)],
121
- [summary_parallel, gr.State(None), gr.State(None)],
122
- queue=False,
123
- ).then(
124
- fn=render_file, inputs=[file_upload], outputs=[show_pdf]
125
- )
126
 
127
- # If you click any button first disable all buttons, then summarzize and then enable the clicked button
128
- for s, summarization_type in [
129
- (summary_short, "short"),
130
- (summary_middle, "middle"),
131
- (summary_long, "long"),
132
- ]:
133
- s.click(
134
- switch_buttons,
135
- [gr.State(False)],
136
- [summary_short, summary_middle, summary_long],
137
- queue=False,
138
- ).then(
139
- summarize_wrapper,
140
- [
141
- file_upload,
142
- gr.State([llm]),
143
- gr.State(summarization_type),
144
- gr.State(summarization_kwargs),
145
- ],
146
- [summary_output],
147
- queue=False,
148
- ).then(
149
- switch_buttons,
150
- [gr.State(True)],
151
- [summary_short, summary_middle, summary_long],
152
- queue=False,
153
- ).then(
154
- switch_buttons,
155
- [gr.State(True)],
156
- [send_email_button, gr.State(None), gr.State(None)],
157
- queue=False,
158
- )
159
-
160
- summary_parallel.click(
161
  switch_buttons,
162
  [gr.State(False)],
163
- [summary_short, summary_middle, summary_long],
164
  queue=False,
165
  ).then(
166
  parallel_summarization,
167
- [file_upload, gr.State([llm]), gr.State(summarization_kwargs)],
168
  [summary_output],
169
  queue=False,
170
  ).then(
171
  switch_buttons,
172
  [gr.State(True)],
173
- [summary_short, summary_middle, summary_long],
174
  queue=False,
175
- ).then(
176
- switch_buttons,
177
- [gr.State(True)],
178
- [send_email_button, gr.State(None), gr.State(None)],
179
- queue=False,
180
- )
181
 
182
  # The clear button clears the dashboard
183
  clear.click(lambda: None, None, summary_output, queue=False).then(
184
- lambda: None, None, file_upload, queue=False
185
- ).then(
186
- switch_buttons,
187
- [gr.State(False)],
188
- [summary_short, summary_middle, summary_long],
189
- queue=False,
190
- ).then(
191
- lambda: None, None, show_pdf, queue=False
192
- ).then(
193
  lambda: None, None, send_email_button, queue=False
194
  ).then(
195
- lambda: None, None, email_instructions, queue=False
196
  ).then(
197
- lambda: None, None, recipiant_email, queue=False
198
  )
199
 
200
  # Email button click opens the default email client and fills in the email instructions
@@ -202,12 +176,129 @@ def run_summarization_model_gradio(
202
  send_email,
203
  [
204
  summary_output,
205
- recipiant_email,
206
- subject_email,
207
- email_instructions,
208
  ],
209
  queue=False,
210
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
 
212
  webui.queue()
213
 
 
4
  import gradio as gr
5
 
6
  from langchain.chat_models import ChatOpenAI
7
+ from src.summarization import (
8
+ parallel_summarization,
9
+ parallel_legal_implications,
10
+ PARALLEL_SUMMARIZATION_MAPPING,
11
+ )
12
  from src.mailing import send_email
13
 
14
+
15
+ def _file_render_helper(file):
16
  pdf = pdfium.PdfDocument(file.name)
17
  images = []
18
  for page_index in range(len(pdf)):
 
22
  rotation=0, # no additional rotation
23
  # ... further rendering options
24
  )
25
+ images.append(
26
+ (bitmap.to_pil(), f"{file.name.split('/')[-1]} Seite {page_index+1}")
27
+ )
28
+ return images
29
+
30
 
31
+ # Function to render a specific page of a PDF file as an image
32
+ def render_file(file):
33
+ images = _file_render_helper(file)
34
  return gr.update(
35
  value=images,
36
  )
37
 
38
 
39
+ def render_files(files):
40
+ all_images = []
41
+ for file in files:
42
+ images = _file_render_helper(file)
43
+ all_images.extend(images)
44
+
45
+ return gr.update(
46
+ value=all_images,
47
+ )
48
+
49
+
50
  def switch_buttons(interactive: bool):
51
  """This switches the buttons to interactive or not interactive.
52
 
 
66
  )
67
 
68
 
69
+ def load_summary_section(llm: ChatOpenAI):
70
+ """Load the summary section
 
 
 
 
 
71
 
72
  Args:
73
  llm (ChatOpenAI): Language model.
 
 
 
74
 
75
+ Returns:
76
+ gr.Blocks: The summarization section
77
  """
 
 
78
 
79
  with gr.Blocks(
80
  theme="soft",
81
+ ) as summary_section:
 
 
 
 
 
 
 
 
 
 
82
  with gr.Row().style(equal_height=True):
83
+ with gr.Column(scale=1):
84
+ file_upload_summary = gr.File(
85
+ file_count="single",
86
+ file_types=[".pdf", ".txt"],
87
+ label="Upload PDF",
88
+ )
89
+ summary_parallel_button = gr.Button(
90
+ "Parallel Summary", interactive=False
91
+ )
92
+ clear = gr.Button("Clear All Components")
93
+ with gr.Column(scale=2):
94
+ sections_to_select = [
95
+ i for i in PARALLEL_SUMMARIZATION_MAPPING.keys() if "I." not in i
96
+ ]
97
+ summary_sections_dropdown = gr.Dropdown(
98
+ sections_to_select,
99
+ value=sections_to_select,
100
+ interactive=True,
101
+ multiselect=True,
102
+ label="Sections for Summarization",
103
+ info="Select the sections you want to include in the summarization.",
104
+ )
105
  with gr.Row().style(equal_height=True):
106
  with gr.Column(scale=1):
107
+ summary_output = gr.Textbox(label="Summary", lines=9).style(
108
  show_copy_button=True
109
  )
110
  with gr.Column(scale=1):
111
+ summary_show_pdf = gr.Gallery(label="Uploaded PDF").style(
112
+ object_fit="contain"
113
+ )
114
 
115
  with gr.Row().style(equal_height=True):
116
  with gr.Column(scale=1):
117
+ recipiant_email_summary = gr.Textbox(
118
  label="Recipiant Email", placeholder="Enter Email"
119
  )
120
+ subject_email_summary = gr.Textbox(
121
+ label="Subject", placeholder="Enter Subject"
122
+ )
123
  send_email_button = gr.Button("Open Email", interactive=False)
124
  with gr.Column(scale=3):
125
+ email_instructions_summary = gr.Textbox(
126
  label="Email Instructions",
127
  placeholder="Write Email Instructions here.",
128
  value=(
 
136
  )
137
 
138
  # Once a file is uploaded, enable the summarization buttons and visualize the uploaded file
139
+ file_upload_summary.upload(
140
  switch_buttons,
141
  [gr.State(True)],
142
+ [summary_parallel_button, gr.State(None), gr.State(None)],
143
  queue=False,
144
+ ).then(fn=render_file, inputs=[file_upload_summary], outputs=[summary_show_pdf])
 
 
 
 
 
 
 
145
 
146
+ summary_parallel_button.click(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  switch_buttons,
148
  [gr.State(False)],
149
+ [summary_parallel_button, gr.State(None), gr.State(None)],
150
  queue=False,
151
  ).then(
152
  parallel_summarization,
153
+ [file_upload_summary, summary_sections_dropdown, gr.State([llm])],
154
  [summary_output],
155
  queue=False,
156
  ).then(
157
  switch_buttons,
158
  [gr.State(True)],
159
+ [summary_parallel_button, gr.State(None), gr.State(None)],
160
  queue=False,
161
+ ).then
 
 
 
 
 
162
 
163
  # The clear button clears the dashboard
164
  clear.click(lambda: None, None, summary_output, queue=False).then(
165
+ lambda: None, None, file_upload_summary, queue=False
166
+ ).then(lambda: None, None, summary_show_pdf, queue=False).then(
 
 
 
 
 
 
 
167
  lambda: None, None, send_email_button, queue=False
168
  ).then(
169
+ lambda: None, None, email_instructions_summary, queue=False
170
  ).then(
171
+ lambda: None, None, recipiant_email_summary, queue=False
172
  )
173
 
174
  # Email button click opens the default email client and fills in the email instructions
 
176
  send_email,
177
  [
178
  summary_output,
179
+ recipiant_email_summary,
180
+ subject_email_summary,
181
+ email_instructions_summary,
182
  ],
183
  queue=False,
184
  )
185
+ return summary_section
186
+
187
+
188
+ def load_legal_implications_section(llm: ChatOpenAI):
189
+ """Load the legal implications section
190
+
191
+ Args:
192
+ llm (ChatOpenAI): Language model.
193
+
194
+ Returns:
195
+ gr.Block: Legal Implications Section
196
+ """
197
+ with gr.Blocks(theme="soft") as legal_implications_section:
198
+
199
+ with gr.Row().style(equal_height=True):
200
+ with gr.Column(scale=3):
201
+ file_upload_legal_implications = gr.File(
202
+ file_count="multiple",
203
+ file_types=[".pdf", ".txt"],
204
+ label="Upload PDF",
205
+ )
206
+ with gr.Column(scale=1):
207
+ extract_legal_implications_button = gr.Button(
208
+ "Extract Legal Implications", interactive=False
209
+ )
210
+ clear_legal_implications_button = gr.Button("Clear All Components")
211
+
212
+ with gr.Row().style(equal_height=True):
213
+ with gr.Column(scale=1):
214
+ legal_implications_output = gr.Textbox(
215
+ label="Legal Implications", lines=9
216
+ ).style(show_copy_button=True)
217
+ with gr.Column(scale=1):
218
+ legal_implications_show_pdf = gr.Gallery(label="Uploaded PDF").style(
219
+ object_fit="contain"
220
+ )
221
+
222
+ with gr.Row().style(equal_height=True):
223
+ with gr.Column(scale=1):
224
+ recipiant_email_legal_implications = gr.Textbox(
225
+ label="Recipiant Email", placeholder="Enter Email"
226
+ )
227
+ subject_email_legal_implications = gr.Textbox(
228
+ label="Subject", placeholder="Enter Subject"
229
+ )
230
+ send_email_button = gr.Button("Open Email", interactive=False)
231
+ with gr.Column(scale=3):
232
+ email_instructions_legal_implications = gr.Textbox(
233
+ label="Email Instructions",
234
+ placeholder="Write Email Instructions here.",
235
+ value=(
236
+ "Dear Recipient\n\n"
237
+ "Please find the Legal Implications of the uploaded documents below.\n\n"
238
+ "<TEXT_FROM_LLM>\n\n"
239
+ "Kind regards,\n"
240
+ "Your Legal Assistant"
241
+ ),
242
+ lines=9,
243
+ )
244
+ # Once a file is uploaded, enable the summarization buttons and visualize the uploaded file
245
+ file_upload_legal_implications.upload(
246
+ switch_buttons,
247
+ [gr.State(True)],
248
+ [extract_legal_implications_button, gr.State(None), gr.State(None)],
249
+ queue=False,
250
+ ).then(
251
+ fn=render_files,
252
+ inputs=[file_upload_legal_implications],
253
+ outputs=[legal_implications_show_pdf],
254
+ )
255
+
256
+ extract_legal_implications_button.click(
257
+ switch_buttons,
258
+ [gr.State(False)],
259
+ [extract_legal_implications_button, gr.State(None), gr.State(None)],
260
+ queue=False,
261
+ ).then(
262
+ parallel_legal_implications,
263
+ [file_upload_legal_implications, gr.State([llm])],
264
+ [legal_implications_output],
265
+ queue=False,
266
+ ).then(
267
+ switch_buttons,
268
+ [gr.State(True)],
269
+ [extract_legal_implications_button, gr.State(None), gr.State(None)],
270
+ queue=False,
271
+ )
272
+
273
+
274
+ def run_summarization_model_gradio(
275
+ llm: ChatOpenAI,
276
+ share_gradio_via_link: bool = False,
277
+ summarization_kwargs: dict = {},
278
+ run_local: bool = False,
279
+ ):
280
+ """Run the Summarization assistant with gradio
281
+
282
+ Args:
283
+ llm (ChatOpenAI): Language model.
284
+ share_gradio_via_link (bool, optional): Whether to launch the gradio app via a public link. Defaults to False.
285
+ summarization_kwargs (dict, optional): Keyword arguments for the summarization. Defaults to {}.
286
+ run_local (bool, optional): Whether to run the gradio app locally. Defaults to False.
287
+
288
+ """
289
+ title = "Summarization of Legal Documents"
290
+ description = f"Upload a document and get a summarization."
291
+
292
+ with gr.Blocks(
293
+ theme="soft",
294
+ title=title,
295
+ ) as webui:
296
+ with gr.Row().style(equal_height=True):
297
+ Header_box = generate_title(title=title, description=description)
298
+ with gr.Tab("Summarize Verdict"):
299
+ load_summary_section(llm=llm)
300
+ with gr.Tab("Legal Implications"):
301
+ load_legal_implications_section(llm=llm)
302
 
303
  webui.queue()
304
 
src/llm_utils.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain.chains.llm import LLMChain
2
+ from langchain.chat_models import ChatOpenAI
3
+ from langchain.docstore.document import Document
4
+ import time
5
+ from typing import List
6
+
7
+
8
+ async def async_generate(
9
+ llm: ChatOpenAI, docs: List[Document], llm_kwargs: dict, k: str
10
+ ) -> dict:
11
+ """Asyncronous LLMChain function.
12
+
13
+ Args:
14
+ llm (ChatOpenAI): Language model to use.
15
+ docs (List[Document]): List of documents.
16
+ llm_kwargs (dict): Keyword arguments for the LLMChain.
17
+ k (str): Key for a dictionary under which the output is returned.
18
+
19
+ Returns:
20
+ dict: Dictionary with the summarization.
21
+ """
22
+ print(f"Starting summarization for {k}")
23
+ now = time.time()
24
+ chain = LLMChain(llm=llm, **llm_kwargs)
25
+
26
+ resp = await chain.arun(text=docs)
27
+ print(f"Time taken for {k}: ", time.time() - now)
28
+ return {k: resp}
src/prompts.py CHANGED
@@ -1,6 +1,10 @@
1
  from langchain.prompts.prompt import PromptTemplate
2
 
3
 
 
 
 
 
4
  prompts = {
5
  ############## SHORT DE
6
  "short_de": {
@@ -152,12 +156,14 @@ Die Teile der Zusammenfassung mit Angabe der Seitenzahlen:
152
  }
153
 
154
 
155
- def get_template_mp(name: str, headline: str, additional_text: str = ""):
 
 
 
156
  base_multi = (
157
  "Schreibe, ein/e <KEY> des Urteils, das durch dreifache Anführungszeichen begrenzt ist, in maximal einem Paragraphen.\n"
158
  "<ADDITIONAL_TEXT>\n"
159
  'Als Überschrift muss "<HEAD_LINE>" angegeben werden. \n'
160
- # "Nach dem Paragraph müssen die Seiten angegeben werden die genutzt wurden."
161
  "Urteil:\n"
162
  "```{text}```\n"
163
  "\n"
@@ -173,18 +179,18 @@ def get_template_mp(name: str, headline: str, additional_text: str = ""):
173
  prompts_parallel = {
174
  "intro": PromptTemplate(
175
  input_variables=["text"],
176
- template=get_template_mp(name="Einleitung", headline="I. Einleitung"),
177
  ),
178
  "darstellung_des_rechtsproblems": PromptTemplate(
179
  input_variables=["text"],
180
- template=get_template_mp(
181
  name="Darstellung des Rechtsproblems",
182
  headline="Darstellung des Rechtsproblems",
183
  ),
184
  ),
185
  "angaben_ueber_das_urteil": PromptTemplate(
186
  input_variables=["text"],
187
- template=get_template_mp(
188
  name="Angaben über das Urteil",
189
  headline="Angaben über das Urteil",
190
  additional_text="Gib die folgenden Informationen an: Gericht, Datum, Aktenzeichen (AZ: ...), Fundstelle(n)",
@@ -192,7 +198,7 @@ prompts_parallel = {
192
  ),
193
  "sachverhalt": PromptTemplate(
194
  input_variables=["text"],
195
- template=get_template_mp(
196
  name="Sachverhalt",
197
  headline="Sachverhalt (unter Rückgriff auf Instanzentscheidung)",
198
  additional_text=(
@@ -203,13 +209,13 @@ prompts_parallel = {
203
  ),
204
  "prozessgeschichte": PromptTemplate(
205
  input_variables=["text"],
206
- template=get_template_mp(
207
  name="Prozessgeschichte", headline="3. Prozessgeschichte"
208
  ),
209
  ),
210
  "rechtsproblem": PromptTemplate(
211
  input_variables=["text"],
212
- template=get_template_mp(
213
  name="Rechtsproblem",
214
  headline="Rechtsproblem",
215
  additional_text="Das Problem des Falles ist genau herauszuarbeiten und im rechtlichen Kontext zu verankern.",
@@ -217,13 +223,13 @@ prompts_parallel = {
217
  ),
218
  "loesung_des_gerichts": PromptTemplate(
219
  input_variables=["text"],
220
- template=get_template_mp(
221
  name="Lösung des Gerichts", headline="Lösung des Gerichts"
222
  ),
223
  ),
224
  "loesungsansaetze_zum_problem": PromptTemplate(
225
  input_variables=["text"],
226
- template=get_template_mp(
227
  name="Lösungsansätze zum Problem",
228
  headline="Lösungsansätze zum Problem",
229
  additional_text="Knappe, aber möglichst vollständige Übersicht der vertretenen Ansichten bzw. der Lösungsvorschläge im Urteil.",
@@ -231,7 +237,7 @@ prompts_parallel = {
231
  ),
232
  "analyse_und_einordnung_der_entscheidung": PromptTemplate(
233
  input_variables=["text"],
234
- template=get_template_mp(
235
  name="Analyse und Einordnung der Entscheidung",
236
  headline="Analyse und Einordnung der Entscheidung",
237
  additional_text="Es soll nur der Inhalt des Urteils wiedergegeben werden.",
@@ -239,7 +245,7 @@ prompts_parallel = {
239
  ),
240
  "bewertung_und_kritik_der_entscheidung": PromptTemplate(
241
  input_variables=["text"],
242
- template=get_template_mp(
243
  name="Bewertung und Kritik der Entscheidung",
244
  headline="Bewertung und Kritik der Entscheidung",
245
  additional_text="Verwende ausschließlich den Kontext des Urteils und schreib keinen neuen Text. Wenn keine Bewertung oder Kritik vorhanden ist, antworte mit 'Keine Bewertung oder Kritik vorhanden.'",
@@ -247,7 +253,7 @@ prompts_parallel = {
247
  ),
248
  "eigener_loesungsvorschlag": PromptTemplate(
249
  input_variables=["text"],
250
- template=get_template_mp(
251
  name="Eigener Lösungsvorschlag",
252
  headline="Eigener Lösungsvorschlag",
253
  additional_text="Es soll nur der Inhalt des Urteils wiedergegeben werden. Wenn das Urteil keinen eigenen Lösungsvorschlag hat schreib: 'Keine Informationen zum eigenen Lösungsvorschlag vorhanden'",
@@ -255,7 +261,7 @@ prompts_parallel = {
255
  ),
256
  "ausblick": PromptTemplate(
257
  input_variables=["text"],
258
- template=get_template_mp(
259
  name="Ausblick",
260
  headline="Ausblick",
261
  additional_text="Es soll nur der Inhalt des Urteils wiedergegeben werden. Wenn das Urteil keinen Ausblick gibt schreib: 'Keine Informationen zum Auslbick vorhanden'.",
 
1
  from langchain.prompts.prompt import PromptTemplate
2
 
3
 
4
+ #########################################
5
+ ###### SUMMARIZATION CHAIN PROMPTS ######
6
+ #########################################
7
+
8
  prompts = {
9
  ############## SHORT DE
10
  "short_de": {
 
156
  }
157
 
158
 
159
+ #########################################
160
+ #### PARALLEL SUMMARIZATION PROMPTS #####
161
+ #########################################
162
+ def get_template_parallel(name: str, headline: str, additional_text: str = ""):
163
  base_multi = (
164
  "Schreibe, ein/e <KEY> des Urteils, das durch dreifache Anführungszeichen begrenzt ist, in maximal einem Paragraphen.\n"
165
  "<ADDITIONAL_TEXT>\n"
166
  'Als Überschrift muss "<HEAD_LINE>" angegeben werden. \n'
 
167
  "Urteil:\n"
168
  "```{text}```\n"
169
  "\n"
 
179
  prompts_parallel = {
180
  "intro": PromptTemplate(
181
  input_variables=["text"],
182
+ template=get_template_parallel(name="Einleitung", headline="I. Einleitung"),
183
  ),
184
  "darstellung_des_rechtsproblems": PromptTemplate(
185
  input_variables=["text"],
186
+ template=get_template_parallel(
187
  name="Darstellung des Rechtsproblems",
188
  headline="Darstellung des Rechtsproblems",
189
  ),
190
  ),
191
  "angaben_ueber_das_urteil": PromptTemplate(
192
  input_variables=["text"],
193
+ template=get_template_parallel(
194
  name="Angaben über das Urteil",
195
  headline="Angaben über das Urteil",
196
  additional_text="Gib die folgenden Informationen an: Gericht, Datum, Aktenzeichen (AZ: ...), Fundstelle(n)",
 
198
  ),
199
  "sachverhalt": PromptTemplate(
200
  input_variables=["text"],
201
+ template=get_template_parallel(
202
  name="Sachverhalt",
203
  headline="Sachverhalt (unter Rückgriff auf Instanzentscheidung)",
204
  additional_text=(
 
209
  ),
210
  "prozessgeschichte": PromptTemplate(
211
  input_variables=["text"],
212
+ template=get_template_parallel(
213
  name="Prozessgeschichte", headline="3. Prozessgeschichte"
214
  ),
215
  ),
216
  "rechtsproblem": PromptTemplate(
217
  input_variables=["text"],
218
+ template=get_template_parallel(
219
  name="Rechtsproblem",
220
  headline="Rechtsproblem",
221
  additional_text="Das Problem des Falles ist genau herauszuarbeiten und im rechtlichen Kontext zu verankern.",
 
223
  ),
224
  "loesung_des_gerichts": PromptTemplate(
225
  input_variables=["text"],
226
+ template=get_template_parallel(
227
  name="Lösung des Gerichts", headline="Lösung des Gerichts"
228
  ),
229
  ),
230
  "loesungsansaetze_zum_problem": PromptTemplate(
231
  input_variables=["text"],
232
+ template=get_template_parallel(
233
  name="Lösungsansätze zum Problem",
234
  headline="Lösungsansätze zum Problem",
235
  additional_text="Knappe, aber möglichst vollständige Übersicht der vertretenen Ansichten bzw. der Lösungsvorschläge im Urteil.",
 
237
  ),
238
  "analyse_und_einordnung_der_entscheidung": PromptTemplate(
239
  input_variables=["text"],
240
+ template=get_template_parallel(
241
  name="Analyse und Einordnung der Entscheidung",
242
  headline="Analyse und Einordnung der Entscheidung",
243
  additional_text="Es soll nur der Inhalt des Urteils wiedergegeben werden.",
 
245
  ),
246
  "bewertung_und_kritik_der_entscheidung": PromptTemplate(
247
  input_variables=["text"],
248
+ template=get_template_parallel(
249
  name="Bewertung und Kritik der Entscheidung",
250
  headline="Bewertung und Kritik der Entscheidung",
251
  additional_text="Verwende ausschließlich den Kontext des Urteils und schreib keinen neuen Text. Wenn keine Bewertung oder Kritik vorhanden ist, antworte mit 'Keine Bewertung oder Kritik vorhanden.'",
 
253
  ),
254
  "eigener_loesungsvorschlag": PromptTemplate(
255
  input_variables=["text"],
256
+ template=get_template_parallel(
257
  name="Eigener Lösungsvorschlag",
258
  headline="Eigener Lösungsvorschlag",
259
  additional_text="Es soll nur der Inhalt des Urteils wiedergegeben werden. Wenn das Urteil keinen eigenen Lösungsvorschlag hat schreib: 'Keine Informationen zum eigenen Lösungsvorschlag vorhanden'",
 
261
  ),
262
  "ausblick": PromptTemplate(
263
  input_variables=["text"],
264
+ template=get_template_parallel(
265
  name="Ausblick",
266
  headline="Ausblick",
267
  additional_text="Es soll nur der Inhalt des Urteils wiedergegeben werden. Wenn das Urteil keinen Ausblick gibt schreib: 'Keine Informationen zum Auslbick vorhanden'.",
src/summarization.py CHANGED
@@ -1,49 +1,13 @@
1
- from langchain.document_loaders import PyPDFLoader, TextLoader
2
  from langchain.chains.summarize import load_summarize_chain
3
- from langchain.chains.llm import LLMChain
4
- from langchain.chains.combine_documents.stuff import StuffDocumentsChain
5
  from langchain.chat_models import ChatOpenAI
6
- from langchain.docstore.document import Document
7
  from src.prompts import prompts, prompts_parallel
 
 
8
  import time
9
  from typing import Dict, List
10
  import asyncio
11
 
12
 
13
- def load_docs(file_path: str, with_pageinfo: bool = True) -> List[Document]:
14
- """Load a file and return the text.
15
-
16
- Args:
17
- file_path (str): Path to the pdf file. This can either be a local path or a tempfile.TemporaryFileWrapper_.
18
- with_pageinfo (bool, optional): If True the page information is added to the document. Defaults to True.
19
-
20
- Raises:
21
- ValueError: If the file type is not supported.
22
-
23
- Returns:
24
- List[Document]: List of documents.
25
- """
26
- if file_path.endswith(".pdf"):
27
- loader = PyPDFLoader(file_path)
28
- docs = loader.load()
29
- elif file_path.endswith(".txt"):
30
- loader = TextLoader(file_path)
31
- docs = loader.load()
32
- else:
33
- raise ValueError(
34
- f"File type ({file_path.split('.')[1]}) not supported. Please upload a pdf or txt file."
35
- )
36
- for doc in docs:
37
- doc.page_content = doc.page_content.replace("\n", " \n ")
38
- # if doc contains a page append it to the text
39
- if with_pageinfo and hasattr(doc, "metadata"):
40
- doc.page_content = f"(Quelle Seite: {doc.metadata.get('page')+1}) .".join(
41
- doc.page_content.split(" .")
42
- )
43
-
44
- return docs
45
-
46
-
47
  def summarize_chain(
48
  file_path: str, llm: ChatOpenAI, summarization_kwargs: Dict[str, str]
49
  ) -> str:
@@ -61,13 +25,6 @@ def summarize_chain(
61
  llm=llm,
62
  **summarization_kwargs,
63
  )
64
- # del summarization_kwargs["map_prompt"]
65
- # summarization_kwargs["prompt"] = summarization_kwargs["combine_prompt"]
66
- # del summarization_kwargs["combine_prompt"]
67
- # llm_chain = LLMChain(llm=llm, **summarization_kwargs)
68
- # chain = StuffDocumentsChain(
69
- # llm_chain=llm_chain, document_variable_name="text"
70
- # )
71
  summary = chain.run(docs)
72
  return summary
73
 
@@ -75,7 +32,8 @@ def summarize_chain(
75
  def summarize_wrapper(
76
  file: str, llm: ChatOpenAI, summarization_type: str, summarization_kwargs: dict
77
  ) -> str:
78
- """Wrapper for the summarization function to make it compatible with gradio.
 
79
 
80
  Args:
81
  file (str): Path to the file. This can either be a local path or a tempfile.TemporaryFileWrapper_.
@@ -115,34 +73,14 @@ def summarize_wrapper(
115
  )
116
 
117
 
118
- async def async_generate(
119
- llm: ChatOpenAI, docs: List[Document], summarization_kwargs: dict, k: str
120
- ) -> dict:
121
- """Asyncronous summarization.
122
-
123
- Args:
124
- llm (ChatOpenAI): Language model to use for the summarization.
125
- docs (List[Document]): List of documents.
126
- summarization_kwargs (dict): Keyword arguments for the summarization.
127
- k (str): Key for the summarization.
128
-
129
- Returns:
130
- dict: Dictionary with the summarization.
131
- """
132
- print(f"Starting summarization for {k}")
133
- now = time.time()
134
- # chain = load_summarize_chain(llm=llm, **summarization_kwargs)
135
- chain = LLMChain(llm=llm, **summarization_kwargs)
136
- resp = await chain.arun(text=docs)
137
- print(f"Time taken for {k}: ", time.time() - now)
138
- return {k: resp}
139
-
140
-
141
- async def generate_concurrently(file_path: str, llm: ChatOpenAI) -> List[dict]:
142
- """Parallel summarization.
143
 
144
  Args:
145
  file_path (str): Path to the pdf file. This can either be a local path or a tempfile.TemporaryFileWrapper_.
 
146
  llm (ChatOpenAI): Language model to use for the summarization.
147
 
148
  Returns:
@@ -154,12 +92,12 @@ async def generate_concurrently(file_path: str, llm: ChatOpenAI) -> List[dict]:
154
 
155
  # create parallel tasks
156
  tasks = []
157
- i = 0
158
- for k, pt in prompts_parallel.items():
159
- sk = summarization_kwargs.copy()
160
- sk["prompt"] = pt
161
- print(f"Appending task for {k}")
162
- tasks.append(async_generate(llm=llm, docs=docs, summarization_kwargs=sk, k=k))
163
  print("-------------------")
164
  # execute all coroutines concurrently
165
  values = await asyncio.gather(*tasks)
@@ -171,55 +109,80 @@ async def generate_concurrently(file_path: str, llm: ChatOpenAI) -> List[dict]:
171
  return values_flattened
172
 
173
 
174
- def parallel_summarization(
175
- file: str, llm: ChatOpenAI, summarization_kwargs: dict
176
- ) -> str:
177
- """Wrapper for the summarization function to make it compatible with gradio.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
  Args:
180
  file (str): Path to the file. This can either be a local path or a tempfile.TemporaryFileWrapper_.
 
181
  llm (ChatOpenAI): Language model.
182
- summarization_kwargs (dict): Keyword arguments for the summarization.
183
 
184
  Returns:
185
  str: Summarization of the file.
186
  """
187
  now = time.time()
188
  values_flattened = asyncio.run(
189
- generate_concurrently(file_path=file.name, llm=llm[0])
 
 
190
  )
191
- print("Time taken: ", time.time() - now)
192
-
193
- output = f"""
194
-
195
- {values_flattened["intro"]}
196
-
197
- {values_flattened["darstellung_des_rechtsproblems"]}
198
-
199
-
200
- II. Die Entscheidung
201
-
202
- {values_flattened["angaben_ueber_das_urteil"]}
203
-
204
- {values_flattened["sachverhalt"]}
205
-
206
- {values_flattened["prozessgeschichte"]}
207
-
208
- {values_flattened["rechtsproblem"]}
209
-
210
- {values_flattened["loesung_des_gerichts"]}
211
-
212
- III. Analyse
213
-
214
- {values_flattened["loesungsansaetze_zum_problem"]}
215
 
216
- {values_flattened["analyse_und_einordnung_der_entscheidung"]}
217
 
218
- {values_flattened["bewertung_und_kritik_der_entscheidung"]}
219
 
220
- {values_flattened["eigener_loesungsvorschlag"]}
 
221
 
222
- {values_flattened["ausblick"]}
223
- """
 
224
 
225
- return output
 
 
 
 
 
1
  from langchain.chains.summarize import load_summarize_chain
 
 
2
  from langchain.chat_models import ChatOpenAI
 
3
  from src.prompts import prompts, prompts_parallel
4
+ from src.doc_loading import load_docs
5
+ from src.llm_utils import async_generate
6
  import time
7
  from typing import Dict, List
8
  import asyncio
9
 
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  def summarize_chain(
12
  file_path: str, llm: ChatOpenAI, summarization_kwargs: Dict[str, str]
13
  ) -> str:
 
25
  llm=llm,
26
  **summarization_kwargs,
27
  )
 
 
 
 
 
 
 
28
  summary = chain.run(docs)
29
  return summary
30
 
 
32
  def summarize_wrapper(
33
  file: str, llm: ChatOpenAI, summarization_type: str, summarization_kwargs: dict
34
  ) -> str:
35
+ """Wrapper for the summarization function to make it compatible with gradio. This function uses a
36
+ single summarization chain.
37
 
38
  Args:
39
  file (str): Path to the file. This can either be a local path or a tempfile.TemporaryFileWrapper_.
 
73
  )
74
 
75
 
76
+ async def generate_summary_concurrently(
77
+ file_path: str, sections: List[str], llm: ChatOpenAI
78
+ ) -> List[dict]:
79
+ """Parallel summarization. This function is used to run different prompts for the same docs in parallel.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
  Args:
82
  file_path (str): Path to the pdf file. This can either be a local path or a tempfile.TemporaryFileWrapper_.
83
+ sections (List[str]): List of sections to summarize.
84
  llm (ChatOpenAI): Language model to use for the summarization.
85
 
86
  Returns:
 
92
 
93
  # create parallel tasks
94
  tasks = []
95
+ for k in PARALLEL_SUMMARIZATION_ORDER:
96
+ if PARALLEL_SUMMARIZATION_MAPPING_INVERSE.get(k, k) in sections:
97
+ sk = summarization_kwargs.copy()
98
+ sk["prompt"] = prompts_parallel[k]
99
+ print(f"Appending task for {k}")
100
+ tasks.append(async_generate(llm=llm, docs=docs, llm_kwargs=sk, k=k))
101
  print("-------------------")
102
  # execute all coroutines concurrently
103
  values = await asyncio.gather(*tasks)
 
109
  return values_flattened
110
 
111
 
112
+ PARALLEL_SUMMARIZATION_ORDER = [
113
+ "intro",
114
+ "darstellung_des_rechtsproblems",
115
+ "II. Die Entscheidung",
116
+ "angaben_ueber_das_urteil",
117
+ "sachverhalt",
118
+ "prozessgeschichte",
119
+ "rechtsproblem",
120
+ "loesung_des_gerichts",
121
+ "III. Analyse",
122
+ "loesungsansaetze_zum_problem",
123
+ "analyse_und_einordnung_der_entscheidung",
124
+ "bewertung_und_kritik_der_entscheidung",
125
+ "eigener_loesungsvorschlag",
126
+ "ausblick",
127
+ ]
128
+ PARALLEL_SUMMARIZATION_MAPPING = {
129
+ "I. Einleitung": "intro",
130
+ "Darstellung des Rechtsproblems": "darstellung_des_rechtsproblems",
131
+ "Angaben über das Urteil": "angaben_ueber_das_urteil",
132
+ "Sachverhalt": "sachverhalt",
133
+ "Prozessgeschichte": "prozessgeschichte",
134
+ "Rechtsproblem": "rechtsproblem",
135
+ "Lösung des Gerichts": "loesung_des_gerichts",
136
+ "Lösungsansätze zum Problem": "loesungsansaetze_zum_problem",
137
+ "Analyse und Einordnung der Entscheidung": "analyse_und_einordnung_der_entscheidung",
138
+ "Bewertung und Kritik der Entscheidung": "bewertung_und_kritik_der_entscheidung",
139
+ "Eigener Lösungsvorschlag": "eigener_loesungsvorschlag",
140
+ "Ausblick": "ausblick",
141
+ }
142
+ PARALLEL_SUMMARIZATION_MAPPING_INVERSE = {
143
+ v: k for k, v in PARALLEL_SUMMARIZATION_MAPPING.items()
144
+ }
145
+
146
+
147
+ def parallel_summarization(file: str, sections: List[str], llm: ChatOpenAI) -> str:
148
+ """Wrapper for the parallel summarization function to make it compatible with gradio.
149
 
150
  Args:
151
  file (str): Path to the file. This can either be a local path or a tempfile.TemporaryFileWrapper_.
152
+ sections (List[str]): List of sections to summarize.
153
  llm (ChatOpenAI): Language model.
 
154
 
155
  Returns:
156
  str: Summarization of the file.
157
  """
158
  now = time.time()
159
  values_flattened = asyncio.run(
160
+ generate_summary_concurrently(
161
+ file_path=file.name, sections=sections, llm=llm[0]
162
+ )
163
  )
164
+ print("Time taken for complete parallel summarization: ", time.time() - now)
165
+ order = PARALLEL_SUMMARIZATION_ORDER
166
+ output = ""
167
+ for section in order:
168
+ output += (
169
+ values_flattened.get(
170
+ section, PARALLEL_SUMMARIZATION_MAPPING_INVERSE.get(section, section)
171
+ )
172
+ + "\n\n"
173
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
+ return output
176
 
 
177
 
178
+ def parallel_legal_implications(file: str, llm: ChatOpenAI) -> str:
179
+ """Wrapper for the parallel legal implication extraction function to make it compatible with gradio.
180
 
181
+ Args:
182
+ file (str): Path to the file. This can either be a local path or a tempfile.TemporaryFileWrapper_.
183
+ llm (ChatOpenAI): Language model.
184
 
185
+ Returns:
186
+ str: Legal Implications of the file.
187
+ """
188
+ return "TBD"