SalexAI commited on
Commit
184de22
·
verified ·
1 Parent(s): 6adff1c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +228 -233
app.py CHANGED
@@ -1,242 +1,237 @@
1
  import json
2
  import gradio as gr
3
- from fastapi import FastAPI, HTTPException
4
- from pydantic import BaseModel
5
- from fastapi.responses import HTMLResponse
6
 
7
  # Store the lists data (in-memory database)
8
  lists = {}
9
 
10
- # Define a model for the incoming request data
11
- class DataRequest(BaseModel):
12
- list_name: str
13
- items: list
14
-
15
- # For Hugging Face Spaces, we need to define the Gradio app first
16
- with gr.Blocks() as demo:
17
- # Create a simple interface to show the data
18
- gr.Markdown("# UniShare Data Viewer")
19
- output_text = gr.Textbox(label="Stored Data")
20
-
21
- def show_data():
22
- return json.dumps(lists, indent=4)
23
-
24
- refresh_btn = gr.Button("Refresh Data")
25
- refresh_btn.click(fn=show_data, inputs=[], outputs=[output_text])
26
-
27
- # Initialize with current data
28
- demo.load(fn=show_data, inputs=[], outputs=[output_text])
29
-
30
- # Create FastAPI app
31
- app = FastAPI()
32
-
33
- # Endpoint for storing data
34
- @app.post("/store_data")
35
- async def store_data(data: DataRequest):
36
- list_name = data.list_name
37
- items = data.items
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
- if list_name not in lists:
40
- lists[list_name] = []
 
 
 
 
 
41
 
42
- lists[list_name].append(items)
43
- return {"message": f"Data stored successfully for {list_name}"}
44
-
45
- # Endpoint to get data
46
- @app.get("/api/data")
47
- async def get_data():
48
- return lists
49
-
50
- # HTML interface endpoint
51
- @app.get("/app", response_class=HTMLResponse)
52
- def read_root():
53
- return """
54
- <!DOCTYPE html>
55
- <html lang="en">
56
- <head>
57
- <meta charset="UTF-8" />
58
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
59
- <title>UniShare</title>
60
- <style>
61
- body {
62
- font-family: Arial, sans-serif;
63
- margin: 0;
64
- padding: 0;
65
- background: #f0f2f5;
66
- }
67
- header {
68
- background: #3b82f6;
69
- color: white;
70
- padding: 1em;
71
- text-align: center;
72
- font-size: 1.8em;
73
- }
74
- #overview {
75
- display: grid;
76
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
77
- gap: 1em;
78
- padding: 1em;
79
- }
80
- .list-tile {
81
- background: white;
82
- padding: 1em;
83
- border-radius: 10px;
84
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
85
- cursor: pointer;
86
- transition: transform 0.2s;
87
- }
88
- .list-tile:hover {
89
- transform: scale(1.02);
90
- }
91
- #list-view {
92
- display: none;
93
- padding: 1em;
94
- }
95
- .back-button {
96
- background: #3b82f6;
97
- color: white;
98
- padding: 0.5em 1em;
99
- border: none;
100
- border-radius: 5px;
101
- cursor: pointer;
102
- margin-bottom: 1em;
103
- }
104
- .card {
105
- background: white;
106
- padding: 1em;
107
- border-radius: 10px;
108
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
109
- margin-bottom: 1em;
110
- }
111
- .submenu {
112
- margin-top: 1em;
113
- }
114
- .submenu h4 {
115
- margin: 0.5em 0;
116
- }
117
- .grid {
118
- display: grid;
119
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
120
- gap: 1em;
121
- }
122
- .item {
123
- background: #f9f9f9;
124
- padding: 1em;
125
- border-radius: 10px;
126
- box-shadow: 0 1px 3px rgba(0,0,0,0.05);
127
- }
128
- .item img {
129
- max-width: 100%;
130
- max-height: 150px;
131
- object-fit: cover;
132
- border-radius: 5px;
133
- margin-bottom: 0.5em;
134
- }
135
- .item a {
136
- display: inline-block;
137
- margin-top: 0.5em;
138
- text-decoration: none;
139
- color: #3b82f6;
140
- }
141
- #toast {
142
- position: fixed;
143
- bottom: 20px;
144
- right: 20px;
145
- background: #333;
146
- color: white;
147
- padding: 1em;
148
- border-radius: 5px;
149
- display: none;
150
- z-index: 1000;
151
- }
152
- </style>
153
- </head>
154
- <body>
155
- <header>UniShare</header>
156
- <div id="overview"></div>
157
- <div id="list-view">
158
- <button class="back-button" onclick="backToOverview()">← Back to Overview</button>
159
- <div id="content"></div>
160
- </div>
161
- <div id="toast"></div>
162
-
163
- <script>
164
- const overviewDiv = document.getElementById('overview');
165
- const contentDiv = document.getElementById('content');
166
- const listViewDiv = document.getElementById('list-view');
167
- const toastDiv = document.getElementById('toast');
168
-
169
- const lists = {}
170
-
171
- function showToast(message) {
172
- toastDiv.textContent = message;
173
- toastDiv.style.display = 'block';
174
- setTimeout(() => {
175
- toastDiv.style.display = 'none';
176
- }, 3000);
177
- }
178
-
179
- function backToOverview() {
180
- listViewDiv.style.display = 'none';
181
- overviewDiv.style.display = 'grid';
182
- }
183
-
184
- function showList(name) {
185
- const sections = lists[name];
186
- contentDiv.innerHTML = '';
187
-
188
- sections.forEach(section => {
189
- const card = document.createElement('div');
190
- card.className = 'card';
191
- const title = document.createElement('h3');
192
- title.textContent = section.sectionTitle;
193
- card.appendChild(title);
194
-
195
- const grid = document.createElement('div');
196
- grid.className = 'grid';
197
-
198
- section.items.forEach(item => {
199
- const div = document.createElement('div');
200
- div.className = 'item';
201
- let content = `<strong>${item.title}</strong><br>`;
202
- if (item.link.match(/\.(jpeg|jpg|gif|png)$/)) {
203
- content += `<img src="${item.link}" alt="${item.title}" />`;
204
- }
205
- content += `<a href="${item.link}" download>Download</a>`;
206
- div.innerHTML = content;
207
- grid.appendChild(div);
208
- });
209
-
210
- card.appendChild(grid);
211
- contentDiv.appendChild(card);
212
- });
213
-
214
- overviewDiv.style.display = 'none';
215
- listViewDiv.style.display = 'block';
216
- }
217
-
218
- // Fetch data and populate the lists dynamically
219
- fetch('/api/data')
220
- .then(response => response.json())
221
- .then(data => {
222
- if (Object.keys(data).length > 0) {
223
- Object.keys(data).forEach((listName, index) => {
224
- const list = data[listName];
225
- const tile = document.createElement('div');
226
- tile.className = 'list-tile';
227
- tile.innerHTML = `<strong>${listName}</strong><br>${list.length} sections`;
228
- tile.onclick = () => showList(listName);
229
- overviewDiv.appendChild(tile);
230
- showToast(`Loaded ${listName}`);
231
- });
232
- } else {
233
- overviewDiv.innerHTML = '<p>No lists found</p>';
234
- }
235
- });
236
- </script>
237
- </body>
238
- </html>
239
- """
240
 
241
- # This is crucial for Hugging Face Spaces
242
- app = gr.mount_gradio_app(app, demo, path="/")
 
 
1
  import json
2
  import gradio as gr
3
+ import os
 
 
4
 
5
  # Store the lists data (in-memory database)
6
  lists = {}
7
 
8
+ # Define a simple Gradio app for UniShare
9
+ def unishare_app():
10
+ # Main UI components
11
+ with gr.Blocks(css="""
12
+ .list-card {
13
+ background: white;
14
+ padding: 16px;
15
+ border-radius: 10px;
16
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
17
+ margin-bottom: 16px;
18
+ cursor: pointer;
19
+ }
20
+ .list-card:hover {
21
+ transform: scale(1.02);
22
+ transition: transform 0.2s;
23
+ }
24
+ .item-grid {
25
+ display: grid;
26
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
27
+ gap: 16px;
28
+ }
29
+ .item-card {
30
+ background: #f9f9f9;
31
+ padding: 16px;
32
+ border-radius: 10px;
33
+ box-shadow: 0 1px 3px rgba(0,0,0,0.05);
34
+ }
35
+ .back-btn {
36
+ margin-bottom: 16px;
37
+ }
38
+ """) as demo:
39
+ gr.Markdown("# UniShare")
40
+
41
+ # Overview page
42
+ with gr.Tab("Overview"):
43
+ overview_container = gr.HTML()
44
+
45
+ def update_overview():
46
+ html = ""
47
+ if lists:
48
+ for list_name, list_data in lists.items():
49
+ html += f"""
50
+ <div class="list-card" onclick="switchToList('{list_name}')">
51
+ <h3>{list_name}</h3>
52
+ <p>{len(list_data)} sections</p>
53
+ </div>
54
+ """
55
+ else:
56
+ html = "<p>No lists found. Add some data first!</p>"
57
+
58
+ # Add JavaScript to handle navigation
59
+ html += """
60
+ <script>
61
+ function switchToList(name) {
62
+ // Using Gradio's built-in tab switching
63
+ const tabs = document.querySelectorAll('.tabs > button');
64
+ if (tabs.length > 1) {
65
+ tabs[1].click(); // Click the "View List" tab
66
+ // Set the list name in the dropdown
67
+ const listSelect = document.getElementById('list-selector');
68
+ for (let i = 0; i < listSelect.options.length; i++) {
69
+ if (listSelect.options[i].value === name) {
70
+ listSelect.selectedIndex = i;
71
+ // Trigger change event
72
+ const event = new Event('change');
73
+ listSelect.dispatchEvent(event);
74
+ break;
75
+ }
76
+ }
77
+ }
78
+ }
79
+ </script>
80
+ """
81
+ return html
82
+
83
+ # Update overview on page load
84
+ demo.load(update_overview, [], [overview_container])
85
+
86
+ # View list page
87
+ with gr.Tab("View List"):
88
+ gr.Markdown("## View List")
89
+
90
+ # List selector dropdown
91
+ list_selector = gr.Dropdown(
92
+ label="Select a list",
93
+ choices=list(lists.keys()) if lists else [],
94
+ interactive=True,
95
+ elem_id="list-selector"
96
+ )
97
+
98
+ # Container for list items
99
+ list_content = gr.HTML()
100
+
101
+ # Back button (visual only, actual navigation handled by JS)
102
+ gr.Button("Back to Overview", elem_classes=["back-btn"]).click(
103
+ lambda: gr.Tabs(selected=0), # This is a hack to trigger tab switching
104
+ [],
105
+ []
106
+ )
107
+
108
+ # Function to display list items
109
+ def display_list(list_name):
110
+ if not list_name or list_name not in lists:
111
+ return "<p>Please select a valid list</p>"
112
+
113
+ sections = lists[list_name]
114
+ html = ""
115
+
116
+ for section in sections:
117
+ html += f"<div class='section-card'><h3>{section.get('sectionTitle', 'Untitled Section')}</h3>"
118
+ html += "<div class='item-grid'>"
119
+
120
+ for item in section.get('items', []):
121
+ title = item.get('title', 'Untitled')
122
+ link = item.get('link', '#')
123
+
124
+ html += f"<div class='item-card'>"
125
+ html += f"<strong>{title}</strong><br>"
126
+
127
+ if link.lower().endswith(('.jpeg', '.jpg', '.gif', '.png')):
128
+ html += f"<img src='{link}' alt='{title}' style='max-width:100%; max-height:150px; margin:10px 0;'><br>"
129
+
130
+ html += f"<a href='{link}' download style='color:#3b82f6; text-decoration:none;'>Download</a>"
131
+ html += "</div>"
132
+
133
+ html += "</div></div>"
134
+
135
+ return html
136
+
137
+ # Update list content when selection changes
138
+ list_selector.change(
139
+ display_list,
140
+ [list_selector],
141
+ [list_content]
142
+ )
143
+
144
+ # Admin page for data management
145
+ with gr.Tab("Admin"):
146
+ gr.Markdown("## Data Management")
147
+
148
+ with gr.Row():
149
+ with gr.Column():
150
+ gr.Markdown("### Add New List Data")
151
+ list_name_input = gr.Textbox(label="List Name")
152
+ json_data = gr.Textbox(
153
+ label="Section Data (JSON format)",
154
+ lines=10,
155
+ placeholder='''
156
+ {
157
+ "sectionTitle": "Sample Section",
158
+ "items": [
159
+ {
160
+ "title": "Sample Item",
161
+ "link": "https://example.com/sample.jpg"
162
+ }
163
+ ]
164
+ }'''
165
+ )
166
+
167
+ add_button = gr.Button("Add Data")
168
+ add_result = gr.Markdown()
169
+
170
+ def add_data(list_name, data_json):
171
+ if not list_name:
172
+ return "Error: List name is required"
173
+
174
+ try:
175
+ data = json.loads(data_json)
176
+ if list_name not in lists:
177
+ lists[list_name] = []
178
+
179
+ lists[list_name].append(data)
180
+
181
+ # Update dropdown choices (will reflect on next page load)
182
+ list_selector.choices = list(lists.keys())
183
+
184
+ return f"Success: Data added to {list_name}"
185
+ except json.JSONDecodeError:
186
+ return "Error: Invalid JSON format"
187
+ except Exception as e:
188
+ return f"Error: {str(e)}"
189
+
190
+ add_button.click(
191
+ add_data,
192
+ [list_name_input, json_data],
193
+ [add_result]
194
+ )
195
+
196
+ with gr.Column():
197
+ gr.Markdown("### View All Data")
198
+ view_data_button = gr.Button("View All Data")
199
+ data_output = gr.JSON()
200
+
201
+ def get_all_data():
202
+ return lists
203
+
204
+ view_data_button.click(
205
+ get_all_data,
206
+ [],
207
+ [data_output]
208
+ )
209
+
210
+ # Add button to clear all data
211
+ clear_button = gr.Button("Clear All Data", variant="stop")
212
+ clear_result = gr.Markdown()
213
+
214
+ def clear_data():
215
+ lists.clear()
216
+ list_selector.choices = []
217
+ return "All data cleared"
218
+
219
+ clear_button.click(
220
+ clear_data,
221
+ [],
222
+ [clear_result]
223
+ )
224
 
225
+ # Update UI components when data changes
226
+ def refresh_ui():
227
+ list_selector.choices = list(lists.keys())
228
+
229
+ # Set up event handlers to refresh UI
230
+ add_button.click(lambda: None, [], [], _js="() => {window.location.reload()}")
231
+ clear_button.click(lambda: None, [], [], _js="() => {window.location.reload()}")
232
 
233
+ return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
 
235
+ # Create and launch the app
236
+ demo = unishare_app()
237
+ demo.launch()