acecalisto3 commited on
Commit
d55a3b2
·
verified ·
1 Parent(s): f4e2fb9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -244
app.py CHANGED
@@ -12,7 +12,8 @@ import atexit
12
  import subprocess
13
  from urllib.parse import urlparse, quote
14
  import webbrowser
15
- import spaces
 
16
 
17
  device = "cuda"
18
 
@@ -63,8 +64,14 @@ LOGS_DIRECTORY = 'logs'
63
  RESOLUTIONS_DIRECTORY = 'resolutions'
64
  REPOS_DIRECTORY = 'repos'
65
 
 
 
 
 
 
 
66
  # Set up logging
67
- def initialize_logger() -> logging.Logger:
68
  log_file = f"{LOGS_DIRECTORY}/github_bot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
69
  logging.basicConfig(
70
  level=logging.INFO,
@@ -77,12 +84,7 @@ def initialize_logger() -> logging.Logger:
77
  return logging.getLogger(__name__)
78
 
79
  # Initialize environment and logger
80
- def initialize_environment():
81
- directories = [LOGS_DIRECTORY, RESOLUTIONS_DIRECTORY, REPOS_DIRECTORY, INPUT_DIRECTORY, OUTPUT_DIRECTORY]
82
- for directory in directories:
83
- os.makedirs(directory, exist_ok=True)
84
-
85
- initialize_environment()
86
  logger = initialize_logger() # Initialize logger globally
87
 
88
  # GitHub API handler
@@ -106,12 +108,12 @@ class GitHubAPI:
106
  if remaining < 10:
107
  wait_time = max(0, reset_time - int(time.time()))
108
  if wait_time > 0:
109
- logger.warning(f"Rate limit nearly exceeded. Waiting {wait_time} seconds before retrying...")
110
  time.sleep(wait_time)
111
  return False
112
  return True
113
  except requests.exceptions.RequestException as e:
114
- logger.error(f"Error checking rate limit: {str(e)}. Retrying...")
115
  return True
116
 
117
  def get_repository(self, owner: str, repo: str) -> Dict:
@@ -120,7 +122,7 @@ class GitHubAPI:
120
  response.raise_for_status()
121
  return response.json()
122
  except requests.HTTPError as e:
123
- logger.error(f"HTTP error getting repository info for {owner}/{repo}: {str(e)}. Please check the repository details.")
124
  raise
125
  except Exception as e:
126
  logger.error(f"Error getting repository info: {str(e)}")
@@ -136,7 +138,7 @@ class GitHubAPI:
136
  issues = response.json()
137
  return [issue for issue in issues if 'pull_request' not in issue]
138
  except Exception as e:
139
- logger.error(f"Error fetching issues for repository {owner}/{repo}: {str(e)}. Please verify the repository and token.")
140
  return []
141
 
142
  # GitHub Bot
@@ -152,7 +154,7 @@ class GitHubBot:
152
  self.initialize_api(token)
153
  return self.github_api.get_issues(owner, repo)
154
  except Exception as e:
155
- logger.error(f"Error fetching issues for repository {owner}/{repo}: {str(e)}")
156
  return []
157
 
158
  def resolve_issue(self, token: str, owner: str, repo: str, issue_number: int, resolution: str, forked_repo: str) -> str:
@@ -174,7 +176,7 @@ class GitHubBot:
174
  os.chdir('/tmp/' + forked_repo.split('/')[-1])
175
 
176
  # Assuming manual intervention now
177
- input("Apply the fix manually and stage the changes (press ENTER)? ")
178
 
179
  # Commit and push the modifications
180
  subprocess.run(['git', 'add', '.'], check=True)
@@ -187,7 +189,7 @@ class GitHubBot:
187
  return f"Resolution saved: {resolution_file}"
188
 
189
  except Exception as e:
190
- error_msg = f"Error resolving issue #{issue_number} in repository {owner}/{repo}: {str(e)}"
191
  logger.error(error_msg)
192
  return error_msg
193
 
@@ -258,240 +260,63 @@ def extract_info(url):
258
  except Exception as e:
259
  return str(e)
260
 
261
- # HTML and CSS integration
262
- custom_html = """
263
- <!DOCTYPE html>
264
- <html>
265
- <head>
266
- <title>GitHub Issue Manager</title>
267
- <meta charset="UTF-8">
268
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
269
- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
270
- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css" rel="stylesheet" type="text/css" />
271
- <style>
272
- body {
273
- background: linear-gradient(to bottom right, #121212, #303030) !important;
274
- color: #e0e0e0;
275
- font-family: 'Roboto', sans-serif;
276
- overflow-x: hidden; /* Prevent horizontal scrollbar */
277
- }
278
- .card {
279
- border-radius: 1.5rem;
280
- box-shadow: 0 15px 25px rgba (0, 0, 0, 0.2);
281
- margin-bottom: 20px;
282
- }
283
- .input, .select, .textarea {
284
- border: 2px solid #4a4a4a;
285
- border-radius: 0.75rem;
286
- padding-inline: 1.5rem;
287
- padding-block: 0.75rem;
288
- }
289
- h1, h2, h3 {
290
- color: #e0e0e0;
291
- }
292
- .output-area {
293
- padding: 1.5rem;
294
- border-radius: 0.75rem;
295
- }
296
- .btn {
297
- border-radius: 0.75rem;
298
- padding-block: 0.75rem;
299
- padding-inline: 1.5rem;
300
- }
301
- .btn-primary {
302
- background-color: #7928CA;
303
- color: white;
304
- border: 2px solid #7928CA;
305
- }
306
- .btn-primary:hover {
307
- background-color: #5e22a1;
308
- }
309
- .btn-success {
310
- background-color: #22c55e;
311
- color: white;
312
- border: 2px solid #22c55e;
313
- }
314
- .btn-success:hover {
315
- background-color: #1a9a46;
316
- }
317
- </style>
318
- </head>
319
- <body class="bg-gray-900">
320
- <div class="container mx-auto p-4">
321
- <h1 class="text-4xl md:text-5xl font-extrabold text-center mb-8">GitHub Issue Manager</h1>
322
- <!-- GitHub Token & Repo URL -->
323
- <div class="card bg-gray-800 p-8">
324
- <div class="form-control">
325
- <label class="label">
326
- <span class="label-text">GitHub Token</span>
327
- </label>
328
- <input type="password" placeholder="Enter your GitHub Personal Access Token" class="input input-bordered input-primary" id="github-token">
329
- </div>
330
- <div class="form-control">
331
- <label class="label">
332
- <span class="label-text">Repository URL</span>
333
- </label>
334
- <input type="text" placeholder="Enter the full GitHub repository URL" class="input input-bordered input-primary" id="repo-url">
335
- </div>
336
- </div>
337
- <!-- Fetch & Resolve Section -->
338
- <div class="card bg-gray-800 p-8">
339
- <div class="flex justify-between gap-4">
340
- <button class="btn btn-primary" id="fetch-issues">Fetch Issues</button>
341
- <select class="select select-primary w-full max-w-xs" id="issue-dropdown">
342
- <option disabled selected>Select Issue</option>
343
- </select>
344
- </div>
345
- <div class="form-control mt-4">
346
- <label class="label">
347
- <span class="label-text">Resolution</span>
348
- </label>
349
- <textarea class="textarea textarea-primary" placeholder="Enter the resolution details" id="resolution-textarea"></textarea>
350
- </div>
351
- <div class="form-control mt-4">
352
- <label class="label">
353
- <span class="label-text">Forked Repository URL</span>
354
- </label>
355
- <input type="text" placeholder="URL to your forked repository (Optional)" class="input input-bordered input-primary" id="forked-repo-url">
356
- </div>
357
- <div class="form-control mt-4">
358
- <button class="btn btn-success" id="resolve-issue">Resolve Issue</button>
359
- </div>
360
- </div>
361
- <!-- Output Area -->
362
- <div class="card bg-gray-800 p-8 mt-4">
363
- <label class="label">
364
- <span class="label-text">Output</span>
365
- </label>
366
- <textarea class="textarea textarea-primary h-48" id="output-textarea" readonly></textarea>
367
- </div>
368
- <!-- URL to Extract -->
369
- <div class="card bg-gray-800 p-8 mt-4">
370
- <div class="form-control">
371
- <label class="label">
372
- <span class="label-text">URL</span>
373
- </label>
374
- <input type="text" placeholder="Enter a URL to extract information" class="input input-bordered input-primary" id="url-textbox">
375
- </div>
376
- <div class="form-control">
377
- <button class="btn btn-primary" id="extract-info">Extract Info</button>
378
- </div>
379
- </div>
380
- </div>
381
- <script>
382
- const githubTokenInput = document.getElementById('github-token');
383
- const repoUrlInput = document.getElementById('repo-url');
384
- const fetchIssuesButton = document.getElementById('fetch-issues');
385
- const issueDropdown = document.getElementById('issue-dropdown');
386
- const resolutionTextarea = document.getElementById('resolution-textarea');
387
- const forkedRepoUrlInput = document.getElementById('forked-repo-url');
388
- const resolveIssueButton = document.getElementById('resolve-issue');
389
- const outputTextarea = document.getElementById('output-textarea');
390
- const urlTextbox = document.getElementById('url-textbox');
391
- const extractInfoButton = document.getElementById('extract-info');
392
-
393
- fetchIssuesButton.addEventListener('click', async () => {
394
- const token = githubTokenInput.value;
395
- const repoUrl = repoUrlInput.value;
396
- if (!token || !repoUrl) {
397
- outputTextarea.value = "Please provide both GitHub Token and Repository URL.";
398
- return;
399
- }
400
- try {
401
- const response = await fetch('/fetch-issues', {
402
- method: 'POST',
403
- headers: {
404
- 'Content-Type': 'application/json',
405
- },
406
- body: JSON.stringify({ githubToken: token, repoUrl: repoUrl }),
407
- });
408
- if (!response.ok) {
409
- throw new Error(`HTTP error! status: ${response.status}`);
410
- }
411
- const data = await response.json();
412
- if (data.error) {
413
- outputTextarea.value = data.error;
414
- } else {
415
- issueDropdown.innerHTML = '';
416
- data.issues.forEach(issue => {
417
- const option = document.createElement('option');
418
- option.value = issue.number;
419
- option.text = `${issue.number}: ${issue.title}`;
420
- issueDropdown.add(option);
421
- });
422
- }
423
- } catch (error) {
424
- outputTextarea.value = `Error fetching issues: ${error.message}`;
425
- }
426
- });
427
-
428
- resolveIssueButton.addEventListener('click', async () => {
429
- const token = githubTokenInput.value;
430
- const repoUrl = repoUrlInput.value;
431
- const issueNumber = issueDropdown.value;
432
- const resolution = resolutionTextarea.value;
433
- const forkedRepoUrl = forkedRepoUrlInput.value;
434
- if (!token || !repoUrl || !issueNumber || !resolution) {
435
- outputTextarea.value = "Please provide all required fields.";
436
- return;
437
- }
438
- try {
439
- const response = await fetch('/resolve-issue', {
440
- method: 'POST',
441
- headers: {
442
- 'Content-Type': 'application/json',
443
- },
444
- body: JSON.stringify({ githubToken: token, repoUrl: repoUrl, issueNumber: issueNumber, resolution: resolution, forkedRepoUrl: forkedRepoUrl }),
445
- });
446
- if (!response.ok) {
447
- throw new Error(`HTTP error! status: ${response.status}`);
448
- }
449
- const data = await response.json();
450
- if (data.error) {
451
- outputTextarea.value = data.error;
452
- } else {
453
- outputTextarea.value = data.output;
454
- }
455
- } catch (error) {
456
- outputTextarea.value = `Error resolving issue: ${error.message}`;
457
- }
458
- });
459
 
460
- extractInfoButton.addEventListener('click', async () => {
461
- const url = urlTextbox.value;
462
- if (!url) {
463
- outputTextarea.value = "Please provide a URL.";
464
- return;
465
- }
466
- try {
467
- const response = await fetch('/extract-info', {
468
- method: 'POST',
469
- headers: {
470
- 'Content-Type': 'application/json',
471
- },
472
- body: JSON.stringify({ url: url }),
473
- });
474
- if (!response.ok) {
475
- throw new Error(`HTTP error! status: ${response.status}`);
476
- }
477
- const data = await response.json();
478
- if (data.error) {
479
- outputTextarea.value = data.error;
480
- } else {
481
- outputTextarea.value = JSON.stringify(data, null, 2);
482
- }
483
- } catch (error) {
484
- outputTextarea.value = `Error extracting info: ${error.message}`;
485
- }
486
- });
487
- </script>
488
- </body>
489
- </html>
490
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
 
492
  def create_gradio_interface():
493
  with gr.Blocks(css=None, theme=None) as demo:
494
  gr.HTML(custom_html)
 
495
  return demo
496
 
497
  # Cleanup function
@@ -517,6 +342,10 @@ if __name__ == "__main__":
517
  signal.signal(signal.SIGINT, signal_handler)
518
  signal.signal(signal.SIGTERM, signal_handler)
519
 
 
 
 
 
520
  # Create Gradio interface
521
  demo = create_gradio_interface()
522
  demo.launch()
 
12
  import subprocess
13
  from urllib.parse import urlparse, quote
14
  import webbrowser
15
+ from flask import Flask, request, jsonify, send_from_directory
16
+ from threading import Thread
17
 
18
  device = "cuda"
19
 
 
64
  RESOLUTIONS_DIRECTORY = 'resolutions'
65
  REPOS_DIRECTORY = 'repos'
66
 
67
+ # Set up environment
68
+ def initialize_environment(input_file, output_directory):
69
+ directories = [LOGS_DIRECTORY, RESOLUTIONS_DIRECTORY, REPOS_DIRECTORY, input_file, output_directory]
70
+ for directory in directories:
71
+ os.makedirs(directory, exist_ok=True)
72
+
73
  # Set up logging
74
+ def initialize_logger():
75
  log_file = f"{LOGS_DIRECTORY}/github_bot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
76
  logging.basicConfig(
77
  level=logging.INFO,
 
84
  return logging.getLogger(__name__)
85
 
86
  # Initialize environment and logger
87
+ initialize_environment(INPUT_DIRECTORY, OUTPUT_DIRECTORY)
 
 
 
 
 
88
  logger = initialize_logger() # Initialize logger globally
89
 
90
  # GitHub API handler
 
108
  if remaining < 10:
109
  wait_time = max(0, reset_time - int(time.time()))
110
  if wait_time > 0:
111
+ logger.warning(f"Rate limit nearly exceeded. Waiting {wait_time} seconds...")
112
  time.sleep(wait_time)
113
  return False
114
  return True
115
  except requests.exceptions.RequestException as e:
116
+ logger.error(f"Error checking rate limit: {str(e)}")
117
  return True
118
 
119
  def get_repository(self, owner: str, repo: str) -> Dict:
 
122
  response.raise_for_status()
123
  return response.json()
124
  except requests.HTTPError as e:
125
+ logger.error(f"HTTP error getting repository info: {str(e)}")
126
  raise
127
  except Exception as e:
128
  logger.error(f"Error getting repository info: {str(e)}")
 
138
  issues = response.json()
139
  return [issue for issue in issues if 'pull_request' not in issue]
140
  except Exception as e:
141
+ logger.error(f"Error fetching issues: {str(e)}")
142
  return []
143
 
144
  # GitHub Bot
 
154
  self.initialize_api(token)
155
  return self.github_api.get_issues(owner, repo)
156
  except Exception as e:
157
+ logger.error(f"Error fetching issues: {str(e)}")
158
  return []
159
 
160
  def resolve_issue(self, token: str, owner: str, repo: str, issue_number: int, resolution: str, forked_repo: str) -> str:
 
176
  os.chdir('/tmp/' + forked_repo.split('/')[-1])
177
 
178
  # Assuming manual intervention now
179
+ input(" Apply the fix manually and stage the changes (press ENTER)? ")
180
 
181
  # Commit and push the modifications
182
  subprocess.run(['git', 'add', '.'], check=True)
 
189
  return f"Resolution saved: {resolution_file}"
190
 
191
  except Exception as e:
192
+ error_msg = f"Error resolving issue: {str(e)}"
193
  logger.error(error_msg)
194
  return error_msg
195
 
 
260
  except Exception as e:
261
  return str(e)
262
 
263
+ def submit_issue(token, repo_url, issue_number, resolution, forked_repo_url):
264
+ try:
265
+ parts = repo_url.split('/')
266
+ if len(parts) < 2:
267
+ raise ValueError("Repository URL is not in the correct format. Expected format: 'owner/repo'.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
 
269
+ owner, repo = parts[-2], parts[-1]
270
+ result = bot.resolve_issue(token, owner, repo, issue_number, resolution, forked_repo_url)
271
+ return result
272
+ except Exception as e:
273
+ return str(e)
274
+
275
+ app = Flask(__name__)
276
+
277
+ @app.route('/index')
278
+ def serve_index():
279
+ return send_from_directory('.', 'index.html')
280
+
281
+ @app.route('/fetch_issues', methods=['POST'])
282
+ def fetch_issues_route():
283
+ data = request.get_json()
284
+ token = data.get('token')
285
+ repo_url = data.get('repoUrl')
286
+ if not token or not repo_url:
287
+ return jsonify({'error': 'Missing token or repoUrl'}), 400
288
+ issues = fetch_issues(token, repo_url)
289
+ return jsonify({'issues': issues})
290
+
291
+ @app.route('/resolve_issue', methods=['POST'])
292
+ def resolve_issue_route():
293
+ data = request.get_json()
294
+ token = data.get('token')
295
+ repo_url = data.get('repoUrl')
296
+ issue_number = data.get('issueNumber')
297
+ resolution = data.get('resolution')
298
+ forked_repo_url = data.get('forkedRepoUrl')
299
+ if not token or not repo_url or not issue_number or not resolution:
300
+ return jsonify({'error': 'Missing required fields'}), 400
301
+ result = resolve_issue(token, repo_url, issue_number, resolution, forked_repo_url)
302
+ return jsonify({'result': result})
303
+
304
+ @app.route('/extract_info', methods=['POST'])
305
+ def extract_info_route():
306
+ data = request.get_json()
307
+ url = data.get('url')
308
+ if not url:
309
+ return jsonify({'error': 'Missing URL'}), 400
310
+ info = extract_info(url)
311
+ return jsonify(info)
312
+
313
+ def run_flask_app():
314
+ app.run(debug=True, use_reloader=False)
315
 
316
  def create_gradio_interface():
317
  with gr.Blocks(css=None, theme=None) as demo:
318
  gr.HTML(custom_html)
319
+
320
  return demo
321
 
322
  # Cleanup function
 
342
  signal.signal(signal.SIGINT, signal_handler)
343
  signal.signal(signal.SIGTERM, signal_handler)
344
 
345
+ # Run Flask app in a separate thread
346
+ flask_thread = Thread(target=run_flask_app)
347
+ flask_thread.start()
348
+
349
  # Create Gradio interface
350
  demo = create_gradio_interface()
351
  demo.launch()