acecalisto3 commited on
Commit
794da70
·
verified ·
1 Parent(s): 51e2f34

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +274 -258
app.py CHANGED
@@ -1,292 +1,308 @@
1
- import gradio as gr
2
- from transformers import pipeline
3
- from sentence_transformers import SentenceTransformer, util
4
  import os
 
 
 
 
 
 
 
 
 
5
  import requests
6
- from transformers import AutoModelForCausalLM, AutoTokenizer
7
- import torch
8
- from huggingface_hub import InferenceClient, HfApi
9
- import git
10
- import gitdb
11
 
12
- # If you have a GPU, move the model to it
13
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
14
 
15
- # Constants for enhanced organization
16
- system_message = "You are GitBot, the Github project guardian angel. You resolve issues and propose implementation of feature requests"
17
- max_tokens = 2048
18
- temperature = 0.71
19
- top_p = 0.95
 
20
 
21
- def fetch_github_issues(github_api_token: str, github_username: str, github_repository: str) -> list:
22
- """Fetches issues from a specified GitHub repository using the GitHub API."""
23
- headers = {'Authorization': f'token {github_api_token}'}
24
- url = f"https://api.github.com/repos/{github_username}/{github_repository}/issues"
25
- response = requests.get(url, headers=headers)
26
- issues = response.json()
27
- return issues
 
 
 
28
 
29
- def resolve_issue(github_api_token: str, github_username: str, github_repository: str, issue_number: int, resolution: str):
30
- """Resolves an issue by pushing a commit with the resolution."""
31
- try:
32
- issue_text = fetch_github_issues(github_api_token, github_username, github_repository)[issue_number]['body']
33
- commit_message = f"Resolved issue {issue_number}: {issue_text}"
34
- commit_file = "resolution.txt"
35
- with open(commit_file, "w") as f:
36
- f.write(resolution)
37
- return push_to_repo(github_api_token, github_username, github_repository, commit_message, commit_file)
38
- except Exception as e:
39
- return f"Error resolving issue: {e}"
40
 
41
- def push_to_repo(github_api_token: str, github_username: str, github_repository: str, commit_message: str, commit_file: str):
42
- """Pushes changes to a GitHub repository."""
43
- try:
44
- repo = git.Repo.clone_from(f"https://github.com/{github_username}/{github_repository}.git", f"{github_repository}")
45
- repo.git.add(commit_file)
46
- repo.git.commit(m=commit_message)
47
- repo.git.push()
48
- return f"Changes pushed to {github_repository} successfully."
49
- except gitdb.exc.InvalidGitRepositoryError:
50
- return f"Invalid repository: {github_repository}"
51
- except Exception as e:
52
- return f"Error pushing to repository: {e}"
53
 
54
- def respond(command, history, system_message, max_tokens, temperature, top_p, github_api_token, github_username, github_repository, selected_model, severity, programming_language):
55
- """Generate a response using the selected model."""
56
- try:
57
- model = pipeline("text-generation", model=selected_model)
58
- prompt = f"{system_message}\nUser: {command}\nAssistant:"
59
-
60
- response = model(
61
- prompt,
62
- max_length=max_tokens,
63
- do_sample=True,
64
- temperature=temperature,
65
- top_p=top_p,
66
- )
67
-
68
- return {
69
- 'assistant_response': response[0]['generated_text'].split("Assistant:")[-1].strip(),
70
- 'severity': severity,
71
- 'programming_language': programming_language
72
- }
73
- except Exception as e:
74
- return {
75
- 'assistant_response': f"Error generating response: {str(e)}",
76
- 'severity': severity,
77
- 'programming_language': programming_language
78
- }
79
 
80
- class MyChatbot(gr.Chatbot):
81
- """Custom Chatbot class for enhanced functionality."""
82
- def __init__(self, **kwargs):
83
- super().__init__(type="messages", **kwargs)
84
- self.issues = []
85
- self.current_issue = None
 
 
 
 
 
 
86
 
87
- def postprocess(self, y):
88
- """Post-processes the response to handle commands and display results."""
89
- if not y:
90
- return []
91
-
92
- if isinstance(y, dict):
93
- assistant_response = y.get('assistant_response', '')
94
- command = y.get('command', '')
95
- else:
96
- assistant_response = str(y)
97
- command = ''
98
 
99
- return [
100
- {
101
- "role": "assistant",
102
- "content": assistant_response
103
- }
104
- ]
 
 
 
 
 
105
 
106
- # Main interface
107
- with gr.Blocks() as demo:
108
- with gr.Row():
109
- github_api_token = gr.Textbox(label="GitHub API Token", type="password")
110
- github_username = gr.Textbox(label="GitHub Username")
111
- github_repository = gr.Textbox(label="GitHub Repository")
 
 
 
 
 
 
112
 
113
- system_message = gr.Textbox(
114
- value="You are GitBot, the Github project guardian angel. You resolve issues and propose implementation of feature requests",
115
- label="System message",
116
- )
117
 
118
- with gr.Row():
119
- model_dropdown = gr.Dropdown(
120
- choices=[
121
- "mistralai/Mixtral-8x7B-Instruct-v0.1",
122
- "Gabriel/Swe-review-setfit-model",
123
- "OpenBMB/multilingual-codeparrot"
124
- ],
125
- label="Select Model for Issue Resolution",
126
- value="OpenBMB/multilingual-codeparrot",
127
- )
128
- severity_dropdown = gr.Dropdown(
129
- choices=["Critical", "Major", "Minor", "Trivial"],
130
- label="Severity",
131
- value=None,
132
- )
133
- programming_language_textbox = gr.Textbox(label="Programming Language")
 
 
 
 
 
 
 
134
 
135
- # Create the chatbot instance
136
- chatbot = MyChatbot()
137
-
138
- # Create input textbox for user messages
139
- msg = gr.Textbox(label="Message")
140
 
141
- # Create state for storing conversation history
142
- state = gr.State([])
 
143
 
144
- with gr.Row():
145
- fetch_issues_button = gr.Button("Fetch Issues")
146
- resolve_issue_button = gr.Button("Resolve Issue")
147
- clear_button = gr.Button("Clear Chat")
148
- submit_button = gr.Button("Submit Message")
149
 
150
- # Add a dropdown to select an issue
151
- issue_dropdown = gr.Dropdown(
152
- choices=[],
153
- label="Select Issue",
154
- interactive=True
155
- )
 
 
 
 
156
 
157
- with gr.Row():
158
- max_tokens_slider = gr.Slider(minimum=1, maximum=8192, value=2048, step=1, label="Max new tokens")
159
- temperature_slider = gr.Slider(minimum=0.1, maximum=4.0, value=0.71, step=0.1, label="Temperature")
160
- top_p_slider = gr.Slider(minimum=0.1, maximum=1.0, value=0.95, step=0.01, label="Top-p")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
- def user(user_message, history):
163
- """Handle user messages"""
164
- return "", history + [[user_message, None]]
165
 
166
- def bot(history, system_msg, max_tokens, temp, top_p, api_token, username, repo, model, severity, lang):
167
- """Generate bot response"""
168
- if len(history) == 0:
169
- return history
170
-
171
- user_message = history[-1][0]
172
- response = respond(
173
- command=user_message,
174
- history=history[:-1],
175
- system_message=system_msg,
176
- max_tokens=max_tokens,
177
- temperature=temp,
178
- top_p=top_p,
179
- github_api_token=api_token,
180
- github_username=username,
181
- github_repository=repo,
182
- selected_model=model,
183
- severity=severity,
184
- programming_language=lang
185
- )
186
 
187
- history[-1][1] = response['assistant_response']
188
- return history
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
- def clear_chat():
191
- return [], []
 
 
 
 
 
192
 
193
- def fetch_issues(api_token, username, repo):
194
- """Fetch GitHub issues and update the chatbot"""
195
- issues = fetch_github_issues(api_token, username, repo)
196
- chatbot.issues = issues
197
- return gr.Dropdown(choices=[f"{i+1}. {issue['title']}" for i, issue in enumerate(issues)])
 
 
198
 
199
- def select_issue(selected, chatbot):
200
- """Handle issue selection"""
201
- if selected:
202
- issue_num = int(selected.split('.')[0]) - 1
203
- chatbot.current_issue = chatbot.issues[issue_num]
204
- return chatbot.postprocess({
205
- 'command': str(issue_num + 1),
206
- 'github_api_token': github_api_token.value,
207
- 'github_username': github_username.value,
208
- 'github_repository': github_repository.value,
209
- 'selected_model': model_dropdown.value,
210
- 'severity': severity_dropdown.value,
211
- 'programming_language': programming_language_textbox.value
212
- })
213
- return []
214
 
215
- def resolve_selected_issue(api_token, username, repo, resolution):
216
- """Resolve the currently selected issue"""
217
- if chatbot.current_issue:
218
- issue_number = chatbot.issues.index(chatbot.current_issue)
219
- return resolve_issue(api_token, username, repo, issue_number, resolution)
220
- return "No issue selected"
 
 
 
 
 
 
221
 
222
- # Connect all the components
223
- msg.submit(user, [msg, chatbot], [msg, chatbot]).then(
224
- bot,
225
- [
226
- chatbot,
227
- system_message,
228
- max_tokens_slider,
229
- temperature_slider,
230
- top_p_slider,
231
- github_api_token,
232
- github_username,
233
- github_repository,
234
- model_dropdown,
235
- severity_dropdown,
236
- programming_language_textbox
237
- ],
238
- [chatbot]
239
- )
240
 
241
- submit_button.click(user, [msg, chatbot], [msg, chatbot]).then(
242
- bot,
243
- [
244
- chatbot,
245
- system_message,
246
- max_tokens_slider,
247
- temperature_slider,
248
- top_p_slider,
249
- github_api_token,
250
- github_username,
251
- github_repository,
252
- model_dropdown,
253
- severity_dropdown,
254
- programming_language_textbox
255
- ],
256
- [chatbot]
257
- )
258
 
259
- fetch_issues_button.click(
260
- fetch_issues,
261
- inputs=[github_api_token, github_username, github_repository],
262
- outputs=[issue_dropdown]
263
- )
 
 
 
 
 
 
264
 
265
- clear_button.click(
266
- clear_chat,
267
- outputs=[chatbot, state]
268
- )
269
 
270
- issue_dropdown.change(
271
- select_issue,
272
- inputs=[issue_dropdown, chatbot],
273
- outputs=[chatbot]
274
- )
 
 
 
 
 
275
 
276
- resolve_issue_button.click(
277
- resolve_selected_issue,
278
- inputs=[
279
- github_api_token,
280
- github_username,
281
- github_repository,
282
- chatbot
283
- ],
284
- outputs=[chatbot]
285
- )
286
 
287
  if __name__ == "__main__":
288
- demo.queue().launch(
289
- share=True,
290
- server_name="0.0.0.0",
291
- server_port=7860
292
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
+ import sys
3
+ import signal
4
+ import warnings
5
+ import shutil
6
+ import logging
7
+ import json
8
+ import time
9
+ from datetime import datetime
10
+ from typing import List, Dict, Optional, Union
11
  import requests
12
+ from requests.exceptions import RequestException
13
+ import gradio as gr
14
+ from git import Repo, GitCommandError
15
+ import base64
16
+ import atexit
17
 
18
+ # Suppress warnings
19
+ warnings.filterwarnings('ignore', category=UserWarning)
20
+ os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
21
 
22
+ def initialize_environment():
23
+ """Initialize application environment and configurations"""
24
+ # Create necessary directories
25
+ directories = ['logs', 'resolutions', 'repos']
26
+ for directory in directories:
27
+ os.makedirs(directory, exist_ok=True)
28
 
29
+ # Configure logging
30
+ log_file = f"logs/github_bot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
31
+ logging.basicConfig(
32
+ level=logging.INFO,
33
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
34
+ handlers=[
35
+ logging.FileHandler(log_file),
36
+ logging.StreamHandler()
37
+ ]
38
+ )
39
 
40
+ # Set up global exception handler
41
+ def handle_exception(exc_type, exc_value, exc_traceback):
42
+ if issubclass(exc_type, KeyboardInterrupt):
43
+ sys.__excepthook__(exc_type, exc_value, exc_traceback)
44
+ return
45
+ logging.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
 
 
 
 
 
46
 
47
+ sys.excepthook = handle_exception
48
+ return logging.getLogger(__name__)
 
 
 
 
 
 
 
 
 
 
49
 
50
+ logger = initialize_environment()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ class GitHubAPI:
53
+ """GitHub API handler with rate limiting and error handling"""
54
+
55
+ def __init__(self, token: str):
56
+ self.token = token
57
+ self.headers = {
58
+ 'Authorization': f'token {token}',
59
+ 'Accept': 'application/vnd.github.v3+json'
60
+ }
61
+ self.base_url = "https://api.github.com"
62
+ self.rate_limit_remaining = None
63
+ self.rate_limit_reset = None
64
 
65
+ def _check_rate_limit(self) -> bool:
66
+ """Check and handle GitHub API rate limits"""
67
+ try:
68
+ response = requests.get(f"{self.base_url}/rate_limit", headers=self.headers)
69
+ response.raise_for_status()
70
+ limits = response.json()
71
+ self.rate_limit_remaining = limits['resources']['core']['remaining']
72
+ self.rate_limit_reset = limits['resources']['core']['reset']
 
 
 
73
 
74
+ if self.rate_limit_remaining < 10:
75
+ reset_time = datetime.fromtimestamp(self.rate_limit_reset)
76
+ wait_time = (reset_time - datetime.now()).total_seconds()
77
+ if wait_time > 0:
78
+ logger.warning(f"Rate limit nearly exceeded. Waiting {wait_time:.0f} seconds...")
79
+ time.sleep(wait_time)
80
+ return False
81
+ return True
82
+ except Exception as e:
83
+ logger.error(f"Error checking rate limit: {str(e)}")
84
+ return True
85
 
86
+ def get_repository(self, owner: str, repo: str) -> Dict:
87
+ """Get repository information"""
88
+ try:
89
+ response = requests.get(
90
+ f"{self.base_url}/repos/{owner}/{repo}",
91
+ headers=self.headers
92
+ )
93
+ response.raise_for_status()
94
+ return response.json()
95
+ except Exception as e:
96
+ logger.error(f"Error getting repository info: {str(e)}")
97
+ raise
98
 
99
+ def get_issues(self, owner: str, repo: str, state: str = 'open') -> List[Dict]:
100
+ """Fetch repository issues"""
101
+ if not self._check_rate_limit():
102
+ return []
103
 
104
+ try:
105
+ response = requests.get(
106
+ f"{self.base_url}/repos/{owner}/{repo}/issues",
107
+ headers=self.headers,
108
+ params={'state': state}
109
+ )
110
+
111
+ if response.status_code == 404:
112
+ logger.error(f"Repository not found: {owner}/{repo}")
113
+ return []
114
+
115
+ response.raise_for_status()
116
+ issues = response.json()
117
+
118
+ # Filter out pull requests
119
+ issues = [issue for issue in issues if 'pull_request' not in issue]
120
+
121
+ logger.info(f"Successfully fetched {len(issues)} issues from {owner}/{repo}")
122
+ return issues
123
+
124
+ except Exception as e:
125
+ logger.error(f"Error fetching issues: {str(e)}")
126
+ return []
127
 
128
+ class GitHubBot:
129
+ """Main GitHub bot implementation"""
 
 
 
130
 
131
+ def __init__(self):
132
+ self.github_api = None
133
+ self.issues = []
134
 
135
+ def initialize_api(self, token: str):
136
+ """Initialize GitHub API with token"""
137
+ self.github_api = GitHubAPI(token)
 
 
138
 
139
+ def fetch_issues(self, token: str, username: str, repo: str) -> List[Dict]:
140
+ """Fetch issues from GitHub repository"""
141
+ try:
142
+ self.initialize_api(token)
143
+ issues = self.github_api.get_issues(username, repo)
144
+ self.issues = issues
145
+ return issues
146
+ except Exception as e:
147
+ logger.error(f"Error fetching issues: {str(e)}")
148
+ return []
149
 
150
+ def resolve_issue(self, token: str, username: str, repo: str, issue_number: int, resolution: str) -> str:
151
+ """Resolve a GitHub issue"""
152
+ try:
153
+ self.initialize_api(token)
154
+
155
+ # Verify repository exists
156
+ self.github_api.get_repository(username, repo)
157
+
158
+ # Create resolution file
159
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
160
+ resolution_file = f"resolutions/resolution_{issue_number}_{timestamp}.md"
161
+
162
+ with open(resolution_file, "w") as f:
163
+ f.write(f"# Resolution for Issue #{issue_number}\n\n{resolution}")
164
+
165
+ return f"Resolution saved: {resolution_file}"
166
+
167
+ except Exception as e:
168
+ error_msg = f"Error resolving issue: {str(e)}"
169
+ logger.error(error_msg)
170
+ return error_msg
171
 
172
+ def create_gradio_interface():
173
+ """Create and configure Gradio interface"""
174
+ bot = GitHubBot()
175
 
176
+ with gr.Blocks(title="GitHub Issue Manager") as demo:
177
+ gr.Markdown("# GitHub Issue Manager")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
+ with gr.Row():
180
+ github_token = gr.Textbox(
181
+ label="GitHub Token",
182
+ placeholder="Enter your GitHub token",
183
+ type="password"
184
+ )
185
+ github_username = gr.Textbox(
186
+ label="Repository Owner",
187
+ placeholder="Enter repository owner username"
188
+ )
189
+ github_repo = gr.Textbox(
190
+ label="Repository Name",
191
+ placeholder="Enter repository name"
192
+ )
193
 
194
+ with gr.Row():
195
+ fetch_button = gr.Button("Fetch Issues")
196
+ issue_dropdown = gr.Dropdown(
197
+ choices=[],
198
+ label="Select Issue",
199
+ interactive=True
200
+ )
201
 
202
+ with gr.Row():
203
+ resolution_text = gr.Textbox(
204
+ label="Resolution",
205
+ placeholder="Enter your resolution here...",
206
+ lines=5
207
+ )
208
+ resolve_button = gr.Button("Resolve Issue")
209
 
210
+ output_text = gr.Textbox(label="Output", interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
 
212
+ def fetch_issues_handler(token, username, repo):
213
+ """Handle issue fetching"""
214
+ if not all([token, username, repo]):
215
+ return gr.Dropdown(choices=["Please provide all required fields"])
216
+
217
+ issues = bot.fetch_issues(token, username, repo)
218
+ if not issues:
219
+ return gr.Dropdown(choices=["No issues found or error occurred"])
220
+
221
+ return gr.Dropdown(
222
+ choices=[f"#{issue['number']}: {issue['title']}" for issue in issues]
223
+ )
224
 
225
+ def resolve_issue_handler(token, username, repo, selected_issue, resolution):
226
+ """Handle issue resolution"""
227
+ if not selected_issue:
228
+ return "Please select an issue first"
229
+
230
+ try:
231
+ issue_number = int(selected_issue.split(':')[0][1:])
232
+ return bot.resolve_issue(token, username, repo, issue_number, resolution)
233
+ except Exception as e:
234
+ return f"Error: {str(e)}"
 
 
 
 
 
 
 
 
235
 
236
+ # Connect components
237
+ fetch_button.click(
238
+ fetch_issues_handler,
239
+ inputs=[github_token, github_username, github_repo],
240
+ outputs=[issue_dropdown]
241
+ )
 
 
 
 
 
 
 
 
 
 
 
242
 
243
+ resolve_button.click(
244
+ resolve_issue_handler,
245
+ inputs=[
246
+ github_token,
247
+ github_username,
248
+ github_repo,
249
+ issue_dropdown,
250
+ resolution_text
251
+ ],
252
+ outputs=[output_text]
253
+ )
254
 
255
+ return demo
 
 
 
256
 
257
+ def cleanup():
258
+ """Cleanup function for graceful shutdown"""
259
+ try:
260
+ temp_dirs = ['repos']
261
+ for dir_name in temp_dirs:
262
+ if os.path.exists(dir_name):
263
+ shutil.rmtree(dir_name)
264
+ logging.shutdown()
265
+ except Exception as e:
266
+ print(f"Error during cleanup: {str(e)}")
267
 
268
+ def signal_handler(signum, frame):
269
+ """Handle termination signals"""
270
+ logger.info(f"Received signal {signum}")
271
+ cleanup()
272
+ sys.exit(0)
 
 
 
 
 
273
 
274
  if __name__ == "__main__":
275
+ # Register cleanup handlers
276
+ atexit.register(cleanup)
277
+ signal.signal(signal.SIGINT, signal_handler)
278
+ signal.signal(signal.SIGTERM, signal_handler)
279
+
280
+ try:
281
+ # Create and launch interface
282
+ demo = create_gradio_interface()
283
+
284
+ # Configure launch parameters
285
+ is_on_spaces = os.getenv("SPACE_ID") is not None
286
+ launch_kwargs = {
287
+ "server_name": "0.0.0.0",
288
+ "server_port": 7860,
289
+ "debug": True,
290
+ "enable_queue": True,
291
+ "max_threads": 10
292
+ }
293
+
294
+ if not is_on_spaces:
295
+ launch_kwargs["share"] = True
296
+ logger.info("Running in local mode with public URL enabled")
297
+ else:
298
+ logger.info("Running on Hugging Face Spaces")
299
+
300
+ # Launch application
301
+ logger.info("Launching Gradio interface...")
302
+ demo.queue().launch(**launch_kwargs)
303
+
304
+ except Exception as e:
305
+ logger.error(f"Error launching application: {str(e)}")
306
+ raise
307
+ finally:
308
+ logger.info("Application shutdown")