acecalisto3 commited on
Commit
86841c5
·
verified ·
1 Parent(s): dd262f4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +276 -273
app.py CHANGED
@@ -13,48 +13,10 @@ import subprocess
13
  from urllib.parse import urlparse, quote
14
  import warnings
15
  import webbrowser
16
- import spaces
17
-
18
- device = "cuda"
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 = False if temperature == 0 else True,
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'
@@ -115,129 +77,120 @@ 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
  # HTML and CSS integration
231
  custom_html = """
232
  <!DOCTYPE html>
233
- <html lang="en">
234
  <head>
 
235
  <meta charset="UTF-8">
236
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
237
- <title>GitHub Issue Manager</title>
238
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css">
239
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
240
  <style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  .btn-primary {
242
  background-color: #7928CA;
243
  color: white;
@@ -250,146 +203,192 @@ custom_html = """
250
  }
251
  </style>
252
  </head>
253
- <body>
254
- <div id="app" class="container mx-auto p-4">
255
- <h1 class="text-4xl md:text-5xl font-extrabold text-center mb-8">GitHub Issue Manager</h1>
256
-
257
- <div class="card bg-gray-800 p-8">
258
- <div class="form-control">
259
- <label class="label">
260
- <span class="label-text">GitHub Token</span>
261
- </label>
262
- <input type="password" placeholder="Enter your GitHub Personal Access Token" class="input input-bordered input-primary" v-model="githubToken">
263
- </div>
264
- <div class="form-control">
265
- <label class="label">
266
- <span class="label-text">Repository URL</span>
267
- </label>
268
- <input type="text" placeholder="Enter the full GitHub repository URL" class="input input-bordered input-primary" v-model="repoUrl">
269
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  </div>
271
-
272
- <div class="card bg-gray-800 p-8">
273
- <div class="flex justify-between gap-4">
274
- <button class="btn btn-primary" @click="fetchIssues">Fetch Issues</button>
275
- <select class="select select-primary w-full max-w-xs" v-model="selectedIssue">
276
- <option disabled="" selected="">Select Issue</option>
277
- <option v-for="issue in issues" :key="issue.id" :value="issue">{{ issue.title }}</option>
278
- </select>
279
- </div>
280
- <div class="form-control mt-4">
281
- <label class="label">
282
- <span class="label-text">Resolution</span>
283
- </label>
284
- <textarea class="textarea textarea-primary" placeholder="Enter the resolution details" v-model="resolution"></textarea>
285
- </div>
286
- <div class="form-control mt-4">
287
- <label class="label">
288
- <span class="label-text">Forked Repository URL</span>
289
- </label>
290
- <input type="text" placeholder="URL to your forked repository (Optional)" class="input input-bordered input-primary" v-model="forkedRepoUrl">
291
- </div>
292
- <div class="form-control mt-4">
293
- <button class="btn btn-success" @click="resolveIssue">Resolve Issue</button>
294
- </div>
295
  </div>
296
-
297
- <div class="card bg-gray-800 p-8 mt-4">
298
  <label class="label">
299
- <span class="label-text">Output</span>
300
  </label>
301
- <textarea class="textarea textarea-primary h-48" v-model="output" readonly></textarea>
302
  </div>
303
-
304
- <div class="card bg-gray-800 p-8 mt-4">
305
- <div class="form-control">
306
- <label class="label">
307
- <span class="label-text">URL</span>
308
- </label>
309
- <input type="text" placeholder="Enter a URL to extract information" class="input input-bordered input-primary" v-model="url">
310
- </div>
311
- <div class="form-control">
312
- <button class="btn btn-primary" @click="extractInfo">Extract Info</button>
313
- </div>
314
  </div>
315
  </div>
316
-
317
- <script>
318
- new Vue({
319
- el: '#app',
320
- data: {
321
- githubToken: '',
322
- repoUrl: '',
323
- issues: [],
324
- selectedIssue: '',
325
- resolution: '',
326
- forkedRepoUrl: '',
327
- output: '',
328
- url: ''
329
- },
330
- methods: {
331
- fetchIssues() {
332
- fetch('/fetch-issues', {
333
- method: 'POST',
334
- headers: {
335
- 'Content-Type': 'application/json'
336
- },
337
- body: JSON.stringify({
338
- githubToken: this.githubToken,
339
- repoUrl: this.repoUrl
340
- })
341
- })
342
- .then(response => response.json())
343
- .then(data => {
344
- this.issues = data.issues;
345
- })
346
- .catch(error => {
347
- console.error(error);
348
- });
349
- },
350
- resolveIssue() {
351
- fetch('/resolve-issue', {
352
- method: 'POST',
353
- headers: {
354
- 'Content-Type': 'application/json'
355
- },
356
- body: JSON.stringify({
357
- githubToken: this.githubToken,
358
- repoUrl: this.repoUrl,
359
- issue: this.selectedIssue,
360
- resolution: this.resolution,
361
- forkedRepoUrl: this.forkedRepoUrl
362
- })
363
- })
364
- .then(response => response.json())
365
- .then(data => {
366
- this.output = data.output;
367
- })
368
- .catch(error => {
369
- console.error(error);
370
- });
371
- },
372
- extractInfo() {
373
- fetch('/extract-info', {
374
- method: 'POST',
375
- headers: {
376
- 'Content-Type': 'application/json'
377
- },
378
- body: JSON.stringify({
379
- url: this.url
380
- })
381
- })
382
- .then(response => response.json())
383
- .then(data => {
384
- this.output = data.output;
385
- })
386
- .catch(error => {
387
- console.error(error);
388
- });
389
- }
390
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
  });
392
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  </body>
394
  </html>
395
  """
@@ -423,6 +422,10 @@ if __name__ == "__main__":
423
  signal.signal(signal.SIGINT, signal_handler)
424
  signal.signal(signal.SIGTERM, signal_handler)
425
 
 
 
 
 
426
  # Create Gradio interface
427
  demo = create_gradio_interface()
428
  demo.launch()
 
13
  from urllib.parse import urlparse, quote
14
  import warnings
15
  import webbrowser
16
+ from flask import Flask, request, jsonify
17
+ from threading import Thread
18
+
19
+ app = Flask(__name__)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
  # Constants
22
  INPUT_DIRECTORY = 'input'
 
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 Exception 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 Exception 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 Exception 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 Exception as e:
113
+ logger.error(f"Error updating issue: {str(e)}")
114
+ return {}
115
+
116
+ @app.route('/fetch-issues', methods=['POST'])
117
+ def fetch_issues():
118
+ data = request.get_json()
119
+ github_token = data['githubToken']
120
+ repo_url = data['repoUrl']
121
+ owner, repo = repo_url.split('/')[-2:]
122
+ github_api = GitHubAPI(github_token)
123
+ issues = github_api.get_issues(owner, repo)
124
+ return jsonify({'issues': issues})
125
+
126
+ @app.route('/resolve-issue', methods=['POST'])
127
+ def resolve_issue():
128
+ data = request.get_json()
129
+ github_token = data['githubToken']
130
+ repo_url = data['repoUrl']
131
+ issue = data['issue']
132
+ resolution = data['resolution']
133
+ forked_repo_url = data['forkedRepoUrl']
134
+ owner, repo = repo_url.split('/')[-2:]
135
+ github_api = GitHubAPI(github_token)
136
+ issue_number = issue['number']
137
+ github_api.update_issue(owner, repo, issue_number, issue['title'], resolution)
138
+ return jsonify({'output': f"Issue {issue_number} resolved"})
139
+
140
+ @app.route('/extract-info', methods=['POST'])
141
+ def extract_info():
142
+ data = request.get_json()
143
+ url = data['url']
144
+ # Extract info from URL
145
+ return jsonify({'output': f"Info extracted from {url}"})
146
+
147
+ def run_flask_app():
148
+ app.run(debug=True, use_reloader=False)
 
 
149
 
150
  # HTML and CSS integration
151
  custom_html = """
152
  <!DOCTYPE html>
153
+ <html>
154
  <head>
155
+ <title>GitHub Issue Manager</title>
156
  <meta charset="UTF-8">
157
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
158
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
159
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css" rel="stylesheet" type="text/css" />
 
160
  <style>
161
+ body {
162
+ background: linear-gradient(to bottom right, #121212, #303030) !important;
163
+ color: #e0e0e0;
164
+ font-family: 'Roboto', sans-serif;
165
+ overflow-x: hidden; /* Prevent horizontal scrollbar */
166
+
167
+ }
168
+ .card {
169
+ border-radius: 1.5rem;
170
+ box-shadow: 0 15px 25px rgba(0, 0, 0, 0.2);
171
+ margin-bottom: 20px;
172
+ }
173
+ .input, .select, .textarea {
174
+ border: 2px solid #4a4a4a;
175
+ border-radius: 0.75rem;
176
+ padding-inline: 1.5rem;
177
+ padding-block: 0.75rem;
178
+
179
+ }
180
+ h1, h2, h3 {
181
+ color: #e0e0e0;
182
+ }
183
+
184
+ .output-area {
185
+ padding: 1.5rem;
186
+ border-radius: 0.75rem;
187
+ }
188
+ .btn {
189
+ border-radius: 0.75rem;
190
+ padding-block: 0.75rem;
191
+ padding-inline: 1.5rem;
192
+
193
+ }
194
  .btn-primary {
195
  background-color: #7928CA;
196
  color: white;
 
203
  }
204
  </style>
205
  </head>
206
+ <body class="bg-gray-900">
207
+ <div class="container mx-auto p-4" >
208
+
209
+ <h1 class="text-4xl md:text-5xl font-extrabold text-center mb-8">GitHub Issue Manager</h1>
210
+
211
+ <!-- GitHub Token & Repo URL -->
212
+ <div class="card bg-gray-800 p-8">
213
+ <div class="form-control">
214
+ <label class="label">
215
+ <span class="label-text">GitHub Token</span>
216
+ </label>
217
+ <input type="password" placeholder="Enter your GitHub Personal Access Token" class="input input-bordered input-primary" id="github-token">
218
+ </div>
219
+ <div class="form-control">
220
+ <label class="label">
221
+ <span class="label-text">Repository URL</span>
222
+ </label>
223
+ <input type="text" placeholder="Enter the full GitHub repository URL" class="input input-bordered input-primary" id="repo-url">
224
+ </div>
225
+ </div>
226
+
227
+ <!-- Fetch & Resolve Section -->
228
+ <div class="card bg-gray-800 p-8">
229
+ <div class="flex justify-between gap-4">
230
+
231
+ <button class="btn btn-primary" id="fetch-issues">Fetch Issues</button>
232
+
233
+ <select class="select select-primary w-full max-w-xs" id="issue-dropdown" >
234
+ <option disabled selected>Select Issue</option>
235
+ </select>
236
  </div>
237
+ <div class="form-control mt-4">
238
+ <label class="label">
239
+ <span class="label-text">Resolution</span>
240
+ </label>
241
+ <textarea class="textarea textarea-primary" placeholder="Enter the resolution details" id="resolution-textarea"></textarea>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  </div>
243
+ <div class="form-control mt-4">
 
244
  <label class="label">
245
+ <span class="label-text">Forked Repository URL</span>
246
  </label>
247
+ <input type="text" placeholder="URL to your forked repository (Optional)" class="input input-bordered input-primary" id="forked-repo-url">
248
  </div>
249
+ <div class="form-control mt-4">
250
+ <button class="btn btn-success" id="resolve-issue">Resolve Issue</button>
 
 
 
 
 
 
 
 
 
251
  </div>
252
  </div>
253
+
254
+ <!-- Output Area -->
255
+ <div class="card bg-gray-800 p-8 mt-4" >
256
+ <label class="label">
257
+ <span class="label-text">Output</span>
258
+ </label>
259
+ <textarea class="textarea textarea-primary h-48" id="output-textarea" readonly></textarea>
260
+ </div>
261
+
262
+ <!-- URL to Extract -->
263
+ <div class="card bg-gray-800 p-8 mt-4">
264
+ <div class="form-control">
265
+ <label class="label">
266
+ <span class="label-text">URL</span>
267
+ </label>
268
+ <input type="text" placeholder="Enter a URL to extract information" class="input input-bordered input-primary" id="url-textbox">
269
+ </div>
270
+ <div class="form-control">
271
+ <button class="btn btn-primary" id="extract-info">Extract Info</button>
272
+ </div>
273
+ </div>
274
+
275
+ </div>
276
+ <script>
277
+ const githubTokenInput = document.getElementById('github-token');
278
+ const repoUrlInput = document.getElementById('repo-url');
279
+ const fetchIssuesButton = document.getElementById('fetch-issues');
280
+ const issueDropdown = document.getElementById('issue-dropdown');
281
+ const resolutionTextarea = document.getElementById('resolution-textarea');
282
+ const forkedRepoUrlInput = document.getElementById('forked-repo-url');
283
+ const resolveIssueButton = document.getElementById('resolve-issue');
284
+ const outputTextarea = document.getElementById('output-textarea');
285
+ const urlTextbox = document.getElementById('url-textbox');
286
+ const extractInfoButton = document.getElementById('extract-info');
287
+
288
+ fetchIssuesButton.addEventListener('click', async () => {
289
+ const token = githubTokenInput.value;
290
+ const repoUrl = repoUrlInput.value;
291
+ if (!token || !repoUrl) {
292
+ outputTextarea.value = "Please provide both GitHub Token and Repository URL.";
293
+ return;
294
+ }
295
+ try {
296
+ const response = await fetch('/fetch-issues', {
297
+ method: 'POST',
298
+ headers: {
299
+ 'Content-Type': 'application/json',
300
+ },
301
+ body: JSON.stringify({ githubToken: token, repoUrl: repoUrl }),
302
+ });
303
+
304
+ if (!response.ok) {
305
+ throw new Error(`HTTP error! status: ${response.status}`);
306
+ }
307
+
308
+ const data = await response.json();
309
+ if (data.error) {
310
+ outputTextarea.value = data.error;
311
+ } else {
312
+ issueDropdown.innerHTML = '';
313
+ data.issues.forEach(issue => {
314
+ const option = document.createElement('option');
315
+ option.value = JSON.stringify(issue);
316
+ option.text = `${issue.number}: ${issue.title}`;
317
+ issueDropdown.add(option);
318
+ });
319
+ }
320
+
321
+ } catch (error) {
322
+ outputTextarea.value = `Error fetching issues: ${error.message}`;
323
+ }
324
+ });
325
+
326
+ resolveIssueButton.addEventListener('click', async () => {
327
+ const token = githubTokenInput.value;
328
+ const repoUrl = repoUrlInput.value;
329
+ const issue = JSON.parse(issueDropdown.value);
330
+ const resolution = resolutionTextarea.value;
331
+ const forkedRepoUrl = forkedRepoUrlInput.value;
332
+
333
+ if (!token || !repoUrl || !issue || !resolution) {
334
+ outputTextarea.value ="Please provide all required fields.";
335
+ return;
336
+ }
337
+ try {
338
+ const response = await fetch('/resolve-issue', {
339
+ method: 'POST',
340
+ headers: {
341
+ 'Content-Type': 'application/json',
342
+ },
343
+ body: JSON.stringify({ githubToken: token, repoUrl: repoUrl, issue: issue, resolution: resolution, forkedRepoUrl: forkedRepoUrl }),
344
  });
345
+
346
+ if (!response.ok) {
347
+ throw new Error(`HTTP error! status: ${response.status}`);
348
+ }
349
+
350
+ const data = await response.json();
351
+ if (data.error) {
352
+ outputTextarea.value = data.error;
353
+ } else {
354
+ outputTextarea.value = data.output;
355
+ }
356
+ } catch (error) {
357
+ outputTextarea.value = `Error resolving issue: ${error.message}`;
358
+ }
359
+ });
360
+
361
+ extractInfoButton.addEventListener('click', async () => {
362
+ const url = urlTextbox.value;
363
+ if (!url) {
364
+ outputTextarea.value = "Please provide a URL.";
365
+ return;
366
+ }
367
+ try {
368
+ const response = await fetch('/extract-info', {
369
+ method: 'POST',
370
+ headers: {
371
+ 'Content-Type': 'application/json',
372
+ },
373
+ body: JSON.stringify({ url: url }),
374
+ });
375
+
376
+ if (!response.ok) {
377
+ throw new Error(`HTTP error! status: ${response.status}`);
378
+ }
379
+
380
+ const data = await response.json();
381
+ if (data.error) {
382
+ outputTextarea.value = data.error;
383
+ } else {
384
+ outputTextarea.value = data.output;
385
+ }
386
+ } catch (error) {
387
+ outputTextarea.value = `Error extracting info: ${error.message}`;
388
+ }
389
+ });
390
+
391
+ </script>
392
  </body>
393
  </html>
394
  """
 
422
  signal.signal(signal.SIGINT, signal_handler)
423
  signal.signal(signal.SIGTERM, signal_handler)
424
 
425
+ # Run Flask app in a separate thread
426
+ flask_thread = Thread(target=run_flask_app)
427
+ flask_thread.start()
428
+
429
  # Create Gradio interface
430
  demo = create_gradio_interface()
431
  demo.launch()