lifan0127 commited on
Commit
bd6783b
1 Parent(s): 707620f

Add additional error handling for missing input

Browse files
Files changed (3) hide show
  1. app.py +29 -75
  2. functions.py +40 -22
  3. style.css +1 -1
app.py CHANGED
@@ -15,7 +15,7 @@ from models import (
15
  Messages,
16
  )
17
 
18
- # load_dotenv()
19
 
20
  css_style = Path('./style.css').read_text()
21
 
@@ -30,15 +30,15 @@ with gr.Blocks(css=css_style) as demo:
30
 
31
  with gr.Row():
32
  gr.Markdown("""
33
- <h2>
34
- <img src='file/assets/zotero-logo.png' alt="Zotero Logo" style="width: 3.2rem; display: inline; margin-right: 10px;" />
35
- Zotero Q&A
36
- </h2>
37
 
38
- Fan Li ([@FanLi_RnD](https://twitter.com/FanLi_RnD)) - https://apex974.com/articles/literature-reviews-with-paper-qa-and-zotero
39
-
40
- This tool allows you to ask questions based on your Zotero library. It was built upon [Paper QA](https://github.com/whitead/paper-qa), [LangChain AI](https://github.com/hwchase17/langchain) and [pyZotero](https://github.com/urschrei/pyzotero).
41
- """)
42
 
43
  with gr.Row():
44
  with gr.Column(scale=1):
@@ -57,16 +57,16 @@ with gr.Blocks(css=css_style) as demo:
57
  zot_selected_col = gr.Radio(
58
  [], label="Zotero Collection", elem_id="zotero-collection", visible=False)
59
  zot_msg = gr.HTML("""
60
- <div style="padding: 1rem; background-color: #fffbe7; font-size: 0.8rem;">
61
- <ul style="margin-bottom: 0;">
62
- <li>Click <a href="https://www.zotero.org/settings/keys/new" target="_blank">here</a> to create Zotero API key.</li>
63
- <li>To access your own library, select "User".</li>
64
- <li>To access a shared group, select "Group".</li>
65
- <li>Personal User ID can be found <a href="https://www.zotero.org/settings/keys" target="_blank">here</a>.</li>
66
- <li style="margin-bottom: 0;">Group ID is part of the group URL (e.g. 4952526).</li>
67
- </ul>
68
- </div>
69
- """, visible=True)
70
  zot_fetch_col_btn = gr.Button('Fetch Collections')
71
 
72
  gr.Error("Some Error Message")
@@ -74,7 +74,7 @@ with gr.Blocks(css=css_style) as demo:
74
  with gr.Column(scale=3):
75
 
76
  question = gr.Textbox(
77
- placeholder="You have to select a Zotero collection to proceed", label="Question", interactive=False, value="What predictive models are used in materials discovery?")
78
 
79
  gr.HTML()
80
 
@@ -89,20 +89,23 @@ with gr.Blocks(css=css_style) as demo:
89
 
90
  zot_api_key.change(
91
  reset_collection,
92
- inputs=[],
93
- outputs=[zot_selected_col, zot_fetch_col_btn, question, answer],
 
94
  show_progress=False,
95
  )
96
  zot_library_type.change(
97
  reset_collection,
98
- inputs=[],
99
- outputs=[zot_selected_col, zot_fetch_col_btn, question, answer],
 
100
  show_progress=False,
101
  )
102
  zot_library_id.change(
103
  reset_collection,
104
- inputs=[],
105
- outputs=[zot_selected_col, zot_fetch_col_btn, question, answer],
 
106
  show_progress=False
107
  )
108
 
@@ -128,54 +131,5 @@ with gr.Blocks(css=css_style) as demo:
128
  show_progress=False
129
  )
130
 
131
- # with gr.Accordion("See Docs:", open=False):
132
- # dataset = gr.Dataframe(
133
- # headers=["filepath", "citation string", "key"],
134
- # datatype=["str", "str", "str"],
135
- # col_count=(3, "fixed"),
136
- # interactive=False,
137
- # label="Documents and Citations",
138
- # overflow_row_behaviour='paginate',
139
- # max_rows=5
140
- # )
141
- # buildb = gr.Textbox("⚠️Waiting for documents and key...",
142
- # label="msg_board", interactive=False, show_label=True,
143
- # max_lines=1)
144
- # stats = gr.Dataframe(headers=['Docs', 'Chunks'],
145
- # datatype=['number', 'number'],
146
- # col_count=(2, "fixed"),
147
- # interactive=False,
148
- # label="Doc Stats")
149
- # openai_api_key.change(validate_dataset, inputs=[
150
- # dataset, openai_api_key], outputs=[buildb])
151
- # dataset.change(validate_dataset, inputs=[
152
- # dataset, openai_api_key], outputs=[buildb])
153
- # uploaded_files.change(request_pathname, inputs=[
154
- # uploaded_files, data, openai_api_key], outputs=[stats, data, dataset, buildb])
155
- # download.click(fn=download_repo, inputs=[
156
- # gh_repo, data, openai_api_key], outputs=[stats, data, dataset, buildb])
157
- # query = gr.Textbox(
158
- # placeholder="Enter your question here...", label="Question")
159
- # with gr.Row():
160
- # length = gr.Slider(25, 200, value=100, step=5,
161
- # label='Words in answer')
162
- # marg = gr.Checkbox(True, label='Max marginal relevance')
163
- # k = gr.Slider(1, 20, value=10, step=1,
164
- # label='Chunks to examine')
165
- # sources = gr.Slider(1, 10, value=5, step=1,
166
- # label='Contexts to include')
167
-
168
- # ask = gr.Button("Ask Question")
169
- # answer = gr.Markdown(label="Answer")
170
- # with gr.Accordion("Context", open=True):
171
- # context = gr.Markdown(label="Context")
172
-
173
- # with gr.Accordion("Raw Text", open=False):
174
- # passages = gr.Markdown(label="Passages")
175
- # ask.click(fn=do_ask, inputs=[query, buildb,
176
- # openai_api_key, dataset,
177
- # length, marg, k, sources,
178
- # docs], outputs=[answer, context, passages, docs, stats])
179
-
180
  demo.queue(concurrency_count=10, api_open=False)
181
  demo.launch()
 
15
  Messages,
16
  )
17
 
18
+ load_dotenv()
19
 
20
  css_style = Path('./style.css').read_text()
21
 
 
30
 
31
  with gr.Row():
32
  gr.Markdown("""
33
+ <h2>
34
+ <img src='file/assets/zotero-logo.png' alt="Zotero Logo" style="width: 3.2rem; display: inline; margin-right: 10px;" />
35
+ Zotero Q&A
36
+ </h2>
37
 
38
+ Fan Li ([@FanLi_RnD](https://twitter.com/FanLi_RnD)) - https://apex974.com/articles/literature-reviews-with-paper-qa-and-zotero
39
+
40
+ This tool allows you to ask questions based on your Zotero library. It was built upon [Paper QA](https://github.com/whitead/paper-qa), [LangChain AI](https://github.com/hwchase17/langchain) and [pyZotero](https://github.com/urschrei/pyzotero).
41
+ """)
42
 
43
  with gr.Row():
44
  with gr.Column(scale=1):
 
57
  zot_selected_col = gr.Radio(
58
  [], label="Zotero Collection", elem_id="zotero-collection", visible=False)
59
  zot_msg = gr.HTML("""
60
+ <div style="padding: 1rem; background-color: #fffbe7; font-size: 0.8rem;">
61
+ <ul style="margin-bottom: 0;">
62
+ <li>Click <a href="https://www.zotero.org/settings/keys/new" target="_blank">here</a> to create Zotero API key.</li>
63
+ <li>To access your own library, select "User".</li>
64
+ <li>To access a shared group, select "Group".</li>
65
+ <li>Personal User ID can be found <a href="https://www.zotero.org/settings/keys" target="_blank">here</a>.</li>
66
+ <li style="margin-bottom: 0;">Group ID is part of the group URL (e.g. 4952526).</li>
67
+ </ul>
68
+ </div>
69
+ """, visible=True)
70
  zot_fetch_col_btn = gr.Button('Fetch Collections')
71
 
72
  gr.Error("Some Error Message")
 
74
  with gr.Column(scale=3):
75
 
76
  question = gr.Textbox(
77
+ placeholder="You have to select a Zotero collection to proceed", label="Question", interactive=False)
78
 
79
  gr.HTML()
80
 
 
89
 
90
  zot_api_key.change(
91
  reset_collection,
92
+ inputs=[messages],
93
+ outputs=[zot_selected_col, zot_fetch_col_btn,
94
+ question, answer, messages, msg_board, zot_selected_col],
95
  show_progress=False,
96
  )
97
  zot_library_type.change(
98
  reset_collection,
99
+ inputs=[messages],
100
+ outputs=[zot_selected_col, zot_fetch_col_btn,
101
+ question, answer, messages, msg_board, zot_selected_col],
102
  show_progress=False,
103
  )
104
  zot_library_id.change(
105
  reset_collection,
106
+ inputs=[messages],
107
+ outputs=[zot_selected_col, zot_fetch_col_btn,
108
+ question, answer, messages, msg_board, zot_selected_col],
109
  show_progress=False
110
  )
111
 
 
131
  show_progress=False
132
  )
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  demo.queue(concurrency_count=10, api_open=False)
135
  demo.launch()
functions.py CHANGED
@@ -146,13 +146,18 @@ def download_attachment(id, type, key, attachment):
146
  f'Unsupported link mode: {link_mode} for {attachment["key"]}.')
147
 
148
 
149
- def reset_collection():
 
 
150
  return (
151
  gr.Radio.update(choices=[], visible=False),
152
  gr.HTML.update(visible=True),
153
  gr.Text.update(
154
  placeholder="You have to select a Zotero collection to proceed", interactive=False),
155
- gr.HTML.update(value=None)
 
 
 
156
  )
157
 
158
 
@@ -268,7 +273,7 @@ def handle_submit(zot, collection_name, collections, question, messages):
268
  None,
269
  )
270
 
271
- # Index attachments
272
  available_attachments = 0
273
  for attachment in attachments:
274
  try:
@@ -282,7 +287,7 @@ def handle_submit(zot, collection_name, collections, question, messages):
282
  temp_file.flush()
283
  docs.add(temp_file.name, citation_dict[attachment["key"]])
284
  messages.append(Message(
285
- Icons.INDEX, f"Indexed PDF attachment: <a href='{attachment['links']['alternate']['href']}' target='_blank'>{attachment['data']['title']}</a>."))
286
  available_attachments += 1
287
  else:
288
  messages.append(Message(
@@ -312,18 +317,28 @@ def handle_submit(zot, collection_name, collections, question, messages):
312
  )
313
  return None, None, None
314
  if docs._faiss_index is None:
315
- messages.append(Message(
316
- Icons.WAIT, f"Building vector index based on {available_attachments} available PDF {'attachment' if attachments==1 else 'attachments'}"))
317
- yield (
318
- messages,
319
- gr.HTML.update(value=str(messages)),
320
- None,
321
- )
322
- docs._build_faiss_index()
 
 
 
 
 
 
 
 
 
 
323
 
324
  # Synthesize response
325
  messages.append(Message(
326
- Icons.WAIT, f"Creating answer. This will loop through all available PDF {'attachment' if attachments==1 else 'attachments'} and may take {'a few' if available_attachments > 2 else 'a couple of'} minutes."))
327
  yield (
328
  messages,
329
  gr.HTML.update(value=str(messages)),
@@ -335,7 +350,7 @@ def handle_submit(zot, collection_name, collections, question, messages):
335
  for i, answer in enumerate(docs.query_gen(question)):
336
  end_time = time.time()
337
  time_dif = end_time - start_time
338
- if time_dif > 5:
339
  start_time = end_time
340
  total_time += time_dif
341
  messages.append(Message(
@@ -345,18 +360,21 @@ def handle_submit(zot, collection_name, collections, question, messages):
345
  gr.HTML.update(value=str(messages)),
346
  None,
347
  )
348
- answer_text = '\n'.join(
349
- [f"<div>{x}</div>" for x in answer.answer.split('\n')])
350
- references = '\n'.join([f"<li>{x.split('.', 1)[1]}</li>"
351
- for x in answer.references.split('\n\n')])
 
 
 
 
 
 
352
  formatted_answer = f"""
353
  <div>{answer_text}</div>
354
 
355
- <h4 style="font-size: 1rem;">References:</h4>
356
- <ol>
357
  {references}
358
- </ol>
359
-
360
  <div>Tokens Used: {answer.tokens} Cost: ${answer.tokens/1000 * 0.002:.2f}</div>
361
  """.strip()
362
  messages.append(Message(
 
146
  f'Unsupported link mode: {link_mode} for {attachment["key"]}.')
147
 
148
 
149
+ def reset_collection(messages):
150
+ messages.set([Message(
151
+ Icons.INFO, "Please provide all the required OpenAI and Zotero information in the left panel.")])
152
  return (
153
  gr.Radio.update(choices=[], visible=False),
154
  gr.HTML.update(visible=True),
155
  gr.Text.update(
156
  placeholder="You have to select a Zotero collection to proceed", interactive=False),
157
+ gr.HTML.update(value=None),
158
+ messages,
159
+ gr.HTML.update(value=str(messages)),
160
+ None
161
  )
162
 
163
 
 
273
  None,
274
  )
275
 
276
+ # Load attachments
277
  available_attachments = 0
278
  for attachment in attachments:
279
  try:
 
287
  temp_file.flush()
288
  docs.add(temp_file.name, citation_dict[attachment["key"]])
289
  messages.append(Message(
290
+ Icons.INDEX, f"Loaded PDF attachment: <a href='{attachment['links']['alternate']['href']}' target='_blank'>{attachment['data']['title']}</a>."))
291
  available_attachments += 1
292
  else:
293
  messages.append(Message(
 
317
  )
318
  return None, None, None
319
  if docs._faiss_index is None:
320
+ try:
321
+ messages.append(Message(
322
+ Icons.WAIT, f"Building vector index based on {available_attachments} available PDF {'attachment' if available_attachments==1 else 'attachments'}."))
323
+ yield (
324
+ messages,
325
+ gr.HTML.update(value=str(messages)),
326
+ None,
327
+ )
328
+ docs._build_faiss_index()
329
+ except Exception as e:
330
+ messages.append(Message(
331
+ Icons.ERR, f"Unable to build vector index: {e}"))
332
+ yield (
333
+ messages,
334
+ gr.HTML.update(value=str(messages)),
335
+ None,
336
+ )
337
+ return None, None, None
338
 
339
  # Synthesize response
340
  messages.append(Message(
341
+ Icons.WAIT, f"""Creating answer. {"This should be done within a minute." if available_attachments==1 else "This will loop through all available PDF attachments and may take a couple of minutes."}."""))
342
  yield (
343
  messages,
344
  gr.HTML.update(value=str(messages)),
 
350
  for i, answer in enumerate(docs.query_gen(question)):
351
  end_time = time.time()
352
  time_dif = end_time - start_time
353
+ if time_dif > 15:
354
  start_time = end_time
355
  total_time += time_dif
356
  messages.append(Message(
 
360
  gr.HTML.update(value=str(messages)),
361
  None,
362
  )
363
+ answer_text = "\n".join(
364
+ [f"<div>{x}</div>" for x in answer.answer.split("\n")])
365
+ reference_list = "" if answer.references == "" else "\n".join([f"<li>{x.split('.', 1)[1]}</li>"
366
+ for x in answer.references.split('\n\n')])
367
+ references = "" if reference_list == "" else f"""
368
+ <h4 style="font-size: 1rem;">References:</h4>
369
+ <ol>
370
+ {reference_list}
371
+ </ol>
372
+ """
373
  formatted_answer = f"""
374
  <div>{answer_text}</div>
375
 
 
 
376
  {references}
377
+
 
378
  <div>Tokens Used: {answer.tokens} Cost: ${answer.tokens/1000 * 0.002:.2f}</div>
379
  """.strip()
380
  messages.append(Message(
style.css CHANGED
@@ -8,7 +8,7 @@
8
  }
9
 
10
  .zotero-link {
11
- font-size: 0.75rem;
12
  color: #2d7ea9;
13
  }
14
 
 
8
  }
9
 
10
  .zotero-link {
11
+ font-size: 0.85rem;
12
  color: #2d7ea9;
13
  }
14