acecalisto3 commited on
Commit
e101753
·
verified ·
1 Parent(s): ef39663

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +271 -231
app.py CHANGED
@@ -10,8 +10,9 @@ import requests
10
  import gradio as gr
11
  import atexit
12
  import subprocess
13
- from urllib.parse import urlparse
14
  import warnings
 
15
 
16
  # Constants
17
  INPUT_DIRECTORY = 'input'
@@ -20,6 +21,12 @@ LOGS_DIRECTORY = 'logs'
20
  RESOLUTIONS_DIRECTORY = 'resolutions'
21
  REPOS_DIRECTORY = 'repos'
22
 
 
 
 
 
 
 
23
  # Set up logging
24
  def initialize_logger():
25
  log_file = f"{LOGS_DIRECTORY}/github_bot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
@@ -33,16 +40,10 @@ def initialize_logger():
33
  )
34
  return logging.getLogger(__name__)
35
 
 
 
36
  logger = initialize_logger() # Initialize logger globally
37
 
38
-
39
- # Set up environment
40
- def initialize_environment(input_file, output_directory):
41
- directories = [LOGS_DIRECTORY, RESOLUTIONS_DIRECTORY, REPOS_DIRECTORY, input_file, output_directory]
42
- for directory in directories:
43
- os.makedirs(directory, exist_ok=True)
44
-
45
-
46
  # GitHub API handler
47
  class GitHubAPI:
48
  def __init__(self, token: str):
@@ -97,7 +98,6 @@ class GitHubAPI:
97
  logger.error(f"Error fetching issues: {str(e)}")
98
  return []
99
 
100
-
101
  # GitHub Bot
102
  class GitHubBot:
103
  def __init__(self):
@@ -137,7 +137,7 @@ class GitHubBot:
137
 
138
  # Commit and push the modifications
139
  subprocess.run(['git', 'add', '.'], check=True)
140
- subprocess.run(['git', 'commit', '-m', f"Resolved issue #{issue_number} ({urllib.parse.quote(resolution)})"], check=True)
141
  subprocess.run(['git', 'push', 'origin', 'HEAD'], check=True)
142
 
143
  # Open Pull Request page
@@ -150,13 +150,11 @@ class GitHubBot:
150
  logger.error(error_msg)
151
  return error_msg
152
 
153
-
154
  def handle_issue_selection(token, owner, repo, issue_number, resolution, forked_repo):
155
  bot = GitHubBot()
156
  result = bot.resolve_issue(token, owner, repo, issue_number, resolution, forked_repo)
157
  return result
158
 
159
-
160
  def extract_info_from_url(url: str) -> Dict[str, Any]:
161
  info = {}
162
  try:
@@ -166,6 +164,17 @@ def extract_info_from_url(url: str) -> Dict[str, Any]:
166
  info['headers'] = dict(response.headers)
167
  info['content'] = response.text[:500] # Limit content to first 500 characters for brevity
168
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
  except requests.HTTPError as e:
171
  info['error'] = f"HTTP error: {str(e)}"
@@ -173,226 +182,262 @@ def extract_info_from_url(url: str) -> Dict[str, Any]:
173
  info['error'] = f"Error: {str(e)}"
174
  return info
175
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
- custom_css = """
178
- /* DaisyUI and Tailwind are loaded from CDN */
179
- @import url('https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css');
180
- @import url('https://cdn.tailwindcss.com');
181
-
182
- /* Futuristic Cyberpunk Style */
183
- body {
184
- background: linear-gradient(to bottom right, #1e1e1e, #303030) !important;
185
- color: #f0f0f0;
186
- font-family: 'Roboto Mono', monospace;
187
- }
188
- .container {
189
- max-width: 800px;
190
- margin: 2rem auto;
191
- padding: 0 1rem;
192
- }
193
- h1 {
194
- color: #00c0ff;
195
- text-shadow: 0 0 10px #00c0ff; /* Glow effect */
196
- }
197
- .card {
198
- background: rgba(20,20,20, 0.8);
199
- border-radius: 1rem;
200
- box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
201
- padding: 2rem;
202
- border: 2px solid #00c0ff;
203
- }
204
- .input, .select, .textarea {
205
- background: rgba(20,20,20, 0.9);
206
- border: 1px solid #00c0ff;
207
- color: #f0f0f0;
208
- border-radius: 0.5rem;
209
- padding: 0.75rem;
210
- width: 100%;
211
- margin-bottom: 1rem;
212
- }
213
- .button {
214
- width: 100%;
215
- padding: 0.75rem;
216
- border-radius: 0.5rem;
217
- font-weight: bold;
218
- cursor: pointer;
219
- transition: all 0.2s;
220
- background: rgba(20, 20, 20, 0.8);
221
- border: 2px solid #00c0ff;
222
- color: #f0f0f0;
223
- }
224
- .button:hover {
225
- background: rgba(10,10,10, 0.9);
226
- border-color: #00ff00; /* Green on hover */
227
- }
228
-
229
- .button-primary {
230
- background: #2c2c2c;
231
- color: #f0f0f0;
232
- border-color: #00c0ff;
233
- }
234
- .button-primary:hover {
235
- background: #4c4c4c;
236
- color: #f0f0f0;
237
- border-color: #00ff00;
238
- }
239
- .button-success {
240
- background: #2c2c2c;
241
- color: #f0f0f0;
242
- border-color: #00c0ff;
243
- }
244
- .button-success:hover {
245
- background: #4c4c4c;
246
- color: #f0f0f0;
247
- border-color: #00ff00;
248
- }
249
- .output-area {
250
- margin-top: 2rem;
251
- padding: 1rem;
252
- background: rgba(20, 20, 20, 0.9);
253
- border-radius: 0.5rem;
254
- color: #f0f0f0;
255
- border: 2px solid #00c0ff;
256
- overflow-y: auto;
257
- max-height: 300px;
258
- }
259
- .label {
260
- color: #a3a3a3;
261
- margin-bottom: 0.5rem;
262
- display: block;
263
- }
264
- /* Add more styling as needed to refine the look */
265
- """
266
 
267
- def create_gradio_interface():
268
- bot = GitHubBot()
 
 
 
 
 
 
269
 
270
- with gr.Blocks(css=custom_css, theme=gr.themes.Base()) as demo:
271
-
272
- gr.Markdown("<h1 style='color: #00c0ff; text-shadow: 0 0 10px #00c0ff;'>GitHub Issue Manager</h1>")
273
-
274
- with gr.Row():
275
- with gr.Column(scale=1):
276
- github_token = gr.Textbox(
277
- label="GitHub Token",
278
- placeholder="Enter your GitHub token",
279
- type="password",
280
- elem_classes="input input-bordered input-primary"
281
- )
282
- repo_link = gr.Textbox(
283
- label="Repository Link",
284
- placeholder="Enter repository link (e.g., https://github.com/owner/repo)",
285
- elem_classes="input input-bordered input-primary"
286
- )
287
-
288
- with gr.Column(scale=1):
289
- fetch_button = gr.Button(
290
- "Fetch Issues",
291
- elem_classes="button button-primary"
292
- )
293
-
294
- with gr.Row():
295
- with gr.Column(scale=1):
296
- issue_dropdown = gr.Dropdown(
297
- choices=[],
298
- label="Select Issue",
299
- interactive=True,
300
- elem_classes="select select-primary"
301
- )
302
-
303
- with gr.Column(scale=1):
304
- resolution_text = gr.Textbox(
305
- label="Resolution",
306
- placeholder="Enter your resolution here...",
307
- lines=5,
308
- elem_classes="textarea textarea-primary"
309
- )
310
-
311
-
312
- with gr.Row():
313
- with gr.Column(scale=1):
314
- forked_repo = gr.Textbox(
315
- label="Forked Repository Path",
316
- placeholder="Enter the path of the forked repository",
317
- elem_classes="input input-bordered input-primary"
318
- )
319
-
320
- with gr.Column(scale=1):
321
- resolve_button = gr.Button(
322
- "Resolve Issue",
323
- elem_classes="button button-success"
324
- )
325
-
326
- output_text = gr.Textbox(
327
- label="Output",
328
- interactive=False,
329
- elem_classes="output-area"
330
- )
331
-
332
-
333
- url_textbox = gr.Textbox(
334
- label="URL",
335
- placeholder="Enter a URL to extract information",
336
- elem_classes="input input-bordered input-primary"
337
- )
338
-
339
- extract_button = gr.Button(
340
- "Extract Info",
341
- elem_classes="button button-primary"
342
- )
343
-
344
- def fetch_issues_handler(token, repo_link):
345
- if not all([token, repo_link]):
346
- return gr.Dropdown.update(choices=["Please provide all required fields"])
347
-
348
- owner, repo = repo_link.split('/')[-2:]
349
- bot.initialize_api(token)
350
- issues = bot.fetch_issues(token, owner, repo)
351
-
352
- if not issues:
353
- return gr.Dropdown.update(choices=["No issues found or error occurred"])
354
-
355
- return gr.Dropdown.update(
356
- choices=[f"#{issue['number']}: {issue['title']}" for issue in issues]
357
- )
358
-
359
- def resolve_issue_handler(token, repo_link, selected_issue, resolution, forked_repo):
360
- if not selected_issue:
361
- return "Please select an issue first"
362
-
363
- try:
364
- owner, repo = repo_link.split('/')[-2:]
365
- issue_number = int(selected_issue.split(':')[0][1:])
366
- return handle_issue_selection(token, owner, repo, issue_number, resolution, forked_repo)
367
- except Exception as e:
368
- return f"Error: {str(e)}"
369
-
370
- def extract_info_handler(url):
371
- info = extract_info_from_url(url)
372
- return str(info)
373
-
374
- fetch_button.click(
375
- fetch_issues_handler,
376
- inputs=[github_token, repo_link],
377
- outputs=[issue_dropdown]
378
- )
379
-
380
- resolve_button.click(
381
- resolve_issue_handler,
382
- inputs=[github_token, repo_link, issue_dropdown, resolution_text, forked_repo],
383
- outputs=[output_text]
384
- )
385
-
386
- extract_button.click(
387
- extract_info_handler,
388
- inputs=[url_textbox],
389
- outputs=[output_text]
390
- )
391
 
 
 
 
 
 
 
 
 
 
 
 
 
392
 
393
- return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
 
 
396
 
397
  # Cleanup function
398
  def cleanup():
@@ -405,23 +450,18 @@ def cleanup():
405
  except Exception as e:
406
  print(f"Error during cleanup: {str(e)}")
407
 
408
-
409
  # Signal handler
410
  def signal_handler(signum, frame):
411
  logger.info(f"Received signal {signum}")
412
  cleanup()
413
  sys.exit(0)
414
 
415
-
416
  if __name__ == "__main__":
417
  # Register cleanup handlers
418
  atexit.register(cleanup)
419
  signal.signal(signal.SIGINT, signal_handler)
420
  signal.signal(signal.SIGTERM, signal_handler)
421
 
422
- # Initialize logger
423
- initialize_environment(INPUT_DIRECTORY, OUTPUT_DIRECTORY)
424
-
425
  # Create Gradio interface
426
  demo = create_gradio_interface()
427
  demo.launch()
 
10
  import gradio as gr
11
  import atexit
12
  import subprocess
13
+ from urllib.parse import urlparse, quote
14
  import warnings
15
+ import webbrowser
16
 
17
  # Constants
18
  INPUT_DIRECTORY = 'input'
 
21
  RESOLUTIONS_DIRECTORY = 'resolutions'
22
  REPOS_DIRECTORY = 'repos'
23
 
24
+ # Set up environment
25
+ def initialize_environment(input_file, output_directory):
26
+ directories = [LOGS_DIRECTORY, RESOLUTIONS_DIRECTORY, REPOS_DIRECTORY, input_file, output_directory]
27
+ for directory in directories:
28
+ os.makedirs(directory, exist_ok=True)
29
+
30
  # Set up logging
31
  def initialize_logger():
32
  log_file = f"{LOGS_DIRECTORY}/github_bot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
 
40
  )
41
  return logging.getLogger(__name__)
42
 
43
+ # Initialize environment and logger
44
+ initialize_environment(INPUT_DIRECTORY, OUTPUT_DIRECTORY)
45
  logger = initialize_logger() # Initialize logger globally
46
 
 
 
 
 
 
 
 
 
47
  # GitHub API handler
48
  class GitHubAPI:
49
  def __init__(self, token: str):
 
98
  logger.error(f"Error fetching issues: {str(e)}")
99
  return []
100
 
 
101
  # GitHub Bot
102
  class GitHubBot:
103
  def __init__(self):
 
137
 
138
  # Commit and push the modifications
139
  subprocess.run(['git', 'add', '.'], check=True)
140
+ subprocess.run(['git', 'commit', '-m', f"Resolved issue #{issue_number} ({quote(resolution)})"], check=True)
141
  subprocess.run(['git', 'push', 'origin', 'HEAD'], check=True)
142
 
143
  # Open Pull Request page
 
150
  logger.error(error_msg)
151
  return error_msg
152
 
 
153
  def handle_issue_selection(token, owner, repo, issue_number, resolution, forked_repo):
154
  bot = GitHubBot()
155
  result = bot.resolve_issue(token, owner, repo, issue_number, resolution, forked_repo)
156
  return result
157
 
 
158
  def extract_info_from_url(url: str) -> Dict[str, Any]:
159
  info = {}
160
  try:
 
164
  info['headers'] = dict(response.headers)
165
  info['content'] = response.text[:500] # Limit content to first 500 characters for brevity
166
 
167
+ parsed_url = urlparse(url)
168
+ if 'github.com' in parsed_url.netloc:
169
+ parts = parsed_url.path.split('/')
170
+ if len(parts) > 2:
171
+ owner = parts[1]
172
+ repo = parts[2]
173
+ issues = bot.fetch_issues(github_token, owner, repo)
174
+ info['issues'] = issues
175
+ elif 'huggingface.co' in parsed_url.netloc:
176
+ # Add Hugging Face specific handling if needed
177
+ pass
178
 
179
  except requests.HTTPError as e:
180
  info['error'] = f"HTTP error: {str(e)}"
 
182
  info['error'] = f"Error: {str(e)}"
183
  return info
184
 
185
+ # Initialize GitHubBot globally
186
+ bot = GitHubBot()
187
+
188
+ # HTML and CSS integration
189
+ custom_html = """
190
+ <!DOCTYPE html>
191
+ <html lang="en">
192
+ <head>
193
+ <meta charset="UTF-8">
194
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
195
+ <title>GitHub Issue Manager</title>
196
+ <!-- Tailwind CSS -->
197
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
198
+ <!-- DaisyUI -->
199
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css" rel="stylesheet" type="text/css" />
200
+ <style>
201
+ body {
202
+ background: linear-gradient(to bottom right, #121212, #303030) !important;
203
+ color: #e0e0e0;
204
+ font-family: 'Roboto', sans-serif;
205
+ overflow-x: hidden; /* Prevent horizontal scrollbar */
206
+
207
+ }
208
+ .card {
209
+ border-radius: 1.5rem;
210
+ box-shadow: 0 15px 25px rgba(0, 0, 0, 0.2);
211
+ margin-bottom: 20px;
212
+ }
213
+ .input, .select, .textarea {
214
+ border: 2px solid #4a4a4a;
215
+ border-radius: 0.75rem;
216
+ padding-inline: 1.5rem;
217
+ padding-block: 0.75rem;
218
 
219
+ }
220
+ h1, h2, h3 {
221
+ color: #e0e0e0;
222
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
+ .output-area {
225
+ padding: 1.5rem;
226
+ border-radius: 0.75rem;
227
+ }
228
+ .btn {
229
+ border-radius: 0.75rem;
230
+ padding-block: 0.75rem;
231
+ padding-inline: 1.5rem;
232
 
233
+ }
234
+ .btn-primary {
235
+ background-color: #7928CA;
236
+ color: white;
237
+ border: 2px solid #7928CA;
238
+ }
239
+ .btn-success {
240
+ background-color: #22c55e;
241
+ color: white;
242
+ border: 2px solid #22c55e;
243
+ }
244
+ </style>
245
+ </head>
246
+ <body class="bg-gray-900">
247
+ <div class="container mx-auto p-4" >
248
+
249
+ <h1 class="text-4xl md:text-5xl font-extrabold text-center mb-8">GitHub Issue Manager</h1>
250
+
251
+ <!-- GitHub Token & Repo URL -->
252
+ <div class="card bg-gray-800 p-8">
253
+ <div class="form-control">
254
+ <label class="label">
255
+ <span class="label-text">GitHub Token</span>
256
+ </label>
257
+ <input type="password" placeholder="Enter your GitHub Personal Access Token" class="input input-bordered input-primary" id="github-token">
258
+ </div>
259
+ <div class="form-control">
260
+ <label class="label">
261
+ <span class="label-text">Repository URL</span>
262
+ </label>
263
+ <input type="text" placeholder="Enter the full GitHub repository URL" class="input input-bordered input-primary" id="repo-url">
264
+ </div>
265
+ </div>
266
+
267
+ <!-- Fetch & Resolve Section -->
268
+ <div class="card bg-gray-800 p-8">
269
+ <div class="flex justify-between gap-4">
270
+
271
+ <button class="btn btn-primary" id="fetch-issues">Fetch Issues</button>
272
+
273
+ <select class="select select-primary w-full max-w-xs" id="issue-dropdown" >
274
+ <option disabled selected>Select Issue</option>
275
+ </select>
276
+ </div>
277
+ <div class="form-control mt-4">
278
+ <label class="label">
279
+ <span class="label-text">Resolution</span>
280
+ </label>
281
+ <textarea class="textarea textarea-primary" placeholder="Enter the resolution details" id="resolution-textarea"></textarea>
282
+ </div>
283
+ <div class="form-control mt-4">
284
+ <label class="label">
285
+ <span class="label-text">Forked Repository URL</span>
286
+ </label>
287
+ <input type="text" placeholder="URL to your forked repository (Optional)" class="input input-bordered input-primary" id="forked-repo-url">
288
+ </div>
289
+ <div class="form-control mt-4">
290
+ <button class="btn btn-success" id="resolve-issue">Resolve Issue</button>
291
+ </div>
292
+ </div>
293
+
294
+ <!-- Output Area -->
295
+ <div class="card bg-gray-800 p-8 mt-4" >
296
+ <label class="label">
297
+ <span class="label-text">Output</span>
298
+ </label>
299
+ <textarea class="textarea textarea-primary h-48" id="output-textarea" readonly></textarea>
300
+ </div>
301
+
302
+ <!-- URL to Extract -->
303
+ <div class="card bg-gray-800 p-8 mt-4">
304
+ <div class="form-control">
305
+ <label class="label">
306
+ <span class="label-text">URL</span>
307
+ </label>
308
+ <input type="text" placeholder="Enter a URL to extract information" class="input input-bordered input-primary" id="url-textbox">
309
+ </div>
310
+ <div class="form-control">
311
+ <button class="btn btn-primary" id="extract-info">Extract Info</button>
312
+ </div>
313
+ </div>
314
+
315
+ </div>
316
+ <script>
317
+ const githubTokenInput = document.getElementById('github-token');
318
+ const repoUrlInput = document.getElementById('repo-url');
319
+ const fetchIssuesButton = document.getElementById('fetch-issues');
320
+ const issueDropdown = document.getElementById('issue-dropdown');
321
+ const resolutionTextarea = document.getElementById('resolution-textarea');
322
+ const forkedRepoUrlInput = document.getElementById('forked-repo-url');
323
+ const resolveIssueButton = document.getElementById('resolve-issue');
324
+ const outputTextarea = document.getElementById('output-textarea');
325
+ const urlTextbox = document.getElementById('url-textbox');
326
+ const extractInfoButton = document.getElementById('extract-info');
327
+
328
+ fetchIssuesButton.addEventListener('click', async () => {
329
+ const token = githubTokenInput.value;
330
+ const repoUrl = repoUrlInput.value;
331
+ if (!token || !repoUrl) {
332
+ outputTextarea.value = "Please provide both GitHub Token and Repository URL.";
333
+ return;
334
+ }
335
+ try {
336
+ const response = await fetch('/fetch_issues', {
337
+ method: 'POST',
338
+ headers: {
339
+ 'Content-Type': 'application/json',
340
+ },
341
+ body: JSON.stringify({ token: token, repoUrl: repoUrl }),
342
+ });
343
+
344
+ if (!response.ok) {
345
+ throw new Error(`HTTP error! status: ${response.status}`);
346
+ }
 
 
 
 
 
 
 
347
 
348
+ const data = await response.json();
349
+ if (data.error) {
350
+ outputTextarea.value = data.error;
351
+ } else {
352
+ issueDropdown.innerHTML = '';
353
+ data.issues.forEach(issue => {
354
+ const option = document.createElement('option');
355
+ option.value = issue.number;
356
+ option.text = `${issue.number}: ${issue.title}`;
357
+ issueDropdown.add(option);
358
+ });
359
+ }
360
 
361
+ } catch (error) {
362
+ outputTextarea.value = `Error fetching issues: ${error.message}`;
363
+ }
364
+ });
365
+
366
+ resolveIssueButton.addEventListener('click', async () => {
367
+ const token = githubTokenInput.value;
368
+ const repoUrl = repoUrlInput.value;
369
+ const issueNumber = issueDropdown.value;
370
+ const resolution = resolutionTextarea.value;
371
+ const forkedRepoUrl = forkedRepoUrlInput.value;
372
+
373
+ if (!token || !repoUrl || !issueNumber || !resolution) {
374
+ outputTextarea.value ="Please provide all required fields.";
375
+ return;
376
+ }
377
+ try {
378
+ const response = await fetch('/resolve_issue', {
379
+ method: 'POST',
380
+ headers: {
381
+ 'Content-Type': 'application/json',
382
+ },
383
+ body: JSON.stringify({ token: token, repoUrl: repoUrl, issueNumber: issueNumber, resolution: resolution, forkedRepoUrl: forkedRepoUrl }),
384
+ });
385
+
386
+ if (!response.ok) {
387
+ throw new Error(`HTTP error! status: ${response.status}`);
388
+ }
389
 
390
+ const data = await response.json();
391
+ if (data.error) {
392
+ outputTextarea.value = data.error;
393
+ } else {
394
+ outputTextarea.value = data.result;
395
+ }
396
+ } catch (error) {
397
+ outputTextarea.value = `Error resolving issue: ${error.message}`;
398
+ }
399
+ });
400
+
401
+ extractInfoButton.addEventListener('click', async () => {
402
+ const url = urlTextbox.value;
403
+ if (!url) {
404
+ outputTextarea.value = "Please provide a URL.";
405
+ return;
406
+ }
407
+ try {
408
+ const response = await fetch('/extract_info', {
409
+ method: 'POST',
410
+ headers: {
411
+ 'Content-Type': 'application/json',
412
+ },
413
+ body: JSON.stringify({ url: url }),
414
+ });
415
+
416
+ if (!response.ok) {
417
+ throw new Error(`HTTP error! status: ${response.status}`);
418
+ }
419
+
420
+ const data = await response.json();
421
+ if (data.error) {
422
+ outputTextarea.value = data.error;
423
+ } else {
424
+ outputTextarea.value = JSON.stringify(data, null, 2);
425
+ }
426
+ } catch (error) {
427
+ outputTextarea.value = `Error extracting info: ${error.message}`;
428
+ }
429
+ });
430
+
431
+ </script>
432
+ </body>
433
+ </html>
434
+ """
435
+
436
+ def create_gradio_interface():
437
+ with gr.Blocks(css=None, theme=None) as demo:
438
+ gr.HTML(custom_html)
439
 
440
+ return demo
441
 
442
  # Cleanup function
443
  def cleanup():
 
450
  except Exception as e:
451
  print(f"Error during cleanup: {str(e)}")
452
 
 
453
  # Signal handler
454
  def signal_handler(signum, frame):
455
  logger.info(f"Received signal {signum}")
456
  cleanup()
457
  sys.exit(0)
458
 
 
459
  if __name__ == "__main__":
460
  # Register cleanup handlers
461
  atexit.register(cleanup)
462
  signal.signal(signal.SIGINT, signal_handler)
463
  signal.signal(signal.SIGTERM, signal_handler)
464
 
 
 
 
465
  # Create Gradio interface
466
  demo = create_gradio_interface()
467
  demo.launch()