jens-l commited on
Commit
d92c7c3
Β·
1 Parent(s): a49b090

Added planning agent

Browse files

Add .env.example and .gitignore files; implement GradioPlanningAgent for AI-powered planning in app.py; update README with setup instructions and features; add settings management; include test script for planning agent.

Files changed (9) hide show
  1. .env.example +12 -0
  2. .gitignore +281 -0
  3. README.md +120 -4
  4. app.py +85 -24
  5. planning_agent.py +288 -0
  6. pyproject.toml +1 -0
  7. settings.py +122 -0
  8. test_planning_agent.py +142 -0
  9. uv.lock +0 -0
.env.example ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MODEL_ID=Qwen/Qwen2.5-Coder-32B-Instruct
2
+ API_BASE_URL=
3
+ API_KEY=
4
+
5
+ # Application Settings
6
+ GRADIO_HOST=127.0.0.1
7
+ GRADIO_PORT=7860
8
+ GRADIO_DEBUG=true
9
+
10
+ # Planning Agent Settings
11
+ PLANNING_VERBOSITY=1
12
+ MAX_PLANNING_STEPS=10
.gitignore ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/#use-with-ide
110
+ .pdm.toml
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # Pyre type checker
147
+ .pyre/
148
+
149
+ # pytype static type analyzer
150
+ .pytype/
151
+
152
+ # Cython debug symbols
153
+ cython_debug/
154
+
155
+ # PyCharm
156
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157
+ # be added to the global gitignore or merged into this project gitignore. For a PyCharm
158
+ # project, it is usually recommended to include .idea/ directory in version control.
159
+ .idea/
160
+
161
+ # VS Code
162
+ .vscode/
163
+ *.code-workspace
164
+
165
+ # Sublime Text
166
+ *.sublime-project
167
+ *.sublime-workspace
168
+
169
+ # Vim
170
+ *.swp
171
+ *.swo
172
+ *~
173
+
174
+ # Emacs
175
+ *~
176
+ \#*\#
177
+ /.emacs.desktop
178
+ /.emacs.desktop.lock
179
+ *.elc
180
+ auto-save-list
181
+ tramp
182
+ .\#*
183
+
184
+ # macOS
185
+ .DS_Store
186
+ .AppleDouble
187
+ .LSOverride
188
+ Icon
189
+ ._*
190
+ .DocumentRevisions-V100
191
+ .fseventsd
192
+ .Spotlight-V100
193
+ .TemporaryItems
194
+ .Trashes
195
+ .VolumeIcon.icns
196
+ .com.apple.timemachine.donotpresent
197
+ .AppleDB
198
+ .AppleDesktop
199
+ Network Trash Folder
200
+ Temporary Items
201
+ .apdisk
202
+
203
+ # Windows
204
+ Thumbs.db
205
+ Thumbs.db:encryptable
206
+ ehthumbs.db
207
+ ehthumbs_vista.db
208
+ Desktop.ini
209
+ $RECYCLE.BIN/
210
+ *.cab
211
+ *.msi
212
+ *.msix
213
+ *.msm
214
+ *.msp
215
+ *.lnk
216
+
217
+ # Linux
218
+ *~
219
+ .fuse_hidden*
220
+ .directory
221
+ .Trash-*
222
+ .nfs*
223
+
224
+ # UV (Python package manager)
225
+ .uv/
226
+
227
+ # Gradio
228
+ gradio_cached_examples/
229
+ flagged/
230
+
231
+ # Project specific
232
+ *.md
233
+ !README.md
234
+ !.env.example
235
+ user_app_plan.md
236
+ plan_*.md
237
+
238
+ # Logs
239
+ *.log
240
+ logs/
241
+
242
+ # Temporary files
243
+ tmp/
244
+ temp/
245
+ .tmp/
246
+
247
+ # Generated content
248
+ generated/
249
+ output/
250
+
251
+ # AI model cache
252
+ .cache/
253
+ models/
254
+ *.pkl
255
+ *.pickle
256
+
257
+ # Jupyter notebooks (optional - uncomment if you don't want to track notebooks)
258
+ # *.ipynb
259
+
260
+ # Local configuration overrides
261
+ local_settings.py
262
+ config_local.py
263
+
264
+ # Screenshots and media (for demos)
265
+ screenshots/
266
+ *.png
267
+ *.jpg
268
+ *.jpeg
269
+ *.gif
270
+ *.mp4
271
+ *.avi
272
+
273
+ # Database files
274
+ *.db
275
+ *.sqlite
276
+ *.sqlite3
277
+
278
+ # Backup files
279
+ *.bak
280
+ *.backup
281
+ *.old
README.md CHANGED
@@ -1,5 +1,121 @@
1
- # πŸ’—Likable
2
- It's almost Lovable - Build Gradio apps, using only a chat interface.
3
 
4
- ## Notes
5
- - Use as little custom css as possible!!!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # πŸ’— Likable
 
2
 
3
+ A Gradio application builder powered by Smolagents CodeAgent for intelligent planning.
4
+
5
+ ## Features
6
+
7
+ - **AI-Powered Planning**: Uses Smolagents CodeAgent to create comprehensive plans for Gradio applications
8
+ - **Interactive Chat Interface**: Describe what you want to build in natural language
9
+ - **Structured Planning Output**: Get detailed action plans, implementation strategies, and testing approaches
10
+ - **Component Analysis**: Automatically identifies required Gradio components and dependencies
11
+ - **Preview & Code Views**: Switch between live preview and generated code
12
+ - **Environment-based Configuration**: Flexible configuration via environment variables
13
+
14
+ ## Setup
15
+
16
+ 1. **Install dependencies:**
17
+ ```bash
18
+ uv install
19
+ ```
20
+
21
+ 2. **Configure environment variables:**
22
+ ```bash
23
+ # Copy the example environment file
24
+ cp .env.example .env
25
+
26
+ # Edit .env with your configuration
27
+ # At minimum, set your API_KEY
28
+ ```
29
+
30
+ 3. **Set up your API_KEY:**
31
+
32
+ Add it to your `.env` file:
33
+ ```
34
+ API_KEY=your_actual_key_here
35
+ ```
36
+
37
+ 4. **Run the application:**
38
+ ```bash
39
+ python app.py
40
+ ```
41
+
42
+ ## Configuration
43
+
44
+ The application uses environment variables for configuration. See `.env.example` for all available options:
45
+
46
+ ### Core Configuration
47
+ - `API_KEY`: Your API key (required)
48
+ - `MODEL_ID`: Model to use for planning (default: Qwen/Qwen2.5-Coder-32B-Instruct)
49
+
50
+ ### Application Settings
51
+ - `GRADIO_HOST`: Host to bind Gradio server (default: 127.0.0.1)
52
+ - `GRADIO_PORT`: Port for Gradio server (default: 7860)
53
+ - `GRADIO_DEBUG`: Enable debug mode (default: true)
54
+
55
+ ### Planning Agent Settings
56
+ - `PLANNING_VERBOSITY`: Agent verbosity level 0-2 (default: 1)
57
+ - `MAX_PLANNING_STEPS`: Maximum planning steps (default: 10)
58
+
59
+ ### Test Your Configuration
60
+ ```bash
61
+ # View current configuration
62
+ python settings.py
63
+
64
+ # Test the planning agent
65
+ python test_planning_agent.py
66
+
67
+ # Interactive demo
68
+ python test_planning_agent.py demo
69
+ ```
70
+
71
+ ## Planning Agent
72
+
73
+ The core of Likable is the `GradioPlanningAgent` which uses Smolagents to:
74
+
75
+ - Analyze your application requirements
76
+ - Create detailed action plans
77
+ - Suggest appropriate Gradio components
78
+ - Plan implementation strategies
79
+ - Design testing approaches
80
+ - Estimate complexity and dependencies
81
+
82
+ ### Using the Planning Agent Directly
83
+
84
+ ```python
85
+ from planning_agent import GradioPlanningAgent
86
+
87
+ # Uses configuration from settings.py (loads from .env)
88
+ agent = GradioPlanningAgent()
89
+ result = agent.plan_application("Create a simple calculator app")
90
+
91
+ print(agent.format_plan_as_markdown(result))
92
+ ```
93
+
94
+ ## Project Structure
95
+
96
+ ```
97
+ likable/
98
+ β”œβ”€β”€ app.py # Main Gradio application
99
+ β”œβ”€β”€ planning_agent.py # Smolagents CodeAgent for planning
100
+ β”œβ”€β”€ settings.py # Configuration management
101
+ β”œβ”€β”€ test_planning_agent.py # Test script and examples
102
+ β”œβ”€β”€ .env.example # Environment variables template
103
+ β”œβ”€β”€ pyproject.toml # Project dependencies
104
+ └── README.md # This file
105
+ ```
106
+
107
+ ## Environment Requirements
108
+
109
+ - Python 3.12+
110
+ - Inference API key
111
+ - Internet connection for model inference
112
+
113
+ ## Dependencies
114
+
115
+ - `gradio` - Web UI framework
116
+ - `smolagents` - AI agent framework
117
+ - `python-dotenv` - Environment variable management
118
+
119
+ ---
120
+
121
+ *Built with ❀️ using Gradio and Smolagents*
app.py CHANGED
@@ -1,27 +1,87 @@
1
- import random
2
- import time
3
-
4
  import gradio as gr
5
 
 
 
 
6
  gr.NO_RELOAD = False
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
- # Mock function to simulate AI responses
10
- def simulate_ai_response(message, history):
11
- """Simulate an AI response for demonstration purposes"""
12
- time.sleep(1) # Simulate processing time
13
 
14
- # Simple demo responses
15
- responses = [
16
- "I'll help you build that! Let me generate some code for you.",
17
- "Great idea! I'm working on implementing that feature.",
18
- "Here's what I can create for you based on your request.",
19
- "Let me design that component and show you a preview.",
20
- "I understand what you need. I'll code that up right now!",
21
- ]
 
 
 
 
 
 
 
 
 
22
 
23
- response = random.choice(responses)
24
- history.append([message, response])
25
  return history, ""
26
 
27
 
@@ -120,7 +180,7 @@ def create_lovable_ui():
120
  height=500,
121
  show_copy_button=True,
122
  avatar_images=(None, "πŸ€–"),
123
- bubble_full_width=False,
124
  )
125
 
126
  with gr.Row():
@@ -151,7 +211,7 @@ def create_lovable_ui():
151
  height=500,
152
  show_copy_button=True,
153
  avatar_images=(None, "πŸ€–"),
154
- bubble_full_width=False,
155
  )
156
 
157
  with gr.Row():
@@ -181,26 +241,26 @@ def create_lovable_ui():
181
 
182
  # Event handlers for Preview tab
183
  msg_input_preview.submit(
184
- simulate_ai_response,
185
  inputs=[msg_input_preview, chatbot_preview],
186
  outputs=[chatbot_preview, msg_input_preview],
187
  )
188
 
189
  send_btn_preview.click(
190
- simulate_ai_response,
191
  inputs=[msg_input_preview, chatbot_preview],
192
  outputs=[chatbot_preview, msg_input_preview],
193
  )
194
 
195
  # Event handlers for Code tab
196
  msg_input_code.submit(
197
- simulate_ai_response,
198
  inputs=[msg_input_code, chatbot_code],
199
  outputs=[chatbot_code, msg_input_code],
200
  )
201
 
202
  send_btn_code.click(
203
- simulate_ai_response,
204
  inputs=[msg_input_code, chatbot_code],
205
  outputs=[chatbot_code, msg_input_code],
206
  )
@@ -210,4 +270,5 @@ def create_lovable_ui():
210
 
211
  if __name__ == "__main__":
212
  demo = create_lovable_ui()
213
- demo.launch(debug=True)
 
 
 
 
 
1
  import gradio as gr
2
 
3
+ from planning_agent import GradioPlanningAgent
4
+ from settings import settings
5
+
6
  gr.NO_RELOAD = False
7
 
8
+ # Initialize the planning agent globally
9
+ planning_agent = None
10
+
11
+
12
+ def get_planning_agent():
13
+ """Get or initialize the planning agent (lazy loading)."""
14
+ global planning_agent
15
+ if planning_agent is None:
16
+ try:
17
+ planning_agent = GradioPlanningAgent()
18
+ except Exception as e:
19
+ print(f"Error initializing planning agent: {e}")
20
+ return None
21
+ return planning_agent
22
+
23
+
24
+ # Enhanced AI response using the planning agent
25
+ def ai_response_with_planning(message, history):
26
+ """Generate AI response using the planning agent for actual planning."""
27
+
28
+ agent = get_planning_agent()
29
+
30
+ if agent is None:
31
+ # Fallback to mock response if agent fails to initialize
32
+ response = (
33
+ "Sorry, the planning agent is not available. "
34
+ "Please check your API_KEY environment variable."
35
+ )
36
+ history.append({"role": "user", "content": message})
37
+ history.append({"role": "assistant", "content": response})
38
+ return history, ""
39
+
40
+ try:
41
+ # Use the planning agent for actual planning
42
+ planning_result = agent.plan_application(message)
43
+
44
+ # Format the response with key insights
45
+ action_summary = (
46
+ planning_result.action_plan[:300] + "..."
47
+ if len(planning_result.action_plan) > 300
48
+ else planning_result.action_plan
49
+ )
50
+
51
+ components_list = chr(10).join(
52
+ [f"β€’ {comp}" for comp in planning_result.gradio_components[:5]]
53
+ )
54
+ dependencies_list = chr(10).join(
55
+ [f"β€’ {dep}" for dep in planning_result.dependencies[:5]]
56
+ )
57
+
58
+ response = f"""I'll help you plan that application! Here's what I've analyzed:
59
+
60
+ **Complexity**: {planning_result.estimated_complexity}
61
 
62
+ **Key Gradio Components Needed**:
63
+ {components_list}
 
 
64
 
65
+ **Dependencies Required**:
66
+ {dependencies_list}
67
+
68
+ **High-Level Action Plan**:
69
+ {action_summary}
70
+
71
+ I've created a comprehensive plan including implementation details and testing \
72
+ strategy. Check the detailed view for the complete plan!"""
73
+
74
+ # Store the full planning result for later use
75
+ # You could save this to a session state or database
76
+
77
+ except Exception as e:
78
+ response = (
79
+ f"I encountered an error while planning: {str(e)}. "
80
+ "Let me try a simpler approach..."
81
+ )
82
 
83
+ history.append({"role": "user", "content": message})
84
+ history.append({"role": "assistant", "content": response})
85
  return history, ""
86
 
87
 
 
180
  height=500,
181
  show_copy_button=True,
182
  avatar_images=(None, "πŸ€–"),
183
+ type="messages",
184
  )
185
 
186
  with gr.Row():
 
211
  height=500,
212
  show_copy_button=True,
213
  avatar_images=(None, "πŸ€–"),
214
+ type="messages",
215
  )
216
 
217
  with gr.Row():
 
241
 
242
  # Event handlers for Preview tab
243
  msg_input_preview.submit(
244
+ ai_response_with_planning,
245
  inputs=[msg_input_preview, chatbot_preview],
246
  outputs=[chatbot_preview, msg_input_preview],
247
  )
248
 
249
  send_btn_preview.click(
250
+ ai_response_with_planning,
251
  inputs=[msg_input_preview, chatbot_preview],
252
  outputs=[chatbot_preview, msg_input_preview],
253
  )
254
 
255
  # Event handlers for Code tab
256
  msg_input_code.submit(
257
+ ai_response_with_planning,
258
  inputs=[msg_input_code, chatbot_code],
259
  outputs=[chatbot_code, msg_input_code],
260
  )
261
 
262
  send_btn_code.click(
263
+ ai_response_with_planning,
264
  inputs=[msg_input_code, chatbot_code],
265
  outputs=[chatbot_code, msg_input_code],
266
  )
 
270
 
271
  if __name__ == "__main__":
272
  demo = create_lovable_ui()
273
+ gradio_config = settings.get_gradio_config()
274
+ demo.launch(**gradio_config)
planning_agent.py ADDED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Smolagents CodeAgent for planning Gradio applications.
3
+
4
+ This module provides a specialized planning agent that can:
5
+ - Take a prompt describing a program
6
+ - Extensively plan how to implement the program using Python and Gradio
7
+ - Return an action, implementation and testing plan
8
+ """
9
+
10
+ from dataclasses import dataclass
11
+
12
+ from smolagents import LiteLLMModel
13
+
14
+ from settings import settings
15
+
16
+
17
+ @dataclass
18
+ class PlanningResult:
19
+ """Result of the planning agent containing structured plans."""
20
+
21
+ action_plan: str
22
+ implementation_plan: str
23
+ testing_plan: str
24
+ gradio_components: list[str]
25
+ estimated_complexity: str
26
+ dependencies: list[str]
27
+
28
+
29
+ class GradioPlanningAgent:
30
+ """
31
+ A specialized CodeAgent for planning Gradio applications.
32
+
33
+ This agent takes natural language descriptions of programs and creates
34
+ comprehensive plans for implementing them with Python and Gradio.
35
+ """
36
+
37
+ def __init__(
38
+ self,
39
+ model_id: str | None = None,
40
+ api_base_url: str | None = None,
41
+ api_key: str | None = None,
42
+ verbosity_level: int | None = None,
43
+ ):
44
+ """
45
+ Initialize the Gradio Planning Agent.
46
+
47
+ Args:
48
+ model_id: Model ID to use for planning (uses settings if None)
49
+ api_base_url: API base URL (uses settings if None)
50
+ api_key: API key (uses settings if None)
51
+ verbosity_level: Level of verbosity for agent output (uses settings if None)
52
+ """
53
+ # Use settings as defaults, but allow override
54
+ self.model_id = model_id or settings.model_id
55
+ self.api_base_url = api_base_url or settings.api_base_url
56
+ self.api_key = api_key or settings.api_key
57
+ verbosity_level = verbosity_level or settings.planning_verbosity
58
+
59
+ # Initialize the language model
60
+ self.model = LiteLLMModel(
61
+ model_id=self.model_id,
62
+ api_base=self.api_base_url,
63
+ api_key=self.api_key,
64
+ )
65
+
66
+ self.planning_prompt = """You are an expert software architect and Gradio \
67
+ application developer. Your role is to create comprehensive, detailed plans \
68
+ for building Gradio applications based on user requirements.
69
+
70
+ IMPORTANT: This is a PLANNING AND ARCHITECTURE phase only. Do NOT write any actual \
71
+ code. Focus on high-level design, structure, and planning. Code implementation will \
72
+ happen in a separate phase.
73
+
74
+ When given a description of a program to build, you must create three detailed plans:
75
+
76
+ 1. **ACTION PLAN**: Break down the high-level steps needed to build the application
77
+ 2. **IMPLEMENTATION PLAN**: Detailed technical implementation using Python and Gradio
78
+ 3. **TESTING PLAN**: Comprehensive testing strategy for the application
79
+
80
+ For each plan, consider:
81
+ - Gradio components needed (gr.Textbox, gr.Button, gr.Chatbot, gr.Plot, etc.)
82
+ - Python dependencies and imports required
83
+ - Data flow and state management
84
+ - User interface design and user experience
85
+ - Error handling and edge cases
86
+ - Performance considerations
87
+ - Deployment considerations
88
+
89
+ You should structure your response using the following format:
90
+
91
+ ## ACTION PLAN
92
+ [High-level steps and workflow]
93
+
94
+ ## IMPLEMENTATION PLAN
95
+ [Detailed technical implementation with Gradio components]
96
+
97
+ ## TESTING PLAN
98
+ [Comprehensive testing strategy]
99
+
100
+ ## GRADIO COMPONENTS
101
+ [List of Gradio components that will be used]
102
+
103
+ ## ESTIMATED COMPLEXITY
104
+ [Simple/Medium/Complex with brief explanation]
105
+
106
+ ## DEPENDENCIES
107
+ [Required Python packages beyond gradio]
108
+
109
+ Be thorough, practical, and consider real-world constraints. Focus on creating \
110
+ maintainable, user-friendly Gradio applications. Remember: NO CODE IMPLEMENTATION \
111
+ at this stage - only architectural planning and structural design."""
112
+
113
+ def plan_application(self, prompt: str) -> PlanningResult:
114
+ """
115
+ Create a comprehensive plan for a Gradio application based on the prompt.
116
+
117
+ Args:
118
+ prompt: Natural language description of the program to build
119
+
120
+ Returns:
121
+ PlanningResult containing structured plans
122
+ """
123
+
124
+ # Enhanced prompt for the agent
125
+ user_prompt = f"""
126
+ Create a comprehensive plan for building the following Gradio application:
127
+
128
+ {prompt}
129
+
130
+ Please provide detailed ACTION, IMPLEMENTATION, and TESTING plans following the \
131
+ specified format. Consider all aspects of the application including UI/UX, \
132
+ functionality, error handling, and deployment.
133
+ """
134
+
135
+ messages = [
136
+ {"role": "system", "content": self.planning_prompt},
137
+ {"role": "user", "content": user_prompt},
138
+ ]
139
+ response = self.model.generate(messages)
140
+
141
+ # Parse the response into structured result
142
+ return self._parse_planning_response(response.content)
143
+
144
+ def _parse_planning_response(self, response: str) -> PlanningResult:
145
+ """
146
+ Parse the agent's response into a structured PlanningResult.
147
+
148
+ Args:
149
+ response: Raw response from the planning agent
150
+
151
+ Returns:
152
+ Structured PlanningResult
153
+ """
154
+
155
+ # Initialize default values
156
+ action_plan = ""
157
+ implementation_plan = ""
158
+ testing_plan = ""
159
+ gradio_components = []
160
+ estimated_complexity = "Medium"
161
+ dependencies = ["gradio"]
162
+
163
+ # Parse sections from the response
164
+ sections = self._extract_sections(response)
165
+
166
+ action_plan = sections.get("ACTION PLAN", "")
167
+ implementation_plan = sections.get("IMPLEMENTATION PLAN", "")
168
+ testing_plan = sections.get("TESTING PLAN", "")
169
+
170
+ # Parse gradio components list
171
+ components_text = sections.get("GRADIO COMPONENTS", "")
172
+ if components_text:
173
+ gradio_components = self._extract_list_items(components_text)
174
+
175
+ # Parse complexity
176
+ complexity_text = sections.get("ESTIMATED COMPLEXITY", "")
177
+ if complexity_text:
178
+ estimated_complexity = complexity_text.strip()
179
+
180
+ # Parse dependencies
181
+ deps_text = sections.get("DEPENDENCIES", "")
182
+ if deps_text:
183
+ dependencies = ["gradio"] + self._extract_list_items(deps_text)
184
+ # Remove duplicates while preserving order
185
+ dependencies = list(dict.fromkeys(dependencies))
186
+
187
+ return PlanningResult(
188
+ action_plan=action_plan,
189
+ implementation_plan=implementation_plan,
190
+ testing_plan=testing_plan,
191
+ gradio_components=gradio_components,
192
+ estimated_complexity=estimated_complexity,
193
+ dependencies=dependencies,
194
+ )
195
+
196
+ def _extract_sections(self, text: str) -> dict[str, str]:
197
+ """Extract sections from markdown-formatted text."""
198
+ sections = {}
199
+ current_section = None
200
+ current_content = []
201
+
202
+ for line in text.split("\n"):
203
+ line = line.strip()
204
+
205
+ # Check if line is a section header
206
+ if line.startswith("## "):
207
+ # Save previous section if exists
208
+ if current_section and current_content:
209
+ sections[current_section] = "\n".join(current_content).strip()
210
+
211
+ # Start new section
212
+ current_section = line[3:].strip()
213
+ current_content = []
214
+ elif current_section:
215
+ current_content.append(line)
216
+
217
+ # Save last section
218
+ if current_section and current_content:
219
+ sections[current_section] = "\n".join(current_content).strip()
220
+
221
+ return sections
222
+
223
+ def _extract_list_items(self, text: str) -> list[str]:
224
+ """Extract list items from text (handles bullet points, numbered lists, etc.)"""
225
+ items = []
226
+ for line in text.split("\n"):
227
+ line = line.strip()
228
+ if line:
229
+ # Remove common list prefixes
230
+ if line.startswith("- "):
231
+ line = line[2:].strip()
232
+ elif line.startswith("* "):
233
+ line = line[2:].strip()
234
+ elif ". " in line and line.split(".")[0].isdigit():
235
+ line = line.split(".", 1)[1].strip()
236
+
237
+ if line:
238
+ items.append(line)
239
+
240
+ return items
241
+
242
+ def format_plan_as_markdown(self, result: PlanningResult) -> str:
243
+ """
244
+ Format the planning result as a well-structured markdown document.
245
+
246
+ Args:
247
+ result: PlanningResult to format
248
+
249
+ Returns:
250
+ Markdown-formatted string
251
+ """
252
+
253
+ markdown = f"""# Gradio Application Plan
254
+
255
+ ## πŸ“‹ Action Plan
256
+ {result.action_plan}
257
+
258
+ ## πŸ”§ Implementation Plan
259
+ {result.implementation_plan}
260
+
261
+ ## πŸ§ͺ Testing Plan
262
+ {result.testing_plan}
263
+
264
+ ## 🎨 Gradio Components
265
+ {chr(10).join([f"- {component}" for component in result.gradio_components])}
266
+
267
+ ## ⚑ Estimated Complexity
268
+ {result.estimated_complexity}
269
+
270
+ ## πŸ“¦ Dependencies
271
+ {chr(10).join([f"- {dep}" for dep in result.dependencies])}
272
+ """
273
+
274
+ return markdown
275
+
276
+
277
+ # Example usage and testing
278
+ if __name__ == "__main__":
279
+ # Example of how to use the planning agent
280
+ agent = GradioPlanningAgent()
281
+
282
+ # Test with a simple calculator example
283
+ result = agent.plan_application(
284
+ "Write a simple calculator app that can perform basic arithmetic operations"
285
+ )
286
+
287
+ print("=== PLANNING RESULT ===")
288
+ print(agent.format_plan_as_markdown(result))
pyproject.toml CHANGED
@@ -6,6 +6,7 @@ readme = "README.md"
6
  requires-python = ">=3.12"
7
  dependencies = [
8
  "gradio>=5.32.0",
 
9
  ]
10
 
11
  [dependency-groups]
 
6
  requires-python = ">=3.12"
7
  dependencies = [
8
  "gradio>=5.32.0",
9
+ "smolagents[litellm]>=1.17.0",
10
  ]
11
 
12
  [dependency-groups]
settings.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Application settings loaded from environment variables.
3
+
4
+ This module handles loading and validation of environment variables
5
+ for the Likable application.
6
+ """
7
+
8
+ import os
9
+
10
+ from dotenv import load_dotenv
11
+
12
+ # Load environment variables from .env file
13
+ load_dotenv()
14
+
15
+
16
+ class Settings:
17
+ """Application settings loaded from environment variables."""
18
+
19
+ def __init__(self):
20
+ """Initialize settings from environment variables."""
21
+
22
+ self.model_id: str = os.getenv("MODEL_ID", "Qwen/Qwen2.5-Coder-32B-Instruct")
23
+ self.api_base_url: str | None = os.getenv("API_BASE_URL")
24
+ self.api_key: str | None = os.getenv("API_KEY")
25
+
26
+ # Application Settings
27
+ self.gradio_host: str = os.getenv("GRADIO_HOST", "127.0.0.1")
28
+ self.gradio_port: int = int(os.getenv("GRADIO_PORT", "7860"))
29
+ self.gradio_debug: bool = os.getenv("GRADIO_DEBUG", "false").lower() == "true"
30
+
31
+ # Planning Agent Settings
32
+ self.planning_verbosity: int = int(os.getenv("PLANNING_VERBOSITY", "1"))
33
+ self.max_planning_steps: int = int(os.getenv("MAX_PLANNING_STEPS", "10"))
34
+
35
+ # Validate critical settings
36
+ self._validate()
37
+
38
+ def _validate(self):
39
+ """Validate critical settings and provide helpful error messages."""
40
+
41
+ if not self.api_key:
42
+ print("⚠️ Warning: API_KEY not set in environment variables.")
43
+ print(" The planning agent may not work without a valid API key.")
44
+ print(" Set it in your .env file or as an environment variable.")
45
+ print()
46
+
47
+ if self.planning_verbosity not in [0, 1, 2]:
48
+ print(
49
+ f"⚠️ Warning: PLANNING_VERBOSITY={self.planning_verbosity} is not \
50
+ in valid range [0, 1, 2]"
51
+ )
52
+ print(" Using default value of 1")
53
+ self.planning_verbosity = 1
54
+
55
+ def get_model_config(self) -> dict:
56
+ """Get model configuration for the planning agent."""
57
+ config = {"model_id": self.model_id, "api_key": self.api_key}
58
+
59
+ if self.api_base_url:
60
+ config["api_base_url"] = self.api_base_url
61
+ if self.api_key:
62
+ config["api_key"] = self.api_key
63
+
64
+ return config
65
+
66
+ def get_gradio_config(self) -> dict:
67
+ """Get Gradio launch configuration."""
68
+ return {
69
+ "server_name": self.gradio_host,
70
+ "server_port": self.gradio_port,
71
+ "debug": self.gradio_debug,
72
+ }
73
+
74
+ def get_planning_config(self) -> dict:
75
+ """Get planning agent configuration."""
76
+ return {
77
+ "verbosity_level": self.planning_verbosity,
78
+ "max_steps": self.max_planning_steps,
79
+ }
80
+
81
+ def __repr__(self) -> str:
82
+ """String representation of settings (excluding sensitive data)."""
83
+ return f"""Settings(
84
+ model_id='{self.model_id}',
85
+ api_key={'***' if self.api_key else 'None'},
86
+ api_base_url='{self.api_base_url}',
87
+ gradio_host='{self.gradio_host}',
88
+ gradio_port={self.gradio_port},
89
+ gradio_debug={self.gradio_debug},
90
+ planning_verbosity={self.planning_verbosity},
91
+ max_planning_steps={self.max_planning_steps}
92
+ )"""
93
+
94
+
95
+ # Global settings instance
96
+ settings = Settings()
97
+
98
+
99
+ # Convenience functions for backward compatibility
100
+ def get_api_key() -> str | None:
101
+ """Get API key."""
102
+ return settings.api_key
103
+
104
+
105
+ def get_model_id() -> str:
106
+ """Get model ID."""
107
+ return settings.model_id
108
+
109
+
110
+ if __name__ == "__main__":
111
+ print("Current Settings:")
112
+ print("=" * 50)
113
+ print(settings)
114
+ print()
115
+ print("Model Config:")
116
+ print(settings.get_model_config())
117
+ print()
118
+ print("Gradio Config:")
119
+ print(settings.get_gradio_config())
120
+ print()
121
+ print("Planning Config:")
122
+ print(settings.get_planning_config())
test_planning_agent.py ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Test script for the Gradio Planning Agent.
3
+
4
+ This script demonstrates how to use the planning agent and tests it with
5
+ various prompts.
6
+ """
7
+
8
+ from planning_agent import GradioPlanningAgent
9
+ from settings import settings
10
+
11
+
12
+ def test_planning_agent():
13
+ """Test the planning agent with different prompts."""
14
+
15
+ # Check if API_KEY is available
16
+ if not settings.api_key:
17
+ print("⚠️ Warning: API_KEY environment variable not set.")
18
+ print(" You may need to set it for the agent to work properly.")
19
+ print()
20
+
21
+ # Display current settings
22
+ print("Current Configuration:")
23
+ print(f" Model ID: {settings.model_id}")
24
+ print(f" API Key: {'***' if settings.api_key else 'None'}")
25
+ print(f" Verbosity: {settings.planning_verbosity}")
26
+ print()
27
+
28
+ # Initialize the planning agent
29
+ print("πŸ€– Initializing Gradio Planning Agent...")
30
+ agent = GradioPlanningAgent()
31
+ print("βœ… Agent initialized successfully!")
32
+ print()
33
+
34
+ # Test prompts for different types of applications
35
+ test_prompts = [
36
+ {
37
+ "name": "Simple Calculator",
38
+ "prompt": (
39
+ "Write a simple calculator app that can perform basic "
40
+ "arithmetic operations (addition, subtraction, multiplication, "
41
+ "division)"
42
+ ),
43
+ },
44
+ {
45
+ "name": "Image Classifier",
46
+ "prompt": (
47
+ "Create an image classification app that allows users to "
48
+ "upload an image and get predictions from a pre-trained model"
49
+ ),
50
+ },
51
+ {
52
+ "name": "Chat Interface",
53
+ "prompt": (
54
+ "Build a chatbot interface where users can have conversations "
55
+ "with an AI assistant"
56
+ ),
57
+ },
58
+ {
59
+ "name": "Data Visualization Tool",
60
+ "prompt": (
61
+ "Create a data visualization tool that lets users upload CSV "
62
+ "files and create different types of charts and plots"
63
+ ),
64
+ },
65
+ ]
66
+
67
+ # Test each prompt
68
+ for i, test_case in enumerate(test_prompts, 1):
69
+ print(f"πŸ§ͺ Test {i}: {test_case['name']}")
70
+ print(f"πŸ“ Prompt: {test_case['prompt']}")
71
+ print("-" * 80)
72
+
73
+ try:
74
+ # Run the planning agent
75
+ result = agent.plan_application(test_case["prompt"])
76
+
77
+ # Display results
78
+ print("πŸ“Š Planning Results:")
79
+ print(f" Complexity: {result.estimated_complexity}")
80
+ print(f" Components: {', '.join(result.gradio_components[:3])}...")
81
+ print(f" Dependencies: {', '.join(result.dependencies[:3])}...")
82
+ print()
83
+
84
+ # Save detailed results to file
85
+ filename = f"plan_{test_case['name'].lower().replace(' ', '_')}.md"
86
+ with open(filename, "w") as f:
87
+ f.write(agent.format_plan_as_markdown(result))
88
+ print(f"πŸ’Ύ Detailed plan saved to: {filename}")
89
+
90
+ except Exception as e:
91
+ print(f"❌ Error testing {test_case['name']}: {e}")
92
+
93
+ print("=" * 80)
94
+ print()
95
+
96
+ print("πŸŽ‰ Testing completed!")
97
+
98
+
99
+ def demo_single_planning():
100
+ """Demonstrate planning for a single application."""
101
+
102
+ print("🎯 Single Application Planning Demo")
103
+ print("=" * 50)
104
+
105
+ # Get user input
106
+ user_prompt = input("Enter your app description: ").strip()
107
+
108
+ if not user_prompt:
109
+ user_prompt = (
110
+ "Create a simple todo list app where users can add, edit, "
111
+ "and delete tasks"
112
+ )
113
+ print(f"Using default prompt: {user_prompt}")
114
+
115
+ print("\nπŸ€– Planning your application...")
116
+
117
+ try:
118
+ # Initialize agent and run planning
119
+ agent = GradioPlanningAgent()
120
+ result = agent.plan_application(user_prompt)
121
+
122
+ # Display formatted results
123
+ print("\n" + "=" * 60)
124
+ print(agent.format_plan_as_markdown(result))
125
+ print("=" * 60)
126
+
127
+ # Save to file
128
+ with open("user_app_plan.md", "w") as f:
129
+ f.write(agent.format_plan_as_markdown(result))
130
+ print("\nπŸ’Ύ Plan saved to: user_app_plan.md")
131
+
132
+ except Exception as e:
133
+ print(f"❌ Error during planning: {e}")
134
+
135
+
136
+ if __name__ == "__main__":
137
+ import sys
138
+
139
+ if len(sys.argv) > 1 and sys.argv[1] == "demo":
140
+ demo_single_planning()
141
+ else:
142
+ test_planning_agent()
uv.lock CHANGED
The diff for this file is too large to render. See raw diff