acecalisto3 commited on
Commit
0ffd4a1
·
verified ·
1 Parent(s): 73ffbb8

Update app.py

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