davanstrien HF staff commited on
Commit
5cc903d
·
1 Parent(s): 37cc5fa

async version

Browse files
Files changed (2) hide show
  1. app.py +120 -123
  2. requirements.txt +167 -23
app.py CHANGED
@@ -1,98 +1,73 @@
 
1
  import copy
2
  import os
3
  from dataclasses import asdict, dataclass
4
  from datetime import datetime, timedelta
5
- from functools import lru_cache
6
  from json import JSONDecodeError
7
  from typing import Any, Dict, List, Optional, Union
8
-
9
- import backoff
10
  import gradio as gr
11
  import httpx
12
  import orjson
13
- import requests
14
- from cachetools import TTLCache, cached
15
- from httpx import Client
16
- from httpx_caching import CachingClient, OneDayCacheHeuristic
17
- # from diskcache import Cache
18
- from huggingface_hub import (HfApi, hf_hub_url, list_repo_commits, logging,
19
- model_info)
20
- from huggingface_hub.utils import (EntryNotFoundError, GatedRepoError,
21
- disable_progress_bars)
22
- from requests.exceptions import HTTPError
23
  from tqdm.auto import tqdm
24
- from tqdm.contrib.concurrent import thread_map
25
-
26
- cache = TTLCache(maxsize=500_000, ttl=timedelta(hours=24), timer=datetime.now)
27
-
28
- client = Client()
29
-
30
-
31
- client = CachingClient(client, heuristic=OneDayCacheHeuristic())
32
 
 
 
 
33
 
34
- # CACHE_DIR = "./cache" if platform == "darwin" else "/data/"
35
 
36
  disable_progress_bars()
37
 
38
  logging.set_verbosity_error()
39
 
40
  token = os.getenv("HF_TOKEN")
41
-
42
- # cache = Cache(CACHE_DIR)
43
 
44
 
45
- def get_model_labels(model):
46
  try:
47
  url = hf_hub_url(repo_id=model, filename="config.json")
48
- return list(requests.get(url).json()["label2id"].keys())
 
49
  except (KeyError, JSONDecodeError, AttributeError):
50
  return None
51
 
52
 
53
- @dataclass
54
- class EngagementStats:
55
- likes: int
56
- downloads: int
57
- created_at: datetime
58
-
59
-
60
- def _get_engagement_stats(hub_id):
61
- api = HfApi(token=token)
62
- repo = api.repo_info(hub_id)
63
- return EngagementStats(
64
- likes=repo.likes,
65
- downloads=repo.downloads,
66
- created_at=list_repo_commits(hub_id, repo_type="model")[-1].created_at,
67
- )
68
-
69
-
70
- def _try_load_model_card(hub_id):
71
  try:
72
  url = hf_hub_url(
73
  repo_id=hub_id, filename="README.md"
74
  ) # We grab card this way rather than via client library to improve performance
75
- card_text = client.get(url).text
76
- length = len(card_text)
77
- except EntryNotFoundError:
78
- card_text = None
79
- length = None
80
- except (
81
- GatedRepoError
82
- ): # TODO return different values to reflect gating rather than no card
83
  card_text = None
84
  length = None
85
  return card_text, length
86
 
87
-
88
- def _try_parse_card_data(hub_id):
89
  data = {}
90
- keys = ["license", "language", "datasets", "tags"]
91
  for key in keys:
92
- try:
93
- value = model_info(hub_id, token=token).cardData[key]
94
- data[key] = value
95
- except (KeyError, AttributeError):
 
 
96
  data[key] = None
97
  return data
98
 
@@ -107,39 +82,46 @@ class ModelMetadata:
107
  pipeline_tag: Optional[str]
108
  labels: Optional[List[str]]
109
  languages: Optional[Union[str, List[str]]]
110
- engagement_stats: Optional[EngagementStats] = None
111
  model_card_text: Optional[str] = None
112
  model_card_length: Optional[int] = None
 
 
 
113
 
114
  @classmethod
115
- def from_hub(cls, hub_id):
 
116
  try:
117
- model = model_info(hub_id)
118
- except (GatedRepoError, HTTPError):
119
- return None # TODO catch gated repos and handle properly
120
- card_text, length = _try_load_model_card(hub_id)
121
- data = _try_parse_card_data(hub_id)
122
- try:
123
- library_name = model.library_name
124
- except AttributeError:
125
- library_name = None
126
- try:
127
- pipeline_tag = model.pipeline_tag
128
- except AttributeError:
129
- pipeline_tag = None
130
- return ModelMetadata(
131
- hub_id=hub_id,
132
- languages=data["language"],
133
- tags=data["tags"],
134
- license=data["license"],
135
- library_name=library_name,
136
- datasets=data["datasets"],
137
- pipeline_tag=pipeline_tag,
138
- labels=get_model_labels(hub_id),
139
- engagement_stats=_get_engagement_stats(hub_id),
140
- model_card_text=card_text,
141
- model_card_length=length,
142
- )
 
 
 
 
143
 
144
 
145
  COMMON_SCORES = {
@@ -242,7 +224,6 @@ ALL_PIPELINES = {
242
  }
243
 
244
 
245
- @lru_cache(maxsize=None)
246
  def generate_task_scores_dict():
247
  task_scores = {}
248
  for task in ALL_PIPELINES:
@@ -281,7 +262,6 @@ def generate_task_scores_dict():
281
  return task_scores
282
 
283
 
284
- @lru_cache(maxsize=None)
285
  def generate_common_scores():
286
  GENERIC_SCORES = copy.deepcopy(COMMON_SCORES)
287
  GENERIC_SCORES["_max_score"] = sum(
@@ -294,13 +274,11 @@ SCORES = generate_task_scores_dict()
294
  GENERIC_SCORES = generate_common_scores()
295
 
296
 
297
- # @cache.memoize(expire=60 * 60 * 24 * 3) # expires after 3 days
298
- @cached(cache)
299
- def _basic_check(hub_id):
300
- data = ModelMetadata.from_hub(hub_id)
301
  score = 0
302
  if data is None:
303
  return None
 
304
  to_fix = {}
305
  if task := data.pipeline_tag:
306
  task_scores = SCORES[task]
@@ -356,38 +334,48 @@ def create_query_url(query, skip=0):
356
  return f"https://huggingface.co/api/search/full-text?q={query}&limit=100&skip={skip}&type=model"
357
 
358
 
359
- @cached(cache)
360
- def get_results(query) -> Dict[Any, Any]:
 
361
  url = create_query_url(query)
362
- r = client.get(url)
363
  return r.json()
364
 
365
 
366
- @backoff.on_exception(
367
- backoff.expo,
368
- Exception,
369
- max_time=2,
370
- raise_on_giveup=False,
371
- )
372
  def parse_single_result(result):
373
  name, filename = result["name"], result["fileName"]
374
  search_result_file_url = hf_hub_url(name, filename)
375
  repo_hub_url = f"https://huggingface.co/{name}"
376
- score = _basic_check(name)
377
- if score is None:
378
- return None
379
- score = orjson.loads(score)
380
  return {
381
  "name": name,
382
  "search_result_file_url": search_result_file_url,
383
  "repo_hub_url": repo_hub_url,
384
- "metadata_score": score["score"],
385
- "model_card_length": score["model_card_length"],
386
- "is_licensed": bool(score["license"]),
387
- # "metadata_report": score
388
  }
389
 
390
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
  def filter_for_license(results):
392
  for result in results:
393
  if result["is_licensed"]:
@@ -406,7 +394,7 @@ def filter_search_results(
406
  min_model_card_length=None,
407
  ): # TODO make code more intuitive
408
  # TODO setup filters as separate functions and chain results
409
- results = thread_map(parse_single_result, results)
410
  for i, parsed_result in tqdm(enumerate(results)):
411
  # parsed_result = parse_single_result(result)
412
  if parsed_result is None:
@@ -418,6 +406,7 @@ def filter_search_results(
418
  or min_score is None
419
  and min_model_card_length is None
420
  ):
 
421
  yield parsed_result
422
  elif min_score is not None:
423
  if parsed_result["metadata_score"] <= min_score:
@@ -472,22 +461,36 @@ def create_markdown(results): # TODO move to separate file
472
  rows.append(row)
473
  return "\n".join(rows)
474
 
475
-
476
- def get_result_card_snippet(result):
 
477
  try:
478
- result_text = httpx.get(result["search_result_file_url"]).text
 
479
  result["text"] = find_context(result_text, query, 100)
480
  except httpx.ConnectError:
481
  result["text"] = "Could not load model card"
482
  return result
483
 
484
- @cached(cache)
 
 
 
 
 
 
 
 
 
 
 
 
485
  def _search_hub(
486
  query: str,
487
  min_score: Optional[int] = None,
488
  min_model_card_length: Optional[int] = None,
489
  ):
490
- results = get_results(query)
491
  print(f"Found {len(results['hits'])} results")
492
  results = results["hits"]
493
  number_original_results = len(results)
@@ -495,12 +498,7 @@ def _search_hub(
495
  results, min_score=min_score, min_model_card_length=min_model_card_length
496
  )
497
  filtered_results = sort_search_results(filtered_results)
498
- # final_results = []
499
- # for result in filtered_results:
500
- # result_text = httpx.get(result["search_result_file_url"]).text
501
- # result["text"] = find_context(result_text, query, 100)
502
- # final_results.append(result)
503
- final_results = thread_map(get_result_card_snippet, filtered_results)
504
  percent_of_original = round(
505
  len(final_results) / number_original_results * 100, ndigits=0
506
  )
@@ -510,7 +508,6 @@ def _search_hub(
510
  | {number_original_results} | {len(final_results)} | {percent_of_original}% |
511
 
512
  """
513
- print(final_results)
514
  return filtered_vs_og, create_markdown(final_results)
515
 
516
 
 
1
+ import asyncio
2
  import copy
3
  import os
4
  from dataclasses import asdict, dataclass
5
  from datetime import datetime, timedelta
 
6
  from json import JSONDecodeError
7
  from typing import Any, Dict, List, Optional, Union
 
 
8
  import gradio as gr
9
  import httpx
10
  import orjson
11
+ from cashews import NOT_NONE, cache
12
+ from httpx import AsyncClient
13
+ from huggingface_hub import hf_hub_url, logging
14
+ from huggingface_hub.utils import disable_progress_bars
15
+ from rich import print
 
 
 
 
 
16
  from tqdm.auto import tqdm
17
+ from httpx import Client
18
+ from datetime import datetime, timedelta
 
 
 
 
 
 
19
 
20
+ cache.setup(
21
+ "mem://"
22
+ )
23
 
 
24
 
25
  disable_progress_bars()
26
 
27
  logging.set_verbosity_error()
28
 
29
  token = os.getenv("HF_TOKEN")
30
+ headers = {"authorization": f"Bearer {token}"}
 
31
 
32
 
33
+ async def get_model_labels(model, client):
34
  try:
35
  url = hf_hub_url(repo_id=model, filename="config.json")
36
+ resp = await client.get(url, timeout=2)
37
+ return list(resp.json()["label2id"].keys())
38
  except (KeyError, JSONDecodeError, AttributeError):
39
  return None
40
 
41
 
42
+ async def _try_load_model_card(hub_id, client=None):
43
+ if not client:
44
+ client = AsyncClient(headers=headers)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  try:
46
  url = hf_hub_url(
47
  repo_id=hub_id, filename="README.md"
48
  ) # We grab card this way rather than via client library to improve performance
49
+ resp = await client.get(url)
50
+ if resp.status_code == 200:
51
+ card_text = resp.text
52
+ length = len(card_text)
53
+ elif resp.status_code == 404:
54
+ card_text = None
55
+ length = 0
56
+ except httpx.ConnectError:
57
  card_text = None
58
  length = None
59
  return card_text, length
60
 
61
+ def _try_parse_card_data(hub_json_data):
 
62
  data = {}
63
+ keys = ["license", "language", "datasets"]
64
  for key in keys:
65
+ if card_data := hub_json_data.get("cardData"):
66
+ try:
67
+ data[key] = card_data.get(key)
68
+ except (KeyError, AttributeError):
69
+ data[key] = None
70
+ else:
71
  data[key] = None
72
  return data
73
 
 
82
  pipeline_tag: Optional[str]
83
  labels: Optional[List[str]]
84
  languages: Optional[Union[str, List[str]]]
 
85
  model_card_text: Optional[str] = None
86
  model_card_length: Optional[int] = None
87
+ likes: Optional[int] = None
88
+ downloads: Optional[int] = None
89
+ created_at: Optional[datetime] = None
90
 
91
  @classmethod
92
+ @cache(ttl=timedelta(hours=3), condition=NOT_NONE)
93
+ async def from_hub(cls, hub_id, client=None):
94
  try:
95
+ if not client:
96
+ client = httpx.AsyncClient()
97
+ url = f"https://huggingface.co/api/models/{hub_id}"
98
+ resp = await client.get(url)
99
+ hub_json_data = resp.json()
100
+ card_text, length = await _try_load_model_card(hub_id)
101
+ data = _try_parse_card_data(hub_json_data)
102
+ library_name = hub_json_data.get("library_name")
103
+ pipeline_tag = hub_json_data.get("pipeline_tag")
104
+ downloads = hub_json_data.get("downloads")
105
+ likes = hub_json_data.get("likes")
106
+ tags = hub_json_data.get("tags")
107
+ labels = await get_model_labels(hub_id, client)
108
+ return ModelMetadata(
109
+ hub_id=hub_id,
110
+ languages=data["language"],
111
+ tags=tags,
112
+ license=data["license"],
113
+ library_name=library_name,
114
+ datasets=data["datasets"],
115
+ pipeline_tag=pipeline_tag,
116
+ labels=labels,
117
+ model_card_text=card_text,
118
+ downloads=downloads,
119
+ likes=likes,
120
+ model_card_length=length,
121
+ )
122
+ except Exception as e:
123
+ print(f"Failed to create ModelMetadata for model {hub_id}: {str(e)}")
124
+ return None
125
 
126
 
127
  COMMON_SCORES = {
 
224
  }
225
 
226
 
 
227
  def generate_task_scores_dict():
228
  task_scores = {}
229
  for task in ALL_PIPELINES:
 
262
  return task_scores
263
 
264
 
 
265
  def generate_common_scores():
266
  GENERIC_SCORES = copy.deepcopy(COMMON_SCORES)
267
  GENERIC_SCORES["_max_score"] = sum(
 
274
  GENERIC_SCORES = generate_common_scores()
275
 
276
 
277
+ def _basic_check(data: Optional[ModelMetadata]):
 
 
 
278
  score = 0
279
  if data is None:
280
  return None
281
+ hub_id = data.hub_id
282
  to_fix = {}
283
  if task := data.pipeline_tag:
284
  task_scores = SCORES[task]
 
334
  return f"https://huggingface.co/api/search/full-text?q={query}&limit=100&skip={skip}&type=model"
335
 
336
 
337
+ def get_results(query,sync_client=None) -> Dict[Any, Any]:
338
+ if not sync_client:
339
+ sync_client = Client(http2=True, headers=headers)
340
  url = create_query_url(query)
341
+ r = sync_client.get(url)
342
  return r.json()
343
 
344
 
 
 
 
 
 
 
345
  def parse_single_result(result):
346
  name, filename = result["name"], result["fileName"]
347
  search_result_file_url = hf_hub_url(name, filename)
348
  repo_hub_url = f"https://huggingface.co/{name}"
 
 
 
 
349
  return {
350
  "name": name,
351
  "search_result_file_url": search_result_file_url,
352
  "repo_hub_url": repo_hub_url,
 
 
 
 
353
  }
354
 
355
 
356
+ @cache(ttl=timedelta(hours=3), condition=NOT_NONE)
357
+ async def get_hub_models(results, client=None):
358
+ parsed_results = [parse_single_result(result) for result in results]
359
+ if not client:
360
+ client = AsyncClient(http2=True, headers=headers)
361
+ model_ids = [result["name"] for result in parsed_results]
362
+ model_objs = [ModelMetadata.from_hub(model, client=client) for model in model_ids]
363
+ models = await asyncio.gather(*model_objs)
364
+ results = []
365
+ for result, model in zip(parsed_results, models):
366
+ score = _basic_check(model)
367
+ # print(f"score for {model} is {score}")
368
+ if score is not None:
369
+ score = orjson.loads(score)
370
+ result["metadata_score"] = score["score"]
371
+ result["model_card_length"] = score["model_card_length"]
372
+ result["is_licensed"] = (bool(score["license"]),)
373
+ results.append(result)
374
+ else:
375
+ results.append(None)
376
+ return results
377
+
378
+
379
  def filter_for_license(results):
380
  for result in results:
381
  if result["is_licensed"]:
 
394
  min_model_card_length=None,
395
  ): # TODO make code more intuitive
396
  # TODO setup filters as separate functions and chain results
397
+ results = asyncio.run(get_hub_models(results))
398
  for i, parsed_result in tqdm(enumerate(results)):
399
  # parsed_result = parse_single_result(result)
400
  if parsed_result is None:
 
406
  or min_score is None
407
  and min_model_card_length is None
408
  ):
409
+ parsed_result["original_position"] = i
410
  yield parsed_result
411
  elif min_score is not None:
412
  if parsed_result["metadata_score"] <= min_score:
 
461
  rows.append(row)
462
  return "\n".join(rows)
463
 
464
+ async def get_result_card_snippet(result, query=None, client=None):
465
+ if not client:
466
+ client = AsyncClient(http2=True, headers=headers)
467
  try:
468
+ resp = await client.get(result["search_result_file_url"])
469
+ result_text = resp.text
470
  result["text"] = find_context(result_text, query, 100)
471
  except httpx.ConnectError:
472
  result["text"] = "Could not load model card"
473
  return result
474
 
475
+ @cache(ttl=timedelta(hours=3), condition=NOT_NONE)
476
+ async def get_result_card_snippets(results, query=None, client=None):
477
+ if not client:
478
+ client = AsyncClient(http2=True, headers=headers)
479
+ result_snippets = [
480
+ get_result_card_snippet(result, query=query, client=client)
481
+ for result in results
482
+ ]
483
+ results = await asyncio.gather(*result_snippets)
484
+ return results
485
+
486
+ sync_client = Client(http2=True, headers=headers)
487
+
488
  def _search_hub(
489
  query: str,
490
  min_score: Optional[int] = None,
491
  min_model_card_length: Optional[int] = None,
492
  ):
493
+ results = get_results(query, sync_client)
494
  print(f"Found {len(results['hits'])} results")
495
  results = results["hits"]
496
  number_original_results = len(results)
 
498
  results, min_score=min_score, min_model_card_length=min_model_card_length
499
  )
500
  filtered_results = sort_search_results(filtered_results)
501
+ final_results = asyncio.run(get_result_card_snippets(filtered_results, query=query))
 
 
 
 
 
502
  percent_of_original = round(
503
  len(final_results) / number_original_results * 100, ndigits=0
504
  )
 
508
  | {number_original_results} | {len(final_results)} | {percent_of_original}% |
509
 
510
  """
 
511
  return filtered_vs_og, create_markdown(final_results)
512
 
513
 
requirements.txt CHANGED
@@ -1,24 +1,36 @@
1
  #
2
- # This file is autogenerated by pip-compile with Python 3.11
3
  # by the following command:
4
  #
5
  # pip-compile --resolver=backtracking
6
  #
 
 
 
 
 
 
 
 
7
  anyio==3.7.0
8
  # via
9
  # httpcore
10
- # httpx-caching
11
  appnope==0.1.3
12
  # via
13
  # ipykernel
14
  # ipython
15
  asttokens==2.2.1
16
  # via stack-data
 
 
 
 
 
 
17
  backcall==0.2.0
18
  # via ipython
19
- backoff==2.2.1
20
- # via -r requirements.in
21
- cachetools==5.3.1
22
  # via -r requirements.in
23
  certifi==2023.5.7
24
  # via
@@ -27,35 +39,73 @@ certifi==2023.5.7
27
  # requests
28
  charset-normalizer==3.1.0
29
  # via
 
30
  # httpx
31
  # requests
 
 
32
  comm==0.1.3
33
  # via ipykernel
 
 
 
 
34
  debugpy==1.6.7
35
  # via ipykernel
36
  decorator==5.1.1
37
  # via ipython
 
 
38
  executing==1.2.0
39
  # via stack-data
 
 
 
 
40
  filelock==3.12.2
41
  # via huggingface-hub
 
 
 
 
 
 
42
  fsspec==2023.6.0
43
- # via huggingface-hub
 
 
 
 
 
 
44
  h11==0.12.0
45
- # via httpcore
 
 
 
 
 
 
46
  httpcore==0.14.7
47
  # via httpx
48
- httpx==0.22.0
49
- # via httpx-caching
50
- httpx-caching==0.1a2
51
- # via -r requirements.in
 
52
  huggingface-hub==0.15.1
53
- # via -r requirements.in
 
 
 
 
 
54
  idna==3.4
55
  # via
56
  # anyio
57
  # requests
58
  # rfc3986
 
59
  ipykernel==6.23.3
60
  # via ipywidgets
61
  ipython==8.14.0
@@ -66,6 +116,12 @@ ipywidgets==8.0.6
66
  # via -r requirements.in
67
  jedi==0.18.2
68
  # via ipython
 
 
 
 
 
 
69
  jupyter-client==8.3.0
70
  # via ipykernel
71
  jupyter-core==5.3.1
@@ -74,28 +130,66 @@ jupyter-core==5.3.1
74
  # jupyter-client
75
  jupyterlab-widgets==3.0.7
76
  # via ipywidgets
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  matplotlib-inline==0.1.6
78
  # via
79
  # ipykernel
80
  # ipython
81
- msgpack==1.0.5
82
- # via httpx-caching
83
- multimethod==1.9.1
84
- # via httpx-caching
 
 
 
 
85
  nest-asyncio==1.5.6
86
  # via ipykernel
 
 
 
 
 
 
 
87
  orjson==3.9.1
88
- # via -r requirements.in
 
 
89
  packaging==23.1
90
  # via
 
91
  # huggingface-hub
92
  # ipykernel
 
 
 
 
 
93
  parso==0.8.3
94
  # via jedi
95
  pexpect==4.8.0
96
  # via ipython
97
  pickleshare==0.7.5
98
  # via ipython
 
 
 
 
99
  platformdirs==3.8.0
100
  # via jupyter-core
101
  prompt-toolkit==3.0.38
@@ -106,20 +200,49 @@ ptyprocess==0.7.0
106
  # via pexpect
107
  pure-eval==0.2.2
108
  # via stack-data
 
 
 
 
 
 
109
  pygments==2.15.1
110
- # via ipython
 
 
 
 
 
 
 
111
  python-dateutil==2.8.2
112
- # via jupyter-client
 
 
 
 
 
 
 
113
  pyyaml==6.0
114
- # via huggingface-hub
 
 
115
  pyzmq==25.1.0
116
  # via
117
  # ipykernel
118
  # jupyter-client
119
  requests==2.31.0
120
- # via huggingface-hub
 
 
 
121
  rfc3986[idna2008]==1.5.0
122
  # via httpx
 
 
 
 
123
  six==1.16.0
124
  # via
125
  # asttokens
@@ -131,8 +254,12 @@ sniffio==1.3.0
131
  # httpx
132
  stack-data==0.6.2
133
  # via ipython
 
 
134
  toolz==0.12.0
135
- # via -r requirements.in
 
 
136
  tornado==6.3.2
137
  # via
138
  # ipykernel
@@ -151,10 +278,27 @@ traitlets==5.9.0
151
  # jupyter-core
152
  # matplotlib-inline
153
  typing-extensions==4.7.0
154
- # via huggingface-hub
 
 
 
 
 
 
 
 
 
155
  urllib3==2.0.3
156
  # via requests
 
 
157
  wcwidth==0.2.6
158
  # via prompt-toolkit
 
 
 
 
159
  widgetsnbextension==4.0.7
160
  # via ipywidgets
 
 
 
1
  #
2
+ # This file is autogenerated by pip-compile with Python 3.10
3
  # by the following command:
4
  #
5
  # pip-compile --resolver=backtracking
6
  #
7
+ aiofiles==23.1.0
8
+ # via gradio
9
+ aiohttp==3.8.4
10
+ # via gradio
11
+ aiosignal==1.3.1
12
+ # via aiohttp
13
+ altair==5.0.1
14
+ # via gradio
15
  anyio==3.7.0
16
  # via
17
  # httpcore
18
+ # starlette
19
  appnope==0.1.3
20
  # via
21
  # ipykernel
22
  # ipython
23
  asttokens==2.2.1
24
  # via stack-data
25
+ async-timeout==4.0.2
26
+ # via aiohttp
27
+ attrs==23.1.0
28
+ # via
29
+ # aiohttp
30
+ # jsonschema
31
  backcall==0.2.0
32
  # via ipython
33
+ cashews==6.2.0
 
 
34
  # via -r requirements.in
35
  certifi==2023.5.7
36
  # via
 
39
  # requests
40
  charset-normalizer==3.1.0
41
  # via
42
+ # aiohttp
43
  # httpx
44
  # requests
45
+ click==8.1.3
46
+ # via uvicorn
47
  comm==0.1.3
48
  # via ipykernel
49
+ contourpy==1.1.0
50
+ # via matplotlib
51
+ cycler==0.11.0
52
+ # via matplotlib
53
  debugpy==1.6.7
54
  # via ipykernel
55
  decorator==5.1.1
56
  # via ipython
57
+ exceptiongroup==1.1.1
58
+ # via anyio
59
  executing==1.2.0
60
  # via stack-data
61
+ fastapi==0.99.1
62
+ # via gradio
63
+ ffmpy==0.3.0
64
+ # via gradio
65
  filelock==3.12.2
66
  # via huggingface-hub
67
+ fonttools==4.40.0
68
+ # via matplotlib
69
+ frozenlist==1.3.3
70
+ # via
71
+ # aiohttp
72
+ # aiosignal
73
  fsspec==2023.6.0
74
+ # via
75
+ # gradio-client
76
+ # huggingface-hub
77
+ gradio==3.35.2
78
+ # via -r requirements.in
79
+ gradio-client==0.2.7
80
+ # via gradio
81
  h11==0.12.0
82
+ # via
83
+ # httpcore
84
+ # uvicorn
85
+ h2==4.1.0
86
+ # via httpx
87
+ hpack==4.0.0
88
+ # via h2
89
  httpcore==0.14.7
90
  # via httpx
91
+ httpx[http2]==0.22.0
92
+ # via
93
+ # -r requirements.in
94
+ # gradio
95
+ # gradio-client
96
  huggingface-hub==0.15.1
97
+ # via
98
+ # -r requirements.in
99
+ # gradio
100
+ # gradio-client
101
+ hyperframe==6.0.1
102
+ # via h2
103
  idna==3.4
104
  # via
105
  # anyio
106
  # requests
107
  # rfc3986
108
+ # yarl
109
  ipykernel==6.23.3
110
  # via ipywidgets
111
  ipython==8.14.0
 
116
  # via -r requirements.in
117
  jedi==0.18.2
118
  # via ipython
119
+ jinja2==3.1.2
120
+ # via
121
+ # altair
122
+ # gradio
123
+ jsonschema==4.17.3
124
+ # via altair
125
  jupyter-client==8.3.0
126
  # via ipykernel
127
  jupyter-core==5.3.1
 
130
  # jupyter-client
131
  jupyterlab-widgets==3.0.7
132
  # via ipywidgets
133
+ kiwisolver==1.4.4
134
+ # via matplotlib
135
+ linkify-it-py==2.0.2
136
+ # via markdown-it-py
137
+ markdown-it-py[linkify]==2.2.0
138
+ # via
139
+ # gradio
140
+ # mdit-py-plugins
141
+ # rich
142
+ markupsafe==2.1.3
143
+ # via
144
+ # gradio
145
+ # jinja2
146
+ matplotlib==3.7.1
147
+ # via gradio
148
  matplotlib-inline==0.1.6
149
  # via
150
  # ipykernel
151
  # ipython
152
+ mdit-py-plugins==0.3.3
153
+ # via gradio
154
+ mdurl==0.1.2
155
+ # via markdown-it-py
156
+ multidict==6.0.4
157
+ # via
158
+ # aiohttp
159
+ # yarl
160
  nest-asyncio==1.5.6
161
  # via ipykernel
162
+ numpy==1.25.0
163
+ # via
164
+ # altair
165
+ # contourpy
166
+ # gradio
167
+ # matplotlib
168
+ # pandas
169
  orjson==3.9.1
170
+ # via
171
+ # -r requirements.in
172
+ # gradio
173
  packaging==23.1
174
  # via
175
+ # gradio-client
176
  # huggingface-hub
177
  # ipykernel
178
+ # matplotlib
179
+ pandas==2.0.3
180
+ # via
181
+ # altair
182
+ # gradio
183
  parso==0.8.3
184
  # via jedi
185
  pexpect==4.8.0
186
  # via ipython
187
  pickleshare==0.7.5
188
  # via ipython
189
+ pillow==10.0.0
190
+ # via
191
+ # gradio
192
+ # matplotlib
193
  platformdirs==3.8.0
194
  # via jupyter-core
195
  prompt-toolkit==3.0.38
 
200
  # via pexpect
201
  pure-eval==0.2.2
202
  # via stack-data
203
+ pydantic==1.10.10
204
+ # via
205
+ # fastapi
206
+ # gradio
207
+ pydub==0.25.1
208
+ # via gradio
209
  pygments==2.15.1
210
+ # via
211
+ # gradio
212
+ # ipython
213
+ # rich
214
+ pyparsing==3.1.0
215
+ # via matplotlib
216
+ pyrsistent==0.19.3
217
+ # via jsonschema
218
  python-dateutil==2.8.2
219
+ # via
220
+ # jupyter-client
221
+ # matplotlib
222
+ # pandas
223
+ python-multipart==0.0.6
224
+ # via gradio
225
+ pytz==2023.3
226
+ # via pandas
227
  pyyaml==6.0
228
+ # via
229
+ # gradio
230
+ # huggingface-hub
231
  pyzmq==25.1.0
232
  # via
233
  # ipykernel
234
  # jupyter-client
235
  requests==2.31.0
236
+ # via
237
+ # gradio
238
+ # gradio-client
239
+ # huggingface-hub
240
  rfc3986[idna2008]==1.5.0
241
  # via httpx
242
+ rich==13.4.2
243
+ # via -r requirements.in
244
+ semantic-version==2.10.0
245
+ # via gradio
246
  six==1.16.0
247
  # via
248
  # asttokens
 
254
  # httpx
255
  stack-data==0.6.2
256
  # via ipython
257
+ starlette==0.27.0
258
+ # via fastapi
259
  toolz==0.12.0
260
+ # via
261
+ # -r requirements.in
262
+ # altair
263
  tornado==6.3.2
264
  # via
265
  # ipykernel
 
278
  # jupyter-core
279
  # matplotlib-inline
280
  typing-extensions==4.7.0
281
+ # via
282
+ # altair
283
+ # fastapi
284
+ # gradio-client
285
+ # huggingface-hub
286
+ # pydantic
287
+ tzdata==2023.3
288
+ # via pandas
289
+ uc-micro-py==1.0.2
290
+ # via linkify-it-py
291
  urllib3==2.0.3
292
  # via requests
293
+ uvicorn==0.22.0
294
+ # via gradio
295
  wcwidth==0.2.6
296
  # via prompt-toolkit
297
+ websockets==11.0.3
298
+ # via
299
+ # gradio
300
+ # gradio-client
301
  widgetsnbextension==4.0.7
302
  # via ipywidgets
303
+ yarl==1.9.2
304
+ # via aiohttp