davanstrien HF staff commited on
Commit
26dad3e
1 Parent(s): 3205980

refactor to use api

Browse files
Files changed (1) hide show
  1. app.py +128 -44
app.py CHANGED
@@ -9,6 +9,7 @@ from huggingface_hub import CommitScheduler
9
  from dotenv import load_dotenv
10
  import os
11
  from functools import lru_cache
 
12
 
13
  load_dotenv()
14
 
@@ -95,57 +96,127 @@ def format_comment(result: str):
95
  return result
96
 
97
 
 
 
 
98
  def post_comment(
99
- paper_url: str, comment: str, token: str | None = None, base_url: str | None = None
100
- ) -> bool:
101
- if not base_url:
102
- base_url = "https://huggingface.co"
103
- paper_id = paper_url.split("/")[-1]
104
- url = f"{base_url}/api/papers/{paper_id}/comment"
105
- comment_data = {"comment": comment}
106
- headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
107
- response = requests.post(url, json=comment_data, headers=headers)
108
- if response.status_code == 201:
109
- print(f"Comment posted successfully for {paper_url}!")
110
- return True
111
- else:
112
- print(f"Failed to post comment! (Status Code: {response.status_code})")
113
- print(response.text)
114
- return False
115
-
116
-
117
- @lru_cache(maxsize=500)
118
- def is_comment_from_librarian_bot(html: str) -> bool:
119
  """
120
- Checks if the given HTML contains a comment from the librarian-bot.
121
 
122
  Args:
123
- html (str): The HTML content to check.
 
 
 
124
 
125
  Returns:
126
- bool: True if a comment from the librarian-bot is found, False otherwise.
 
 
 
 
 
127
  """
128
- soup = BeautifulSoup(html, "lxml")
129
- librarian_bot_links = soup.find_all("a", string="librarian-bot")
130
- return any(librarian_bot_links)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
 
133
- def check_if_lib_bot_comment_exists(paper_url: str) -> bool:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  """
135
- Checks if a comment from the librarian bot exists for a given paper URL.
136
 
137
  Args:
138
- paper_url (str): The URL of the paper.
139
 
140
  Returns:
141
- bool: True if a comment from the librarian bot exists, False otherwise.
 
 
 
 
 
142
  """
143
  try:
144
- resp = client.get(paper_url)
145
- return is_comment_from_librarian_bot(resp.text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  except Exception as e:
147
  print(f"Error checking if comment exists for {paper_url}: {e}")
148
- return True # default to not posting comment
149
 
150
 
151
  def log_comments(paper_url: str, comment: str):
@@ -168,22 +239,34 @@ def log_comments(paper_url: str, comment: str):
168
  json.dump(data, f)
169
 
170
 
171
- def return_recommendations(url: str, post_to_paper: bool = True) -> str:
 
 
172
  arxiv_id = parse_arxiv_id_from_paper_url(url)
173
  recommendations = get_recommendations_from_semantic_scholar(f"ArXiv:{arxiv_id}")
174
  filtered_recommendations = filter_recommendations(recommendations)
175
  if post_to_paper:
176
- if comment_already_exists := check_if_lib_bot_comment_exists(url):
177
- gr.Info(
178
- f"Existing comment: {comment_already_exists}...skipping posting comment"
179
- )
180
  else:
181
  comment = format_comment(
182
  format_recommendation_into_markdown(arxiv_id, filtered_recommendations)
183
  )
184
- if comment_status := post_comment(url, comment, token=HF_TOKEN):
185
- log_comments(url, comment)
186
- gr.Info(f"Comment status: {comment_status}")
 
 
 
 
 
 
 
 
 
 
 
187
  else:
188
  gr.Info("Failed to post comment")
189
  return format_recommendation_into_markdown(arxiv_id, filtered_recommendations)
@@ -196,14 +279,15 @@ description = (
196
  " yet if they are new or have not been indexed by Semantic Scholar."
197
  )
198
  examples = [
199
- ["https://huggingface.co/papers/2309.12307", False],
200
- ["https://huggingface.co/papers/2211.10086", False],
201
  ]
202
  interface = gr.Interface(
203
  return_recommendations,
204
  [
205
  gr.Textbox(lines=1),
206
- gr.Checkbox(label="Post recommendations to Paper page?", default=False),
 
207
  ],
208
  gr.Markdown(),
209
  examples=examples,
 
9
  from dotenv import load_dotenv
10
  import os
11
  from functools import lru_cache
12
+ from typing import Tuple
13
 
14
  load_dotenv()
15
 
 
96
  return result
97
 
98
 
99
+ from typing import Tuple
100
+
101
+
102
  def post_comment(
103
+ paper_url: str, comment: str, comment_id: str | None = None, token: str = HF_TOKEN
104
+ ) -> Tuple[bool, str]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  """
106
+ Post a comment on a paper or a reply to a comment using the Hugging Face API.
107
 
108
  Args:
109
+ paper_url (str): The URL of the paper to post the comment on.
110
+ comment (str): The text of the comment or reply to post.
111
+ comment_id (str, optional): The ID of the comment to reply to. If provided, the function will post a reply to the specified comment. Defaults to None.
112
+ token (str, optional): The authentication token to use for the API request. Defaults to HF_TOKEN.
113
 
114
  Returns:
115
+ Tuple[bool, str]: A tuple containing two elements:
116
+ - bool: True if the comment or reply was posted successfully, False otherwise.
117
+ - str: The ID of the posted comment or reply if successful, an empty string otherwise.
118
+
119
+ Raises:
120
+ requests.exceptions.RequestException: If an error occurs while making the API request.
121
  """
122
+ try:
123
+ paper_id = paper_url.split("/")[-1]
124
+ if comment_id:
125
+ url = f"https://huggingface.co/api/papers/{paper_id}/comment/{comment_id}/reply"
126
+ else:
127
+ url = f"https://huggingface.co/api/papers/{paper_id}/comment"
128
+
129
+ headers = {
130
+ "Authorization": f"Bearer {token}",
131
+ "Content-Type": "application/json",
132
+ }
133
+ comment_data = {"comment": comment}
134
+
135
+ response = requests.post(url, json=comment_data, headers=headers)
136
+
137
+ if response.status_code == 201:
138
+ posted_comment_id = response.json().get("id", "")
139
+ if comment_id:
140
+ print(
141
+ f"Reply posted successfully to comment {comment_id} for {paper_url}. Reply ID: {posted_comment_id}"
142
+ )
143
+ else:
144
+ print(
145
+ f"Comment posted successfully for {paper_url}. Comment ID: {posted_comment_id}"
146
+ )
147
+ return True, posted_comment_id
148
+ else:
149
+ print(
150
+ f"Failed to post {'reply' if comment_id else 'comment'} for {paper_url}. Status code: {response.status_code}"
151
+ )
152
+ print(f"Response text: {response.text}")
153
+ return False, ""
154
+
155
+ except requests.exceptions.RequestException as e:
156
+ print(
157
+ f"Error posting {'reply' if comment_id else 'comment'} for {paper_url}: {e}"
158
+ )
159
+ return False, ""
160
 
161
 
162
+ # @lru_cache(maxsize=500)
163
+ # def is_comment_from_librarian_bot(html: str) -> bool:
164
+ # """
165
+ # Checks if the given HTML contains a comment from the librarian-bot.
166
+
167
+ # Args:
168
+ # html (str): The HTML content to check.
169
+
170
+ # Returns:
171
+ # bool: True if a comment from the librarian-bot is found, False otherwise.
172
+ # """
173
+ # soup = BeautifulSoup(html, "lxml")
174
+ # librarian_bot_links = soup.find_all("a", string="librarian-bot")
175
+ # return any(librarian_bot_links)
176
+
177
+
178
+ def check_if_lib_bot_comment_exists(paper_url: str) -> Tuple[bool, str]:
179
  """
180
+ Check if a comment or reply from the librarian-bot exists for a given paper URL using the Hugging Face API.
181
 
182
  Args:
183
+ paper_url (str): The URL of the paper to check for librarian-bot comments.
184
 
185
  Returns:
186
+ Tuple[bool, str]: A tuple containing two elements:
187
+ - bool: True if a comment or reply from the librarian-bot is found, False otherwise.
188
+ - str: The ID of the comment if a librarian-bot comment is found, an empty string otherwise.
189
+
190
+ Raises:
191
+ Exception: If an error occurs while retrieving comments from the API.
192
  """
193
  try:
194
+ paper_id = paper_url.split("/")[-1]
195
+ url = f"https://huggingface.co/api/papers/{paper_id}/?field=comments"
196
+ headers = {"Authorization": f"Bearer {HF_TOKEN}"}
197
+ response = requests.get(url, headers=headers)
198
+
199
+ if response.status_code == 200:
200
+ paper_data = response.json()
201
+ comments = paper_data.get("comments", [])
202
+ for comment in comments:
203
+ comment_author = comment.get("author", {}).get("name")
204
+ if comment_author == "librarian-bot":
205
+ return True, comment.get("id")
206
+ replies = comment.get("replies", [])
207
+ for reply in replies:
208
+ reply_author = reply.get("author", {}).get("name")
209
+ if reply_author == "librarian-bot":
210
+ return True, comment.get("id")
211
+ else:
212
+ print(
213
+ f"Failed to retrieve comments for {paper_url}. Status code: {response.status_code}"
214
+ )
215
+
216
+ return False, ""
217
  except Exception as e:
218
  print(f"Error checking if comment exists for {paper_url}: {e}")
219
+ return True, "" # default to not posting comment
220
 
221
 
222
  def log_comments(paper_url: str, comment: str):
 
239
  json.dump(data, f)
240
 
241
 
242
+ def return_recommendations(
243
+ url: str, comment_id: str | None = None, post_to_paper: bool = True
244
+ ) -> str:
245
  arxiv_id = parse_arxiv_id_from_paper_url(url)
246
  recommendations = get_recommendations_from_semantic_scholar(f"ArXiv:{arxiv_id}")
247
  filtered_recommendations = filter_recommendations(recommendations)
248
  if post_to_paper:
249
+ existing_comments, comment_id = check_if_lib_bot_comment_exists(url)
250
+ if existing_comments:
251
+ gr.Info(f"Existing comment: {comment_id}...skipping posting comment")
 
252
  else:
253
  comment = format_comment(
254
  format_recommendation_into_markdown(arxiv_id, filtered_recommendations)
255
  )
256
+ if comment_id:
257
+ comment_status, posted_comment_id = post_comment(
258
+ url, comment, comment_id, token=HF_TOKEN
259
+ )
260
+ if comment_status:
261
+ log_comments(url, comment)
262
+ gr.Info(f"Posted reply to comment {posted_comment_id}")
263
+ if not comment_id:
264
+ comment_status, posted_comment_id = post_comment(
265
+ url, comment, token=HF_TOKEN
266
+ )
267
+ if comment_status:
268
+ log_comments(url, comment)
269
+ gr.Info(f"Posted comment {posted_comment_id}")
270
  else:
271
  gr.Info("Failed to post comment")
272
  return format_recommendation_into_markdown(arxiv_id, filtered_recommendations)
 
279
  " yet if they are new or have not been indexed by Semantic Scholar."
280
  )
281
  examples = [
282
+ ["https://huggingface.co/papers/2309.12307", None, False],
283
+ ["https://huggingface.co/papers/2211.10086", None, False],
284
  ]
285
  interface = gr.Interface(
286
  return_recommendations,
287
  [
288
  gr.Textbox(lines=1),
289
+ gr.Textbox(None, lines=1, label="Comment ID (if replying to a comment)"),
290
+ gr.Checkbox(False, label="Post recommendations to Paper page?"),
291
  ],
292
  gr.Markdown(),
293
  examples=examples,