-
Notifications
You must be signed in to change notification settings - Fork 1
Added Social Media Manager Dashboard with Lilac Theme & Wizard Wand Cursor #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| # Social Media Manager Dashboard | ||
|
|
||
| A beautiful, modern dashboard for generating social media posts using Mistral AI. | ||
|
|
||
| ## Quick Start | ||
|
|
||
| 1. **Install dependencies:** | ||
| ```bash | ||
| uv pip install -r requirements.txt | ||
| ``` | ||
|
|
||
| 2. **Get your Mistral API Key:** | ||
| - Sign up at [Mistral AI](https://console.mistral.ai/) | ||
| - Generate an API key from your dashboard | ||
|
|
||
| 3. **Start the server:** | ||
| ```bash | ||
| python run_server.py | ||
| ``` | ||
|
|
||
| 4. **Open the dashboard:** | ||
| Navigate to `http://localhost:8000` in your browser | ||
|
|
||
| ## Features | ||
|
|
||
| - 🎨 **Modern UI** - Clean, responsive design with dark theme | ||
| - ⚡ **Fast Generation** - Powered by Mistral AI models | ||
| - 🔒 **Secure** - API key stored locally in browser | ||
| - 📋 **Easy Copy** - One-click copy to clipboard | ||
| - 🎯 **Model Selection** - Choose between Small, Medium, or Large models | ||
| - 💾 **Auto-save** - Your API key is remembered across sessions | ||
|
|
||
| ## Usage | ||
|
|
||
| 1. Enter your Mistral API key (stored securely in your browser) | ||
| 2. Describe the social media post you want to create | ||
| 3. Select the AI model (Small is fastest, Large is highest quality) | ||
| 4. Click "Generate Post" and wait for the magic ✨ | ||
| 5. Copy the result and use it on your social media platforms! | ||
|
|
||
| ## API Endpoints | ||
|
|
||
| - `GET /` - Dashboard UI | ||
| - `GET /health` - Health check | ||
| - `POST /generate-post` - Generate social media post | ||
|
|
||
| ## Keyboard Shortcuts | ||
|
|
||
| - `Ctrl/Cmd + Enter` - Submit form and generate post | ||
|
|
||
| ## Development | ||
|
|
||
| The dashboard consists of: | ||
| - **Backend**: FastAPI server ([src/social_media_backend.py](src/social_media_backend.py)) | ||
| - **Frontend**: HTML/CSS/JavaScript ([src/static/](src/static/)) | ||
| - **Launcher**: Quick start script ([run_server.py](run_server.py)) | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| **Port already in use?** | ||
| Edit [run_server.py](run_server.py) and change the port number. | ||
|
|
||
| **API key not working?** | ||
| Make sure you're using a valid Mistral API key from https://console.mistral.ai/ | ||
|
|
||
| **Can't connect to server?** | ||
| Check that the server is running and visit `http://localhost:8000` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| """Start the AgentOps Guardian social media manager server.""" | ||
|
|
||
| import os | ||
| import uvicorn | ||
|
|
||
| if __name__ == "__main__": | ||
| # Read configuration from environment variables with safer defaults | ||
| host = os.getenv("BIND_HOST", "127.0.0.1") | ||
| port = int(os.getenv("BIND_PORT", "8000")) | ||
| reload = os.getenv("BIND_RELOAD", "false").lower() in ("true", "1", "yes") | ||
|
|
||
| uvicorn.run( | ||
| "src.social_media_backend:app", | ||
| host=host, | ||
| port=port, | ||
| reload=reload, | ||
| log_level="info" | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,12 +2,21 @@ | |
|
|
||
| import requests | ||
| from fastapi import FastAPI | ||
| from fastapi.staticfiles import StaticFiles | ||
| from fastapi.responses import FileResponse | ||
| from pydantic import BaseModel | ||
| from pathlib import Path | ||
|
|
||
| MISTRAL_CHAT_COMPLETIONS_URL = "https://api.mistral.ai/v1/chat/completions" | ||
|
|
||
| app = FastAPI(title="Social Media Manager Backend") | ||
|
|
||
| # Get the directory where this file is located | ||
| BASE_DIR = Path(__file__).resolve().parent | ||
|
|
||
| # Mount static files | ||
| app.mount("/static", StaticFiles(directory=str(BASE_DIR / "static")), name="static") | ||
|
|
||
|
|
||
| class GeneratePostRequest(BaseModel): | ||
| """Request payload for social media post generation.""" | ||
|
|
@@ -17,6 +26,12 @@ class GeneratePostRequest(BaseModel): | |
| model: str = "mistral-small-latest" | ||
|
|
||
|
|
||
| @app.get("/") | ||
| def index(): | ||
| """Serve the frontend dashboard.""" | ||
| return FileResponse(str(BASE_DIR / "static" / "index.html")) | ||
|
|
||
|
|
||
| @app.get("/health") | ||
| def health() -> dict: | ||
| """Health endpoint for quick service checks.""" | ||
|
|
@@ -26,25 +41,70 @@ def health() -> dict: | |
| @app.post("/generate-post") | ||
| def generate_post(payload: GeneratePostRequest) -> dict: | ||
| """Generate a social media post from a user prompt using Mistral.""" | ||
| response = requests.post( | ||
| MISTRAL_CHAT_COMPLETIONS_URL, | ||
| headers={ | ||
| "Authorization": f"Bearer {payload.api_key}", | ||
| "Content-Type": "application/json", | ||
| }, | ||
| json={ | ||
| try: | ||
| # Clean the API key (remove any whitespace) | ||
| clean_api_key = payload.api_key.strip() | ||
|
|
||
| # Log key format for debugging (first/last 4 chars only) | ||
| key_preview = f"{clean_api_key[:4]}...{clean_api_key[-4:]}" if len(clean_api_key) > 8 else "***" | ||
| print(f"DEBUG: Using API key: {key_preview}, length: {len(clean_api_key)}") | ||
|
|
||
| response = requests.post( | ||
| MISTRAL_CHAT_COMPLETIONS_URL, | ||
| headers={ | ||
| "Authorization": f"Bearer {clean_api_key}", | ||
| "Content-Type": "application/json", | ||
| }, | ||
| json={ | ||
| "model": payload.model, | ||
| "messages": [{"role": "user", "content": payload.prompt}], | ||
| }, | ||
| timeout=60, | ||
| ) | ||
|
|
||
| # Handle API errors with helpful messages | ||
| if response.status_code == 401: | ||
| from fastapi import HTTPException | ||
| error_msg = response.json().get("message", "") if response.text else "" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n src/social_media_backend.py | sed -n '50,100p'Repository: mitanuriel/agentSecOps_Guardian Length of output: 2420 Safely parse non-JSON error responses before building HTTP errors. Lines 68 and 82 call Create a helper function to safely parse responses: Suggested fix+def _safe_json(response: requests.Response) -> dict:
+ try:
+ return response.json()
+ except ValueError:
+ return {}
+
if response.status_code == 401:
from fastapi import HTTPException
- error_msg = response.json().get("message", "") if response.text else ""
+ body = _safe_json(response)
+ error_msg = body.get("message", "") if response.text else ""
print(f"DEBUG: 401 error details - {error_msg}")
elif response.status_code >= 400:
from fastapi import HTTPException
- error_detail = response.json().get("error", {}).get("message", "Unknown error")
+ body = _safe_json(response)
+ error_detail = body.get("error", {}).get("message", "Unknown error")🤖 Prompt for AI Agents |
||
| print(f"DEBUG: 401 error details - {error_msg}") | ||
| raise HTTPException( | ||
| status_code=401, | ||
| detail=f"Invalid API key. Check: 1) Key is correctly copied from Mistral console 2) No extra spaces 3) Key is activated. API response: {error_msg}" | ||
| ) | ||
| elif response.status_code == 429: | ||
| from fastapi import HTTPException | ||
| raise HTTPException( | ||
| status_code=429, | ||
| detail="Rate limit exceeded. Please wait a moment and try again." | ||
| ) | ||
| elif response.status_code >= 400: | ||
| from fastapi import HTTPException | ||
| error_detail = response.json().get("error", {}).get("message", "Unknown error") | ||
| raise HTTPException( | ||
| status_code=response.status_code, | ||
| detail=f"Mistral API error: {error_detail}" | ||
| ) | ||
|
|
||
| response.raise_for_status() | ||
|
|
||
| completion = response.json() | ||
| post_text = completion["choices"][0]["message"]["content"] | ||
|
|
||
| return { | ||
| "post": post_text, | ||
| "model": payload.model, | ||
| "messages": [{"role": "user", "content": payload.prompt}], | ||
| }, | ||
| timeout=60, | ||
| ) | ||
| response.raise_for_status() | ||
|
|
||
| completion = response.json() | ||
| post_text = completion["choices"][0]["message"]["content"] | ||
|
|
||
| return { | ||
| "post": post_text, | ||
| "model": payload.model, | ||
| "provider": "mistral", | ||
| } | ||
| "provider": "mistral", | ||
| } | ||
|
|
||
| except requests.exceptions.Timeout: | ||
| from fastapi import HTTPException | ||
| raise HTTPException( | ||
| status_code=504, | ||
| detail="Request timeout. The API took too long to respond. Please try again." | ||
| ) | ||
| except requests.exceptions.RequestException as e: | ||
| from fastapi import HTTPException | ||
| raise HTTPException( | ||
| status_code=500, | ||
| detail=f"Network error: {str(e)}" | ||
| ) | ||
|
Comment on lines
41
to
+110
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CI is currently blocked by formatting in this file. Pipeline reports 🧰 Tools🪛 Ruff (0.15.2)[warning] 93-97: Consider moving this statement to an (TRY300) [warning] 101-104: Within an (B904) [warning] 107-110: Within an (B904) [warning] 109-109: Use explicit conversion flag Replace with conversion flag (RUF010) 🤖 Prompt for AI Agents |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove API-key fingerprint logging from request path.
Lines 48-50 log key preview and length. Secret-derived values should not be emitted to logs.
Suggested fix
📝 Committable suggestion
🤖 Prompt for AI Agents