SanthiSastra commited on
Commit
ec27e62
Β·
verified Β·
1 Parent(s): 1abfbda

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +237 -0
app.py ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import datetime as dt
4
+ import pandas as pd
5
+ import gradio as gr
6
+
7
+ import gspread
8
+ from google.oauth2.service_account import Credentials
9
+
10
+
11
+ APP_TITLE = "SRC IPA (IDEA-PROMPT-APP) Workshop"
12
+
13
+ # =========================
14
+ # Google Sheets Helpers
15
+ # =========================
16
+ REQUIRED_ENV = ["GSPREAD_SERVICE_ACCOUNT_JSON", "GOOGLE_SHEET_ID"]
17
+
18
+
19
+ def _get_gspread_client():
20
+ missing = [k for k in REQUIRED_ENV if not os.getenv(k)]
21
+ if missing:
22
+ raise RuntimeError(
23
+ "Missing HF Secrets / Environment variables: " + ", ".join(missing) +
24
+ "\nAdd them in Space β†’ Settings β†’ Secrets."
25
+ )
26
+
27
+ sa_json_str = os.environ["GSPREAD_SERVICE_ACCOUNT_JSON"].strip()
28
+ sheet_id = os.environ["GOOGLE_SHEET_ID"].strip()
29
+
30
+ sa_info = json.loads(sa_json_str)
31
+
32
+ scopes = [
33
+ "https://www.googleapis.com/auth/spreadsheets",
34
+ "https://www.googleapis.com/auth/drive",
35
+ ]
36
+ creds = Credentials.from_service_account_info(sa_info, scopes=scopes)
37
+ client = gspread.authorize(creds)
38
+ sh = client.open_by_key(sheet_id)
39
+ return sh
40
+
41
+
42
+ def _ensure_worksheet(sh, ws_title="Responses"):
43
+ try:
44
+ ws = sh.worksheet(ws_title)
45
+ except gspread.WorksheetNotFound:
46
+ ws = sh.add_worksheet(title=ws_title, rows=2000, cols=20)
47
+
48
+ # Ensure header row exists
49
+ headers = [
50
+ "Timestamp(IST)",
51
+ "Name",
52
+ "ID",
53
+ "Department",
54
+ "SharableLink",
55
+ "BriefDescription",
56
+ "Feedback",
57
+ "SampleFileName",
58
+ "SampleFileType",
59
+ "SamplePreview(TopRowsOrText)",
60
+ ]
61
+
62
+ existing = ws.row_values(1)
63
+ if existing != headers:
64
+ # If sheet is empty, set headers; if mismatch but has content, do not overwrite silently.
65
+ if len(existing) == 0 and ws.get_all_values() == []:
66
+ ws.append_row(headers)
67
+ elif len(existing) == 0:
68
+ ws.insert_row(headers, index=1)
69
+ else:
70
+ # If existing header differs, add a new header row at top to avoid destroying data
71
+ ws.insert_row(headers, index=1)
72
+
73
+ return ws
74
+
75
+
76
+ def _ist_timestamp():
77
+ # Asia/Kolkata = UTC+5:30 (fixed offset for our use-case)
78
+ now_utc = dt.datetime.utcnow()
79
+ ist = now_utc + dt.timedelta(hours=5, minutes=30)
80
+ return ist.strftime("%Y-%m-%d %H:%M:%S")
81
+
82
+
83
+ def _file_preview(file_obj):
84
+ """
85
+ Returns (filename, filetype, preview_text)
86
+ For CSV/XLSX -> top few rows as TSV text.
87
+ For others -> store first ~1000 chars (if text) else blank.
88
+ """
89
+ if file_obj is None:
90
+ return "", "", ""
91
+
92
+ # Gradio gives a temp file path-like object with attributes
93
+ path = getattr(file_obj, "name", None) or str(file_obj)
94
+ filename = os.path.basename(path)
95
+ ext = os.path.splitext(filename)[1].lower().replace(".", "")
96
+
97
+ preview = ""
98
+ try:
99
+ if ext in ["csv"]:
100
+ df = pd.read_csv(path)
101
+ preview = df.head(8).to_csv(index=False)
102
+ elif ext in ["xlsx", "xls"]:
103
+ df = pd.read_excel(path)
104
+ preview = df.head(8).to_csv(index=False)
105
+ elif ext in ["txt", "md", "log"]:
106
+ with open(path, "r", encoding="utf-8", errors="ignore") as f:
107
+ preview = f.read(1200)
108
+ else:
109
+ preview = "" # for pdf/images/etc.
110
+ except Exception as e:
111
+ preview = f"(Preview not available: {e})"
112
+
113
+ # Keep preview small for Google Sheet cell limits
114
+ preview = (preview[:4500] + "...(truncated)") if len(preview) > 4500 else preview
115
+ return filename, ext, preview
116
+
117
+
118
+ def submit_response(name, user_id, dept, link, brief, feedback, sample_file):
119
+ # Basic validation
120
+ if not name or not name.strip():
121
+ return gr.update(value="❌ Please enter Name."), None
122
+ if not user_id or not str(user_id).strip():
123
+ return gr.update(value="❌ Please enter ID."), None
124
+ if not dept or not dept.strip():
125
+ return gr.update(value="❌ Please enter Department."), None
126
+
127
+ try:
128
+ sh = _get_gspread_client()
129
+ ws = _ensure_worksheet(sh, "Responses")
130
+ except Exception as e:
131
+ return gr.update(value=f"❌ Google Sheet connection error:\n{e}"), None
132
+
133
+ fname, ftype, fprev = _file_preview(sample_file)
134
+
135
+ row = [
136
+ _ist_timestamp(),
137
+ name.strip(),
138
+ str(user_id).strip(),
139
+ dept.strip(),
140
+ (link or "").strip(),
141
+ (brief or "").strip(),
142
+ (feedback or "").strip(),
143
+ fname,
144
+ ftype,
145
+ fprev,
146
+ ]
147
+
148
+ try:
149
+ ws.append_row(row, value_input_option="USER_ENTERED")
150
+ except Exception as e:
151
+ return gr.update(value=f"❌ Failed to write to Google Sheet:\n{e}"), None
152
+
153
+ # Load last rows for preview table
154
+ try:
155
+ values = ws.get_all_values()
156
+ if len(values) <= 1:
157
+ df = pd.DataFrame(columns=values[0] if values else [])
158
+ else:
159
+ df = pd.DataFrame(values[1:], columns=values[0])
160
+ # Show last 25
161
+ df_view = df.tail(25).copy()
162
+ except Exception:
163
+ df_view = None
164
+
165
+ # Make a share link for the sheet (best effort)
166
+ sheet_url = f"https://docs.google.com/spreadsheets/d/{os.environ['GOOGLE_SHEET_ID']}"
167
+ msg = f"βœ… Submitted successfully!\n\nOpen Google Sheet: {sheet_url}"
168
+
169
+ return gr.update(value=msg), df_view
170
+
171
+
172
+ def load_preview_table():
173
+ try:
174
+ sh = _get_gspread_client()
175
+ ws = _ensure_worksheet(sh, "Responses")
176
+ values = ws.get_all_values()
177
+ if len(values) <= 1:
178
+ return pd.DataFrame(columns=values[0] if values else [])
179
+ df = pd.DataFrame(values[1:], columns=values[0])
180
+ return df.tail(25)
181
+ except Exception as e:
182
+ return pd.DataFrame({"Status": [f"Preview not available: {e}"]})
183
+
184
+
185
+ # =========================
186
+ # UI
187
+ # =========================
188
+ with gr.Blocks(title=APP_TITLE) as demo:
189
+ # Header with logo (place logo.jpg in Space root)
190
+ with gr.Row():
191
+ logo_path = "logo.jpg"
192
+ if os.path.exists(logo_path):
193
+ gr.Image(value=logo_path, show_label=False, height=90)
194
+ gr.Markdown(f"# {APP_TITLE}\nCollect responses and store them in Google Sheets.")
195
+
196
+ with gr.Row():
197
+ with gr.Column(scale=1):
198
+ name = gr.Textbox(label="Name *", placeholder="Enter your name")
199
+ user_id = gr.Textbox(label="ID *", placeholder="Enter your ID / Reg No")
200
+ dept = gr.Textbox(label="Department *", placeholder="e.g., CSE / Maths / Physics")
201
+ link = gr.Textbox(
202
+ label="Sharable Link (paste here)",
203
+ placeholder="Google Drive / GitHub / HF Space / any URL"
204
+ )
205
+ sample_file = gr.File(
206
+ label="Attach Sample Data (CSV/XLSX/TXT/PDF etc.)",
207
+ file_types=[".csv", ".xlsx", ".xls", ".txt", ".pdf", ".png", ".jpg", ".jpeg", ".zip"],
208
+ )
209
+
210
+ with gr.Column(scale=1):
211
+ brief = gr.Textbox(
212
+ label="Brief Description",
213
+ placeholder="What is your idea/prompt/app about? (2–5 lines)",
214
+ lines=5
215
+ )
216
+ feedback = gr.Textbox(
217
+ label="Feedback",
218
+ placeholder="Workshop feedback / suggestions",
219
+ lines=5
220
+ )
221
+
222
+ submit_btn = gr.Button("Submit to Google Sheet βœ…", variant="primary")
223
+ status = gr.Textbox(label="Status", interactive=False, lines=4)
224
+
225
+ gr.Markdown("## Latest submissions (last 25 rows)")
226
+ refresh_btn = gr.Button("Refresh Table")
227
+ table = gr.Dataframe(value=load_preview_table, interactive=False, wrap=True)
228
+
229
+ submit_btn.click(
230
+ fn=submit_response,
231
+ inputs=[name, user_id, dept, link, brief, feedback, sample_file],
232
+ outputs=[status, table],
233
+ )
234
+
235
+ refresh_btn.click(fn=load_preview_table, inputs=[], outputs=[table])
236
+
237
+ demo.queue().launch()