Update app.py
Browse files
app.py
CHANGED
@@ -1,686 +1,9 @@
|
|
1 |
-
import gradio as gr
|
2 |
-
from github import Github, GithubException
|
3 |
-
import os
|
4 |
-
import requests
|
5 |
-
import re
|
6 |
-
from collections import Counter
|
7 |
-
import jinja2 # Import Jinja2
|
8 |
-
|
9 |
-
# Load token. Best practice is to use environment variables.
|
10 |
-
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
|
11 |
-
if not GITHUB_TOKEN: # Good practice to have this check.
|
12 |
-
raise ValueError("GITHUB_TOKEN environment variable not set!")
|
13 |
-
g = Github(GITHUB_TOKEN)
|
14 |
-
|
15 |
-
# Project templates (parameterized with Jinja2) including shadcn.
|
16 |
-
PROJECT_TEMPLATES = {
|
17 |
-
"flask": {
|
18 |
-
"params": { # Define parameters for the template
|
19 |
-
"database_type": {
|
20 |
-
"type": "choice",
|
21 |
-
"default": "sqlite",
|
22 |
-
"choices": ["sqlite", "postgresql", "mysql"],
|
23 |
-
"description": "Type of database to configure for the Flask app."
|
24 |
-
}
|
25 |
-
},
|
26 |
-
"files": {
|
27 |
-
"app.py": """from flask import Flask
|
28 |
-
from flask_sqlalchemy import SQLAlchemy
|
29 |
-
import os
|
30 |
-
|
31 |
-
basedir = os.path.abspath(os.path.dirname(__file__))
|
32 |
-
|
33 |
-
app = Flask(__name__)
|
34 |
-
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL') or \\
|
35 |
-
'{{database_uri}}' # Placeholder for database URI
|
36 |
-
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
37 |
-
|
38 |
-
db = SQLAlchemy(app)
|
39 |
-
|
40 |
-
class HelloWorld(db.Model):
|
41 |
-
id = db.Column(db.Integer, primary_key=True)
|
42 |
-
message = db.Column(db.String(128))
|
43 |
-
|
44 |
-
def __repr__(self):
|
45 |
-
return f'<HelloWorld {self.message}>'
|
46 |
-
|
47 |
-
@app.route('/')
|
48 |
-
def hello():
|
49 |
-
return "Hello, Flask!"
|
50 |
-
|
51 |
-
@app.route('/db_test')
|
52 |
-
def db_test():
|
53 |
-
try:
|
54 |
-
HelloWorld.query.first() # Simple DB query to test connection
|
55 |
-
return "Database connection successful!"
|
56 |
-
except Exception as e:
|
57 |
-
return f"Database connection failed: {e}"
|
58 |
-
|
59 |
-
|
60 |
-
if __name__ == '__main__':
|
61 |
-
with app.app_context(): # Create application context for DB operations
|
62 |
-
db.create_all()
|
63 |
-
if not HelloWorld.query.first(): # Initialize DB with a default entry if empty
|
64 |
-
default_hello = HelloWorld(message="Hello, Database!")
|
65 |
-
db.session.add(default_hello)
|
66 |
-
db.session.commit()
|
67 |
-
app.run(debug=True)""",
|
68 |
-
"requirements.txt": """Flask
|
69 |
-
Flask-SQLAlchemy
|
70 |
-
{{sqlalchemy_dependency}} # Placeholder for SQLAlchemy dependency""", # Conditional dependency
|
71 |
-
".gitignore": "__pycache__/\n*.pyc\nvenv/\ninstance/\n*.db"
|
72 |
-
},
|
73 |
-
"post_process": "install_dependencies" # Define a post-processing action
|
74 |
-
},
|
75 |
-
"react": {
|
76 |
-
"files": {
|
77 |
-
"package.json": """{
|
78 |
-
"name": "react-app",
|
79 |
-
"private": true,
|
80 |
-
"version": "0.0.0",
|
81 |
-
"type": "module",
|
82 |
-
"scripts": {
|
83 |
-
"dev": "vite",
|
84 |
-
"build": "vite build",
|
85 |
-
"preview": "vite preview"
|
86 |
-
},
|
87 |
-
"dependencies": {
|
88 |
-
"react": "^18.2.0",
|
89 |
-
"react-dom": "^18.2.0"
|
90 |
-
},
|
91 |
-
"devDependencies": {
|
92 |
-
"@vitejs/plugin-react": "^4.2.1",
|
93 |
-
"vite": "^5.0.8"
|
94 |
-
}}""",
|
95 |
-
"vite.config.js": """import { defineConfig } from 'vite'
|
96 |
-
import react from '@vitejs/plugin-react'
|
97 |
-
# https://vitejs.dev/config/
|
98 |
-
export default defineConfig({
|
99 |
-
plugins: [react()],
|
100 |
-
})""",
|
101 |
-
"index.html": """<!doctype html>
|
102 |
-
<html lang="en">
|
103 |
-
<head>
|
104 |
-
<meta charset="UTF-8" />
|
105 |
-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
106 |
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
107 |
-
<title>Vite + React</title>
|
108 |
-
</head>
|
109 |
-
<body>
|
110 |
-
<div id="root"></div>
|
111 |
-
<script type="module" src="/src/main.jsx"></script>
|
112 |
-
</body>
|
113 |
-
</html>""",
|
114 |
-
"src/main.jsx": """import React from 'react'
|
115 |
-
import ReactDOM from 'react-dom/client'
|
116 |
-
import App from './App.jsx'
|
117 |
-
import './index.css'
|
118 |
-
ReactDOM.createRoot(document.getElementById('root')).render(
|
119 |
-
<React.StrictMode>
|
120 |
-
<App />
|
121 |
-
</React.StrictMode>,
|
122 |
-
)""",
|
123 |
-
"src/App.jsx": """import React from 'react'
|
124 |
-
import './App.css'
|
125 |
-
function App() {
|
126 |
-
return (
|
127 |
-
<>
|
128 |
-
<h1>Hello from React!</h1>
|
129 |
-
</>
|
130 |
-
)
|
131 |
-
}
|
132 |
-
export default App""",
|
133 |
-
"src/index.css": """body {
|
134 |
-
margin: 0;
|
135 |
-
font-family: sans-serif;
|
136 |
-
-webkit-font-smoothing: antialiased;
|
137 |
-
-moz-osx-font-smoothing: grayscale;
|
138 |
-
}
|
139 |
-
code {
|
140 |
-
font-family: monospace;
|
141 |
-
}""",
|
142 |
-
".gitignore": "node_modules/\ndist/"
|
143 |
-
}
|
144 |
-
},
|
145 |
-
"django": {
|
146 |
-
"files": {
|
147 |
-
"manage.py": """#!/usr/bin/env python
|
148 |
-
import os
|
149 |
-
import sys
|
150 |
-
|
151 |
-
if __name__ == "__main__":
|
152 |
-
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
|
153 |
-
try:
|
154 |
-
from django.core.management import execute_from_command_line
|
155 |
-
except ImportError as exc:
|
156 |
-
raise ImportError(
|
157 |
-
"Couldn't import Django. Are you sure it is installed and "
|
158 |
-
"available on your PYTHONPATH environment variable? Did you "
|
159 |
-
"forget to activate a virtual environment?"
|
160 |
-
) from exc
|
161 |
-
execute_from_command_line(sys.argv)""",
|
162 |
-
"myapp/settings.py": """import os
|
163 |
-
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
164 |
-
SECRET_KEY = 'your_secret_key_here'
|
165 |
-
DEBUG = True
|
166 |
-
ALLOWED_HOSTS = []
|
167 |
-
INSTALLED_APPS = [
|
168 |
-
'django.contrib.admin',
|
169 |
-
'django.contrib.auth',
|
170 |
-
'django.contrib.contenttypes',
|
171 |
-
'django.contrib.sessions',
|
172 |
-
'django.contrib.messages',
|
173 |
-
'django.contrib.staticfiles',
|
174 |
-
]
|
175 |
-
MIDDLEWARE = [
|
176 |
-
'django.middleware.security.SecurityMiddleware',
|
177 |
-
'django.contrib.sessions.middleware.SessionMiddleware',
|
178 |
-
'django.middleware.common.CommonMiddleware',
|
179 |
-
'django.middleware.csrf.CsrfViewMiddleware',
|
180 |
-
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
181 |
-
'django.contrib.messages.middleware.MessageMiddleware',
|
182 |
-
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
183 |
-
]
|
184 |
-
ROOT_URLCONF = 'myapp.urls'
|
185 |
-
TEMPLATES = [
|
186 |
-
{
|
187 |
-
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
188 |
-
'DIRS': [],
|
189 |
-
'APP_DIRS': True,
|
190 |
-
'OPTIONS': {
|
191 |
-
'context_processors': [
|
192 |
-
'django.template.context_processors.debug',
|
193 |
-
'django.template.context_processors.request',
|
194 |
-
'django.contrib.auth.context_processors.auth',
|
195 |
-
'django.contrib.messages.context_processors.messages',
|
196 |
-
],
|
197 |
-
},
|
198 |
-
},
|
199 |
-
]
|
200 |
-
WSGI_APPLICATION = 'myapp.wsgi.application'
|
201 |
-
DATABASES = {
|
202 |
-
'default': {
|
203 |
-
'ENGINE': 'django.db.backends.sqlite3',
|
204 |
-
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
205 |
-
}
|
206 |
-
}
|
207 |
-
AUTH_PASSWORD_VALIDATORS = [
|
208 |
-
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',},
|
209 |
-
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',},
|
210 |
-
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',},
|
211 |
-
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',},
|
212 |
-
]
|
213 |
-
LANGUAGE_CODE = 'en-us'
|
214 |
-
TIME_ZONE = 'UTC'
|
215 |
-
USE_I18N = True
|
216 |
-
USE_L10N = True
|
217 |
-
USE_TZ = True
|
218 |
-
STATIC_URL = '/static/'
|
219 |
-
""",
|
220 |
-
"myapp/urls.py": """from django.contrib import admin
|
221 |
-
from django.urls import path
|
222 |
-
from django.http import HttpResponse
|
223 |
-
|
224 |
-
def home(request):
|
225 |
-
return HttpResponse("Hello, Django!")
|
226 |
-
|
227 |
-
urlpatterns = [
|
228 |
-
path('admin/', admin.site.urls),
|
229 |
-
path('', home, name='home'),
|
230 |
-
]""",
|
231 |
-
"myapp/wsgi.py": """import os
|
232 |
-
from django.core.wsgi import get_wsgi_application
|
233 |
-
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
|
234 |
-
application = get_wsgi_application()""",
|
235 |
-
"requirements.txt": "Django",
|
236 |
-
".gitignore": "__pycache__/\n*.pyc\nvenv/\ndb.sqlite3\n",
|
237 |
-
},
|
238 |
-
"rename_files": {"myapp": "{{repo_name_snake_case}}"} # Placeholder for repo name
|
239 |
-
},
|
240 |
-
"nodejs_express": {
|
241 |
-
"files": {
|
242 |
-
"server.js": """const express = require('express')
|
243 |
-
const app = express()
|
244 |
-
const port = 3000
|
245 |
-
|
246 |
-
app.get('/', (req, res) => {
|
247 |
-
res.send('Hello World from Express!')
|
248 |
-
})
|
249 |
-
|
250 |
-
app.listen(port, () => {
|
251 |
-
console.log(`Server listening on port ${port}`)
|
252 |
-
})""",
|
253 |
-
"package.json": """{
|
254 |
-
"name": "express-app",
|
255 |
-
"version": "1.0.0",
|
256 |
-
"description": "",
|
257 |
-
"main": "server.js",
|
258 |
-
"scripts": {
|
259 |
-
"start": "node server.js"
|
260 |
-
},
|
261 |
-
"dependencies": {
|
262 |
-
"express": "^4.17.1"
|
263 |
-
}
|
264 |
-
}""",
|
265 |
-
".gitignore": "node_modules/\n"
|
266 |
-
}
|
267 |
-
},
|
268 |
-
"static_website": {
|
269 |
-
"files": {
|
270 |
-
"index.html": """<!DOCTYPE html>
|
271 |
-
<html>
|
272 |
-
<head>
|
273 |
-
<title>Simple Static Website</title>
|
274 |
-
</head>
|
275 |
-
<body>
|
276 |
-
<h1>Hello from Static Website!</h1>
|
277 |
-
<p>This is a basic HTML page.</p>
|
278 |
-
</body>
|
279 |
-
</html>""",
|
280 |
-
"style.css": """body {
|
281 |
-
font-family: sans-serif;
|
282 |
-
margin: 20px;
|
283 |
-
}""",
|
284 |
-
"script.js": """console.log("Hello from JavaScript!");""",
|
285 |
-
".gitignore": ""
|
286 |
-
}
|
287 |
-
},
|
288 |
-
"python_script": {
|
289 |
-
"files": {
|
290 |
-
"main.py": """def main():
|
291 |
-
print("Hello from Python script!")
|
292 |
-
|
293 |
-
if __name__ == "__main__":
|
294 |
-
main()""",
|
295 |
-
"requirements.txt": "",
|
296 |
-
".gitignore": "__pycache__/\n*.pyc\nvenv/\n"
|
297 |
-
}
|
298 |
-
},
|
299 |
-
"empty": {
|
300 |
-
"files": {
|
301 |
-
"README.md": "# {{repo_name}}", # Placeholder for repo name
|
302 |
-
".gitignore": ""
|
303 |
-
},
|
304 |
-
"rename_files": {"README.md": "{{readme_filename}}"} # Placeholder for readme filename
|
305 |
-
},
|
306 |
-
"shadcn": {
|
307 |
-
"files": {
|
308 |
-
"package.json": """{
|
309 |
-
"name": "shadcn-react-app",
|
310 |
-
"private": true,
|
311 |
-
"version": "0.0.0",
|
312 |
-
"type": "module",
|
313 |
-
"scripts": {
|
314 |
-
"dev": "vite",
|
315 |
-
"build": "vite build",
|
316 |
-
"preview": "vite preview",
|
317 |
-
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
|
318 |
-
"preview": "vite preview"
|
319 |
-
},
|
320 |
-
"dependencies": {
|
321 |
-
"@radix-ui/react-slot": "^1.0.2",
|
322 |
-
"class-variance-authority": "^0.7.0",
|
323 |
-
"clsx": "^2.1.0",
|
324 |
-
"lucide-react": "^0.303.0",
|
325 |
-
"react": "^18.2.0",
|
326 |
-
"react-dom": "^18.2.0",
|
327 |
-
"tailwind-merge": "^2.2.0",
|
328 |
-
"tailwindcss-animate": "^1.0.7"
|
329 |
-
},
|
330 |
-
"devDependencies": {
|
331 |
-
"@vitejs/plugin-react": "^4.2.1",
|
332 |
-
"autoprefixer": "^10.4.16",
|
333 |
-
"eslint": "^8.55.0",
|
334 |
-
"eslint-plugin-react": "^7.33.2",
|
335 |
-
"eslint-plugin-react-hooks": "^4.6.0",
|
336 |
-
"eslint-plugin-react-refresh": "^0.4.5",
|
337 |
-
"postcss": "^8.4.33",
|
338 |
-
"tailwindcss": "^3.4.1",
|
339 |
-
"vite": "^5.0.8"
|
340 |
-
}
|
341 |
-
}""",
|
342 |
-
"vite.config.js": """import { defineConfig } from 'vite'
|
343 |
-
import react from '@vitejs/plugin-react'
|
344 |
-
|
345 |
-
// https://vitejs.dev/config/
|
346 |
-
export default defineConfig({
|
347 |
-
plugins: [react()],
|
348 |
-
})""",
|
349 |
-
"index.html": """<!doctype html>
|
350 |
-
<html lang="en">
|
351 |
-
<head>
|
352 |
-
<meta charset="UTF-8" />
|
353 |
-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
354 |
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
355 |
-
<title>Vite + React + Shadcn</title>
|
356 |
-
</head>
|
357 |
-
<body class="bg-background">
|
358 |
-
<div id="root"></div>
|
359 |
-
<script type="module" src="/src/main.jsx"></script>
|
360 |
-
</body>
|
361 |
-
</html>""",
|
362 |
-
"src/main.jsx": """import React from 'react'
|
363 |
-
import ReactDOM from 'react-dom/client'
|
364 |
-
import App from './App.jsx'
|
365 |
-
import './index.css'
|
366 |
-
|
367 |
-
ReactDOM.createRoot(document.getElementById('root')).render(
|
368 |
-
<React.StrictMode>
|
369 |
-
<App />
|
370 |
-
</React.StrictMode>,
|
371 |
-
)""",
|
372 |
-
"src/App.jsx": """import React from 'react'
|
373 |
-
import { Button } from "./components/ui/button"
|
374 |
-
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./components/ui/card"
|
375 |
-
|
376 |
-
|
377 |
-
function App() {
|
378 |
-
return (
|
379 |
-
<div className="container mx-auto py-10">
|
380 |
-
<h1 className="text-3xl font-bold text-center mb-5">
|
381 |
-
Witaj w aplikacji Shadcn UI!
|
382 |
-
</h1>
|
383 |
-
|
384 |
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
385 |
-
<Card>
|
386 |
-
<CardHeader>
|
387 |
-
<CardTitle>Karta 1</CardTitle>
|
388 |
-
<CardDescription>Prosta karta z Shadcn UI.</CardDescription>
|
389 |
-
</CardHeader>
|
390 |
-
<CardContent>
|
391 |
-
<p>Zawartość karty.</p>
|
392 |
-
<Button className="mt-4">Przycisk Akcji</Button>
|
393 |
-
</CardContent>
|
394 |
-
</Card>
|
395 |
-
|
396 |
-
<Card>
|
397 |
-
<CardHeader>
|
398 |
-
<CardTitle>Karta 2</CardTitle>
|
399 |
-
<CardDescription>Kolejna karta dla przykładu.</CardDescription>
|
400 |
-
</CardHeader>
|
401 |
-
<CardContent>
|
402 |
-
<p>Więcej zawartości.</p>
|
403 |
-
<Button variant="secondary" className="mt-4">Przycisk Wtórny</Button>
|
404 |
-
</CardContent>
|
405 |
-
</Card>
|
406 |
-
|
407 |
-
<Card className="lg:col-span-1 md:col-span-2">
|
408 |
-
<CardHeader>
|
409 |
-
<CardTitle>Dłuższa Karta</CardTitle>
|
410 |
-
<CardDescription>Karta zajmująca więcej miejsca.</CardDescription>
|
411 |
-
</CardHeader>
|
412 |
-
<CardContent>
|
413 |
-
<p>
|
414 |
-
Ta karta demonstruje jak karty mogą dostosowywać się do różnych
|
415 |
-
rozmiarów ekranów i układów. Shadcn UI i Tailwind CSS
|
416 |
-
dają dużą elastyczność w projektowaniu interfejsów.
|
417 |
-
</p>
|
418 |
-
<Button variant="destructive" className="mt-4">Przycisk Destrukcyjny</Button>
|
419 |
-
</CardContent>
|
420 |
-
</Card>
|
421 |
-
</div>
|
422 |
-
</div>
|
423 |
-
)
|
424 |
-
}
|
425 |
-
|
426 |
-
export default App""",
|
427 |
-
"src/index.css": """@tailwind base;
|
428 |
-
@tailwind components;
|
429 |
-
@tailwind utilities;
|
430 |
-
|
431 |
-
@layer base {
|
432 |
-
:root {
|
433 |
-
--background: 0 0% 100%;
|
434 |
-
--foreground: 222.2 84.9% 4.9%;
|
435 |
-
|
436 |
-
--card: 0 0% 100%;
|
437 |
-
--card-foreground: 222.2 84.9% 4.9%;
|
438 |
-
|
439 |
-
--popover: 0 0% 100%;
|
440 |
-
--popover-foreground: 222.2 84.9% 4.9%;
|
441 |
-
|
442 |
-
--primary: 221.2 83.2% 53.3%;
|
443 |
-
--primary-foreground: 210 40% 98%;
|
444 |
-
|
445 |
-
--secondary: 210 40% 96.1%;
|
446 |
-
--secondary-foreground: 222.2 47.4% 11.2%;
|
447 |
-
|
448 |
-
--muted: 210 40% 96.1%;
|
449 |
-
--muted-foreground: 215.4 16.3% 46.9%;
|
450 |
-
|
451 |
-
--accent: 210 40% 96.1%;
|
452 |
-
--accent-foreground: 222.2 47.4% 11.2%;
|
453 |
-
|
454 |
-
--destructive: 0 84.2% 60.2%;
|
455 |
-
--destructive-foreground: 210 40% 98%;
|
456 |
-
|
457 |
-
--border: 214.3 31.8% 91.4%;
|
458 |
-
--input: 214.3 31.8% 91.4%;
|
459 |
-
--ring: 221.2 83.2% 53.3%;
|
460 |
-
|
461 |
-
--radius: 0.5rem;
|
462 |
-
}
|
463 |
-
|
464 |
-
.dark {
|
465 |
-
--background: 222.2 84.9% 4.9%;
|
466 |
-
--foreground: 210 40% 98%;
|
467 |
-
|
468 |
-
--card: 222.2 84.9% 4.9%;
|
469 |
-
--card-foreground: 210 40% 98%;
|
470 |
-
|
471 |
-
--popover: 222.2 84.9% 4.9%;
|
472 |
-
--popover-foreground: 210 40% 98%;
|
473 |
-
|
474 |
-
--primary: 217.2 91.2% 59.8%;
|
475 |
-
--primary-foreground: 222.2 47.4% 11.2%;
|
476 |
-
|
477 |
-
--secondary: 217.2 32.6% 17.5%;
|
478 |
-
--secondary-foreground: 210 40% 98%;
|
479 |
-
|
480 |
-
--muted: 217.2 32.6% 17.5%;
|
481 |
-
--muted-foreground: 215 20.2% 65.1%;
|
482 |
-
|
483 |
-
--accent: 217.2 32.6% 17.5%;
|
484 |
-
--accent-foreground: 210 40% 98%;
|
485 |
-
|
486 |
-
--destructive: 0 62.8% 30.6%;
|
487 |
-
--destructive-foreground: 210 40% 98%;
|
488 |
-
|
489 |
-
--border: 217.2 32.6% 17.5%;
|
490 |
-
--input: 217.2 32.6% 17.5%;
|
491 |
-
--ring: 224.9 98.6% 67.3%;
|
492 |
-
}
|
493 |
-
}
|
494 |
-
|
495 |
-
@layer components {
|
496 |
-
.container {
|
497 |
-
@apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8;
|
498 |
-
}
|
499 |
-
}
|
500 |
-
""",
|
501 |
-
"postcss.config.js": """module.exports = {
|
502 |
-
plugins: {
|
503 |
-
tailwindcss: {},
|
504 |
-
autoprefixer: {},
|
505 |
-
},
|
506 |
-
}""",
|
507 |
-
"tailwind.config.js": """/** @type {import('tailwindcss').Config} */
|
508 |
-
module.exports = {
|
509 |
-
darkMode: ["class"],
|
510 |
-
content: [
|
511 |
-
'./pages/**/*.{js,jsx}',
|
512 |
-
'./components/**/*.{js,jsx}',
|
513 |
-
'./app/**/*.{js,jsx}',
|
514 |
-
'./src/**/*.{js,jsx}',
|
515 |
-
],
|
516 |
-
prefix: "",
|
517 |
-
theme: {
|
518 |
-
container: {
|
519 |
-
center: true,
|
520 |
-
padding: "2rem",
|
521 |
-
screens: {
|
522 |
-
"2xl": "1400px",
|
523 |
-
},
|
524 |
-
},
|
525 |
-
extend: {
|
526 |
-
colors: {
|
527 |
-
border: "hsl(var(--border))",
|
528 |
-
input: "hsl(var(--input))",
|
529 |
-
ring: "hsl(var(--ring))",
|
530 |
-
background: "hsl(var(--background))",
|
531 |
-
foreground: "hsl(var(--foreground))",
|
532 |
-
primary: {
|
533 |
-
DEFAULT: "hsl(var(--primary))",
|
534 |
-
foreground: "hsl(var(--primary-foreground))",
|
535 |
-
},
|
536 |
-
secondary: {
|
537 |
-
DEFAULT: "hsl(var(--secondary))",
|
538 |
-
foreground: "hsl(var(--secondary-foreground))",
|
539 |
-
},
|
540 |
-
destructive: {
|
541 |
-
DEFAULT: "hsl(var(--destructive))",
|
542 |
-
foreground: "hsl(var(--destructive-foreground))",
|
543 |
-
},
|
544 |
-
muted: {
|
545 |
-
DEFAULT: "hsl(var(--muted))",
|
546 |
-
foreground: "hsl(var(--muted-foreground))",
|
547 |
-
},
|
548 |
-
accent: {
|
549 |
-
DEFAULT: "hsl(var(--accent))",
|
550 |
-
foreground: "hsl(var(--accent-foreground))",
|
551 |
-
},
|
552 |
-
popover: {
|
553 |
-
DEFAULT: "hsl(var(--popover))",
|
554 |
-
foreground: "hsl(var(--popover-foreground))",
|
555 |
-
},
|
556 |
-
card: {
|
557 |
-
DEFAULT: "hsl(var(--card))",
|
558 |
-
foreground: "hsl(var(--card-foreground))",
|
559 |
-
},
|
560 |
-
},
|
561 |
-
borderRadius: {
|
562 |
-
lg: "var(--radius)",
|
563 |
-
md: "calc(var(--radius) - 2px)",
|
564 |
-
sm: "calc(var(--radius) - 4px)",
|
565 |
-
},
|
566 |
-
keyframes: {
|
567 |
-
"accordion-down": {
|
568 |
-
from: { height: "0" },
|
569 |
-
to: { height: "var(--radix-accordion-content-height)" },
|
570 |
-
},
|
571 |
-
"accordion-up": {
|
572 |
-
from: { height: "var(--radix-accordion-content-height)" },
|
573 |
-
},
|
574 |
-
},
|
575 |
-
animation: {
|
576 |
-
"accordion-down": "accordion-down 0.2s ease-out",
|
577 |
-
"accordion-up": "accordion-up 0.2s ease-out",
|
578 |
-
},
|
579 |
-
},
|
580 |
-
},
|
581 |
-
plugins: [require("tailwindcss-animate")],
|
582 |
-
}""",
|
583 |
-
"src/components/ui/button.jsx": """import * as React from "react"
|
584 |
-
import { cn } from "@/lib/utils"
|
585 |
-
import { Slot } from "@radix-ui/react-slot"
|
586 |
-
import { cva } from "class-variance-authority";
|
587 |
-
|
588 |
-
const buttonVariants = cva(
|
589 |
-
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
590 |
-
{
|
591 |
-
variants: {
|
592 |
-
variant: {
|
593 |
-
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
594 |
-
destructive:
|
595 |
-
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
596 |
-
outline:
|
597 |
-
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
598 |
-
secondary:
|
599 |
-
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
600 |
-
ghost: "hover:bg-accent hover:text-accent-foreground",
|
601 |
-
link: "underline-offset-4 hover:underline text-primary",
|
602 |
-
},
|
603 |
-
size: {
|
604 |
-
default: "h-10 px-4 py-2",
|
605 |
-
sm: "h-9 rounded-md px-3",
|
606 |
-
lg: "h-11 rounded-md px-8",
|
607 |
-
icon: "h-10 w-10",
|
608 |
-
},
|
609 |
-
},
|
610 |
-
defaultVariants: {
|
611 |
-
variant: "default",
|
612 |
-
size: "default",
|
613 |
-
},
|
614 |
-
}
|
615 |
-
)
|
616 |
-
|
617 |
-
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
|
618 |
-
const Comp = asChild ? Slot : "button"
|
619 |
-
return (<Comp
|
620 |
-
className={cn(buttonVariants({ variant, size, className }))}
|
621 |
-
ref={ref} {...props} />)
|
622 |
-
})
|
623 |
-
Button.displayName = "Button"
|
624 |
-
|
625 |
-
export { Button, buttonVariants }""",
|
626 |
-
"src/components/ui/card.jsx": """import * as React from "react"
|
627 |
-
import { cn } from "@/lib/utils"
|
628 |
-
|
629 |
-
const Card = React.forwardRef(({ className, ...props }, ref) => (<div
|
630 |
-
className={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)}
|
631 |
-
ref={ref}
|
632 |
-
{...props} />))
|
633 |
-
Card.displayName = "Card"
|
634 |
-
|
635 |
-
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (<div
|
636 |
-
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
637 |
-
ref={ref}
|
638 |
-
{...props} />))
|
639 |
-
CardHeader.displayName = "CardHeader"
|
640 |
-
|
641 |
-
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (<h3
|
642 |
-
className={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
643 |
-
ref={ref}
|
644 |
-
{...props} />))
|
645 |
-
CardTitle.displayName = "CardTitle"
|
646 |
-
|
647 |
-
const CardDescription = React.forwardRef(({ className, ...props }, ref) => (<p
|
648 |
-
className={cn("text-sm text-muted-foreground", className)}
|
649 |
-
ref={ref}
|
650 |
-
{...props} />))
|
651 |
-
CardDescription.displayName = "CardDescription"
|
652 |
-
|
653 |
-
const CardContent = React.forwardRef(({ className, ...props }, ref) => (<div
|
654 |
-
className={cn("p-6 pt-0", className)}
|
655 |
-
ref={ref}
|
656 |
-
{...props} />))
|
657 |
-
CardContent.displayName = "CardContent"
|
658 |
-
|
659 |
-
const CardFooter = React.forwardRef(({ className, ...props }, ref) => (<div
|
660 |
-
className={cn("flex items-center p-6 pt-0", className)}
|
661 |
-
ref={ref}
|
662 |
-
{...props} />))
|
663 |
-
CardFooter.displayName = "CardFooter"
|
664 |
-
|
665 |
-
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }""",
|
666 |
-
"src/lib/utils.js": """import { clsx } from "clsx"
|
667 |
-
import { twMerge } from "tailwind-merge"
|
668 |
-
|
669 |
-
export function cn(...inputs) {
|
670 |
-
return twMerge(clsx(inputs))
|
671 |
-
}"""
|
672 |
-
},
|
673 |
-
"post_process": "shadcn_setup" # Now using a specific post_process action
|
674 |
-
},
|
675 |
-
}
|
676 |
-
|
677 |
-
|
678 |
def get_file_content(owner, repo_name, path, branch="main"):
|
679 |
"""Fetches file content from a GitHub repository."""
|
680 |
url = f"https://raw.githubusercontent.com/{owner}/{repo_name}/{branch}/{path}"
|
681 |
try:
|
682 |
response = requests.get(url)
|
683 |
-
response.raise_for_status()
|
684 |
return response.text
|
685 |
except requests.exceptions.RequestException as e:
|
686 |
return f"Error fetching file: {e}"
|
@@ -725,20 +48,27 @@ def github_tool(
|
|
725 |
file_url: str = None,
|
726 |
repo_url: str = None,
|
727 |
template_name: str = None,
|
728 |
-
template_params: dict = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
729 |
):
|
730 |
"""Manages GitHub repositories."""
|
731 |
user = g.get_user()
|
732 |
|
733 |
-
try:
|
734 |
if action == "import_repository":
|
735 |
if not all([owner, repo_name, vcs_url]):
|
736 |
raise ValueError("Missing parameters: owner, repo_name, vcs_url")
|
737 |
try:
|
738 |
-
user.get_repo(repo_name)
|
739 |
return "Repository already exists."
|
740 |
except GithubException:
|
741 |
-
pass
|
742 |
|
743 |
headers = {
|
744 |
'Authorization': f'token {GITHUB_TOKEN}',
|
@@ -746,7 +76,7 @@ def github_tool(
|
|
746 |
}
|
747 |
import_url = f'https://api.github.com/repos/{owner}/{repo_name}/import'
|
748 |
response = requests.put(import_url, json={'vcs_url': vcs_url, 'vcs': 'git'}, headers=headers)
|
749 |
-
response.raise_for_status()
|
750 |
return "Repository import started."
|
751 |
|
752 |
elif action == "create_repository":
|
@@ -765,40 +95,31 @@ def github_tool(
|
|
765 |
repo = user.create_repo(name=repo_name)
|
766 |
template = PROJECT_TEMPLATES[template_name]
|
767 |
|
768 |
-
# Prepare template parameters, use defaults if not provided
|
769 |
template_params_final = {}
|
770 |
if "params" in template:
|
771 |
for param_name, param_config in template["params"].items():
|
772 |
-
template_params_final[param_name] = template_params.get(param_name,
|
773 |
-
param_config.get("default")) if template_params else param_config.get(
|
774 |
-
"default")
|
775 |
|
776 |
-
|
777 |
-
|
778 |
-
readme_filename = "README.md" # Default readme name
|
779 |
|
780 |
-
env = jinja2.Environment()
|
781 |
|
782 |
for file_path, file_content in template["files"].items():
|
783 |
final_file_path = file_path
|
784 |
final_file_content = file_content
|
785 |
|
786 |
-
# Apply file renaming if defined in template
|
787 |
if "rename_files" in template:
|
788 |
for old_name, new_name_template in template["rename_files"].items():
|
789 |
if file_path == old_name:
|
790 |
-
final_file_path = new_name_template.replace("{{repo_name_snake_case}}",
|
791 |
-
repo_name_snake_case).replace("{{repo_name}}",
|
792 |
-
repo_name).replace(
|
793 |
-
"{{readme_filename}}", readme_filename)
|
794 |
|
795 |
-
# Render file content using Jinja2 template
|
796 |
template_render = env.from_string(final_file_content)
|
797 |
final_file_content = template_render.render(
|
798 |
repo_name=repo_name,
|
799 |
repo_name_snake_case=repo_name_snake_case,
|
800 |
readme_filename=readme_filename,
|
801 |
-
**template_params_final
|
802 |
)
|
803 |
|
804 |
repo.create_file(
|
@@ -808,13 +129,12 @@ def github_tool(
|
|
808 |
branch="main",
|
809 |
)
|
810 |
|
811 |
-
# Post-processing actions (example: install dependencies)
|
812 |
if "post_process" in template:
|
813 |
post_process_action = template["post_process"]
|
814 |
if post_process_action == "install_dependencies":
|
815 |
print(
|
816 |
-
f"Post-processing: install_dependencies for {repo_name} (Not fully implemented in this example).")
|
817 |
-
elif post_process_action == "shadcn_setup":
|
818 |
instructions = f"""
|
819 |
**Konfiguracja Shadcn UI wymaga dodatkowych kroków po stronie klienta!**
|
820 |
|
@@ -828,18 +148,18 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
828 |
"""
|
829 |
return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})\n\n{instructions}"
|
830 |
else:
|
831 |
-
print(f"Unknown post-process action: {post_process_action}")
|
832 |
|
833 |
return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})"
|
834 |
|
835 |
-
elif action == "create_file":
|
836 |
if not all([repo_name, path, content, message]):
|
837 |
raise ValueError("Missing parameters: repo_name, path, content, message")
|
838 |
repo = user.get_repo(repo_name)
|
839 |
repo.create_file(path, message, content, branch=branch)
|
840 |
return f"File **`{path}`** created in repository **`{repo_name}`** on branch **`{branch}`**."
|
841 |
|
842 |
-
elif action == "get_file":
|
843 |
if not all([repo_name, path]):
|
844 |
raise ValueError("Missing parameters: repo_name, path")
|
845 |
repo = user.get_repo(repo_name)
|
@@ -848,13 +168,13 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
848 |
f"File content of **`{path}`** from **`{repo_name}`**:\n\n`\n{file_content.decoded_content.decode()}\n`"
|
849 |
)
|
850 |
|
851 |
-
elif action == "get_file_content_by_url":
|
852 |
if not file_url:
|
853 |
raise ValueError("Missing parameter: file_url")
|
854 |
-
file_content = get_file_content(None, None, None, None)
|
855 |
return f"File content from URL **`{file_url}`**:\n\n`\n{file_content}\n`"
|
856 |
|
857 |
-
elif action == "delete_file":
|
858 |
if not all([repo_name, path]):
|
859 |
raise ValueError("Missing parameters: repo_name, path")
|
860 |
repo = user.get_repo(repo_name)
|
@@ -862,7 +182,7 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
862 |
repo.delete_file(path, "Delete file", file_contents.sha, branch=branch)
|
863 |
return f"File **`{path}`** deleted from repository **`{repo_name}`** on branch **`{branch}`**."
|
864 |
|
865 |
-
elif action == "update_file":
|
866 |
if not all([repo_name, path, content, message]):
|
867 |
raise ValueError("Missing parameters: repo_name, path, content, message")
|
868 |
repo = user.get_repo(repo_name)
|
@@ -870,7 +190,32 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
870 |
repo.update_file(path, message, content, file_contents.sha, branch=branch)
|
871 |
return f"File **`{path}`** updated in repository **`{repo_name}`** on branch **`{branch}`**."
|
872 |
|
873 |
-
elif action == "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
874 |
if not repo_name:
|
875 |
raise ValueError("Missing parameter: repo_name")
|
876 |
repo = user.get_repo(repo_name)
|
@@ -878,7 +223,7 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
878 |
branch_list = "\n".join([f"- `{branch.name}`" for branch in branches])
|
879 |
return f"Branches in repository **`{repo_name}`**:\n{branch_list}"
|
880 |
|
881 |
-
elif action == "create_branch":
|
882 |
if not all([repo_name, base, head]):
|
883 |
raise ValueError("Missing parameters: repo_name, base, head")
|
884 |
repo = user.get_repo(repo_name)
|
@@ -886,21 +231,21 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
886 |
repo.create_git_ref(ref=f"refs/heads/{head}", sha=source_branch.commit.sha)
|
887 |
return f"Branch **`{head}`** created from **`{base}`** in repository **`{repo_name}`**."
|
888 |
|
889 |
-
elif action == "delete_branch":
|
890 |
if not all([repo_name, branch]):
|
891 |
raise ValueError("Missing parameters: repo_name, branch")
|
892 |
repo = user.get_repo(repo_name)
|
893 |
repo.get_git_ref(f"heads/{branch}").delete()
|
894 |
return f"Branch **`{branch}`** deleted from repository **`{repo_name}`**."
|
895 |
|
896 |
-
elif action == "create_pull_request":
|
897 |
if not all([repo_name, title, body, base, head]):
|
898 |
raise ValueError("Missing parameters: repo_name, title, body, base, head")
|
899 |
repo = user.get_repo(repo_name)
|
900 |
pr = repo.create_pull(title=title, body=body, base=base, head=head)
|
901 |
return f"Pull request created! [Open Pull Request]({pr.html_url})"
|
902 |
|
903 |
-
elif action == "list_open_pull_requests":
|
904 |
if not repo_name:
|
905 |
raise ValueError("Missing parameter: repo_name")
|
906 |
repo = user.get_repo(repo_name)
|
@@ -910,14 +255,14 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
910 |
prs_list = "\n".join([f"- [{pr.title}]({pr.html_url})" for pr in open_prs])
|
911 |
return f"Open pull requests in repository **`{repo_name}`**:\n{prs_list}"
|
912 |
|
913 |
-
elif action == "create_issue":
|
914 |
if not all([repo_name, title, body]):
|
915 |
raise ValueError("Missing parameters: repo_name, title, body")
|
916 |
repo = user.get_repo(repo_name)
|
917 |
issue = repo.create_issue(title=title, body=body)
|
918 |
return f"Issue created! [Open Issue]({issue.html_url})"
|
919 |
|
920 |
-
elif action == "list_issues":
|
921 |
if not repo_name:
|
922 |
raise ValueError("Missing parameter: repo_name")
|
923 |
repo = user.get_repo(repo_name)
|
@@ -927,7 +272,7 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
927 |
issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues])
|
928 |
return f"Open issues in repository **`{repo_name}`**:\n{issues_list}"
|
929 |
|
930 |
-
elif action == "add_label_to_issue":
|
931 |
if not all([repo_name, issue_number, labels]):
|
932 |
raise ValueError("Missing parameters: repo_name, issue_number, labels")
|
933 |
repo = user.get_repo(repo_name)
|
@@ -938,7 +283,7 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
938 |
f"Labels **`{labels}`** added to issue **#{issue_number}** in repository **`{repo_name}`**."
|
939 |
)
|
940 |
|
941 |
-
elif action == "close_issue":
|
942 |
if not all([repo_name, issue_number]):
|
943 |
raise ValueError("Missing parameters: repo_name, issue_number")
|
944 |
repo = user.get_repo(repo_name)
|
@@ -946,7 +291,7 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
946 |
issue.edit(state='closed')
|
947 |
return f"Issue **#{issue_number}** closed in repository **`{repo_name}`**."
|
948 |
|
949 |
-
elif action == "add_comment_to_issue":
|
950 |
if not all([repo_name, issue_number, message]):
|
951 |
raise ValueError("Missing parameters: repo_name, issue_number, message")
|
952 |
repo = user.get_repo(repo_name)
|
@@ -954,7 +299,7 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
954 |
issue.create_comment(body=message)
|
955 |
return f"Comment added to issue **#{issue_number}** in repository **`{repo_name}`**."
|
956 |
|
957 |
-
elif action == "create_release":
|
958 |
if not all([repo_name, tag, name, message]):
|
959 |
raise ValueError("Missing parameters: repo_name, tag, name, message")
|
960 |
repo = user.get_repo(repo_name)
|
@@ -963,7 +308,7 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
963 |
f"Release **`{name}`** created in repository **`{repo_name}`**! [Open Release]({release.html_url})"
|
964 |
)
|
965 |
|
966 |
-
elif action == "list_releases":
|
967 |
if not repo_name:
|
968 |
raise ValueError("Missing parameter: repo_name")
|
969 |
repo = user.get_repo(repo_name)
|
@@ -973,14 +318,14 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
973 |
releases_list = "\n".join([f"- [{release.tag_name}]({release.html_url})" for release in releases])
|
974 |
return f"Releases in repository **`{repo_name}`**:\n{releases_list}"
|
975 |
|
976 |
-
elif action == "fork_repository":
|
977 |
if not repo_name:
|
978 |
raise ValueError("Missing parameter: repo_name")
|
979 |
repo = g.get_repo(repo_name)
|
980 |
fork = user.create_fork(repo)
|
981 |
return f"Repository **`{repo_name}`** forked! [Open fork]({fork.html_url})"
|
982 |
|
983 |
-
elif action == "list_forks":
|
984 |
if not repo_name:
|
985 |
raise ValueError("Missing parameter: repo_name")
|
986 |
repo = g.get_repo(repo_name)
|
@@ -990,17 +335,17 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
990 |
forks_list = "\n".join([f"- [{fork.full_name}]({fork.html_url})" for fork in forks])
|
991 |
return f"Forks of repository **`{repo_name}`**:\n{forks_list}"
|
992 |
|
993 |
-
elif action == "list_files":
|
994 |
if not all([owner, repo_name]):
|
995 |
raise ValueError("Missing parameters: owner, repo_name")
|
996 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
997 |
-
contents = repo.get_contents("" if not path else path)
|
998 |
if not contents:
|
999 |
return f"No files in path **`{path}`** of repository **`{repo_name}`**."
|
1000 |
files_list = "\n".join([f"- [{content.name}]({content.download_url})" for content in contents])
|
1001 |
return f"Files in path **`{path}`** of repository **`{repo_name}`**:\n{files_list}"
|
1002 |
|
1003 |
-
elif action == "get_repository_info":
|
1004 |
if not all([owner, repo_name]):
|
1005 |
raise ValueError("Missing parameters: owner, repo_name")
|
1006 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
@@ -1019,7 +364,7 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
1019 |
info_md = "\n".join([f"- **{key}**: {value}" for key, value in info.items()])
|
1020 |
return f"Repository info for **`{repo_name}`**:\n{info_md}"
|
1021 |
|
1022 |
-
elif action == "get_file_content":
|
1023 |
if not all([owner, repo_name, path]):
|
1024 |
raise ValueError("Missing parameters: owner, repo_name, path")
|
1025 |
content_text = get_file_content(owner, repo_name, path, branch)
|
@@ -1027,7 +372,7 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
1027 |
f"File content of **`{path}`** from repository **`{repo_name}`**:\n\n`\n{content_text}\n`"
|
1028 |
)
|
1029 |
|
1030 |
-
elif action == "analyze_repository_by_url":
|
1031 |
if not repo_url:
|
1032 |
raise ValueError("Missing parameter: repo_url")
|
1033 |
owner, repo_name = extract_repo_info(repo_url)
|
@@ -1055,7 +400,7 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
1055 |
])
|
1056 |
return analysis_md
|
1057 |
|
1058 |
-
elif action == "analyze_repository_content":
|
1059 |
if not all([owner, repo_name]):
|
1060 |
raise ValueError("Missing parameters: owner, repo_name")
|
1061 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
@@ -1063,7 +408,7 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
1063 |
file_analyses = []
|
1064 |
for content in contents:
|
1065 |
if content.type == "file":
|
1066 |
-
file_content = get_file_content(owner, repo_name, content.path, branch)
|
1067 |
analysis = analyze_file_content(file_content, content.path)
|
1068 |
file_analyses.append({
|
1069 |
"name": content.name,
|
@@ -1079,18 +424,88 @@ Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfiguro
|
|
1079 |
])
|
1080 |
return analysis_md
|
1081 |
|
1082 |
-
|
1083 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1084 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1085 |
|
1086 |
except GithubException as e:
|
1087 |
return f"**GitHub Error:** {e}"
|
1088 |
except ValueError as e:
|
1089 |
-
return f"**Error:** {e}"
|
1090 |
except requests.exceptions.RequestException as e:
|
1091 |
return f"**Connection Error:** {e}"
|
1092 |
except Exception as e:
|
1093 |
-
return f"**Unexpected Error:** {e}"
|
1094 |
|
1095 |
|
1096 |
with gr.Blocks() as demo:
|
@@ -1099,54 +514,33 @@ with gr.Blocks() as demo:
|
|
1099 |
with gr.Column():
|
1100 |
action = gr.Dropdown(
|
1101 |
choices=[
|
1102 |
-
"import_repository",
|
1103 |
-
"
|
1104 |
-
"
|
1105 |
-
|
1106 |
-
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
"
|
1111 |
-
"
|
1112 |
-
"
|
1113 |
-
"
|
1114 |
-
"update_file",
|
1115 |
-
"list_branches",
|
1116 |
-
"create_branch",
|
1117 |
-
"delete_branch",
|
1118 |
-
"create_pull_request",
|
1119 |
-
"list_open_pull_requests",
|
1120 |
-
"create_issue",
|
1121 |
-
"list_issues",
|
1122 |
-
"add_label_to_issue",
|
1123 |
-
"close_issue",
|
1124 |
-
"add_comment_to_issue",
|
1125 |
-
"create_release",
|
1126 |
-
"list_releases",
|
1127 |
-
"fork_repository",
|
1128 |
-
"list_forks",
|
1129 |
-
"list_files",
|
1130 |
-
"get_repository_info",
|
1131 |
-
"get_file_content",
|
1132 |
-
"analyze_repository_by_url",
|
1133 |
-
"analyze_repository_content",
|
1134 |
],
|
1135 |
label="Select Action",
|
1136 |
)
|
1137 |
repo_name = gr.Textbox(label="Repository Name")
|
1138 |
template_name = gr.Dropdown(
|
1139 |
-
choices=[""] + list(PROJECT_TEMPLATES.keys()),
|
1140 |
label="Project Template",
|
1141 |
-
value="",
|
1142 |
-
allow_custom_value=True,
|
1143 |
)
|
1144 |
-
# Template parameters UI - dynamically generated based on template
|
1145 |
template_params_ui = {}
|
1146 |
-
with gr.Row():
|
1147 |
for template_key, template_config in PROJECT_TEMPLATES.items():
|
1148 |
if "params" in template_config:
|
1149 |
-
with gr.Column(visible=False, elem_classes=f"params_{template_key}") as params_section:
|
1150 |
for param_name, param_details in template_config["params"].items():
|
1151 |
if param_details["type"] == "choice":
|
1152 |
template_params_ui[param_name] = gr.Dropdown(
|
@@ -1154,17 +548,19 @@ with gr.Blocks() as demo:
|
|
1154 |
label=param_details["description"] or param_name,
|
1155 |
value=param_details["default"]
|
1156 |
)
|
1157 |
-
else:
|
1158 |
template_params_ui[param_name] = gr.Textbox(
|
1159 |
label=param_details["description"] or param_name,
|
1160 |
value=param_details["default"] if "default" in param_details else ""
|
1161 |
)
|
1162 |
-
template_params_ui[template_key] = params_section
|
1163 |
|
1164 |
branch = gr.Textbox(label="Branch", value="main")
|
1165 |
path = gr.Textbox(label="File Path")
|
1166 |
-
content = gr.Code(label="File Content", lines=5, language='python')
|
1167 |
-
|
|
|
|
|
1168 |
owner = gr.Textbox(label="Owner")
|
1169 |
vcs_url = gr.Textbox(label="VCS URL")
|
1170 |
title = gr.Textbox(label="Title")
|
@@ -1177,18 +573,21 @@ with gr.Blocks() as demo:
|
|
1177 |
release_name = gr.Textbox(label="Release Name")
|
1178 |
file_url = gr.Textbox(label="File URL")
|
1179 |
repo_url = gr.Textbox(label="Repository URL")
|
|
|
|
|
|
|
|
|
1180 |
|
1181 |
-
# Function to show/hide template parameters based on template selection
|
1182 |
def show_template_params(template_name):
|
1183 |
visibility_map = {key: gr.Column.update(visible=False) for key in PROJECT_TEMPLATES if
|
1184 |
-
"params" in PROJECT_TEMPLATES[key]}
|
1185 |
if template_name and template_name in PROJECT_TEMPLATES and "params" in PROJECT_TEMPLATES[template_name]:
|
1186 |
-
visibility_map[template_name] = gr.Column.update(visible=True)
|
1187 |
return [visibility_map.get(key, gr.Column.update(visible=False)) for key in PROJECT_TEMPLATES if
|
1188 |
-
"params" in PROJECT_TEMPLATES[key]]
|
1189 |
|
1190 |
template_param_visibility_outputs = [template_params_ui[key] for key in PROJECT_TEMPLATES if
|
1191 |
-
"params" in PROJECT_TEMPLATES[key]]
|
1192 |
template_name.change(
|
1193 |
show_template_params,
|
1194 |
inputs=[template_name],
|
@@ -1196,40 +595,110 @@ with gr.Blocks() as demo:
|
|
1196 |
)
|
1197 |
|
1198 |
run_button = gr.Button("Execute")
|
1199 |
-
output = gr.Markdown(label="Result")
|
1200 |
|
1201 |
input_components = [
|
1202 |
-
action,
|
1203 |
-
|
1204 |
-
|
1205 |
-
path,
|
1206 |
-
content,
|
1207 |
-
message,
|
1208 |
-
owner,
|
1209 |
-
vcs_url,
|
1210 |
-
title,
|
1211 |
-
body,
|
1212 |
-
base,
|
1213 |
-
head,
|
1214 |
-
issue_number,
|
1215 |
-
labels,
|
1216 |
-
tag,
|
1217 |
-
release_name,
|
1218 |
-
file_url,
|
1219 |
-
repo_url,
|
1220 |
-
template_name,
|
1221 |
]
|
1222 |
|
1223 |
-
# Add template parameters dynamically to input components
|
1224 |
for template_key in PROJECT_TEMPLATES:
|
1225 |
if "params" in PROJECT_TEMPLATES[template_key]:
|
1226 |
-
for param_name in template_params_ui:
|
1227 |
-
if param_name in PROJECT_TEMPLATES[template_key]["params"]:
|
1228 |
-
input_components.append(template_params_ui[param_name])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1229 |
|
1230 |
run_button.click(
|
1231 |
github_tool,
|
1232 |
-
inputs=input_components,
|
1233 |
outputs=output,
|
1234 |
api_name="github_tool"
|
1235 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
def get_file_content(owner, repo_name, path, branch="main"):
|
2 |
"""Fetches file content from a GitHub repository."""
|
3 |
url = f"https://raw.githubusercontent.com/{owner}/{repo_name}/{branch}/{path}"
|
4 |
try:
|
5 |
response = requests.get(url)
|
6 |
+
response.raise_for_status()
|
7 |
return response.text
|
8 |
except requests.exceptions.RequestException as e:
|
9 |
return f"Error fetching file: {e}"
|
|
|
48 |
file_url: str = None,
|
49 |
repo_url: str = None,
|
50 |
template_name: str = None,
|
51 |
+
template_params: dict = None,
|
52 |
+
diff: str = None,
|
53 |
+
diff_message: str = None,
|
54 |
+
new_description: str = None,
|
55 |
+
issue_title: str = None,
|
56 |
+
issue_body: str = None,
|
57 |
+
issue_state: str = None,
|
58 |
+
**kwargs
|
59 |
):
|
60 |
"""Manages GitHub repositories."""
|
61 |
user = g.get_user()
|
62 |
|
63 |
+
try:
|
64 |
if action == "import_repository":
|
65 |
if not all([owner, repo_name, vcs_url]):
|
66 |
raise ValueError("Missing parameters: owner, repo_name, vcs_url")
|
67 |
try:
|
68 |
+
user.get_repo(repo_name)
|
69 |
return "Repository already exists."
|
70 |
except GithubException:
|
71 |
+
pass
|
72 |
|
73 |
headers = {
|
74 |
'Authorization': f'token {GITHUB_TOKEN}',
|
|
|
76 |
}
|
77 |
import_url = f'https://api.github.com/repos/{owner}/{repo_name}/import'
|
78 |
response = requests.put(import_url, json={'vcs_url': vcs_url, 'vcs': 'git'}, headers=headers)
|
79 |
+
response.raise_for_status()
|
80 |
return "Repository import started."
|
81 |
|
82 |
elif action == "create_repository":
|
|
|
95 |
repo = user.create_repo(name=repo_name)
|
96 |
template = PROJECT_TEMPLATES[template_name]
|
97 |
|
|
|
98 |
template_params_final = {}
|
99 |
if "params" in template:
|
100 |
for param_name, param_config in template["params"].items():
|
101 |
+
template_params_final[param_name] = template_params.get(param_name, param_config.get("default")) if template_params else param_config.get("default")
|
|
|
|
|
102 |
|
103 |
+
repo_name_snake_case = repo_name.replace("-", "_")
|
104 |
+
readme_filename = "README.md"
|
|
|
105 |
|
106 |
+
env = jinja2.Environment()
|
107 |
|
108 |
for file_path, file_content in template["files"].items():
|
109 |
final_file_path = file_path
|
110 |
final_file_content = file_content
|
111 |
|
|
|
112 |
if "rename_files" in template:
|
113 |
for old_name, new_name_template in template["rename_files"].items():
|
114 |
if file_path == old_name:
|
115 |
+
final_file_path = new_name_template.replace("{{repo_name_snake_case}}", repo_name_snake_case).replace("{{repo_name}}", repo_name).replace("{{readme_filename}}", readme_filename)
|
|
|
|
|
|
|
116 |
|
|
|
117 |
template_render = env.from_string(final_file_content)
|
118 |
final_file_content = template_render.render(
|
119 |
repo_name=repo_name,
|
120 |
repo_name_snake_case=repo_name_snake_case,
|
121 |
readme_filename=readme_filename,
|
122 |
+
**template_params_final
|
123 |
)
|
124 |
|
125 |
repo.create_file(
|
|
|
129 |
branch="main",
|
130 |
)
|
131 |
|
|
|
132 |
if "post_process" in template:
|
133 |
post_process_action = template["post_process"]
|
134 |
if post_process_action == "install_dependencies":
|
135 |
print(
|
136 |
+
f"Post-processing: install_dependencies for {repo_name} (Not fully implemented in this example).")
|
137 |
+
elif post_process_action == "shadcn_setup":
|
138 |
instructions = f"""
|
139 |
**Konfiguracja Shadcn UI wymaga dodatkowych kroków po stronie klienta!**
|
140 |
|
|
|
148 |
"""
|
149 |
return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})\n\n{instructions}"
|
150 |
else:
|
151 |
+
print(f"Unknown post-process action: {post_process_action}")
|
152 |
|
153 |
return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})"
|
154 |
|
155 |
+
elif action == "create_file":
|
156 |
if not all([repo_name, path, content, message]):
|
157 |
raise ValueError("Missing parameters: repo_name, path, content, message")
|
158 |
repo = user.get_repo(repo_name)
|
159 |
repo.create_file(path, message, content, branch=branch)
|
160 |
return f"File **`{path}`** created in repository **`{repo_name}`** on branch **`{branch}`**."
|
161 |
|
162 |
+
elif action == "get_file":
|
163 |
if not all([repo_name, path]):
|
164 |
raise ValueError("Missing parameters: repo_name, path")
|
165 |
repo = user.get_repo(repo_name)
|
|
|
168 |
f"File content of **`{path}`** from **`{repo_name}`**:\n\n`\n{file_content.decoded_content.decode()}\n`"
|
169 |
)
|
170 |
|
171 |
+
elif action == "get_file_content_by_url":
|
172 |
if not file_url:
|
173 |
raise ValueError("Missing parameter: file_url")
|
174 |
+
file_content = get_file_content(None, None, None, None)
|
175 |
return f"File content from URL **`{file_url}`**:\n\n`\n{file_content}\n`"
|
176 |
|
177 |
+
elif action == "delete_file":
|
178 |
if not all([repo_name, path]):
|
179 |
raise ValueError("Missing parameters: repo_name, path")
|
180 |
repo = user.get_repo(repo_name)
|
|
|
182 |
repo.delete_file(path, "Delete file", file_contents.sha, branch=branch)
|
183 |
return f"File **`{path}`** deleted from repository **`{repo_name}`** on branch **`{branch}`**."
|
184 |
|
185 |
+
elif action == "update_file":
|
186 |
if not all([repo_name, path, content, message]):
|
187 |
raise ValueError("Missing parameters: repo_name, path, content, message")
|
188 |
repo = user.get_repo(repo_name)
|
|
|
190 |
repo.update_file(path, message, content, file_contents.sha, branch=branch)
|
191 |
return f"File **`{path}`** updated in repository **`{repo_name}`** on branch **`{branch}`**."
|
192 |
|
193 |
+
elif action == "update_file_diff":
|
194 |
+
if not all([repo_name, path, diff, diff_message]):
|
195 |
+
raise ValueError("Missing parameters: repo_name, path, diff, diff_message")
|
196 |
+
repo = user.get_repo(repo_name)
|
197 |
+
file_contents = repo.get_contents(path, ref=branch)
|
198 |
+
current_content_text = file_contents.decoded_content.decode()
|
199 |
+
|
200 |
+
dmp = diff_match_patch()
|
201 |
+
|
202 |
+
try:
|
203 |
+
patches = dmp.patch_fromText(diff)
|
204 |
+
except ValueError:
|
205 |
+
raise ValueError("Invalid patch format. Please provide a valid patch in 'diff' format.")
|
206 |
+
|
207 |
+
patched_content_tuple = dmp.patch_apply(patches, current_content_text)
|
208 |
+
patched_content_text = patched_content_tuple[0]
|
209 |
+
patch_results = patched_content_tuple[1]
|
210 |
+
|
211 |
+
if not any(patch_results):
|
212 |
+
raise ValueError("Failed to apply patch. Diff might be outdated or invalid.")
|
213 |
+
|
214 |
+
repo.update_file(path, diff_message, patched_content_text, file_contents.sha, branch=branch)
|
215 |
+
return f"File **`{path}`** updated using diff in repository **`{repo_name}`** on branch **`{branch}`**."
|
216 |
+
|
217 |
+
|
218 |
+
elif action == "list_branches":
|
219 |
if not repo_name:
|
220 |
raise ValueError("Missing parameter: repo_name")
|
221 |
repo = user.get_repo(repo_name)
|
|
|
223 |
branch_list = "\n".join([f"- `{branch.name}`" for branch in branches])
|
224 |
return f"Branches in repository **`{repo_name}`**:\n{branch_list}"
|
225 |
|
226 |
+
elif action == "create_branch":
|
227 |
if not all([repo_name, base, head]):
|
228 |
raise ValueError("Missing parameters: repo_name, base, head")
|
229 |
repo = user.get_repo(repo_name)
|
|
|
231 |
repo.create_git_ref(ref=f"refs/heads/{head}", sha=source_branch.commit.sha)
|
232 |
return f"Branch **`{head}`** created from **`{base}`** in repository **`{repo_name}`**."
|
233 |
|
234 |
+
elif action == "delete_branch":
|
235 |
if not all([repo_name, branch]):
|
236 |
raise ValueError("Missing parameters: repo_name, branch")
|
237 |
repo = user.get_repo(repo_name)
|
238 |
repo.get_git_ref(f"heads/{branch}").delete()
|
239 |
return f"Branch **`{branch}`** deleted from repository **`{repo_name}`**."
|
240 |
|
241 |
+
elif action == "create_pull_request":
|
242 |
if not all([repo_name, title, body, base, head]):
|
243 |
raise ValueError("Missing parameters: repo_name, title, body, base, head")
|
244 |
repo = user.get_repo(repo_name)
|
245 |
pr = repo.create_pull(title=title, body=body, base=base, head=head)
|
246 |
return f"Pull request created! [Open Pull Request]({pr.html_url})"
|
247 |
|
248 |
+
elif action == "list_open_pull_requests":
|
249 |
if not repo_name:
|
250 |
raise ValueError("Missing parameter: repo_name")
|
251 |
repo = user.get_repo(repo_name)
|
|
|
255 |
prs_list = "\n".join([f"- [{pr.title}]({pr.html_url})" for pr in open_prs])
|
256 |
return f"Open pull requests in repository **`{repo_name}`**:\n{prs_list}"
|
257 |
|
258 |
+
elif action == "create_issue":
|
259 |
if not all([repo_name, title, body]):
|
260 |
raise ValueError("Missing parameters: repo_name, title, body")
|
261 |
repo = user.get_repo(repo_name)
|
262 |
issue = repo.create_issue(title=title, body=body)
|
263 |
return f"Issue created! [Open Issue]({issue.html_url})"
|
264 |
|
265 |
+
elif action == "list_issues":
|
266 |
if not repo_name:
|
267 |
raise ValueError("Missing parameter: repo_name")
|
268 |
repo = user.get_repo(repo_name)
|
|
|
272 |
issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues])
|
273 |
return f"Open issues in repository **`{repo_name}`**:\n{issues_list}"
|
274 |
|
275 |
+
elif action == "add_label_to_issue":
|
276 |
if not all([repo_name, issue_number, labels]):
|
277 |
raise ValueError("Missing parameters: repo_name, issue_number, labels")
|
278 |
repo = user.get_repo(repo_name)
|
|
|
283 |
f"Labels **`{labels}`** added to issue **#{issue_number}** in repository **`{repo_name}`**."
|
284 |
)
|
285 |
|
286 |
+
elif action == "close_issue":
|
287 |
if not all([repo_name, issue_number]):
|
288 |
raise ValueError("Missing parameters: repo_name, issue_number")
|
289 |
repo = user.get_repo(repo_name)
|
|
|
291 |
issue.edit(state='closed')
|
292 |
return f"Issue **#{issue_number}** closed in repository **`{repo_name}`**."
|
293 |
|
294 |
+
elif action == "add_comment_to_issue":
|
295 |
if not all([repo_name, issue_number, message]):
|
296 |
raise ValueError("Missing parameters: repo_name, issue_number, message")
|
297 |
repo = user.get_repo(repo_name)
|
|
|
299 |
issue.create_comment(body=message)
|
300 |
return f"Comment added to issue **#{issue_number}** in repository **`{repo_name}`**."
|
301 |
|
302 |
+
elif action == "create_release":
|
303 |
if not all([repo_name, tag, name, message]):
|
304 |
raise ValueError("Missing parameters: repo_name, tag, name, message")
|
305 |
repo = user.get_repo(repo_name)
|
|
|
308 |
f"Release **`{name}`** created in repository **`{repo_name}`**! [Open Release]({release.html_url})"
|
309 |
)
|
310 |
|
311 |
+
elif action == "list_releases":
|
312 |
if not repo_name:
|
313 |
raise ValueError("Missing parameter: repo_name")
|
314 |
repo = user.get_repo(repo_name)
|
|
|
318 |
releases_list = "\n".join([f"- [{release.tag_name}]({release.html_url})" for release in releases])
|
319 |
return f"Releases in repository **`{repo_name}`**:\n{releases_list}"
|
320 |
|
321 |
+
elif action == "fork_repository":
|
322 |
if not repo_name:
|
323 |
raise ValueError("Missing parameter: repo_name")
|
324 |
repo = g.get_repo(repo_name)
|
325 |
fork = user.create_fork(repo)
|
326 |
return f"Repository **`{repo_name}`** forked! [Open fork]({fork.html_url})"
|
327 |
|
328 |
+
elif action == "list_forks":
|
329 |
if not repo_name:
|
330 |
raise ValueError("Missing parameter: repo_name")
|
331 |
repo = g.get_repo(repo_name)
|
|
|
335 |
forks_list = "\n".join([f"- [{fork.full_name}]({fork.html_url})" for fork in forks])
|
336 |
return f"Forks of repository **`{repo_name}`**:\n{forks_list}"
|
337 |
|
338 |
+
elif action == "list_files":
|
339 |
if not all([owner, repo_name]):
|
340 |
raise ValueError("Missing parameters: owner, repo_name")
|
341 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
342 |
+
contents = repo.get_contents("" if not path else path)
|
343 |
if not contents:
|
344 |
return f"No files in path **`{path}`** of repository **`{repo_name}`**."
|
345 |
files_list = "\n".join([f"- [{content.name}]({content.download_url})" for content in contents])
|
346 |
return f"Files in path **`{path}`** of repository **`{repo_name}`**:\n{files_list}"
|
347 |
|
348 |
+
elif action == "get_repository_info":
|
349 |
if not all([owner, repo_name]):
|
350 |
raise ValueError("Missing parameters: owner, repo_name")
|
351 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
|
|
364 |
info_md = "\n".join([f"- **{key}**: {value}" for key, value in info.items()])
|
365 |
return f"Repository info for **`{repo_name}`**:\n{info_md}"
|
366 |
|
367 |
+
elif action == "get_file_content":
|
368 |
if not all([owner, repo_name, path]):
|
369 |
raise ValueError("Missing parameters: owner, repo_name, path")
|
370 |
content_text = get_file_content(owner, repo_name, path, branch)
|
|
|
372 |
f"File content of **`{path}`** from repository **`{repo_name}`**:\n\n`\n{content_text}\n`"
|
373 |
)
|
374 |
|
375 |
+
elif action == "analyze_repository_by_url":
|
376 |
if not repo_url:
|
377 |
raise ValueError("Missing parameter: repo_url")
|
378 |
owner, repo_name = extract_repo_info(repo_url)
|
|
|
400 |
])
|
401 |
return analysis_md
|
402 |
|
403 |
+
elif action == "analyze_repository_content":
|
404 |
if not all([owner, repo_name]):
|
405 |
raise ValueError("Missing parameters: owner, repo_name")
|
406 |
repo = g.get_repo(f"{owner}/{repo_name}")
|
|
|
408 |
file_analyses = []
|
409 |
for content in contents:
|
410 |
if content.type == "file":
|
411 |
+
file_content = get_file_content(owner, repo_name, content.path, branch)
|
412 |
analysis = analyze_file_content(file_content, content.path)
|
413 |
file_analyses.append({
|
414 |
"name": content.name,
|
|
|
424 |
])
|
425 |
return analysis_md
|
426 |
|
427 |
+
elif action == "delete_repository":
|
428 |
+
if not repo_name:
|
429 |
+
raise ValueError("Missing parameter: repo_name")
|
430 |
+
repo = user.get_repo(repo_name)
|
431 |
+
repo.delete()
|
432 |
+
return f"Repository **`{repo_name}`** deleted!"
|
433 |
+
|
434 |
+
elif action == "update_repository_description":
|
435 |
+
if not all([repo_name, new_description]):
|
436 |
+
raise ValueError("Missing parameters: repo_name, new_description")
|
437 |
+
repo = user.get_repo(repo_name)
|
438 |
+
repo.edit(description=new_description)
|
439 |
+
return f"Repository **`{repo_name}`** description updated to: \"{new_description}\""
|
440 |
+
|
441 |
+
elif action == "edit_issue":
|
442 |
+
if not all([repo_name, issue_number]):
|
443 |
+
raise ValueError("Missing parameters: repo_name, issue_number")
|
444 |
+
repo = user.get_repo(repo_name)
|
445 |
+
issue = repo.get_issue(number=int(issue_number))
|
446 |
+
issue_update_params = {}
|
447 |
+
if issue_title is not None:
|
448 |
+
issue_update_params['title'] = issue_title
|
449 |
+
if issue_body is not None:
|
450 |
+
issue_update_params['body'] = issue_body
|
451 |
+
if issue_state is not None:
|
452 |
+
issue_update_params['state'] = issue_state
|
453 |
+
if not issue_update_params:
|
454 |
+
raise ValueError("No issue details to update provided (title, body, or state)")
|
455 |
+
issue.edit(**issue_update_params)
|
456 |
+
updated_fields = ", ".join(issue_update_params.keys())
|
457 |
+
return f"Issue **#{issue_number}** in repository **`{repo_name}`** updated fields: {updated_fields}"
|
458 |
+
|
459 |
+
elif action == "list_closed_issues":
|
460 |
+
if not repo_name:
|
461 |
+
raise ValueError("Missing parameter: repo_name")
|
462 |
+
repo = user.get_repo(repo_name)
|
463 |
+
issues = repo.get_issues(state='closed')
|
464 |
+
if not issues:
|
465 |
+
return f"No closed issues in repository **`{repo_name}`**."
|
466 |
+
issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues])
|
467 |
+
return f"Closed issues in repository **`{repo_name}`**:\n{issues_list}"
|
468 |
|
469 |
+
elif action == "get_issue_details":
|
470 |
+
if not all([repo_name, issue_number]):
|
471 |
+
raise ValueError("Missing parameters: repo_name, issue_number")
|
472 |
+
repo = user.get_repo(repo_name)
|
473 |
+
issue = repo.get_issue(number=int(issue_number))
|
474 |
+
comments = issue.get_comments()
|
475 |
+
details = f"""
|
476 |
+
**Issue #{issue.number}: {issue.title}**
|
477 |
+
State: {issue.state}
|
478 |
+
Created At: {issue.created_at}
|
479 |
+
Author: {issue.user.login}
|
480 |
+
|
481 |
+
**Body:**
|
482 |
+
{issue.body}
|
483 |
+
|
484 |
+
**Comments:**
|
485 |
+
"""
|
486 |
+
if comments:
|
487 |
+
for comment in comments:
|
488 |
+
details += f"""
|
489 |
+
---
|
490 |
+
**{comment.user.login}** at {comment.created_at}:
|
491 |
+
{comment.body}
|
492 |
+
"""
|
493 |
+
else:
|
494 |
+
details += "No comments."
|
495 |
+
|
496 |
+
return details
|
497 |
+
|
498 |
+
else:
|
499 |
+
raise ValueError(f"Unknown action: {action}")
|
500 |
|
501 |
except GithubException as e:
|
502 |
return f"**GitHub Error:** {e}"
|
503 |
except ValueError as e:
|
504 |
+
return f"**Error:** {e}"
|
505 |
except requests.exceptions.RequestException as e:
|
506 |
return f"**Connection Error:** {e}"
|
507 |
except Exception as e:
|
508 |
+
return f"**Unexpected Error:** {e}"
|
509 |
|
510 |
|
511 |
with gr.Blocks() as demo:
|
|
|
514 |
with gr.Column():
|
515 |
action = gr.Dropdown(
|
516 |
choices=[
|
517 |
+
"import_repository", "create_repository", "create_project_from_template",
|
518 |
+
"create_file", "get_file", "get_file_content_by_url",
|
519 |
+
"delete_file", "update_file", "update_file_diff",
|
520 |
+
"list_branches", "create_branch", "delete_branch",
|
521 |
+
"create_pull_request", "list_open_pull_requests",
|
522 |
+
"create_issue", "list_issues", "list_closed_issues", "get_issue_details",
|
523 |
+
"add_label_to_issue", "close_issue", "add_comment_to_issue",
|
524 |
+
"create_release", "list_releases",
|
525 |
+
"fork_repository", "list_forks",
|
526 |
+
"list_files", "get_repository_info",
|
527 |
+
"analyze_repository_by_url", "analyze_repository_content",
|
528 |
+
"delete_repository", "update_repository_description", "edit_issue"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
529 |
],
|
530 |
label="Select Action",
|
531 |
)
|
532 |
repo_name = gr.Textbox(label="Repository Name")
|
533 |
template_name = gr.Dropdown(
|
534 |
+
choices=[""] + list(PROJECT_TEMPLATES.keys()),
|
535 |
label="Project Template",
|
536 |
+
value="",
|
537 |
+
allow_custom_value=True,
|
538 |
)
|
|
|
539 |
template_params_ui = {}
|
540 |
+
with gr.Row():
|
541 |
for template_key, template_config in PROJECT_TEMPLATES.items():
|
542 |
if "params" in template_config:
|
543 |
+
with gr.Column(visible=False, elem_classes=f"params_{template_key}") as params_section:
|
544 |
for param_name, param_details in template_config["params"].items():
|
545 |
if param_details["type"] == "choice":
|
546 |
template_params_ui[param_name] = gr.Dropdown(
|
|
|
548 |
label=param_details["description"] or param_name,
|
549 |
value=param_details["default"]
|
550 |
)
|
551 |
+
else:
|
552 |
template_params_ui[param_name] = gr.Textbox(
|
553 |
label=param_details["description"] or param_name,
|
554 |
value=param_details["default"] if "default" in param_details else ""
|
555 |
)
|
556 |
+
template_params_ui[template_key] = params_section
|
557 |
|
558 |
branch = gr.Textbox(label="Branch", value="main")
|
559 |
path = gr.Textbox(label="File Path")
|
560 |
+
content = gr.Code(label="File Content", lines=5, language='python', visible=True)
|
561 |
+
diff = gr.Code(label="Diff Content", lines=5, language='diff', visible=False)
|
562 |
+
message = gr.Textbox(label="Message/Comment", visible=True)
|
563 |
+
diff_message = gr.Textbox(label="Diff Message", visible=False)
|
564 |
owner = gr.Textbox(label="Owner")
|
565 |
vcs_url = gr.Textbox(label="VCS URL")
|
566 |
title = gr.Textbox(label="Title")
|
|
|
573 |
release_name = gr.Textbox(label="Release Name")
|
574 |
file_url = gr.Textbox(label="File URL")
|
575 |
repo_url = gr.Textbox(label="Repository URL")
|
576 |
+
new_description = gr.Textbox(label="New Repository Description", visible=False)
|
577 |
+
issue_title = gr.Textbox(label="New Issue Title", visible=False)
|
578 |
+
issue_body = gr.Textbox(label="New Issue Body", visible=False, lines=3)
|
579 |
+
issue_state = gr.Dropdown(label="New Issue State (open/closed)", choices=["open", "closed", None], value=None, allow_none=True, visible=False)
|
580 |
|
|
|
581 |
def show_template_params(template_name):
|
582 |
visibility_map = {key: gr.Column.update(visible=False) for key in PROJECT_TEMPLATES if
|
583 |
+
"params" in PROJECT_TEMPLATES[key]}
|
584 |
if template_name and template_name in PROJECT_TEMPLATES and "params" in PROJECT_TEMPLATES[template_name]:
|
585 |
+
visibility_map[template_name] = gr.Column.update(visible=True)
|
586 |
return [visibility_map.get(key, gr.Column.update(visible=False)) for key in PROJECT_TEMPLATES if
|
587 |
+
"params" in PROJECT_TEMPLATES[key]]
|
588 |
|
589 |
template_param_visibility_outputs = [template_params_ui[key] for key in PROJECT_TEMPLATES if
|
590 |
+
"params" in PROJECT_TEMPLATES[key]]
|
591 |
template_name.change(
|
592 |
show_template_params,
|
593 |
inputs=[template_name],
|
|
|
595 |
)
|
596 |
|
597 |
run_button = gr.Button("Execute")
|
598 |
+
output = gr.Markdown(label="Result")
|
599 |
|
600 |
input_components = [
|
601 |
+
action, repo_name, branch, path, content, message, owner, vcs_url, title, body, base, head, issue_number,
|
602 |
+
labels, tag, release_name, file_url, repo_url, template_name, new_description, issue_title, issue_body,
|
603 |
+
issue_state, diff, diff_message
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
604 |
]
|
605 |
|
|
|
606 |
for template_key in PROJECT_TEMPLATES:
|
607 |
if "params" in PROJECT_TEMPLATES[template_key]:
|
608 |
+
for param_name in template_params_ui:
|
609 |
+
if param_name in PROJECT_TEMPLATES[template_key]["params"]:
|
610 |
+
input_components.append(template_params_ui[param_name])
|
611 |
+
|
612 |
+
def show_hide_input_fields(action_name):
|
613 |
+
visibility_map = {
|
614 |
+
"repo_name": gr.Textbox.update(visible=False),
|
615 |
+
"branch": gr.Textbox.update(visible=False),
|
616 |
+
"path": gr.Textbox.update(visible=False),
|
617 |
+
"content": gr.Code.update(visible=False),
|
618 |
+
"diff": gr.Code.update(visible=False),
|
619 |
+
"message": gr.Textbox.update(visible=False),
|
620 |
+
"diff_message": gr.Textbox.update(visible=False),
|
621 |
+
"owner": gr.Textbox.update(visible=False),
|
622 |
+
"vcs_url": gr.Textbox.update(visible=False),
|
623 |
+
"title": gr.Textbox.update(visible=False),
|
624 |
+
"body": gr.Textbox.update(visible=False),
|
625 |
+
"base": gr.Textbox.update(visible=False),
|
626 |
+
"head": gr.Textbox.update(visible=False),
|
627 |
+
"issue_number": gr.Number.update(visible=False),
|
628 |
+
"labels": gr.Textbox.update(visible=False),
|
629 |
+
"tag": gr.Textbox.update(visible=False),
|
630 |
+
"release_name": gr.Textbox.update(visible=False),
|
631 |
+
"file_url": gr.Textbox.update(visible=False),
|
632 |
+
"repo_url": gr.Textbox.update(visible=False),
|
633 |
+
"template_name": gr.Dropdown.update(visible=False),
|
634 |
+
"new_description": gr.Textbox.update(visible=False),
|
635 |
+
"issue_title": gr.Textbox.update(visible=False),
|
636 |
+
"issue_body": gr.Textbox.update(visible=False),
|
637 |
+
"issue_state": gr.Dropdown.update(visible=False),
|
638 |
+
}
|
639 |
+
|
640 |
+
if action_name in ["import_repository"]:
|
641 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "owner": gr.Textbox.update(visible=True), "vcs_url": gr.Textbox.update(visible=True)})
|
642 |
+
elif action_name in ["create_repository", "delete_repository", "list_branches", "list_open_pull_requests", "list_issues", "list_closed_issues", "list_releases", "list_forks"]:
|
643 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True)})
|
644 |
+
elif action_name == "create_project_from_template":
|
645 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "template_name": gr.Dropdown.update(visible=True)})
|
646 |
+
elif action_name in ["create_file", "get_file", "delete_file", "get_file_content"]:
|
647 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "path": gr.Textbox.update(visible=True), "branch": gr.Textbox.update(visible=True)})
|
648 |
+
if action_name == "create_file":
|
649 |
+
visibility_map.update({"content": gr.Code.update(visible=True), "message": gr.Textbox.update(visible=True)})
|
650 |
+
elif action_name == "update_file":
|
651 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "path": gr.Textbox.update(visible=True), "branch": gr.Textbox.update(visible=True), "content": gr.Code.update(visible=True), "message": gr.Textbox.update(visible=True)})
|
652 |
+
elif action_name == "update_file_diff":
|
653 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "path": gr.Textbox.update(visible=True), "branch": gr.Textbox.update(visible=True), "diff": gr.Code.update(visible=True), "diff_message": gr.Textbox.update(visible=True)})
|
654 |
+
elif action_name == "get_file_content_by_url":
|
655 |
+
visibility_map.update({"file_url": gr.Textbox.update(visible=True)})
|
656 |
+
elif action_name in ["create_branch", "delete_branch"]:
|
657 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "branch": gr.Textbox.update(visible=True)})
|
658 |
+
if action_name == "create_branch":
|
659 |
+
visibility_map.update({"base": gr.Textbox.update(visible=True), "head": gr.Textbox.update(visible=True)})
|
660 |
+
elif action_name == "create_pull_request":
|
661 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "title": gr.Textbox.update(visible=True), "body": gr.Textbox.update(visible=True), "base": gr.Textbox.update(visible=True), "head": gr.Textbox.update(visible=True)})
|
662 |
+
elif action_name == "create_issue":
|
663 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "title": gr.Textbox.update(visible=True), "body": gr.Textbox.update(visible=True)})
|
664 |
+
elif action_name == "add_label_to_issue":
|
665 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "issue_number": gr.Number.update(visible=True), "labels": gr.Textbox.update(visible=True)})
|
666 |
+
elif action_name in ["close_issue", "add_comment_to_issue", "get_issue_details", "edit_issue"]:
|
667 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "issue_number": gr.Number.update(visible=True)})
|
668 |
+
if action_name == "add_comment_to_issue":
|
669 |
+
visibility_map.update({"message": gr.Textbox.update(visible=True)})
|
670 |
+
if action_name == "edit_issue":
|
671 |
+
visibility_map.update({"issue_title": gr.Textbox.update(visible=True), "issue_body": gr.Textbox.update(visible=True), "issue_state": gr.Dropdown.update(visible=True)})
|
672 |
+
elif action_name == "create_release":
|
673 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "tag": gr.Textbox.update(visible=True), "release_name": gr.Textbox.update(visible=True), "message": gr.Textbox.update(visible=True)})
|
674 |
+
elif action_name == "fork_repository":
|
675 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True)})
|
676 |
+
elif action_name in ["list_files", "get_repository_info", "analyze_repository_content"]:
|
677 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "owner": gr.Textbox.update(visible=True)})
|
678 |
+
elif action_name == "analyze_repository_by_url":
|
679 |
+
visibility_map.update({"repo_url": gr.Textbox.update(visible=True)})
|
680 |
+
elif action_name == "update_repository_description":
|
681 |
+
visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "new_description": gr.Textbox.update(visible=True)})
|
682 |
+
|
683 |
+
|
684 |
+
return [visibility_map.get(key, gr.Textbox.update(visible=False)) for key in visibility_map]
|
685 |
+
|
686 |
+
output_components_visibility = [
|
687 |
+
repo_name, branch, path, content, message, owner, vcs_url, title, body, base, head, issue_number, labels,
|
688 |
+
tag, release_name, file_url, repo_url, template_name, new_description, issue_title, issue_body,
|
689 |
+
issue_state, diff, diff_message
|
690 |
+
]
|
691 |
+
|
692 |
+
action.change(
|
693 |
+
show_hide_input_fields,
|
694 |
+
inputs=[action],
|
695 |
+
outputs=output_components_visibility
|
696 |
+
)
|
697 |
+
|
698 |
|
699 |
run_button.click(
|
700 |
github_tool,
|
701 |
+
inputs=input_components,
|
702 |
outputs=output,
|
703 |
api_name="github_tool"
|
704 |
)
|