nbroad HF staff commited on
Commit
37ba1ba
1 Parent(s): d89bb88

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +149 -0
app.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fasthtml.common import *
2
+ from datetime import datetime, timedelta
3
+ import requests
4
+ from datetime import datetime
5
+ import json
6
+
7
+ from dotenv import load_dotenv
8
+
9
+ loaded = load_dotenv("./.env", override=True)
10
+ print("Loaded .env file:", loaded)
11
+
12
+ API_URL = os.getenv("API_URL")
13
+ API_KEY = os.getenv("MS_SEARCH_KEY")
14
+
15
+
16
+ css_content = open("styles.css").read()
17
+
18
+ app, rt = fast_app(hdrs=(Style(css_content),))
19
+
20
+ def date_range_inputs(start_date, end_date):
21
+ return Div(
22
+ Input(type="date", name="start_date", value=start_date.strftime("%Y-%m-%d")),
23
+ Input(type="date", name="end_date", value=end_date.strftime("%Y-%m-%d")),
24
+ cls="date-range"
25
+ )
26
+
27
+ def search_form(start_date, end_date):
28
+ return Form(
29
+ Input(type="text", name="query", placeholder="Enter search query"),
30
+ date_range_inputs(start_date, end_date),
31
+ Button("Search", type="submit"),
32
+ hx_post="/search",
33
+ hx_target="#search-results",
34
+ hx_trigger="submit"
35
+ )
36
+
37
+ def iso_to_unix_timestamp(iso_string):
38
+ dt = datetime.fromisoformat(iso_string)
39
+ return int(dt.timestamp())
40
+
41
+ def unix_timestamp_to_iso(timestamp):
42
+ dt = datetime.fromtimestamp(timestamp)
43
+ return dt.isoformat()
44
+
45
+ def make_query(query, start_date, end_date, page=1, limit=10):
46
+ url = f"{API_URL}/indexes/comments/search"
47
+ headers = {
48
+ "Content-Type": "application/json",
49
+ "Authorization": f"Bearer {API_KEY}",
50
+ }
51
+
52
+ after_timestamp = iso_to_unix_timestamp(start_date)
53
+ before_timestamp = iso_to_unix_timestamp(end_date)
54
+
55
+ query = {
56
+ "q": query,
57
+ "limit": limit,
58
+ "offset": (page - 1) * limit,
59
+ "filter": f"comment_updatedAt_timestamp >= {after_timestamp} AND comment_updatedAt_timestamp < {before_timestamp}",
60
+ "attributesToCrop": ['comment_text'],
61
+ "cropLength": 30,
62
+ "attributesToHighlight": ["comment_text", "discussion_title"],
63
+ "highlightPreTag": "<span class=\"highlight\">",
64
+ "highlightPostTag": "</span>"
65
+ }
66
+
67
+ response = requests.post(url, headers=headers, json=query)
68
+
69
+ return response.json()
70
+
71
+ def search_results(query, start_date, end_date, page=1):
72
+ raw_results = make_query(query, start_date, end_date, page)
73
+
74
+ return Div(
75
+ make_results_bar(raw_results),
76
+ Div(*[make_card(r) for r in raw_results["hits"]]),
77
+ make_pagination(query, start_date, end_date, page, raw_results["estimatedTotalHits"]),
78
+ id="search-results"
79
+ )
80
+
81
+ def make_results_bar(results):
82
+ processing_time = results["processingTimeMs"]
83
+ estimated_hits = results["estimatedTotalHits"]
84
+ return Div(
85
+ Div(f"Processing time: {processing_time}ms"),
86
+ Div(f"Estimated total hits: {estimated_hits}"),
87
+ cls="results-bar"
88
+ )
89
+
90
+ def make_card(result):
91
+ result = result["_formatted"]
92
+ url = f"https://hf.co/{result['repo_id']}/discussions/{result['discussion_num']}"
93
+ date = unix_timestamp_to_iso(int(result["comment_updatedAt_timestamp"]))
94
+
95
+ return Div(
96
+ Div(
97
+ Strong(NotStr(result["discussion_title"])),
98
+ P(NotStr(result["comment_text"]), cls="comment-text"),
99
+ Span(date),
100
+ A(url, href=url, target="_blank"),
101
+ ),
102
+ cls="card-item"
103
+ )
104
+
105
+ def make_pagination(query, start_date, end_date, current_page, total_hits, limit=10):
106
+ total_pages = -(-total_hits // limit) # Ceiling division
107
+
108
+ pagination = Div(cls="pagination")
109
+
110
+ if current_page > 1:
111
+ pagination.children += tuple(
112
+ Button("Previous",
113
+ hx_post=f"/search?page={current_page-1}",
114
+ hx_target="#search-results",
115
+ hx_include="[name='query'], [name='start_date'], [name='end_date']")
116
+ )
117
+
118
+ pagination.children += tuple(Span(f"Page {current_page} of {total_pages}"))
119
+
120
+ if current_page < total_pages:
121
+ pagination.children += tuple(
122
+ Button("Next",
123
+ hx_post=f"/search?page={current_page+1}",
124
+ hx_target="#search-results",
125
+ hx_include="[name='query'], [name='start_date'], [name='end_date']",
126
+
127
+ )
128
+ )
129
+
130
+ return pagination
131
+
132
+ @rt("/")
133
+ def get():
134
+ end_date = datetime.now()
135
+ start_date = end_date - timedelta(days=7)
136
+ return Titled(
137
+ "HF Discussion Search",
138
+ Div(
139
+ search_form(start_date, end_date),
140
+ Div(id="search-results"),
141
+ cls="container"
142
+ )
143
+ )
144
+
145
+ @rt("/search")
146
+ def post(query: str, start_date: str, end_date: str, page: int = 1):
147
+ return search_results(query, start_date, end_date, page)
148
+
149
+ serve()