Spaces:
Sleeping
Sleeping
Deploy Pak Angels AI Tutor
Browse files- .env.example +4 -0
- .gitignore +19 -0
- README.md +208 -7
- app.py +292 -0
- config.py +20 -0
- deploy_requirements.txt +1 -0
- deploy_to_huggingface.py +205 -0
- openai_service.py +62 -0
- prompts.py +360 -0
- requirements.txt +2 -0
.env.example
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
OPENAI_API_KEY=your_openai_api_key_here
|
| 2 |
+
OPENAI_MODEL=your_preferred_model_here
|
| 3 |
+
HF_TOKEN=your_hugging_face_write_token_here
|
| 4 |
+
HF_SPACE_ID=your-username/your-space-name
|
.gitignore
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.env
|
| 2 |
+
.venv/
|
| 3 |
+
venv/
|
| 4 |
+
__pycache__/
|
| 5 |
+
*.py[cod]
|
| 6 |
+
*$py.class
|
| 7 |
+
.Python
|
| 8 |
+
.DS_Store
|
| 9 |
+
.cache/
|
| 10 |
+
.huggingface/
|
| 11 |
+
.pytest_cache/
|
| 12 |
+
.ruff_cache/
|
| 13 |
+
.mypy_cache/
|
| 14 |
+
dist/
|
| 15 |
+
build/
|
| 16 |
+
*.egg-info/
|
| 17 |
+
*.log
|
| 18 |
+
tmp/
|
| 19 |
+
temp/
|
README.md
CHANGED
|
@@ -1,14 +1,215 @@
|
|
| 1 |
---
|
| 2 |
title: Pak Angels AI Tutor
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
-
python_version: '3.12'
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
| 11 |
-
short_description: Pak Angels AI Tutoring Platform
|
| 12 |
---
|
| 13 |
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
title: Pak Angels AI Tutor
|
| 3 |
+
emoji: 🎓
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: indigo
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 5.50.0
|
|
|
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
|
|
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# Pak Angels AI Tutor
|
| 13 |
+
|
| 14 |
+
Pak Angels AI Tutor is an AI-powered learning companion for the Pak Angels AI
|
| 15 |
+
Training Program. It helps students, faculty, researchers, professionals,
|
| 16 |
+
entrepreneurs, startup founders, AI developers, business leaders, and innovation
|
| 17 |
+
teams learn Artificial Intelligence, build practical applications, design
|
| 18 |
+
intelligent workflows, automate business processes, and develop AI-powered
|
| 19 |
+
startups.
|
| 20 |
+
|
| 21 |
+
The app is built with Gradio and the official OpenAI Python SDK. It is
|
| 22 |
+
prepared for functional testing and demonstration on Hugging Face Spaces.
|
| 23 |
+
|
| 24 |
+
## Features
|
| 25 |
+
|
| 26 |
+
- Clean blue-and-white Pak Angels visual identity
|
| 27 |
+
- Sidebar navigation with specialized learning modes
|
| 28 |
+
- Selected learning-mode label above the conversation area
|
| 29 |
+
- Streaming AI responses through the OpenAI Responses API
|
| 30 |
+
- Session-based chat history
|
| 31 |
+
- Suggested-question buttons for every learning mode
|
| 32 |
+
- New Conversation and Clear Chat controls
|
| 33 |
+
- Markdown rendering and syntax-highlighted code blocks
|
| 34 |
+
- Clear missing-key and OpenAI API error messages
|
| 35 |
+
- Privacy notice for sensitive information
|
| 36 |
+
- Hugging Face Spaces-compatible environment-variable configuration
|
| 37 |
+
|
| 38 |
+
## Learning Modules
|
| 39 |
+
|
| 40 |
+
- Home
|
| 41 |
+
- AI-101 Foundations
|
| 42 |
+
- Prompt Engineering
|
| 43 |
+
- Generative AI
|
| 44 |
+
- Agentic AI
|
| 45 |
+
- Retrieval-Augmented Generation (RAG)
|
| 46 |
+
- Multi-Agent Systems
|
| 47 |
+
- AI Workflow Design
|
| 48 |
+
- Business Process Automation
|
| 49 |
+
- Gradio Development
|
| 50 |
+
- AI Startup Mentor
|
| 51 |
+
- About Pak Angels
|
| 52 |
+
|
| 53 |
+
## Local Setup
|
| 54 |
+
|
| 55 |
+
Local setup is optional. Hugging Face Spaces can run the app directly from these
|
| 56 |
+
files.
|
| 57 |
+
|
| 58 |
+
1. Create a virtual environment:
|
| 59 |
+
|
| 60 |
+
```bash
|
| 61 |
+
python -m venv .venv
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
2. Activate the virtual environment:
|
| 65 |
+
|
| 66 |
+
```bash
|
| 67 |
+
source .venv/bin/activate
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
3. Install dependencies:
|
| 71 |
+
|
| 72 |
+
```bash
|
| 73 |
+
pip install -r requirements.txt
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
4. Configure environment variables:
|
| 77 |
+
|
| 78 |
+
```bash
|
| 79 |
+
cp .env.example .env
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
Add your real key only to `.env` or your shell environment. Do not commit
|
| 83 |
+
`.env`.
|
| 84 |
+
|
| 85 |
+
5. Run the app:
|
| 86 |
+
|
| 87 |
+
```bash
|
| 88 |
+
python app.py
|
| 89 |
+
```
|
| 90 |
+
|
| 91 |
+
## Hugging Face Spaces Deployment
|
| 92 |
+
|
| 93 |
+
1. Create a Hugging Face account.
|
| 94 |
+
2. Create a new Space.
|
| 95 |
+
3. Select Gradio as the application SDK if available.
|
| 96 |
+
4. Choose the desired visibility.
|
| 97 |
+
5. Upload or push all project files from this folder.
|
| 98 |
+
6. Open the Space Settings.
|
| 99 |
+
7. Go to Variables and secrets.
|
| 100 |
+
8. Add a new secret named `OPENAI_API_KEY`.
|
| 101 |
+
9. Optionally add `OPENAI_MODEL`.
|
| 102 |
+
10. Allow Hugging Face to build the application.
|
| 103 |
+
11. Review build logs if deployment fails.
|
| 104 |
+
12. Open the Space URL and test all learning modes.
|
| 105 |
+
|
| 106 |
+
To update the Space, replace the files through the Hugging Face web interface or
|
| 107 |
+
push changes through Git. Hugging Face will rebuild the Space after new changes
|
| 108 |
+
are uploaded.
|
| 109 |
+
|
| 110 |
+
### Deploy With the Hugging Face Hub API
|
| 111 |
+
|
| 112 |
+
This project includes `deploy_to_huggingface.py`, which uploads the current
|
| 113 |
+
project folder to a Hugging Face Space using the Hugging Face Hub API.
|
| 114 |
+
|
| 115 |
+
Install the deployment helper dependency locally:
|
| 116 |
+
|
| 117 |
+
```bash
|
| 118 |
+
python3 -m pip install -r deploy_requirements.txt
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
Set the Hugging Face deployment credentials in your local environment:
|
| 122 |
+
|
| 123 |
+
```bash
|
| 124 |
+
export HF_TOKEN=your_hugging_face_write_token_here
|
| 125 |
+
export HF_SPACE_ID=your-username/your-space-name
|
| 126 |
+
```
|
| 127 |
+
|
| 128 |
+
Use your real Hugging Face username and Space name. Do not leave
|
| 129 |
+
`your-username/your-space-name` in the command.
|
| 130 |
+
|
| 131 |
+
Then upload the project to an existing Space:
|
| 132 |
+
|
| 133 |
+
```bash
|
| 134 |
+
python3 deploy_to_huggingface.py
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
If the Space does not exist yet, create it as a Gradio Space and upload in one
|
| 138 |
+
step:
|
| 139 |
+
|
| 140 |
+
```bash
|
| 141 |
+
python3 deploy_to_huggingface.py --create
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
You can also pass the Space id directly:
|
| 145 |
+
|
| 146 |
+
```bash
|
| 147 |
+
python3 deploy_to_huggingface.py --space-id your-username/your-space-name --create
|
| 148 |
+
```
|
| 149 |
+
|
| 150 |
+
The script excludes local-only files such as `.env`, `.venv/`, caches, logs, and
|
| 151 |
+
compiled Python files. It does not create or upload OpenAI secrets. Add
|
| 152 |
+
`OPENAI_API_KEY` separately in the Space settings.
|
| 153 |
+
|
| 154 |
+
## Required Hugging Face Secret
|
| 155 |
+
|
| 156 |
+
The required secret name is:
|
| 157 |
+
|
| 158 |
+
```text
|
| 159 |
+
OPENAI_API_KEY
|
| 160 |
+
```
|
| 161 |
+
|
| 162 |
+
Optional:
|
| 163 |
+
|
| 164 |
+
```text
|
| 165 |
+
OPENAI_MODEL
|
| 166 |
+
```
|
| 167 |
+
|
| 168 |
+
Never upload a `.env` file containing a real API key to Hugging Face Spaces.
|
| 169 |
+
|
| 170 |
+
## Troubleshooting
|
| 171 |
+
|
| 172 |
+
Missing API key: Add `OPENAI_API_KEY` under Hugging Face Space -> Settings ->
|
| 173 |
+
Variables and secrets -> New secret, then restart or rebuild the Space.
|
| 174 |
+
|
| 175 |
+
Quota exceeded or billing errors: Check OpenAI usage limits, billing settings,
|
| 176 |
+
and project access. The app will show a clear message for rate limits and quota
|
| 177 |
+
related API failures.
|
| 178 |
+
|
| 179 |
+
Dependency installation errors: Confirm `requirements.txt` is present in the
|
| 180 |
+
Space root folder and that the Space is using Python with Gradio support.
|
| 181 |
+
|
| 182 |
+
Python version problems: Use a current Hugging Face Gradio environment. The
|
| 183 |
+
code uses standard cross-platform Python and avoids Mac-specific paths.
|
| 184 |
+
|
| 185 |
+
Missing assets: The app does not require local image assets. Optional future
|
| 186 |
+
assets should use relative paths and should be committed with the app.
|
| 187 |
+
|
| 188 |
+
OpenAI API errors: Check the API key, selected model, quota, billing, and build
|
| 189 |
+
logs. If using `OPENAI_MODEL`, verify that the account has access to the model.
|
| 190 |
+
|
| 191 |
+
Gradio startup failures: Make sure `app.py` exists at the Space root. For local
|
| 192 |
+
testing, run `python app.py`.
|
| 193 |
+
|
| 194 |
+
Hugging Face build failures: Review the Space build logs, confirm all required
|
| 195 |
+
files are uploaded, and check that only necessary dependencies are listed.
|
| 196 |
+
|
| 197 |
+
## Security
|
| 198 |
+
|
| 199 |
+
- API keys must never be committed to Git.
|
| 200 |
+
- API keys must never be placed directly in `app.py`.
|
| 201 |
+
- Real secrets must not be placed in `.env.example`.
|
| 202 |
+
- Users should not enter confidential, proprietary, financial, medical,
|
| 203 |
+
personal, or otherwise sensitive information into the tutor.
|
| 204 |
+
|
| 205 |
+
## Architecture
|
| 206 |
+
|
| 207 |
+
- `app.py`: Gradio interface, navigation, chat state, and page rendering
|
| 208 |
+
- `config.py`: environment-variable configuration
|
| 209 |
+
- `prompts.py`: learning modules, suggested questions, and specialized tutor instructions
|
| 210 |
+
- `openai_service.py`: OpenAI Responses API streaming integration and error handling
|
| 211 |
+
- `requirements.txt`: deployment dependencies
|
| 212 |
+
- `deploy_to_huggingface.py`: Hugging Face Hub API upload script
|
| 213 |
+
- `deploy_requirements.txt`: local-only dependency for the upload script
|
| 214 |
+
- `.env.example`: safe placeholder environment variables
|
| 215 |
+
- `.gitignore`: local secrets and development artifact exclusions
|
app.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
from functools import partial
|
| 4 |
+
|
| 5 |
+
import gradio as gr
|
| 6 |
+
|
| 7 |
+
from config import APP_NAME, APP_SUBTITLE, get_openai_api_key, get_openai_model
|
| 8 |
+
from openai_service import format_openai_error, stream_tutor_response
|
| 9 |
+
from prompts import ABOUT_PAK_ANGELS, MODULES, build_system_instructions
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
PRIVACY_NOTICE = (
|
| 13 |
+
"Privacy notice: Do not enter confidential, proprietary, financial, medical, "
|
| 14 |
+
"personal, or otherwise sensitive information into the AI Tutor."
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
CSS = """
|
| 19 |
+
:root {
|
| 20 |
+
--pak-blue: #0b5cab;
|
| 21 |
+
--pak-blue-dark: #073f78;
|
| 22 |
+
--pak-blue-soft: #eaf4ff;
|
| 23 |
+
--pak-line: #d8e5f2;
|
| 24 |
+
--pak-text: #14213d;
|
| 25 |
+
}
|
| 26 |
+
body,
|
| 27 |
+
.gradio-container {
|
| 28 |
+
background: #f7fbff !important;
|
| 29 |
+
color: var(--pak-text);
|
| 30 |
+
}
|
| 31 |
+
.main-shell {
|
| 32 |
+
max-width: 1180px;
|
| 33 |
+
margin: 0 auto;
|
| 34 |
+
}
|
| 35 |
+
.hero {
|
| 36 |
+
background: linear-gradient(135deg, #ffffff 0%, #eaf4ff 62%, #d6ebff 100%);
|
| 37 |
+
border: 1px solid var(--pak-line);
|
| 38 |
+
border-radius: 8px;
|
| 39 |
+
padding: 24px;
|
| 40 |
+
margin-bottom: 14px;
|
| 41 |
+
}
|
| 42 |
+
.hero h1 {
|
| 43 |
+
color: var(--pak-blue-dark);
|
| 44 |
+
font-size: 38px;
|
| 45 |
+
line-height: 1.1;
|
| 46 |
+
margin: 0 0 8px 0;
|
| 47 |
+
}
|
| 48 |
+
.hero p {
|
| 49 |
+
margin: 5px 0;
|
| 50 |
+
font-size: 16px;
|
| 51 |
+
}
|
| 52 |
+
.mode-label {
|
| 53 |
+
border-left: 5px solid var(--pak-blue);
|
| 54 |
+
background: #ffffff;
|
| 55 |
+
border-radius: 8px;
|
| 56 |
+
padding: 14px 16px;
|
| 57 |
+
box-shadow: 0 1px 4px rgba(11, 92, 171, 0.08);
|
| 58 |
+
}
|
| 59 |
+
.privacy {
|
| 60 |
+
background: #fff8e8;
|
| 61 |
+
border: 1px solid #f1d28c;
|
| 62 |
+
border-radius: 8px;
|
| 63 |
+
padding: 12px 14px;
|
| 64 |
+
font-size: 14px;
|
| 65 |
+
}
|
| 66 |
+
.side-panel {
|
| 67 |
+
background: #ffffff;
|
| 68 |
+
border: 1px solid var(--pak-line);
|
| 69 |
+
border-radius: 8px;
|
| 70 |
+
padding: 14px;
|
| 71 |
+
}
|
| 72 |
+
.suggestion-button {
|
| 73 |
+
min-height: 46px;
|
| 74 |
+
}
|
| 75 |
+
button.primary {
|
| 76 |
+
background: var(--pak-blue) !important;
|
| 77 |
+
border-color: var(--pak-blue) !important;
|
| 78 |
+
}
|
| 79 |
+
"""
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def hero_html() -> str:
|
| 83 |
+
return f"""
|
| 84 |
+
<div class="hero">
|
| 85 |
+
<h1>{APP_NAME}</h1>
|
| 86 |
+
<p><strong>{APP_SUBTITLE}</strong></p>
|
| 87 |
+
<p>Pak Angels AI Tutor helps students, faculty, professionals,
|
| 88 |
+
entrepreneurs, and startup founders learn Artificial Intelligence,
|
| 89 |
+
build practical applications, design intelligent workflows, automate
|
| 90 |
+
business processes, and develop AI-powered startups.</p>
|
| 91 |
+
</div>
|
| 92 |
+
"""
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def module_summary_html(module_name: str) -> str:
|
| 96 |
+
module = MODULES[module_name]
|
| 97 |
+
about = ""
|
| 98 |
+
if module_name == "About Pak Angels":
|
| 99 |
+
about = f"<p>{ABOUT_PAK_ANGELS}</p>"
|
| 100 |
+
return f"""
|
| 101 |
+
<div class="mode-label">
|
| 102 |
+
<strong>Selected learning mode:</strong> {module_name}<br>
|
| 103 |
+
<span>{module["summary"]}</span>
|
| 104 |
+
{about}
|
| 105 |
+
</div>
|
| 106 |
+
"""
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def topics_markdown(module_name: str) -> str:
|
| 110 |
+
topics = "\n".join(f"- {topic}" for topic in MODULES[module_name]["topics"])
|
| 111 |
+
return f"### Topics in this mode\n{topics}"
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def get_suggestion(module_name: str, index: int) -> str:
|
| 115 |
+
suggestions = MODULES[module_name]["suggestions"]
|
| 116 |
+
return suggestions[index] if index < len(suggestions) else ""
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def update_module(module_name: str):
|
| 120 |
+
suggestions = MODULES[module_name]["suggestions"]
|
| 121 |
+
button_updates = [
|
| 122 |
+
gr.update(value=suggestion, visible=True) for suggestion in suggestions[:5]
|
| 123 |
+
]
|
| 124 |
+
while len(button_updates) < 5:
|
| 125 |
+
button_updates.append(gr.update(value="", visible=False))
|
| 126 |
+
|
| 127 |
+
return (
|
| 128 |
+
module_summary_html(module_name),
|
| 129 |
+
topics_markdown(module_name),
|
| 130 |
+
*button_updates,
|
| 131 |
+
)
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def add_user_message(message: str, history: list[dict[str, str]] | None):
|
| 135 |
+
history = list(history or [])
|
| 136 |
+
message = (message or "").strip()
|
| 137 |
+
if not message:
|
| 138 |
+
return "", history
|
| 139 |
+
history.append({"role": "user", "content": message})
|
| 140 |
+
return "", history
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def generate_response(history: list[dict[str, str]] | None, module_name: str):
|
| 144 |
+
history = list(history or [])
|
| 145 |
+
if not history or history[-1]["role"] != "user":
|
| 146 |
+
yield history
|
| 147 |
+
return
|
| 148 |
+
|
| 149 |
+
api_key = get_openai_api_key()
|
| 150 |
+
if not api_key:
|
| 151 |
+
message = (
|
| 152 |
+
"OPENAI_API_KEY is not configured. In Hugging Face Spaces, add it under "
|
| 153 |
+
"Settings -> Variables and secrets -> New secret, then restart the Space."
|
| 154 |
+
)
|
| 155 |
+
history.append({"role": "assistant", "content": message})
|
| 156 |
+
yield history
|
| 157 |
+
return
|
| 158 |
+
|
| 159 |
+
history.append({"role": "assistant", "content": ""})
|
| 160 |
+
try:
|
| 161 |
+
for delta in stream_tutor_response(
|
| 162 |
+
api_key=api_key,
|
| 163 |
+
model=get_openai_model(),
|
| 164 |
+
system_instructions=build_system_instructions(module_name),
|
| 165 |
+
messages=history[:-1],
|
| 166 |
+
):
|
| 167 |
+
history[-1]["content"] += delta
|
| 168 |
+
yield history
|
| 169 |
+
except Exception as error:
|
| 170 |
+
history[-1]["content"] = format_openai_error(error)
|
| 171 |
+
yield history
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def submit_message(message: str, history: list[dict[str, str]] | None, module_name: str):
|
| 175 |
+
textbox, updated_history = add_user_message(message, history)
|
| 176 |
+
yield textbox, updated_history
|
| 177 |
+
for streamed_history in generate_response(updated_history, module_name):
|
| 178 |
+
yield textbox, streamed_history
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
def submit_suggestion(
|
| 182 |
+
suggestion_index: int,
|
| 183 |
+
history: list[dict[str, str]] | None,
|
| 184 |
+
module_name: str,
|
| 185 |
+
):
|
| 186 |
+
question = get_suggestion(module_name, suggestion_index)
|
| 187 |
+
yield from submit_message(question, history, module_name)
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
def clear_conversation():
|
| 191 |
+
return []
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
def build_app() -> gr.Blocks:
|
| 195 |
+
with gr.Blocks(
|
| 196 |
+
title=APP_NAME,
|
| 197 |
+
css=CSS,
|
| 198 |
+
theme=gr.themes.Soft(primary_hue="blue", neutral_hue="slate"),
|
| 199 |
+
) as demo:
|
| 200 |
+
with gr.Column(elem_classes=["main-shell"]):
|
| 201 |
+
gr.HTML(hero_html())
|
| 202 |
+
|
| 203 |
+
with gr.Row(equal_height=False):
|
| 204 |
+
with gr.Column(scale=1, min_width=260, elem_classes=["side-panel"]):
|
| 205 |
+
module_selector = gr.Radio(
|
| 206 |
+
choices=list(MODULES.keys()),
|
| 207 |
+
value="Home",
|
| 208 |
+
label="Learning mode",
|
| 209 |
+
)
|
| 210 |
+
gr.Textbox(
|
| 211 |
+
value=get_openai_model(),
|
| 212 |
+
label="OpenAI model",
|
| 213 |
+
interactive=False,
|
| 214 |
+
)
|
| 215 |
+
new_button = gr.Button("New Conversation")
|
| 216 |
+
clear_button = gr.Button("Clear Chat")
|
| 217 |
+
with gr.Accordion("About Pak Angels", open=False):
|
| 218 |
+
gr.Markdown(ABOUT_PAK_ANGELS)
|
| 219 |
+
|
| 220 |
+
with gr.Column(scale=3, min_width=420):
|
| 221 |
+
module_summary = gr.HTML(module_summary_html("Home"))
|
| 222 |
+
gr.HTML(f'<div class="privacy">{PRIVACY_NOTICE}</div>')
|
| 223 |
+
topics = gr.Markdown(topics_markdown("Home"))
|
| 224 |
+
|
| 225 |
+
gr.Markdown("### Suggested questions")
|
| 226 |
+
suggestion_buttons = []
|
| 227 |
+
with gr.Row():
|
| 228 |
+
suggestion_buttons.append(
|
| 229 |
+
gr.Button(get_suggestion("Home", 0), elem_classes=["suggestion-button"])
|
| 230 |
+
)
|
| 231 |
+
suggestion_buttons.append(
|
| 232 |
+
gr.Button(get_suggestion("Home", 1), elem_classes=["suggestion-button"])
|
| 233 |
+
)
|
| 234 |
+
with gr.Row():
|
| 235 |
+
suggestion_buttons.append(
|
| 236 |
+
gr.Button(get_suggestion("Home", 2), elem_classes=["suggestion-button"])
|
| 237 |
+
)
|
| 238 |
+
suggestion_buttons.append(
|
| 239 |
+
gr.Button(get_suggestion("Home", 3), elem_classes=["suggestion-button"])
|
| 240 |
+
)
|
| 241 |
+
suggestion_buttons.append(
|
| 242 |
+
gr.Button(get_suggestion("Home", 4), elem_classes=["suggestion-button"])
|
| 243 |
+
)
|
| 244 |
+
|
| 245 |
+
chatbot = gr.Chatbot(
|
| 246 |
+
label="Pak Angels AI Tutor",
|
| 247 |
+
type="messages",
|
| 248 |
+
height=520,
|
| 249 |
+
show_copy_button=True,
|
| 250 |
+
)
|
| 251 |
+
message_box = gr.Textbox(
|
| 252 |
+
label="Ask Pak Angels AI Tutor",
|
| 253 |
+
placeholder="Ask a question or choose a suggested question above.",
|
| 254 |
+
lines=3,
|
| 255 |
+
)
|
| 256 |
+
send_button = gr.Button("Send", variant="primary")
|
| 257 |
+
|
| 258 |
+
module_selector.change(
|
| 259 |
+
update_module,
|
| 260 |
+
inputs=[module_selector],
|
| 261 |
+
outputs=[module_summary, topics, *suggestion_buttons],
|
| 262 |
+
)
|
| 263 |
+
|
| 264 |
+
send_button.click(
|
| 265 |
+
submit_message,
|
| 266 |
+
inputs=[message_box, chatbot, module_selector],
|
| 267 |
+
outputs=[message_box, chatbot],
|
| 268 |
+
)
|
| 269 |
+
message_box.submit(
|
| 270 |
+
submit_message,
|
| 271 |
+
inputs=[message_box, chatbot, module_selector],
|
| 272 |
+
outputs=[message_box, chatbot],
|
| 273 |
+
)
|
| 274 |
+
|
| 275 |
+
for index, button in enumerate(suggestion_buttons):
|
| 276 |
+
button.click(
|
| 277 |
+
partial(submit_suggestion, index),
|
| 278 |
+
inputs=[chatbot, module_selector],
|
| 279 |
+
outputs=[message_box, chatbot],
|
| 280 |
+
)
|
| 281 |
+
|
| 282 |
+
new_button.click(clear_conversation, outputs=[chatbot])
|
| 283 |
+
clear_button.click(clear_conversation, outputs=[chatbot])
|
| 284 |
+
|
| 285 |
+
return demo
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
demo = build_app()
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
if __name__ == "__main__":
|
| 292 |
+
demo.queue().launch()
|
config.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Application configuration for Pak Angels AI Tutor."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
APP_NAME = "Pak Angels AI Tutor"
|
| 9 |
+
APP_SUBTITLE = "Learn • Build • Innovate • Launch with Artificial Intelligence"
|
| 10 |
+
DEFAULT_MODEL = "gpt-4.1-mini"
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def get_openai_api_key() -> str:
|
| 14 |
+
"""Read the OpenAI API key from the environment."""
|
| 15 |
+
return os.getenv("OPENAI_API_KEY", "").strip()
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def get_openai_model() -> str:
|
| 19 |
+
"""Read the optional model name, falling back to a practical default."""
|
| 20 |
+
return os.getenv("OPENAI_MODEL", DEFAULT_MODEL).strip() or DEFAULT_MODEL
|
deploy_requirements.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
huggingface_hub>=0.24,<1
|
deploy_to_huggingface.py
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Upload Pak Angels AI Tutor to a Hugging Face Space.
|
| 2 |
+
|
| 3 |
+
Required environment variables:
|
| 4 |
+
HF_TOKEN: A Hugging Face access token with write access to the Space.
|
| 5 |
+
HF_SPACE_ID: The Space repo id, for example "your-username/pak-angels-ai-tutor".
|
| 6 |
+
|
| 7 |
+
Optional environment variables:
|
| 8 |
+
HF_COMMIT_MESSAGE: Custom commit message for the upload.
|
| 9 |
+
HF_PRIVATE_SPACE: Set to "true" to create a private Space when using --create.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
from __future__ import annotations
|
| 13 |
+
|
| 14 |
+
import argparse
|
| 15 |
+
import os
|
| 16 |
+
import sys
|
| 17 |
+
from pathlib import Path
|
| 18 |
+
|
| 19 |
+
from huggingface_hub import HfApi
|
| 20 |
+
from huggingface_hub.utils import HfHubHTTPError
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
PROJECT_ROOT = Path(__file__).resolve().parent
|
| 24 |
+
DEFAULT_IGNORE_PATTERNS = [
|
| 25 |
+
".env",
|
| 26 |
+
".env.local",
|
| 27 |
+
".env.*.local",
|
| 28 |
+
".git/",
|
| 29 |
+
".git/**",
|
| 30 |
+
".venv/",
|
| 31 |
+
".venv/**",
|
| 32 |
+
"venv/",
|
| 33 |
+
"venv/**",
|
| 34 |
+
"__pycache__/",
|
| 35 |
+
"__pycache__/**",
|
| 36 |
+
"*.pyc",
|
| 37 |
+
".DS_Store",
|
| 38 |
+
".pytest_cache/",
|
| 39 |
+
".pytest_cache/**",
|
| 40 |
+
".ruff_cache/",
|
| 41 |
+
".ruff_cache/**",
|
| 42 |
+
".mypy_cache/",
|
| 43 |
+
".mypy_cache/**",
|
| 44 |
+
"dist/",
|
| 45 |
+
"dist/**",
|
| 46 |
+
"build/",
|
| 47 |
+
"build/**",
|
| 48 |
+
"*.egg-info/",
|
| 49 |
+
"*.egg-info/**",
|
| 50 |
+
"*.log",
|
| 51 |
+
"tmp/",
|
| 52 |
+
"tmp/**",
|
| 53 |
+
"temp/",
|
| 54 |
+
"temp/**",
|
| 55 |
+
]
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def parse_args() -> argparse.Namespace:
|
| 59 |
+
parser = argparse.ArgumentParser(
|
| 60 |
+
description="Upload the current Pak Angels AI Tutor project to Hugging Face Spaces."
|
| 61 |
+
)
|
| 62 |
+
parser.add_argument(
|
| 63 |
+
"--space-id",
|
| 64 |
+
default=os.getenv("HF_SPACE_ID", "").strip(),
|
| 65 |
+
help='Hugging Face Space id, for example "username/pak-angels-ai-tutor".',
|
| 66 |
+
)
|
| 67 |
+
parser.add_argument(
|
| 68 |
+
"--token",
|
| 69 |
+
default=os.getenv("HF_TOKEN", "").strip(),
|
| 70 |
+
help="Hugging Face write token. Prefer setting HF_TOKEN instead of passing this flag.",
|
| 71 |
+
)
|
| 72 |
+
parser.add_argument(
|
| 73 |
+
"--commit-message",
|
| 74 |
+
default=os.getenv("HF_COMMIT_MESSAGE", "Deploy Pak Angels AI Tutor"),
|
| 75 |
+
help="Commit message shown in the Hugging Face Space repository.",
|
| 76 |
+
)
|
| 77 |
+
parser.add_argument(
|
| 78 |
+
"--repo-type",
|
| 79 |
+
default="space",
|
| 80 |
+
choices=["space"],
|
| 81 |
+
help="Repository type. Spaces deployments use 'space'.",
|
| 82 |
+
)
|
| 83 |
+
parser.add_argument(
|
| 84 |
+
"--create",
|
| 85 |
+
action="store_true",
|
| 86 |
+
help="Create the Gradio Space if it does not already exist.",
|
| 87 |
+
)
|
| 88 |
+
parser.add_argument(
|
| 89 |
+
"--private",
|
| 90 |
+
action="store_true",
|
| 91 |
+
default=os.getenv("HF_PRIVATE_SPACE", "").lower() in {"1", "true", "yes"},
|
| 92 |
+
help="Create the Space as private when --create is used.",
|
| 93 |
+
)
|
| 94 |
+
return parser.parse_args()
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def validate_inputs(space_id: str, token: str) -> None:
|
| 98 |
+
missing = []
|
| 99 |
+
if not space_id:
|
| 100 |
+
missing.append("HF_SPACE_ID")
|
| 101 |
+
if not token:
|
| 102 |
+
missing.append("HF_TOKEN")
|
| 103 |
+
|
| 104 |
+
if missing:
|
| 105 |
+
joined = ", ".join(missing)
|
| 106 |
+
raise ValueError(
|
| 107 |
+
f"Missing required setting(s): {joined}. Set them as environment variables "
|
| 108 |
+
"or pass --space-id and --token."
|
| 109 |
+
)
|
| 110 |
+
|
| 111 |
+
if "/" not in space_id:
|
| 112 |
+
raise ValueError('HF_SPACE_ID should look like "username/space-name".')
|
| 113 |
+
|
| 114 |
+
placeholder_values = {
|
| 115 |
+
"your_hugging_face_write_token_here",
|
| 116 |
+
"your-token",
|
| 117 |
+
"your_token",
|
| 118 |
+
}
|
| 119 |
+
placeholder_space_ids = {
|
| 120 |
+
"your-username/your-space-name",
|
| 121 |
+
"username/space-name",
|
| 122 |
+
"your-username/pak-angels-ai-tutor",
|
| 123 |
+
}
|
| 124 |
+
if token in placeholder_values:
|
| 125 |
+
raise ValueError("HF_TOKEN is still a placeholder. Use a real Hugging Face write token.")
|
| 126 |
+
if space_id in placeholder_space_ids:
|
| 127 |
+
raise ValueError(
|
| 128 |
+
"HF_SPACE_ID is still a placeholder. Use your real Space id, such as "
|
| 129 |
+
'"mohammadanwarkhan/pak-angels-ai-tutor".'
|
| 130 |
+
)
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def ensure_space_exists(api: HfApi, args: argparse.Namespace) -> None:
|
| 134 |
+
if not args.create:
|
| 135 |
+
return
|
| 136 |
+
|
| 137 |
+
api.create_repo(
|
| 138 |
+
repo_id=args.space_id,
|
| 139 |
+
repo_type=args.repo_type,
|
| 140 |
+
private=args.private,
|
| 141 |
+
space_sdk="gradio",
|
| 142 |
+
exist_ok=True,
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def preflight_check(api: HfApi, args: argparse.Namespace) -> None:
|
| 147 |
+
whoami = api.whoami()
|
| 148 |
+
account_name = whoami.get("name") or whoami.get("fullname") or "authenticated account"
|
| 149 |
+
print(f"Authenticated with Hugging Face as: {account_name}")
|
| 150 |
+
|
| 151 |
+
try:
|
| 152 |
+
api.repo_info(repo_id=args.space_id, repo_type=args.repo_type)
|
| 153 |
+
print(f"Space is accessible: {args.space_id}")
|
| 154 |
+
except HfHubHTTPError as error:
|
| 155 |
+
if args.create:
|
| 156 |
+
raise
|
| 157 |
+
raise RuntimeError(
|
| 158 |
+
f"The token cannot access the Space '{args.space_id}'. Check that the Space id "
|
| 159 |
+
"is exact and that this Hugging Face token has write access to that Space. "
|
| 160 |
+
"If the Space does not exist, rerun with --create."
|
| 161 |
+
) from error
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
def upload_project(args: argparse.Namespace) -> str:
|
| 165 |
+
api = HfApi(token=args.token)
|
| 166 |
+
ensure_space_exists(api, args)
|
| 167 |
+
preflight_check(api, args)
|
| 168 |
+
api.upload_folder(
|
| 169 |
+
folder_path=str(PROJECT_ROOT),
|
| 170 |
+
repo_id=args.space_id,
|
| 171 |
+
repo_type=args.repo_type,
|
| 172 |
+
commit_message=args.commit_message,
|
| 173 |
+
ignore_patterns=DEFAULT_IGNORE_PATTERNS,
|
| 174 |
+
)
|
| 175 |
+
return f"https://huggingface.co/spaces/{args.space_id}"
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def main() -> int:
|
| 179 |
+
args = parse_args()
|
| 180 |
+
try:
|
| 181 |
+
validate_inputs(args.space_id, args.token)
|
| 182 |
+
url = upload_project(args)
|
| 183 |
+
except ValueError as error:
|
| 184 |
+
print(f"Configuration error: {error}", file=sys.stderr)
|
| 185 |
+
return 2
|
| 186 |
+
except HfHubHTTPError as error:
|
| 187 |
+
print(f"Hugging Face upload failed: {error}", file=sys.stderr)
|
| 188 |
+
print(
|
| 189 |
+
"Check that HF_SPACE_ID is your real Space id, HF_TOKEN is a real write token, "
|
| 190 |
+
"and the Space exists. If it does not exist, rerun with --create.",
|
| 191 |
+
file=sys.stderr,
|
| 192 |
+
)
|
| 193 |
+
return 1
|
| 194 |
+
except Exception as error:
|
| 195 |
+
print(f"Deployment failed: {error}", file=sys.stderr)
|
| 196 |
+
return 1
|
| 197 |
+
|
| 198 |
+
print("Deployment upload complete.")
|
| 199 |
+
print(f"Space URL: {url}")
|
| 200 |
+
print("Remember to set OPENAI_API_KEY in the Space secrets before testing the tutor.")
|
| 201 |
+
return 0
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
if __name__ == "__main__":
|
| 205 |
+
raise SystemExit(main())
|
openai_service.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""OpenAI Responses API integration."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
from collections.abc import Iterable
|
| 6 |
+
|
| 7 |
+
from openai import APIConnectionError, APIStatusError, AuthenticationError, OpenAI, RateLimitError
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def format_openai_error(error: Exception) -> str:
|
| 11 |
+
"""Return a learner-friendly error message."""
|
| 12 |
+
if isinstance(error, AuthenticationError):
|
| 13 |
+
return (
|
| 14 |
+
"The OpenAI API key was rejected. Please check that OPENAI_API_KEY is "
|
| 15 |
+
"set correctly in Hugging Face Secrets."
|
| 16 |
+
)
|
| 17 |
+
if isinstance(error, RateLimitError):
|
| 18 |
+
return (
|
| 19 |
+
"The request was rate limited or the account may have quota or billing "
|
| 20 |
+
"limits. Please wait briefly, then check OpenAI usage and billing settings."
|
| 21 |
+
)
|
| 22 |
+
if isinstance(error, APIConnectionError):
|
| 23 |
+
return (
|
| 24 |
+
"The app could not reach OpenAI. Please check the network connection and "
|
| 25 |
+
"try again."
|
| 26 |
+
)
|
| 27 |
+
if isinstance(error, APIStatusError):
|
| 28 |
+
status = getattr(error, "status_code", "unknown")
|
| 29 |
+
return (
|
| 30 |
+
f"OpenAI returned an API error with status {status}. Please review the "
|
| 31 |
+
"API key, model name, quota, billing status, and request details."
|
| 32 |
+
)
|
| 33 |
+
return "An unexpected AI service error occurred. Please try again or review the Space logs."
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def stream_tutor_response(
|
| 37 |
+
*,
|
| 38 |
+
api_key: str,
|
| 39 |
+
model: str,
|
| 40 |
+
system_instructions: str,
|
| 41 |
+
messages: list[dict[str, str]],
|
| 42 |
+
) -> Iterable[str]:
|
| 43 |
+
"""Yield text deltas from the current event-based OpenAI Responses API stream."""
|
| 44 |
+
client = OpenAI(api_key=api_key)
|
| 45 |
+
input_messages = [
|
| 46 |
+
{"role": message["role"], "content": message["content"]}
|
| 47 |
+
for message in messages
|
| 48 |
+
if message.get("role") in {"user", "assistant"} and message.get("content")
|
| 49 |
+
]
|
| 50 |
+
|
| 51 |
+
stream = client.responses.create(
|
| 52 |
+
model=model,
|
| 53 |
+
instructions=system_instructions,
|
| 54 |
+
input=input_messages,
|
| 55 |
+
stream=True,
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
for event in stream:
|
| 59 |
+
if getattr(event, "type", None) == "response.output_text.delta":
|
| 60 |
+
delta = getattr(event, "delta", "")
|
| 61 |
+
if delta:
|
| 62 |
+
yield delta
|
prompts.py
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Learning-module content and tutor instructions."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
BASE_TUTOR_INSTRUCTIONS = """
|
| 7 |
+
You are Pak Angels AI Tutor, an educational AI companion for the Pak Angels AI
|
| 8 |
+
Training Program.
|
| 9 |
+
|
| 10 |
+
Your teaching style:
|
| 11 |
+
- Teach clearly and step by step.
|
| 12 |
+
- Adjust depth to the learner's apparent level.
|
| 13 |
+
- Use practical examples, frameworks, exercises, quiz questions, and project ideas.
|
| 14 |
+
- Encourage responsible and ethical AI use.
|
| 15 |
+
- Explain code in simple language when code is useful.
|
| 16 |
+
- Help learners move through Learn -> Practice -> Build -> Deploy -> Innovate -> Launch.
|
| 17 |
+
- Be encouraging, professional, and practical.
|
| 18 |
+
- Do not present uncertain information as fact.
|
| 19 |
+
- Encourage users to verify important legal, medical, financial, and technical decisions.
|
| 20 |
+
- Do not request confidential, proprietary, financial, medical, personal, or sensitive data.
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
MODULES = {
|
| 25 |
+
"Home": {
|
| 26 |
+
"summary": "Start here for an overview of the Pak Angels AI learning journey.",
|
| 27 |
+
"topics": [
|
| 28 |
+
"AI learning roadmap",
|
| 29 |
+
"Practical projects",
|
| 30 |
+
"Responsible AI",
|
| 31 |
+
"Startup and innovation pathways",
|
| 32 |
+
],
|
| 33 |
+
"suggestions": [
|
| 34 |
+
"Help me choose where to start.",
|
| 35 |
+
"Create a 30-day AI learning plan.",
|
| 36 |
+
"What should I build after learning AI basics?",
|
| 37 |
+
"How can I use this tutor responsibly?",
|
| 38 |
+
],
|
| 39 |
+
"instructions": """
|
| 40 |
+
Orient the learner. Recommend a pathway based on their background and goals.
|
| 41 |
+
Connect learning modules to practical projects, hackathons, entrepreneurship, and deployment.
|
| 42 |
+
""",
|
| 43 |
+
},
|
| 44 |
+
"AI-101 Foundations": {
|
| 45 |
+
"summary": "AI fundamentals, responsible use, careers, and practical applications.",
|
| 46 |
+
"topics": [
|
| 47 |
+
"Artificial Intelligence fundamentals",
|
| 48 |
+
"Machine Learning",
|
| 49 |
+
"Deep Learning",
|
| 50 |
+
"Large Language Models",
|
| 51 |
+
"Generative AI",
|
| 52 |
+
"Responsible AI",
|
| 53 |
+
"AI ethics",
|
| 54 |
+
"AI careers",
|
| 55 |
+
"Practical AI applications",
|
| 56 |
+
],
|
| 57 |
+
"suggestions": [
|
| 58 |
+
"What is Artificial Intelligence?",
|
| 59 |
+
"What is the difference between AI, Machine Learning, and Generative AI?",
|
| 60 |
+
"How do Large Language Models work?",
|
| 61 |
+
"How can students use AI responsibly?",
|
| 62 |
+
"What AI career paths are available?",
|
| 63 |
+
],
|
| 64 |
+
"instructions": """
|
| 65 |
+
Teach AI foundations with simple analogies, clear definitions, responsible AI guidance,
|
| 66 |
+
and practical examples for students, faculty, professionals, and entrepreneurs.
|
| 67 |
+
""",
|
| 68 |
+
},
|
| 69 |
+
"Prompt Engineering": {
|
| 70 |
+
"summary": "Design better prompts, templates, evaluations, and reliable outputs.",
|
| 71 |
+
"topics": [
|
| 72 |
+
"Prompt design",
|
| 73 |
+
"Prompt optimization",
|
| 74 |
+
"Role prompting",
|
| 75 |
+
"Context setting",
|
| 76 |
+
"Few-shot prompting",
|
| 77 |
+
"Structured prompts",
|
| 78 |
+
"Reusable prompt templates",
|
| 79 |
+
"Output formatting",
|
| 80 |
+
"Prompt evaluation",
|
| 81 |
+
],
|
| 82 |
+
"suggestions": [
|
| 83 |
+
"How do I write an effective prompt?",
|
| 84 |
+
"Improve this prompt for me.",
|
| 85 |
+
"Why is context important in prompting?",
|
| 86 |
+
"Create a reusable research prompt template.",
|
| 87 |
+
"How can I make AI responses more consistent?",
|
| 88 |
+
],
|
| 89 |
+
"instructions": """
|
| 90 |
+
Act as a prompt-engineering coach. Diagnose vague prompts, improve structure,
|
| 91 |
+
offer reusable templates, and explain why each change improves reliability.
|
| 92 |
+
""",
|
| 93 |
+
},
|
| 94 |
+
"Generative AI": {
|
| 95 |
+
"summary": "Text, image, code, productivity, and business uses of Generative AI.",
|
| 96 |
+
"topics": [
|
| 97 |
+
"Generative AI fundamentals",
|
| 98 |
+
"Large Language Models",
|
| 99 |
+
"Text generation",
|
| 100 |
+
"Image generation",
|
| 101 |
+
"Code generation",
|
| 102 |
+
"AI productivity",
|
| 103 |
+
"Content creation",
|
| 104 |
+
"Practical business applications",
|
| 105 |
+
],
|
| 106 |
+
"suggestions": [
|
| 107 |
+
"How does ChatGPT work?",
|
| 108 |
+
"What can Generative AI create?",
|
| 109 |
+
"Compare major types of Generative AI tools.",
|
| 110 |
+
"How can professionals use AI productively?",
|
| 111 |
+
"What are common Generative AI business use cases?",
|
| 112 |
+
],
|
| 113 |
+
"instructions": """
|
| 114 |
+
Teach Generative AI concepts and use cases. Explain capabilities, limitations,
|
| 115 |
+
responsible use, and concrete workflows for education, business, and creativity.
|
| 116 |
+
""",
|
| 117 |
+
},
|
| 118 |
+
"Agentic AI": {
|
| 119 |
+
"summary": "Goals, planning, tools, memory, supervision, and agent safety.",
|
| 120 |
+
"topics": [
|
| 121 |
+
"AI agents",
|
| 122 |
+
"Agent goals",
|
| 123 |
+
"Planning",
|
| 124 |
+
"Tool calling",
|
| 125 |
+
"Memory",
|
| 126 |
+
"Multi-step workflows",
|
| 127 |
+
"Human supervision",
|
| 128 |
+
"Autonomous task execution",
|
| 129 |
+
"Agent safety",
|
| 130 |
+
],
|
| 131 |
+
"suggestions": [
|
| 132 |
+
"What is an AI agent?",
|
| 133 |
+
"How is an agent different from a chatbot?",
|
| 134 |
+
"How do AI agents use tools?",
|
| 135 |
+
"Design a simple research agent.",
|
| 136 |
+
"Explain memory and planning in agentic systems.",
|
| 137 |
+
],
|
| 138 |
+
"instructions": """
|
| 139 |
+
Teach agentic systems with emphasis on goals, planning, tools, memory,
|
| 140 |
+
human oversight, safeguards, and practical workflow design.
|
| 141 |
+
""",
|
| 142 |
+
},
|
| 143 |
+
"Retrieval-Augmented Generation (RAG)": {
|
| 144 |
+
"summary": "Retrieval, embeddings, vector databases, and knowledge assistants.",
|
| 145 |
+
"topics": [
|
| 146 |
+
"RAG architecture",
|
| 147 |
+
"Embeddings",
|
| 148 |
+
"Vector databases",
|
| 149 |
+
"Knowledge retrieval",
|
| 150 |
+
"Document search",
|
| 151 |
+
"Enterprise knowledge assistants",
|
| 152 |
+
"Chunking",
|
| 153 |
+
"Retrieval quality",
|
| 154 |
+
"RAG evaluation",
|
| 155 |
+
],
|
| 156 |
+
"suggestions": [
|
| 157 |
+
"What is Retrieval-Augmented Generation?",
|
| 158 |
+
"When should I use RAG?",
|
| 159 |
+
"Explain a simple RAG architecture.",
|
| 160 |
+
"Compare RAG with fine-tuning.",
|
| 161 |
+
"How do embeddings and vector databases work?",
|
| 162 |
+
],
|
| 163 |
+
"instructions": """
|
| 164 |
+
Teach RAG architecture and evaluation. Compare RAG with fine-tuning, explain
|
| 165 |
+
chunking and retrieval quality, and use enterprise knowledge-assistant examples.
|
| 166 |
+
""",
|
| 167 |
+
},
|
| 168 |
+
"Multi-Agent Systems": {
|
| 169 |
+
"summary": "Agent roles, delegation, orchestration, collaboration, and review.",
|
| 170 |
+
"topics": [
|
| 171 |
+
"Agent collaboration",
|
| 172 |
+
"Agent specialization",
|
| 173 |
+
"Agent roles",
|
| 174 |
+
"Task delegation",
|
| 175 |
+
"Workflow orchestration",
|
| 176 |
+
"Communication between agents",
|
| 177 |
+
"Supervisor agents",
|
| 178 |
+
"Quality-control agents",
|
| 179 |
+
],
|
| 180 |
+
"suggestions": [
|
| 181 |
+
"How do multiple AI agents collaborate?",
|
| 182 |
+
"What roles can agents perform in a workflow?",
|
| 183 |
+
"Design a multi-agent research team.",
|
| 184 |
+
"What is an agent supervisor?",
|
| 185 |
+
"How can agents review one another's work?",
|
| 186 |
+
],
|
| 187 |
+
"instructions": """
|
| 188 |
+
Teach multi-agent design. Emphasize role clarity, handoffs, orchestration,
|
| 189 |
+
supervisor agents, quality control, and human review.
|
| 190 |
+
""",
|
| 191 |
+
},
|
| 192 |
+
"AI Workflow Design": {
|
| 193 |
+
"summary": "Turn real problems into structured, validated AI workflows.",
|
| 194 |
+
"topics": [
|
| 195 |
+
"Problem decomposition",
|
| 196 |
+
"Workflow mapping",
|
| 197 |
+
"Inputs and outputs",
|
| 198 |
+
"Decision points",
|
| 199 |
+
"Human-in-the-loop review",
|
| 200 |
+
"Tool selection",
|
| 201 |
+
"Task routing",
|
| 202 |
+
"Agent orchestration",
|
| 203 |
+
"Workflow validation",
|
| 204 |
+
"Error handling",
|
| 205 |
+
"Monitoring",
|
| 206 |
+
"Workflow optimization",
|
| 207 |
+
],
|
| 208 |
+
"suggestions": [
|
| 209 |
+
"Design an AI workflow for customer support.",
|
| 210 |
+
"Create an AI workflow for invoice processing.",
|
| 211 |
+
"Design a healthcare appointment workflow.",
|
| 212 |
+
"Explain human-in-the-loop workflow design.",
|
| 213 |
+
"Convert this business problem into an AI workflow.",
|
| 214 |
+
],
|
| 215 |
+
"instructions": """
|
| 216 |
+
Help users convert practical problems into structured AI workflows. Identify
|
| 217 |
+
inputs, outputs, decision points, tools, review steps, monitoring, and failure handling.
|
| 218 |
+
""",
|
| 219 |
+
},
|
| 220 |
+
"Business Process Automation": {
|
| 221 |
+
"summary": "Automate operations across sales, support, finance, HR, and more.",
|
| 222 |
+
"topics": [
|
| 223 |
+
"Business Process Automation",
|
| 224 |
+
"Intelligent automation",
|
| 225 |
+
"Email automation",
|
| 226 |
+
"Document processing",
|
| 227 |
+
"Customer support automation",
|
| 228 |
+
"Sales automation",
|
| 229 |
+
"Marketing automation",
|
| 230 |
+
"Human resources automation",
|
| 231 |
+
"Finance automation",
|
| 232 |
+
"Operations automation",
|
| 233 |
+
"Approval workflows",
|
| 234 |
+
"Exception handling",
|
| 235 |
+
"Process measurement",
|
| 236 |
+
],
|
| 237 |
+
"suggestions": [
|
| 238 |
+
"Automate my sales follow-up process.",
|
| 239 |
+
"Build an AI-powered HR assistant.",
|
| 240 |
+
"Design an invoice-processing system.",
|
| 241 |
+
"Automate customer-support triage.",
|
| 242 |
+
"Help me identify which business process to automate first.",
|
| 243 |
+
],
|
| 244 |
+
"instructions": """
|
| 245 |
+
Act as an AI business-automation mentor. Help users prioritize processes,
|
| 246 |
+
map workflows, select tools, measure outcomes, and design exception handling.
|
| 247 |
+
""",
|
| 248 |
+
},
|
| 249 |
+
"Gradio Development": {
|
| 250 |
+
"summary": "Build, debug, and deploy practical Gradio applications.",
|
| 251 |
+
"topics": [
|
| 252 |
+
"Python basics",
|
| 253 |
+
"Gradio applications",
|
| 254 |
+
"User-interface design",
|
| 255 |
+
"Blocks",
|
| 256 |
+
"Buttons",
|
| 257 |
+
"Chatbots",
|
| 258 |
+
"State management",
|
| 259 |
+
"OpenAI API integration",
|
| 260 |
+
"Error handling",
|
| 261 |
+
"Deployment",
|
| 262 |
+
"Debugging",
|
| 263 |
+
],
|
| 264 |
+
"suggestions": [
|
| 265 |
+
"Help me build my first Gradio application.",
|
| 266 |
+
"How do I add buttons, inputs, and chatbots?",
|
| 267 |
+
"How do I connect the OpenAI API?",
|
| 268 |
+
"How does Gradio state management work?",
|
| 269 |
+
"How can I deploy a Gradio app on Hugging Face Spaces?",
|
| 270 |
+
],
|
| 271 |
+
"instructions": """
|
| 272 |
+
Teach Gradio development in beginner-friendly steps. Provide small runnable
|
| 273 |
+
examples, explain Blocks, chatbot interfaces, state management, OpenAI integration,
|
| 274 |
+
deployment on Hugging Face Spaces, and debugging.
|
| 275 |
+
""",
|
| 276 |
+
},
|
| 277 |
+
"AI Startup Mentor": {
|
| 278 |
+
"summary": "Refine ideas, design MVPs, evaluate markets, and prepare to launch.",
|
| 279 |
+
"topics": [
|
| 280 |
+
"Startup idea refinement",
|
| 281 |
+
"Customer problems",
|
| 282 |
+
"Target markets",
|
| 283 |
+
"Customer discovery",
|
| 284 |
+
"Value propositions",
|
| 285 |
+
"Business models",
|
| 286 |
+
"MVP planning",
|
| 287 |
+
"Product-market fit",
|
| 288 |
+
"Risk analysis",
|
| 289 |
+
"Go-to-market strategy",
|
| 290 |
+
"Investor pitches",
|
| 291 |
+
"Financial assumptions",
|
| 292 |
+
"Investor readiness",
|
| 293 |
+
"Scaling",
|
| 294 |
+
],
|
| 295 |
+
"suggestions": [
|
| 296 |
+
"Help me evaluate my startup idea.",
|
| 297 |
+
"Create a Business Model Canvas.",
|
| 298 |
+
"Help me prepare a three-minute investor pitch.",
|
| 299 |
+
"Build an MVP roadmap.",
|
| 300 |
+
"Develop a go-to-market strategy.",
|
| 301 |
+
"Identify the key risks in my startup idea.",
|
| 302 |
+
],
|
| 303 |
+
"instructions": """
|
| 304 |
+
Act as a practical startup mentor. Ask clarifying questions when needed,
|
| 305 |
+
challenge assumptions, structure ideas, identify risks, and help users move
|
| 306 |
+
toward investor-ready and customer-validated plans.
|
| 307 |
+
""",
|
| 308 |
+
},
|
| 309 |
+
"About Pak Angels": {
|
| 310 |
+
"summary": "Learn about the Pak Angels mission and innovation ecosystem.",
|
| 311 |
+
"topics": [
|
| 312 |
+
"AI education",
|
| 313 |
+
"Entrepreneurship",
|
| 314 |
+
"Startup innovation",
|
| 315 |
+
"Technology commercialization",
|
| 316 |
+
"Investment readiness",
|
| 317 |
+
"Global Pakistani community",
|
| 318 |
+
],
|
| 319 |
+
"suggestions": [
|
| 320 |
+
"What is Pak Angels?",
|
| 321 |
+
"How can Pak Angels support AI learners?",
|
| 322 |
+
"How can startups benefit from Pak Angels?",
|
| 323 |
+
"Suggest a Pak Angels AI training pathway.",
|
| 324 |
+
],
|
| 325 |
+
"instructions": """
|
| 326 |
+
Explain the Pak Angels mission and connect users to education, practical AI
|
| 327 |
+
projects, entrepreneurship, startup innovation, and investment readiness.
|
| 328 |
+
""",
|
| 329 |
+
},
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
ABOUT_PAK_ANGELS = """
|
| 334 |
+
Pak Angels is a Silicon Valley-based global platform dedicated to accelerating
|
| 335 |
+
Artificial Intelligence education, entrepreneurship, startup innovation, technology
|
| 336 |
+
commercialization, and investment across Pakistan and the global Pakistani community.
|
| 337 |
+
|
| 338 |
+
Pak Angels helps students, faculty, professionals, entrepreneurs, and startups
|
| 339 |
+
learn, build, deploy, commercialize, and scale AI-powered solutions through
|
| 340 |
+
structured education, practical application development, hackathons, mentorship,
|
| 341 |
+
investment readiness, and access to global innovation ecosystems.
|
| 342 |
+
"""
|
| 343 |
+
|
| 344 |
+
|
| 345 |
+
def build_system_instructions(module_name: str) -> str:
|
| 346 |
+
"""Compose module-specific instructions for the selected learning mode."""
|
| 347 |
+
module = MODULES.get(module_name, MODULES["Home"])
|
| 348 |
+
topics = "\n".join(f"- {topic}" for topic in module["topics"])
|
| 349 |
+
return f"""
|
| 350 |
+
{BASE_TUTOR_INSTRUCTIONS}
|
| 351 |
+
|
| 352 |
+
Selected learning mode: {module_name}
|
| 353 |
+
Mode summary: {module["summary"]}
|
| 354 |
+
|
| 355 |
+
Priority topics:
|
| 356 |
+
{topics}
|
| 357 |
+
|
| 358 |
+
Specialized instructions:
|
| 359 |
+
{module["instructions"]}
|
| 360 |
+
"""
|
requirements.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio>=5.50,<6
|
| 2 |
+
openai>=1.93,<2
|