@guyycodes/plugin-sdk
Version:
AI-powered plugin scaffolding tool - Create full-stack applications with 7+ AI models, 50+ business integrations, and production-ready infrastructure
289 lines (235 loc) ⢠9.45 kB
JavaScript
// inside the /server/chat folder there exist 1 file:
// 1. chat.py
const fs = require('fs-extra');
const path = require('path');
const chalk = require('chalk');
async function createEnvConfigFiles(serverPath) {
console.log(chalk.blue('š¤ Creating config files...'));
// Create agent directory
const configPath = path.join(serverPath, 'config');
fs.ensureDirSync(configPath);
// Create __init__.py
await createEnvInit(configPath);
// Create env.py
await createEnv(configPath);
// Create auth.py
await createAuth(configPath);
// Create routing.py
await createRouting(configPath);
// Create utils.py
await createUtils(configPath);
console.log(chalk.green('ā
Config files created successfully'));
}
async function createEnvInit(envPath) {
const initPy = `"""
Env package for LangGraph chatbot
Provides state management and graph execution for the chatbot env
"""`;
fs.writeFileSync(path.join(envPath, '__init__.py'), initPy);
}
async function createEnv(envPath) {
const envPy = `"""
Environment Configuration for LangGraph Chatbot
Ensures all required environment variables are loaded and available
"""
import os
import sys
from typing import Dict, Optional
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
def validate_environment() -> None:
"""
Validate that all required environment variables are set
"""
required_vars = [
"OPENAI_API_KEY",
"TAVILY_API_KEY",
"LANGCHAIN_API_KEY"
]
missing_vars = [var for var in required_vars if not os.getenv(var)]
if missing_vars:
print("ā Missing required environment variables:")
for var in missing_vars:
print(f" - {var}")
print("""Please set these environment variables and try again.
OpenAi: https://platform.openai.com/docs/api-reference/introduction,
Tavily: https://tavily.ai/api,
LangChain: https://smith.langchain.com/ to get the API keys.""")
sys.stdout.flush()
sys.exit(1)
# Check optional B2 variables and log their status
b2_vars = ["B2_MODEL_BUCKET_ID_API_KEY", "B2_MODEL_BUCKET_API_KEY"]
print("š¦ Checking optional B2 storage variables:")
for var in b2_vars:
if os.getenv(var):
print(f" ā
{var}: Available")
else:
print(f" ā {var}: Not available")
sys.stdout.flush()
# Set defaults for optional variables
os.environ["LANGCHAIN_TRACING_V2"] = os.getenv("LANGCHAIN_TRACING_V2", "true")
os.environ["LANGCHAIN_PROJECT"] = os.getenv("LANGCHAIN_PROJECT", "chatbot-agent")
os.environ["LANGCHAIN_ENDPOINT"] = os.getenv("LANGCHAIN_ENDPOINT", "https://api.smith.langchain.com")
os.environ["NODE_ENV"] = os.getenv("NODE_ENV", "development")
os.environ["PORT"] = os.getenv("PORT", "3000")
def get_environment_info() -> Dict[str, Optional[str]]:
"""
Get environment configuration for display
"""
return {
"NODE_ENV": os.getenv("NODE_ENV"),
"PORT": os.getenv("PORT"),
"LANGCHAIN_TRACING_V2": os.getenv("LANGCHAIN_TRACING_V2"),
"LANGCHAIN_PROJECT": os.getenv("LANGCHAIN_PROJECT"),
"LANGCHAIN_ENDPOINT": os.getenv("LANGCHAIN_ENDPOINT"),
"REDIS_URI": os.getenv("REDIS_URI"),
"POSTGRES_URI": os.getenv("POSTGRES_URI"),
# Don't expose API keys for security
"OPENAI_API_KEY": "ā
Set" if os.getenv("OPENAI_API_KEY") else "ā Missing",
"TAVILY_API_KEY": "ā
Set" if os.getenv("TAVILY_API_KEY") else "ā Missing",
"LANGCHAIN_API_KEY": "ā
Set" if os.getenv("LANGCHAIN_API_KEY") else "ā Missing",
# Optional B2 storage variables
"B2_MODEL_BUCKET_ID_API_KEY": "ā
Set" if os.getenv("B2_MODEL_BUCKET_ID_API_KEY") else "ā Not available",
"B2_MODEL_BUCKET_API_KEY": "ā
Set" if os.getenv("B2_MODEL_BUCKET_API_KEY") else "ā Not available",
}
`;
fs.writeFileSync(path.join(envPath, 'env.py'), envPy);
}
async function createAuth(configPath) {
const authPy = `
\# Simple API key authentication for development
from typing import Optional
\# Development API keys - in production, these should be stored securely
VALID_API_KEYS = [
"pk_dev_7f8a9b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a",
"pk_test_3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f",
"pk_demo_9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b"
]
def validate_api_key(api_key: Optional[str]) -> bool:
"""
Validate if the provided API key is valid
Args:
api_key: The API key to validate
Returns:
bool: True if valid, False otherwise
"""
if not api_key:
return False
return api_key in VALID_API_KEYS
def get_api_key_from_headers(headers) -> Optional[str]:
"""
Extract API key from request headers
Args:
headers: Request headers
Returns:
Optional[str]: API key if found, None otherwise
"""
return headers.get("X-API-Key") or headers.get("x-api-key")
`;
fs.writeFileSync(path.join(configPath, 'auth.py'), authPy);
}
async function createRouting(configPath) {
const routingPy = `
from fastapi import HTTPException, Request
from typing import Tuple
from .auth import validate_api_key, get_api_key_from_headers
def parse_and_validate_request(request: Request) -> Tuple[str, str]:
"""
Parse X-Method-Endpoint header and validate API key authentication
Args:
request: FastAPI Request object
Returns:
Tuple[str, str]: (method, endpoint) parsed from header
Raises:
HTTPException: If header is missing, invalid, or API key is invalid
"""
\# Get method endpoint from header
method_endpoint = request.headers.get("X-Method-Endpoint", "")
actual_method = request.method
\# Log incoming request for debugging
print(f"\\nš Incoming request:")
print(f" Actual Method: {actual_method}")
print(f" URL: {request.url}")
print(f" X-Method-Endpoint: {method_endpoint}")
print(f" X-Backend-Service: {request.headers.get('X-Backend-Service', 'Not provided')}")
print(f" X-Support-GPU: {request.headers.get('X-Support-GPU', 'Not provided')}")
print(f" X-API-Key: {'[PROVIDED]' if request.headers.get('X-API-Key') else 'Not provided'}")
print(f" Content-Type: {request.headers.get('Content-Type', 'Not provided')}")
\# Validate method endpoint header exists
if not method_endpoint:
print(f"ā Missing X-Method-Endpoint header")
raise HTTPException(status_code=400, detail="Missing X-Method-Endpoint header")
\# Parse the header
try:
method, endpoint = method_endpoint.split(":", 1)
print(f" Parsed: Method={method}, Endpoint={endpoint}")
except ValueError:
print(f"ā Invalid X-Method-Endpoint format: {method_endpoint}")
raise HTTPException(status_code=400, detail="Invalid X-Method-Endpoint format. Expected 'METHOD:endpoint'")
\# API Key validation (skip for health check)
if endpoint != "/health":
api_key = get_api_key_from_headers(request.headers)
if not validate_api_key(api_key):
print(f"ā Invalid or missing API key")
raise HTTPException(
status_code=401,
detail="Invalid or missing API key. Please provide a valid API Key."
)
print(f"ā
API key validated successfully")
return method, endpoint
`;
fs.writeFileSync(path.join(configPath, 'routing.py'), routingPy);
}
async function createUtils(configPath) {
const utilsPy = `
"""
Config utilities for reading app.config.json
"""
import json
from pathlib import Path
from typing import Optional
def get_environment() -> str:
"""Get environment setting from app.config.json
Returns:
str: The environment value from config, defaults to 'localhost'
"""
try:
# Find app.config.json by going up the directory tree
current_dir = Path(__file__).parent
while current_dir != current_dir.parent:
config_file = current_dir / "app.config.json"
if config_file.exists():
with open(config_file, 'r') as f:
config = json.load(f)
return config.get("environment", "localhost")
current_dir = current_dir.parent
# If not found, default to localhost
return "localhost"
except Exception as e:
print(f"Warning: Could not read app.config.json: {e}")
return "localhost"
def get_app_config() -> Optional[dict]:
"""Get the full app.config.json configuration
Returns:
dict: The full config object, or None if not found
"""
try:
current_dir = Path(__file__).parent
while current_dir != current_dir.parent:
config_file = current_dir / "app.config.json"
if config_file.exists():
with open(config_file, 'r') as f:
return json.load(f)
current_dir = current_dir.parent
return None
except Exception:
return None
`;
fs.writeFileSync(path.join(configPath, 'utils.py'), utilsPy);
}
module.exports = {
createEnvConfigFiles,
createEnvInit,
createEnv
}