acecalisto3 commited on
Commit
c36f5cb
·
verified ·
1 Parent(s): 09b9180

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +291 -196
app.py CHANGED
@@ -10,15 +10,52 @@ import requests
10
  import gradio as gr
11
  import atexit
12
  import subprocess
13
- import webbrowser
14
- import urllib.parse
15
  import warnings
16
- import torch
17
- import flask
18
- from flask import Flask, request, jsonify
19
  import spaces
20
- from accelerate import Accelerator
21
- from threading import Thread
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  # Constants
24
  INPUT_DIRECTORY = 'input'
@@ -27,8 +64,14 @@ LOGS_DIRECTORY = 'logs'
27
  RESOLUTIONS_DIRECTORY = 'resolutions'
28
  REPOS_DIRECTORY = 'repos'
29
 
 
 
 
 
 
 
30
  # Set up logging
31
- def initialize_logger() -> logging.Logger:
32
  log_file = f"{LOGS_DIRECTORY}/github_bot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
33
  logging.basicConfig(
34
  level=logging.INFO,
@@ -40,13 +83,9 @@ def initialize_logger() -> logging.Logger:
40
  )
41
  return logging.getLogger(__name__)
42
 
43
- # Set up environment
44
- @spaces.GPU
45
- def initialize_environment(input_file: str, output_directory: str) -> logging.Logger:
46
- directories = [LOGS_DIRECTORY, RESOLUTIONS_DIRECTORY, REPOS_DIRECTORY, input_file, output_directory]
47
- for directory in directories:
48
- os.makedirs(directory, exist_ok=True)
49
- return initialize_logger()
50
 
51
  # GitHub API handler
52
  class GitHubAPI:
@@ -73,81 +112,121 @@ class GitHubAPI:
73
  time.sleep(wait_time)
74
  return False
75
  return True
76
- except requests.exceptions.RequestException as e:
77
  logger.error(f"Error checking rate limit: {str(e)}")
78
  return True
79
 
80
- def get_repository(self, owner: str, repo: str) -> Dict[str, Any]:
81
  try:
82
  response = requests.get(f"{self.base_url}/repos/{owner}/{repo}", headers=self.headers)
83
  response.raise_for_status()
84
  return response.json()
85
- except requests.exceptions.RequestException as e:
86
- logger.error(f"Error getting repository: {str(e)}")
87
- return {}
 
 
 
 
 
 
 
88
 
89
- def get_issues(self, owner: str, repo: str) -> List[Dict[str, Any]]:
90
  try:
91
- response = requests.get(f"{self.base_url}/repos/{owner}/{repo}/issues", headers=self.headers)
92
  response.raise_for_status()
93
- return response.json()
94
- except requests.exceptions.RequestException as e:
95
- logger.error(f"Error getting issues: {str(e)}")
 
96
  return []
97
 
98
- def create_issue(self, owner: str, repo: str, title: str, body: str) -> Dict[str, Any]:
 
 
 
 
 
 
 
 
99
  try:
100
- response = requests.post(f"{self.base_url}/repos/{owner}/{repo}/issues", headers=self.headers, json={'title': title, 'body': body})
101
- response.raise_for_status()
102
- return response.json()
103
- except requests.exceptions.RequestException as e:
104
- logger.error(f"Error creating issue: {str(e)}")
105
- return {}
106
 
107
- def update_issue(self, owner: str, repo: str, issue_number: int, title: str, body: str) -> Dict[str, Any]:
108
  try:
109
- response = requests.patch(f"{self.base_url}/repos/{owner}/{repo}/issues/{issue_number}", headers=self.headers, json={'title': title, 'body': body})
110
- response.raise_for_status()
111
- return response.json()
112
- except requests.exceptions.RequestException as e:
113
- logger.error(f"Error updating issue: {str(e)}")
114
- return {}
115
-
116
- app = Flask(__name__)
117
-
118
- @app.route('/fetch-issues', methods=['POST'])
119
- def fetch_issues() -> Dict[str, Any]:
120
- data = request.get_json()
121
- github_token = data['githubToken']
122
- repo_url = data['repoUrl']
123
- owner, repo = repo_url.split('/')[-2:]
124
- github_api = GitHubAPI(github_token)
125
- issues = github_api.get_issues(owner , repo)
126
- return jsonify({'issues': issues})
127
-
128
- @app.route('/resolve-issue', methods=['POST'])
129
- def resolve_issue() -> Dict[str, Any]:
130
- data = request.get_json()
131
- github_token = data['githubToken']
132
- repo_url = data['repoUrl']
133
- issue = data['issue']
134
- resolution = data['resolution']
135
- forked_repo_url = data['forkedRepoUrl']
136
- owner, repo = repo_url.split('/')[-2:]
137
- github_api = GitHubAPI(github_token)
138
- issue_number = issue['number']
139
- github_api.update_issue(owner, repo, issue_number, issue['title'], resolution)
140
- return jsonify({'output': f"Issue {issue_number} resolved"})
141
-
142
- @app.route('/extract-info', methods=['POST'])
143
- def extract_info() -> Dict[str, Any]:
144
- data = request.get_json()
145
- url = data['url']
146
- # Extract info from URL
147
- return jsonify({'output': f"Info extracted from {url}"})
148
-
149
- def run_flask_app() -> None:
150
- app.run(debug=True, use_reloader=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
  # HTML and CSS integration
153
  custom_html = """
@@ -165,6 +244,7 @@ custom_html = """
165
  color: #e0e0e0;
166
  font-family: 'Roboto', sans-serif;
167
  overflow-x: hidden; /* Prevent horizontal scrollbar */
 
168
  }
169
  .card {
170
  border-radius: 1.5rem;
@@ -199,13 +279,10 @@ custom_html = """
199
  color: white;
200
  border: 2px solid #22c55e;
201
  }
202
- .loading {
203
- display: none;
204
- }
205
  </style>
206
  </head>
207
  <body class="bg-gray-900">
208
- <div class="container mx-auto p-4">
209
  <h1 class="text-4xl md:text-5xl font-extrabold text-center mb-8">GitHub Issue Manager</h1>
210
  <!-- GitHub Token & Repo URL -->
211
  <div class="card bg-gray-800 p-8">
@@ -226,11 +303,12 @@ custom_html = """
226
  <div class="card bg-gray-800 p-8">
227
  <div class="flex justify-between gap-4">
228
  <button class="btn btn-primary" id="fetch-issues">Fetch Issues</button>
229
- <select class="select select-primary w-full max-w-xs" id="issue-dropdown">
230
  <option disabled selected>Select Issue</option>
231
  </select>
232
  </div>
233
- <div class="form-control mt-4 <label class="label">
 
234
  <span class="label-text">Resolution</span>
235
  </label>
236
  <textarea class="textarea textarea-primary" placeholder="Enter the resolution details" id="resolution-textarea"></textarea>
@@ -246,7 +324,7 @@ custom_html = """
246
  </div>
247
  </div>
248
  <!-- Output Area -->
249
- <div class="card bg-gray-800 p-8 mt-4">
250
  <label class="label">
251
  <span class="label-text">Output</span>
252
  </label>
@@ -264,7 +342,6 @@ custom_html = """
264
  <button class="btn btn-primary" id="extract-info">Extract Info</button>
265
  </div>
266
  </div>
267
- <div class="loading" id="loading-indicator">Loading...</div>
268
  </div>
269
  <script>
270
  const githubTokenInput = document.getElementById('github-token');
@@ -277,137 +354,112 @@ custom_html = """
277
  const outputTextarea = document.getElementById('output-textarea');
278
  const urlTextbox = document.getElementById('url-textbox');
279
  const extractInfoButton = document.getElementById('extract-info');
280
- const loadingIndicator = document.getElementById('loading-indicator');
281
-
282
- const showLoading = () => {
283
- loadingIndicator.style.display = 'block';
284
- fetchIssuesButton.disabled = true;
285
- resolveIssueButton.disabled = true;
286
- extractInfoButton.disabled = true;
287
- };
288
-
289
- const hideLoading = () => {
290
- loadingIndicator.style.display = 'none';
291
- fetchIssuesButton.disabled = false;
292
- resolveIssueButton.disabled = false;
293
- extractInfoButton.disabled = false;
294
- };
295
-
296
  fetchIssuesButton.addEventListener('click', async () => {
297
- const token = githubTokenInput.value;
298
- const repoUrl = repoUrlInput.value;
299
- if (!token || !repoUrl) {
300
- outputTextarea.value = "Please provide both GitHub Token and Repository URL.";
301
- return;
 
 
 
 
 
 
 
 
 
 
 
302
  }
303
- showLoading();
304
- try {
305
- const response = await fetch('/fetch-issues', {
306
- method: 'POST',
307
- headers: {
308
- 'Content-Type': 'application/json',
309
- },
310
- body: JSON.stringify({ githubToken: token, repoUrl: repoUrl }),
 
 
311
  });
312
- if (!response.ok) {
313
- throw new Error(`HTTP error! status: ${response.status}`);
314
- }
315
- const data = await response.json();
316
- if (data.error) {
317
- outputTextarea.value = data.error;
318
- } else {
319
- issueDropdown.innerHTML = '';
320
- data.issues.forEach(issue => {
321
- const option = document.createElement('option');
322
- option.value = JSON.stringify(issue);
323
- option.text = `${issue.number}: ${issue.title}`;
324
- issueDropdown.add(option);
325
- });
326
- }
327
- } catch (error) {
328
- outputTextarea.value = `Error fetching issues: ${error.message}`;
329
- } finally {
330
- hideLoading();
331
  }
 
 
 
332
  });
333
-
334
  resolveIssueButton.addEventListener('click', async () => {
335
- const token = githubTokenInput.value;
336
- const repoUrl = repoUrlInput.value;
337
- const issue = JSON.parse(issueDropdown.value);
338
- const resolution = resolutionTextarea.value;
339
- const forkedRepoUrl = forkedRepoUrlInput.value;
340
- if (!token || !repoUrl || !issue || !resolution) {
341
- outputTextarea.value = "Please provide all required fields.";
342
- return;
 
 
 
 
 
 
 
 
 
 
 
343
  }
344
- show Loading();
345
- try {
346
- const response = await fetch('/resolve-issue', {
347
- method: 'POST',
348
- headers: {
349
- 'Content-Type': 'application/json',
350
- },
351
- body: JSON.stringify({ githubToken: token, repoUrl: repoUrl, issue: issue, resolution: resolution, forkedRepoUrl: forkedRepoUrl }),
352
- });
353
- if (!response.ok) {
354
- throw new Error(`HTTP error! status: ${response.status}`);
355
- }
356
- const data = await response.json();
357
- if (data.error) {
358
- outputTextarea.value = data.error;
359
- } else {
360
- outputTextarea.value = data.output;
361
- }
362
- } catch (error) {
363
- outputTextarea.value = `Error resolving issue: ${error.message}`;
364
- } finally {
365
- hideLoading();
366
  }
 
 
 
367
  });
368
-
369
  extractInfoButton.addEventListener('click', async () => {
370
- const url = urlTextbox.value;
371
- if (!url) {
372
- outputTextarea.value = "Please provide a URL.";
373
- return;
 
 
 
 
 
 
 
 
 
 
 
374
  }
375
- showLoading();
376
- try {
377
- const response = await fetch('/extract-info', {
378
- method: 'POST',
379
- headers: {
380
- 'Content-Type': 'application/json',
381
- },
382
- body: JSON.stringify({ url: url }),
383
- });
384
- if (!response.ok) {
385
- throw new Error(`HTTP error! status: ${response.status}`);
386
- }
387
- const data = await response.json();
388
- if (data.error) {
389
- outputTextarea.value = data.error;
390
- } else {
391
- outputTextarea.value = data.output;
392
- }
393
- } catch (error) {
394
- outputTextarea.value = `Error extracting info: ${error.message}`;
395
- } finally {
396
- hideLoading();
397
  }
 
 
 
398
  });
 
399
  </script>
400
  </body>
401
  </html>
402
  """
403
 
404
- def create_gradio_interface() -> gr.Blocks:
405
  with gr.Blocks(css=None, theme=None) as demo:
406
  gr.HTML(custom_html)
 
407
  return demo
408
 
409
  # Cleanup function
410
- def cleanup() -> None:
411
  try:
412
  temp_dirs = [REPOS_DIRECTORY]
413
  for dir_name in temp_dirs:
@@ -418,7 +470,7 @@ def cleanup() -> None:
418
  print(f"Error during cleanup: {str(e)}")
419
 
420
  # Signal handler
421
- def signal_handler(signum: int, frame) -> None:
422
  logger.info(f"Received signal {signum}")
423
  cleanup()
424
  sys.exit(0)
@@ -429,10 +481,53 @@ if __name__ == "__main__":
429
  signal.signal(signal.SIGINT, signal_handler)
430
  signal.signal(signal.SIGTERM, signal_handler)
431
 
432
- # Run Flask app in a separate thread
433
- flask_thread = Thread(target=run_flask_app)
434
- flask_thread.start()
435
-
436
  # Create Gradio interface
437
  demo = create_gradio_interface()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
  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
  import spaces
17
+
18
+ device = "cuda"
19
+
20
+ @spaces.GPU()
21
+ def stream_chat(
22
+ message: str,
23
+ history: list,
24
+ system_prompt: str,
25
+ temperature: float = 0.8,
26
+ max_new_tokens: int = 1024,
27
+ top_p: float = 1.0,
28
+ top_k: int = 20,
29
+ penalty: float = 1.2,
30
+ ):
31
+ print(f'message: {message}')
32
+ print(f'history: {history}')
33
+
34
+ conversation = [
35
+ {"role": "system", "content": system_prompt}
36
+ ]
37
+ for prompt, answer in history:
38
+ conversation.extend([
39
+ {"role": "user", "content": prompt},
40
+ {"role": "assistant", "content": answer},
41
+ ])
42
+
43
+ conversation.append({"role": "user", "content": message})
44
+
45
+ input_ids = tokenizer.apply_chat_template(conversation, add_generation_prompt=True, return_tensors="pt").to(model.device)
46
+
47
+ streamer = TextIteratorStreamer(tokenizer, timeout=60.0, skip_prompt=True, skip_special_tokens=True)
48
+
49
+ generate_kwargs = dict(
50
+ input_ids=input_ids,
51
+ max_new_tokens = max_new_tokens,
52
+ do_sample = False if temperature == 0 else True,
53
+ top_p = top_p,
54
+ top_k = top_k,
55
+ temperature = temperature,
56
+ eos_token_id=[128001,128008,128009],
57
+ streamer=streamer,
58
+ )
59
 
60
  # Constants
61
  INPUT_DIRECTORY = 'input'
 
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,
 
83
  )
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
91
  class GitHubAPI:
 
112
  time.sleep(wait_time)
113
  return False
114
  return True
115
+ except Exception 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:
120
  try:
121
  response = requests.get(f"{self.base_url}/repos/{owner}/{repo}", headers=self.headers)
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)}")
129
+ raise
130
+
131
+ def get_issues(self, owner: str, repo: str, state: str = 'open') -> List[Dict]:
132
+ if not self._check_rate_limit():
133
+ return []
134
 
 
135
  try:
136
+ response = requests.get(f"{self.base_url}/repos/{owner}/{repo}/issues", headers=self.headers, params={'state': state})
137
  response.raise_for_status()
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
145
+ class GitHubBot:
146
+ def __init__(self):
147
+ self.github_api = None
148
+
149
+ def initialize_api(self, token: str):
150
+ self.github_api = GitHubAPI(token)
151
+
152
+ def fetch_issues(self, token: str, owner: str, repo: str) -> List[Dict]:
153
  try:
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:
161
  try:
162
+ self.initialize_api(token)
163
+ self.github_api.get_repository(owner, repo)
164
+
165
+ # Create resolution file
166
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
167
+ resolution_file = f"{RESOLUTIONS_DIRECTORY}/resolution_{issue_number}_{timestamp}.md"
168
+
169
+ with open(resolution_file, "w") as f:
170
+ f.write(f"# Resolution for Issue #{issue_number}\n\n{resolution}")
171
+
172
+ # Clone the forked repo
173
+ subprocess.run(['git', 'clone', forked_repo, '/tmp/' + forked_repo.split('/')[-1]], check=True)
174
+
175
+ # Change to the cloned directory
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)
183
+ subprocess.run(['git', 'commit', '-m', f"Resolved issue #{issue_number} ({quote(resolution)})"], check=True)
184
+ subprocess.run(['git', 'push', 'origin', 'HEAD'], check=True)
185
+
186
+ # Open Pull Request page
187
+ webbrowser.open(f'https://github.com/{forked_repo.split("/")[-1]}/compare/master...{owner}:{forked_repo.split("/")[-1]}_resolved_issue_{issue_number}')
188
+
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
+
196
+ def handle_issue_selection(token, owner, repo, issue_number, resolution, forked_repo):
197
+ bot = GitHubBot()
198
+ result = bot.resolve_issue(token, owner, repo, issue_number, resolution, forked_repo)
199
+ return result
200
+
201
+ def extract_info_from_url(url: str) -> Dict[str, Any]:
202
+ info = {}
203
+ try:
204
+ response = requests.get(url)
205
+ response.raise_for_status()
206
+ info['status_code'] = response.status_code
207
+ info['headers'] = dict(response.headers)
208
+ info['content'] = response.text[:500] # Limit content to first 500 characters for brevity
209
+
210
+ parsed_url = urlparse(url)
211
+ if 'github.com' in parsed_url.netloc:
212
+ parts = parsed_url.path.split('/')
213
+ if len(parts) > 2:
214
+ owner = parts[1]
215
+ repo = parts[2]
216
+ issues = bot.fetch_issues(github_token, owner, repo)
217
+ info['issues'] = issues
218
+ elif 'huggingface.co' in parsed_url.netloc:
219
+ # Add Hugging Face specific handling if needed
220
+ pass
221
+
222
+ except requests.HTTPError as e:
223
+ info['error'] = f"HTTP error: {str(e)}"
224
+ except Exception as e:
225
+ info['error'] = f"Error: {str(e)}"
226
+ return info
227
+
228
+ # Initialize GitHubBot globally
229
+ bot = GitHubBot()
230
 
231
  # HTML and CSS integration
232
  custom_html = """
 
244
  color: #e0e0e0;
245
  font-family: 'Roboto', sans-serif;
246
  overflow-x: hidden; /* Prevent horizontal scrollbar */
247
+
248
  }
249
  .card {
250
  border-radius: 1.5rem;
 
279
  color: white;
280
  border: 2px solid #22c55e;
281
  }
 
 
 
282
  </style>
283
  </head>
284
  <body class="bg-gray-900">
285
+ <div class="container mx-auto p-4" >
286
  <h1 class="text-4xl md:text-5xl font-extrabold text-center mb-8">GitHub Issue Manager</h1>
287
  <!-- GitHub Token & Repo URL -->
288
  <div class="card bg-gray-800 p-8">
 
303
  <div class="card bg-gray-800 p-8">
304
  <div class="flex justify-between gap-4">
305
  <button class="btn btn-primary" id="fetch-issues">Fetch Issues</button>
306
+ <select class="select select-primary w-full max-w-xs" id="issue-dropdown" >
307
  <option disabled selected>Select Issue</option>
308
  </select>
309
  </div>
310
+ <div class="form-control mt-4">
311
+ <label class="label">
312
  <span class="label-text">Resolution</span>
313
  </label>
314
  <textarea class="textarea textarea-primary" placeholder="Enter the resolution details" id="resolution-textarea"></textarea>
 
324
  </div>
325
  </div>
326
  <!-- Output Area -->
327
+ <div class="card bg-gray-800 p-8 mt-4" >
328
  <label class="label">
329
  <span class="label-text">Output</span>
330
  </label>
 
342
  <button class="btn btn-primary" id="extract-info">Extract Info</button>
343
  </div>
344
  </div>
 
345
  </div>
346
  <script>
347
  const githubTokenInput = document.getElementById('github-token');
 
354
  const outputTextarea = document.getElementById('output-textarea');
355
  const urlTextbox = document.getElementById('url-textbox');
356
  const extractInfoButton = document.getElementById('extract-info');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  fetchIssuesButton.addEventListener('click', async () => {
358
+ const token = githubTokenInput.value;
359
+ const repoUrl = repoUrlInput.value;
360
+ if (!token || !repoUrl) {
361
+ outputTextarea.value = "Please provide both GitHub Token and Repository URL.";
362
+ return;
363
+ }
364
+ try {
365
+ const response = await fetch('/fetch_issues', {
366
+ method: 'POST',
367
+ headers: {
368
+ 'Content-Type': 'application/json',
369
+ },
370
+ body: JSON.stringify({ token: token, repoUrl: repoUrl }),
371
+ });
372
+ if (!response.ok) {
373
+ throw new Error(`HTTP error! status: ${response.status}`);
374
  }
375
+ const data = await response.json();
376
+ if (data.error) {
377
+ outputTextarea.value = data.error;
378
+ } else {
379
+ issueDropdown.innerHTML = '';
380
+ data.issues.forEach(issue => {
381
+ const option = document.createElement('option');
382
+ option.value = issue.number;
383
+ option.text = `${issue.number}: ${issue.title}`;
384
+ issueDropdown.add(option);
385
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  }
387
+ } catch (error) {
388
+ outputTextarea.value = `Error fetching issues: ${error.message}`;
389
+ }
390
  });
 
391
  resolveIssueButton.addEventListener('click', async () => {
392
+ const token = githubTokenInput.value;
393
+ const repoUrl = repoUrlInput.value;
394
+ const issueNumber = issueDropdown.value;
395
+ const resolution = resolutionTextarea.value;
396
+ const forkedRepoUrl = forkedRepoUrlInput.value;
397
+ if (!token || !repoUrl || !issueNumber || !resolution) {
398
+ outputTextarea.value ="Please provide all required fields.";
399
+ return;
400
+ }
401
+ try {
402
+ const response = await fetch('/resolve_issue', {
403
+ method: 'POST',
404
+ headers: {
405
+ 'Content-Type': 'application/json',
406
+ },
407
+ body: JSON.stringify({ token: token, repoUrl: repoUrl, issueNumber: issueNumber, resolution: resolution, forkedRepoUrl: forkedRepoUrl }),
408
+ });
409
+ if (!response.ok) {
410
+ throw new Error(`HTTP error! status: ${response.status}`);
411
  }
412
+ const data = await response.json();
413
+ if (data.error) {
414
+ outputTextarea.value = data.error;
415
+ } else {
416
+ outputTextarea.value = data.result;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
417
  }
418
+ } catch (error) {
419
+ outputTextarea.value = `Error resolving issue: ${error.message}`;
420
+ }
421
  });
 
422
  extractInfoButton.addEventListener('click', async () => {
423
+ const url = urlTextbox.value;
424
+ if (!url) {
425
+ outputTextarea.value = "Please provide a URL.";
426
+ return;
427
+ }
428
+ try {
429
+ const response = await fetch('/extract_info', {
430
+ method: 'POST',
431
+ headers: {
432
+ 'Content-Type': 'application/json',
433
+ },
434
+ body: JSON.stringify({ url: url }),
435
+ });
436
+ if (!response.ok) {
437
+ throw new Error(`HTTP error! status: ${response.status}`);
438
  }
439
+ const data = await response.json();
440
+ if (data.error) {
441
+ outputTextarea.value = data.error;
442
+ } else {
443
+ outputTextarea.value = JSON.stringify(data, null, 2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
  }
445
+ } catch (error) {
446
+ outputTextarea.value = `Error extracting info: ${error.message}`;
447
+ }
448
  });
449
+
450
  </script>
451
  </body>
452
  </html>
453
  """
454
 
455
+ def create_gradio_interface():
456
  with gr.Blocks(css=None, theme=None) as demo:
457
  gr.HTML(custom_html)
458
+
459
  return demo
460
 
461
  # Cleanup function
462
+ def cleanup():
463
  try:
464
  temp_dirs = [REPOS_DIRECTORY]
465
  for dir_name in temp_dirs:
 
470
  print(f"Error during cleanup: {str(e)}")
471
 
472
  # Signal handler
473
+ def signal_handler(signum, frame):
474
  logger.info(f"Received signal {signum}")
475
  cleanup()
476
  sys.exit(0)
 
481
  signal.signal(signal.SIGINT, signal_handler)
482
  signal.signal(signal.SIGTERM, signal_handler)
483
 
 
 
 
 
484
  # Create Gradio interface
485
  demo = create_gradio_interface()
486
+
487
+ # Define Gradio endpoints
488
+ def fetch_issues(github_token, repo_url):
489
+ try:
490
+ issues = bot.fetch_issues(github_token, repo_url.split('/')[-2], repo_url.split('/')[-1])
491
+ return {'issues': issues}
492
+ except Exception as e:
493
+ return {'error': str(e)}
494
+
495
+ def resolve_issue(github_token, repo_url, issue_number, resolution, forked_repo_url):
496
+ try:
497
+ result = handle_issue_selection(github_token, repo_url.split('/')[-2], repo_url.split('/')[-1], issue_number, resolution, forked_repo_url)
498
+ return {'result': result}
499
+ except Exception as e:
500
+ return {'error': str(e)}
501
+
502
+ def extract_info(url):
503
+ try:
504
+ info = extract_info_from_url(url)
505
+ return info
506
+ except Exception as e:
507
+ return {'error': str(e)}
508
+
509
+ # Define Gradio interface
510
+ demo = gr.Blocks()
511
+ with demo:
512
+ gr.HTML(custom_html)
513
+
514
+ # Fetch issues endpoint
515
+ fetch_issues_button = gr.Button("Fetch Issues")
516
+ fetch_issues_button.click(
517
+ lambda: gr.update(value=fetch_issues(github_token_input.value, repo_url_input.value))
518
+ )
519
+
520
+ # Resolve issue endpoint
521
+ resolve_issue_button = gr.Button("Resolve Issue")
522
+ resolve_issue_button.click(
523
+ lambda: gr.update(value=resolve_issue(github_token_input.value, repo_url_input.value, issue_dropdown.value, resolution_textarea.value, forked_repo_url_input.value))
524
+ )
525
+
526
+ # Extract info endpoint
527
+ extract_info_button = gr.Button("Extract Info")
528
+ extract_info_button.click(
529
+ lambda: gr.update(value=extract_info(url_textbox.value))
530
+ )
531
+
532
+ # Launch Gradio interface
533
  demo.launch()