diff --git a/docs/TurboDocx Templating/API Templates.md b/docs/TurboDocx Templating/API Templates.md
new file mode 100644
index 0000000..cc86b92
--- /dev/null
+++ b/docs/TurboDocx Templating/API Templates.md
@@ -0,0 +1,885 @@
+---
+title: Template Generation API Integration
+sidebar_position: 1
+description: Complete guide for integrating Template Generation API to upload templates, browse existing templates, and generate deliverables. Learn the dual-path process with detailed examples and code samples.
+keywords:
+ - template generation api
+ - document template api
+ - template upload api
+ - template browsing api
+ - deliverable generation api
+ - api integration
+ - document generation workflow
+ - turbodocx api
+ - template api endpoints
+ - api authentication
+ - document processing api
+ - api tutorial
+ - template api examples
+ - postman examples
+ - curl examples
+ - javascript api
+ - python api
+ - nodejs api
+ - php api
+ - template automation
+ - document workflow api
+ - template integration
+ - api best practices
+ - api troubleshooting
+ - bearer token authentication
+---
+
+import ScriptLoader from '@site/src/components/ScriptLoader';
+
+# Template Generation API Integration
+
+This comprehensive guide walks you through the Template Generation API integration process. Learn how to programmatically upload new templates or select existing ones, then generate beautiful documents with variable substitution using our RESTful API.
+
+
+
+## Overview
+
+The Template Generation API offers **two flexible paths** to document creation, because we believe in choice (and because forcing everyone down one path would be like making everyone eat vanilla ice cream forever):
+
+### **Path A: Upload New Template**
+
+1. **Upload & Create** - Upload your .docx/.pptx template and extract variables automatically
+2. **Generate Document** - Fill variables and create your deliverable
+
+### **Path B: Select Existing Template**
+
+1. **Browse Templates** - Explore your template library with search and filtering
+2. **Template Details** - Load template variables and preview PDF
+3. **Generate Document** - Fill variables and create your deliverable
+
+
+
+### Key Features
+
+- **RESTful API**: Standard HTTP methods with JSON and multipart payloads
+- **Bearer Token Authentication**: Secure API access using JWT tokens
+- **Dual Entry Points**: Start fresh with uploads OR use existing templates
+- **Smart Variable Extraction**: Automatic detection of placeholders in uploaded documents
+- **Rich Variable Types**: Support for text, subvariables, stacks, and AI-powered content
+- **Template Library**: Full CRUD operations with search, filtering, and organization
+- **Real-time Processing**: Track document generation status throughout the process
+
+## TLDR; Complete Working Examples 🚀
+
+Don't want to read the novel? Here's the executive summary:
+
+### Available Variable Types
+
+| Type | Description | Example Placeholder | Use Case |
+| --------------- | ----------------------------- | ---------------------- | --------------------------- |
+| `text` | Simple text replacement | `{CompanyName}` | Basic text substitution |
+| `subvariables` | Nested variable structures | `{Employee.FirstName}` | Complex hierarchical data |
+| `variableStack` | Multiple instances of content | `{Projects[0].Name}` | Repeating sections, lists |
+| `richText` | HTML/formatted text content | `{Description}` | Formatted text with styling |
+| `aiPrompt` | AI-generated content | `{Summary}` | Dynamic content generation |
+
+### Complete Dual-Path Workflow
+
+
+
+### Quick Variable Structure Example
+
+Here's what a complex variable payload looks like:
+
+```json
+{
+ "templateId": "abc123-def456-ghi789",
+ "name": "Employee Contract Draft",
+ "description": "Generated contract for new hire",
+ "variables": [
+ {
+ "name": "Employee",
+ "placeholder": "{Employee}",
+ "text": "John Smith",
+ "subvariables": [
+ {
+ "placeholder": "{Employee.Title}",
+ "text": "Senior Developer"
+ },
+ {
+ "placeholder": "{Employee.StartDate}",
+ "text": "2024-01-15"
+ }
+ ]
+ },
+ {
+ "name": "Projects",
+ "placeholder": "{Projects}",
+ "variableStack": {
+ "0": {
+ "text": "Project Alpha - Backend Development",
+ "subvariables": [
+ {
+ "placeholder": "{Projects.Duration}",
+ "text": "6 months"
+ }
+ ]
+ },
+ "1": {
+ "text": "Project Beta - API Integration",
+ "subvariables": [
+ {
+ "placeholder": "{Projects.Duration}",
+ "text": "3 months"
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
+```
+
+Now let's dive into the template wizardry...
+
+## Prerequisites
+
+Before you begin your journey into template automation nirvana, ensure you have:
+
+- **API Access Token**: Bearer token for authentication
+- **Organization ID**: Your organization identifier
+- **Template Files**: .docx or .pptx files with placeholder variables (for uploads)
+
+### Getting Your Credentials
+
+1. **Login to TurboDocx**: Visit [https://www.turbodocx.com](https://www.turbodocx.com)
+2. **Navigate to Settings**: Access your organization settings
+3. **API Keys Section**: Generate or retrieve your API access token
+4. **Organization ID**: Copy your organization ID from the settings
+
+
+
+
+## Authentication
+
+All Template Generation API requests require authentication using a Bearer token in the Authorization header:
+
+```http
+Authorization: Bearer YOUR_API_TOKEN
+```
+
+Additional required headers for all requests:
+
+```http
+x-rapiddocx-org-id: YOUR_ORGANIZATION_ID
+User-Agent: TurboDocx API Client
+```
+
+## Path A: Upload New Template
+
+Start fresh by uploading a new template document. This path is perfect when you've crafted a beautiful new template and want to jump straight into document generation.
+
+### Endpoint
+
+```http
+POST https://api.turbodocx.com/template/upload-and-create
+```
+
+### Headers
+
+```http
+Content-Type: multipart/form-data
+Authorization: Bearer YOUR_API_TOKEN
+x-rapiddocx-org-id: YOUR_ORGANIZATION_ID
+User-Agent: TurboDocx API Client
+```
+
+### Request Body (Form Data)
+
+```javascript
+{
+ "templateFile": [DOCX_OR_PPTX_FILE_BINARY],
+ "name": "Employee Contract Template",
+ "description": "Standard employee contract with variable placeholders",
+ "variables": "[]", // Optional: Pre-defined variables (usually extracted automatically)
+ "tags": "[]" // Optional: Categorization tags
+}
+```
+
+### Response
+
+```json
+{
+ "data": {
+ "results": {
+ "template": {
+ "name": "Employee Contract Template",
+ "description": "Standard employee contract with variable placeholders",
+ "fonts": [
+ {
+ "name": "Arial",
+ "usage": 269
+ },
+ {
+ "name": "Calibri",
+ "usage": 45
+ }
+ ],
+ "defaultFont": "Arial",
+ "orgId": "2d66ecf0-a749-475d-9403-9956d0f67884",
+ "createdBy": "9d829e80-1135-4a97-93ea-cc2a1eecc9da",
+ "createdOn": "2025-09-19T15:45:47.000Z",
+ "updatedOn": "2025-09-19T15:45:47.000Z",
+ "isActive": 1,
+ "id": "31cc4cce-4ed7-4f3b-aa80-0b9a4f995412",
+ "variables": null,
+ "projectspaceId": null,
+ "templateFolderId": null,
+ "metadata": null
+ },
+ "redirectUrl": "/templates/31cc4cce-4ed7-4f3b-aa80-0b9a4f995412/generate"
+ }
+ }
+}
+```
+
+### Response Fields
+
+| Field | Type | Description |
+| ---------------------------------------- | ------------ | ----------------------------------------------- |
+| `data.results.template.id` | string | Unique template identifier (use for generation) |
+| `data.results.template.name` | string | Template name as provided |
+| `data.results.template.description` | string | Template description |
+| `data.results.template.fonts` | array | Array of font objects with name and usage |
+| `data.results.template.defaultFont` | string | Default font name for the template |
+| `data.results.template.orgId` | string | Organization ID |
+| `data.results.template.createdBy` | string | User ID who created the template |
+| `data.results.template.createdOn` | string | ISO timestamp of template creation |
+| `data.results.template.updatedOn` | string | ISO timestamp of last template update |
+| `data.results.template.isActive` | number | Active status (1 = active, 0 = inactive) |
+| `data.results.template.variables` | array\|null | Auto-extracted variables (null if none found) |
+| `data.results.template.projectspaceId` | string\|null | Project space ID (null if not assigned) |
+| `data.results.template.templateFolderId` | string\|null | Folder ID (null if not in folder) |
+| `data.results.template.metadata` | object\|null | Additional metadata (null if not set) |
+| `data.results.redirectUrl` | string | Frontend URL to redirect for variable filling |
+
+### Deliverable Response Fields
+
+| Field | Type | Description |
+| ------------------------------------- | ------- | -------------------------------- |
+| `data.results.deliverable.id` | string | Unique deliverable identifier |
+| `data.results.deliverable.name` | string | Deliverable name as provided |
+| `data.results.deliverable.createdBy` | string | Email of the user who created it |
+| `data.results.deliverable.createdOn` | string | ISO timestamp of creation |
+| `data.results.deliverable.orgId` | string | Organization ID |
+| `data.results.deliverable.isActive` | boolean | Whether deliverable is active |
+| `data.results.deliverable.templateId` | string | Original template ID used |
+
+### Code Examples
+
+
+
+## Path B: Select Existing Template
+
+Browse your template library to find the perfect starting point. This path lets you leverage templates you've already created and organized.
+
+### Step 1: Browse Templates
+
+List all available templates and folders in your organization.
+
+#### Endpoint
+
+```http
+GET https://api.turbodocx.com/template-item
+```
+
+#### Headers
+
+```http
+Authorization: Bearer YOUR_API_TOKEN
+x-rapiddocx-org-id: YOUR_ORGANIZATION_ID
+User-Agent: TurboDocx API Client
+```
+
+#### Query Parameters
+
+```http
+?limit=25&offset=0&query=contract&showTags=true&selectedTags[]=tag-123
+```
+
+| Parameter | Type | Description |
+| -------------- | ------- | ----------------------------------- |
+| `limit` | number | Items per page (default: 6) |
+| `offset` | number | Pagination offset (default: 0) |
+| `query` | string | Search term for template names |
+| `showTags` | boolean | Include tag information in response |
+| `selectedTags` | array | Filter by specific tag IDs |
+
+#### Response
+
+```json
+{
+ "data": {
+ "results": [
+ {
+ "id": "0b1099cf-d7b9-41a4-822b-51b68fd4885a",
+ "name": "Employee / Contractor IP Agreement Example",
+ "description": "A Statement of Work template provided by TurboDocx",
+ "createdOn": "2025-05-29T19:07:16.000Z",
+ "updatedOn": "2025-09-08T11:44:11.000Z",
+ "isActive": 1,
+ "type": "template",
+ "createdBy": "9d829e80-1135-4a97-93ea-cc2a1eecc9da",
+ "email": "kahlerasse@gmail.com",
+ "templateFolderId": null,
+ "deliverableCount": 4,
+ "fileSize": 24942,
+ "fileType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ "templateCount": 0,
+ "tags": []
+ },
+ {
+ "id": "604d1e63-6cdc-4849-9e71-548409bfec69",
+ "name": "Legal",
+ "description": null,
+ "createdOn": "2025-05-29T19:07:16.000Z",
+ "updatedOn": "2025-05-29T19:07:16.000Z",
+ "isActive": 1,
+ "type": "folder",
+ "createdBy": "9d829e80-1135-4a97-93ea-cc2a1eecc9da",
+ "email": "kahlerasse@gmail.com",
+ "templateFolderId": null,
+ "deliverableCount": 0,
+ "fileSize": null,
+ "fileType": null,
+ "templateCount": 0,
+ "tags": []
+ }
+ ],
+ "totalRecords": 26
+ }
+}
+```
+
+#### Browse Response Fields
+
+| Field | Type | Description |
+| --------------------------------- | ------------ | ----------------------------------------------- |
+| `data.results[]` | array | Array of templates and folders |
+| `data.results[].id` | string | Unique identifier for template or folder |
+| `data.results[].name` | string | Name of the template or folder |
+| `data.results[].description` | string\|null | Description (null for some items) |
+| `data.results[].createdOn` | string | ISO timestamp of creation |
+| `data.results[].updatedOn` | string | ISO timestamp of last update |
+| `data.results[].isActive` | number | Active status (1 = active, 0 = inactive) |
+| `data.results[].type` | string | Item type ("template" or "folder") |
+| `data.results[].createdBy` | string | User ID who created the item |
+| `data.results[].email` | string | Email of the creator |
+| `data.results[].templateFolderId` | string\|null | Parent folder ID (null if at root level) |
+| `data.results[].deliverableCount` | number | Number of deliverables generated from template |
+| `data.results[].fileSize` | number\|null | File size in bytes (null for folders) |
+| `data.results[].fileType` | string\|null | MIME type of template file (null for folders) |
+| `data.results[].templateCount` | number | Number of templates in folder (0 for templates) |
+| `data.results[].tags` | array | Array of tag objects |
+| `data.totalRecords` | number | Total number of items available |
+
+### Step 2: Get Template Details
+
+Load specific template information including variables and metadata.
+
+#### Endpoint
+
+```http
+GET https://api.turbodocx.com/template/{templateId}
+```
+
+#### Response
+
+```json
+{
+ "data": {
+ "results": {
+ "id": "0b1099cf-d7b9-41a4-822b-51b68fd4885a",
+ "name": "Employee Contract Template",
+ "description": "Standard employment agreement template",
+ "templateFileType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ "templateFolderId": "folder-def456",
+ "variables": [
+ {
+ "id": "var-123",
+ "name": "Employee Name",
+ "placeholder": "{EmployeeName}",
+ "text": "",
+ "mimeType": "text",
+ "allowRichTextInjection": false,
+ "order": 1,
+ "subvariables": []
+ },
+ {
+ "id": "var-456",
+ "name": "Department",
+ "placeholder": "{Department}",
+ "text": "",
+ "mimeType": "text",
+ "allowRichTextInjection": true,
+ "order": 2,
+ "subvariables": [
+ {
+ "placeholder": "{Department.Manager}",
+ "text": ""
+ }
+ ]
+ }
+ ],
+ "fonts": [
+ {
+ "name": "Arial",
+ "usage": 269
+ }
+ ],
+ "defaultFont": "Arial"
+ }
+ }
+}
+```
+
+### Step 3: Get PDF Preview (Optional)
+
+Generate a preview PDF of the template for visual confirmation.
+
+#### Endpoint
+
+```http
+GET https://api.turbodocx.com/template/{templateId}/previewpdflink
+```
+
+#### Response
+
+```json
+{
+ "results": "https://api.turbodocx.com/template/pdf/preview-abc123.pdf"
+}
+```
+
+### Code Examples
+
+
+
+## Final Step: Generate Deliverable
+
+Both paths converge here - time to fill those variables and create your masterpiece! This is where the magic happens and placeholders become real content.
+
+### Step 1: Generate Deliverable
+
+### Endpoint
+
+```http
+POST https://api.turbodocx.com/deliverable
+```
+
+### Headers
+
+```http
+Content-Type: application/json
+Authorization: Bearer YOUR_API_TOKEN
+x-rapiddocx-org-id: YOUR_ORGANIZATION_ID
+User-Agent: TurboDocx API Client
+```
+
+### Request Body
+
+```json
+{
+ "templateId": "0b1099cf-d7b9-41a4-822b-51b68fd4885a",
+ "name": "Employee Contract - John Smith",
+ "description": "Employment contract for new senior developer",
+ "variables": [
+ {
+ "mimeType": "text",
+ "name": "Employee Name",
+ "placeholder": "{EmployeeName}",
+ "text": "John Smith",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 1,
+ "order": 1,
+ "subvariables": [
+ {
+ "placeholder": "{Employee.Title}",
+ "text": "Senior Software Developer"
+ },
+ {
+ "placeholder": "{Employee.StartDate}",
+ "text": "January 15, 2024"
+ }
+ ],
+ "aiPrompt": "Generate a professional job description for a senior developer role"
+ },
+ {
+ "mimeType": "text",
+ "name": "Department",
+ "placeholder": "{Department}",
+ "text": "Engineering",
+ "allowRichTextInjection": 1,
+ "autogenerated": false,
+ "count": 3,
+ "order": 2,
+ "subvariables": [
+ {
+ "placeholder": "{Department.Manager}",
+ "text": "Sarah Johnson"
+ }
+ ],
+ "variableStack": {
+ "0": {
+ "text": "Frontend Development Team",
+ "subvariables": [
+ {
+ "placeholder": "{Team.Focus}",
+ "text": "React and TypeScript development"
+ }
+ ]
+ },
+ "1": {
+ "text": "Backend Development Team",
+ "subvariables": [
+ {
+ "placeholder": "{Team.Focus}",
+ "text": "Node.js and database optimization"
+ }
+ ]
+ }
+ },
+ "metadata": {
+ "customField": "Engineering Department"
+ },
+ "aiPrompt": "Describe the key responsibilities of the engineering department"
+ }
+ ],
+ "tags": ["hr-template", "contract", "full-time"],
+ "fonts": "[{\"name\":\"Arial\",\"usage\":269}]",
+ "defaultFont": "Arial",
+ "replaceFonts": true,
+ "metadata": {
+ "sessions": [
+ {
+ "id": "session-abc123",
+ "starttime": "2024-01-15T14:12:10.721Z",
+ "endtime": "2024-01-15T14:13:45.724Z"
+ }
+ ]
+ }
+}
+```
+
+### Response
+
+```json
+{
+ "data": {
+ "results": {
+ "deliverable": {
+ "id": "39697685-ca00-43b8-92b8-7722544c574f",
+ "name": "Employee Contract - John Smith",
+ "description": "Employment contract for new senior developer",
+ "createdBy": "api-user@company.com",
+ "createdOn": "2024-12-19T21:22:10.000Z",
+ "orgId": "your-organization-id",
+ "isActive": true,
+ "templateId": "0b1099cf-d7b9-41a4-822b-51b68fd4885a"
+ }
+ }
+ }
+}
+```
+
+### Variable Structure Deep Dive
+
+Understanding the variable structure is key to successful document generation:
+
+#### Basic Variable
+
+```json
+{
+ "name": "Company Name",
+ "placeholder": "{CompanyName}",
+ "text": "Acme Corporation",
+ "mimeType": "text",
+ "allowRichTextInjection": false,
+ "order": 1
+}
+```
+
+#### Variable with Subvariables
+
+```json
+{
+ "name": "Employee",
+ "placeholder": "{Employee}",
+ "text": "John Smith",
+ "subvariables": [
+ {
+ "placeholder": "{Employee.Title}",
+ "text": "Senior Developer"
+ },
+ {
+ "placeholder": "{Employee.Email}",
+ "text": "john.smith@company.com"
+ }
+ ]
+}
+```
+
+#### Variable Stack (Repeating Content)
+
+```json
+{
+ "name": "Projects",
+ "placeholder": "{Projects}",
+ "variableStack": {
+ "0": {
+ "text": "Project Alpha",
+ "subvariables": [
+ {
+ "placeholder": "{Projects.Status}",
+ "text": "In Progress"
+ }
+ ]
+ },
+ "1": {
+ "text": "Project Beta",
+ "subvariables": [
+ {
+ "placeholder": "{Projects.Status}",
+ "text": "Completed"
+ }
+ ]
+ }
+ }
+}
+```
+
+### Request Fields
+
+| Field | Type | Required | Description |
+| ------------------------------------ | ------- | -------- | ---------------------------------------------- |
+| `templateId` | string | Yes | Template ID from upload or selection |
+| `name` | string | Yes | Name for the generated deliverable |
+| `description` | string | No | Description of the deliverable |
+| `variables[]` | array | Yes | Array of variable definitions and values |
+| `variables[].name` | string | Yes | Variable display name |
+| `variables[].placeholder` | string | Yes | Placeholder text in template (e.g., "{Name}") |
+| `variables[].text` | string | Yes | Actual value to replace placeholder |
+| `variables[].mimeType` | string | Yes | Content type ("text", "html", etc.) |
+| `variables[].allowRichTextInjection` | number | No | Allow HTML/rich text (0 or 1) |
+| `variables[].subvariables` | array | No | Nested variables within this variable |
+| `variables[].variableStack` | object | No | Multiple instances for repeating content |
+| `variables[].aiPrompt` | string | No | AI prompt for content generation |
+| `variables[].metadata` | object | No | Custom metadata for the variable |
+| `tags` | array | No | Tags for categorization |
+| `fonts` | string | No | JSON string of font usage statistics |
+| `defaultFont` | string | No | Default font for the document |
+| `replaceFonts` | boolean | No | Whether to replace fonts during generation |
+| `metadata` | object | No | Additional metadata (sessions, tracking, etc.) |
+
+### Step 2: Download Generated File
+
+After generating a deliverable, you'll need to download the actual file.
+
+#### Endpoint
+
+```http
+GET https://api.turbodocx.com/deliverable/file/{deliverableId}
+```
+
+#### Headers
+
+```http
+Authorization: Bearer YOUR_API_TOKEN
+x-rapiddocx-org-id: YOUR_ORGANIZATION_ID
+User-Agent: TurboDocx API Client
+```
+
+#### Example Request
+
+```bash
+curl -X GET "https://api.turbodocx.com/deliverable/file/39697685-ca00-43b8-92b8-7722544c574f" \
+ -H "Authorization: Bearer YOUR_API_TOKEN" \
+ -H "x-rapiddocx-org-id: YOUR_ORGANIZATION_ID" \
+ -H "User-Agent: TurboDocx API Client" \
+ --output "employee-contract-john-smith.docx"
+```
+
+#### Response
+
+Returns the binary content of the generated document with appropriate content-type headers:
+
+```http
+Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
+Content-Disposition: attachment; filename="employee-contract-john-smith.docx"
+Content-Length: 287456
+```
+
+### Code Examples
+
+
+
+## Best Practices
+
+### Security
+
+- **Never expose API tokens**: Store tokens securely in environment variables
+- **Use HTTPS only**: All API calls must use HTTPS in production
+- **Validate file uploads**: Check file types and sizes before upload
+- **Sanitize variables**: Validate variable content to prevent injection attacks
+
+### Error Handling
+
+- **Check HTTP status codes**: Always verify response status before processing
+- **Handle file upload failures**: Implement retry logic for large file uploads
+- **Validate template variables**: Ensure all required variables are provided
+- **Log API responses**: Keep detailed logs for debugging and monitoring
+
+### Performance
+
+- **Optimize file uploads**: Compress .docx/.pptx files when possible
+- **Cache template details**: Store frequently used template information
+- **Batch variable processing**: Group related variables together
+- **Async processing**: Use webhooks for long-running document generation
+
+### Template Preparation
+
+- **Use clear placeholders**: Name variables descriptively (e.g., `{CompanyName}` not `{CN}`)
+- **Consistent formatting**: Use consistent placeholder formats throughout templates
+- **Test variable extraction**: Verify automatic variable detection works correctly
+- **Document structure**: Organize templates logically with folders and tags
+
+### Variable Management
+
+- **Hierarchical organization**: Use subvariables for related data
+- **Stack for repetition**: Use variableStack for lists and repeating sections
+- **Rich text sparingly**: Only enable rich text injection when formatting is needed
+- **AI prompts**: Provide clear, specific prompts for AI-generated content
+
+## Error Handling & Troubleshooting
+
+### Common HTTP Status Codes
+
+| Status Code | Description | Solution |
+| ----------- | --------------------- | --------------------------------------------- |
+| `200` | Success | Request completed successfully |
+| `400` | Bad Request | Check request body format and required fields |
+| `401` | Unauthorized | Verify API token and headers |
+| `403` | Forbidden | Check organization ID and permissions |
+| `404` | Not Found | Verify template ID and endpoint URLs |
+| `413` | Payload Too Large | Reduce file size or compress template |
+| `422` | Unprocessable Entity | Validate field values and constraints |
+| `429` | Too Many Requests | Implement rate limiting and retry logic |
+| `500` | Internal Server Error | Contact support if persistent |
+
+### Common Issues
+
+#### Template Upload Failures
+
+**Symptoms**: Upload returns error or times out
+
+**Solutions**:
+
+- Verify file is .docx or .pptx format
+- Check file size is under the maximum limit (typically 25MB)
+- Ensure file is not corrupted or password-protected
+- Verify network connection and try again
+
+#### Variable Extraction Issues
+
+**Symptoms**: Variables not detected automatically
+
+**Solutions**:
+
+- Use consistent placeholder format: `{VariableName}`
+- Avoid special characters in placeholder names
+- Ensure placeholders are in main document content (not headers/footers)
+- Check that placeholders are properly formatted text (not images)
+
+#### Template Selection Problems
+
+**Symptoms**: Templates not appearing in browse results
+
+**Solutions**:
+
+- Verify organization ID matches your account
+- Check that templates are active and not archived
+- Use correct API endpoint for browsing vs. folder contents
+- Verify search parameters and filters
+
+#### Document Generation Failures
+
+**Symptoms**: Deliverable generation fails or produces incorrect output
+
+**Solutions**:
+
+- Validate all required variables have values
+- Check variable names match template placeholders exactly
+- Ensure subvariable structure matches template expectations
+- Verify file permissions and storage availability
+
+#### Font and Formatting Issues
+
+**Symptoms**: Generated documents have incorrect fonts or formatting
+
+**Solutions**:
+
+- Use `replaceFonts: true` to normalize font usage
+- Specify `defaultFont` for consistent appearance
+- Check that rich text injection is enabled only when needed
+- Validate HTML content in rich text variables
+
+### Debugging Tips
+
+1. **Test with simple templates**: Start with basic templates before adding complexity
+2. **Validate JSON payloads**: Use JSON validators before sending requests
+3. **Check file encoding**: Ensure .docx/.pptx files are not corrupted
+4. **Monitor API quotas**: Track usage to avoid rate limiting
+5. **Use development endpoints**: Test with development environment first
+
+## Next Steps
+
+### Advanced Features to Explore
+
+Now that you've mastered the basics, consider exploring these advanced capabilities:
+
+📖 **[AI-Powered Content Generation →](/docs/TurboDocx%20Templating/ai-variable-generation)**
+📖 **[Webhook Integration for Status Updates →](/docs/Webhooks/webhook-configuration)**
+📖 **[Bulk Document Generation →](/docs/Templates/bulk-generation)**
+📖 **[Template Version Management →](/docs/Templates/version-control)**
+
+### Related Documentation
+
+- [Template Management Guide](/docs/Templates/template-management)
+- [Variable Types and Formatting](/docs/Templates/variable-types)
+- [API Authentication](/docs/API/turbodocx-api-documentation)
+- [Integration Examples](/docs/Integrations)
+
+## Support
+
+Need help with your template integration? We've got you covered:
+
+- **Discord Community**: [Join our Discord server](https://discord.gg/NYKwz4BcpX) for real-time support and template wizardry discussions
+- **Documentation**: [https://docs.turbodocx.com](https://docs.turbodocx.com)
+- **Template Gallery**: Browse example templates for inspiration
+
+---
+
+Ready to become a template automation wizard? Choose your path (upload new or select existing) and start generating beautiful documents programmatically! 🎯
diff --git a/docs/TurboDocx Templating/ai-variable-generation.md b/docs/TurboDocx Templating/ai-variable-generation.md
new file mode 100644
index 0000000..c60a6c3
--- /dev/null
+++ b/docs/TurboDocx Templating/ai-variable-generation.md
@@ -0,0 +1,653 @@
+---
+title: AI-Powered Variable Generation API
+sidebar_position: 1
+description: Complete guide for AI-powered variable generation API with file attachments, context-aware content creation, and intelligent data extraction from documents.
+keywords:
+ - ai variable generation
+ - ai content generation api
+ - intelligent variable creation
+ - ai document processing
+ - file attachment api
+ - context-aware ai
+ - ai prompt engineering
+ - variable automation
+ - ai api integration
+ - document intelligence
+ - smart content generation
+ - ai-powered templates
+ - turbodocx ai api
+ - ai variable extraction
+ - intelligent placeholder filling
+ - ai content api
+ - automated variable creation
+ - ai document analysis
+ - smart variable generation
+ - ai template integration
+---
+
+import ScriptLoader from '@site/src/components/ScriptLoader';
+
+# AI-Powered Variable Generation API
+
+Transform your document workflows with intelligent, context-aware variable generation. This API leverages advanced AI to automatically create rich, relevant content for your template variables by analyzing uploaded files, understanding context, and generating human-quality text based on your specific prompts.
+
+
+
+## Overview
+
+The AI Variable Generation API represents the cutting edge of document automation, enabling you to:
+
+- **Generate Intelligent Content**: Create contextually relevant variable content using AI
+- **Process File Attachments**: Extract insights from Excel, Word, PDF, and other document formats
+- **Context-Aware Generation**: Leverage template context for more accurate content creation
+- **Rich Text Support**: Generate formatted content with HTML, markdown, or plain text
+- **Smart Data Extraction**: Automatically parse and understand structured data from spreadsheets
+
+### Key Capabilities
+
+🧠 **AI-Powered Content Creation**: Advanced language models generate human-quality content
+📎 **File Attachment Processing**: Upload and analyze documents for context-driven generation
+📊 **Spreadsheet Intelligence**: Select specific sheets and extract relevant data automatically
+🎯 **Context Integration**: Use existing templates to inform and guide content generation
+✨ **Rich Text Generation**: Create formatted content with styling and structure
+🔧 **Customizable Prompts**: Fine-tune AI behavior with specific instructions and hints
+
+## How It Works
+
+The AI Variable Generation process follows a simple but powerful workflow:
+
+1. **Upload Context Files** - Attach documents (Excel, Word, PDF) that contain relevant data
+2. **Define Variable Parameters** - Specify the variable name, placeholder, and generation context
+3. **Craft AI Prompts** - Provide specific instructions to guide content generation
+4. **Generate Content** - AI analyzes files and context to create intelligent variable content
+5. **Integrate Results** - Use generated content directly in your template workflows
+
+
+
+## TLDR; Quick Example 🚀
+
+Ready to jump in? Here's a complete working example:
+
+```bash
+curl 'https://api.turbodocx.com/ai/generate/variable/one' \
+ -H 'Authorization: Bearer YOUR_API_TOKEN' \
+ -H 'x-rapiddocx-org-id: YOUR_ORG_ID' \
+ -H 'Content-Type: multipart/form-data' \
+ -F 'FileResource-123e4567-e89b-12d3-a456-426614174000=@financial-report.xlsx' \
+ -F 'fileResourceMetadata={"123e4567-e89b-12d3-a456-426614174000":{"selectedSheet":"Q4 Results","hasMultipleSheets":true}}' \
+ -F 'name=Company Performance Summary' \
+ -F 'placeholder={Q4Performance}' \
+ -F 'templateId=template-abc123' \
+ -F 'aiHint=Generate a professional executive summary of Q4 financial performance based on the attached spreadsheet data' \
+ -F 'richTextEnabled=true'
+```
+
+**Response:**
+
+```json
+{
+ "data": {
+ "mimeType": "html",
+ "text": "
Q4 Performance Summary: Our organization achieved exceptional results in Q4 2024, with revenue growing 23% year-over-year to $4.2M. Key highlights include improved operational efficiency, successful product launches, and strong market penetration in target segments.
"
+ }
+}
+```
+
+Now let's dive into the complete implementation guide...
+
+## Prerequisites
+
+Before you begin generating AI-powered variables, ensure you have:
+
+- **API Access Token**: Bearer token for authentication
+- **Organization ID**: Your organization identifier
+- **Template Context** (Optional): Existing template ID for enhanced context
+- **Source Files** (Optional): Documents containing data for AI analysis
+
+### Getting Your Credentials
+
+1. **Login to TurboDocx**: Visit [https://www.turbodocx.com](https://www.turbodocx.com)
+2. **Navigate to Settings**: Access your organization settings
+3. **API Keys Section**: Generate or retrieve your API access token
+4. **Organization ID**: Copy your organization ID from the settings
+
+
+
+### Supported File Types
+
+The AI Variable Generation API supports a wide range of file formats:
+
+| File Type | Extensions | Use Cases |
+| ----------------- | ----------------------- | ----------------------------------------------- |
+| **Spreadsheets** | `.xlsx`, `.xls`, `.csv` | Financial data, reports, lists, structured data |
+| **Documents** | `.docx`, `.doc`, `.pdf` | Contracts, reports, proposals, text content |
+| **Presentations** | `.pptx`, `.ppt` | Slide content, presentations, visual data |
+| **Images** | `.png`, `.jpg`, `.jpeg` | Charts, diagrams, visual content analysis |
+| **Text Files** | `.txt`, `.md` | Plain text, documentation, notes |
+
+## Authentication
+
+All AI Variable Generation API requests require authentication using a Bearer token:
+
+```http
+Authorization: Bearer YOUR_API_TOKEN
+x-rapiddocx-org-id: YOUR_ORGANIZATION_ID
+User-Agent: TurboDocx AI Client
+```
+
+## API Reference
+
+### Generate Single Variable
+
+Create AI-powered content for a single template variable with optional file attachments.
+
+#### Endpoint
+
+```http
+POST https://api.turbodocx.com/ai/generate/variable/one
+```
+
+#### Headers
+
+```http
+Content-Type: multipart/form-data
+Authorization: Bearer YOUR_API_TOKEN
+x-rapiddocx-org-id: YOUR_ORGANIZATION_ID
+User-Agent: TurboDocx AI Client
+```
+
+#### Request Body (Form Data)
+
+The request uses multipart form data to support file uploads alongside variable parameters:
+
+```javascript
+{
+ // File attachment (optional)
+ "FileResource-{uuid}": [BINARY_FILE_DATA],
+
+ // File metadata (required if file attached)
+ "fileResourceMetadata": "{\"file-uuid\":{\"selectedSheet\":\"Sheet1\",\"hasMultipleSheets\":true}}",
+
+ // Variable definition
+ "name": "Company Performance Summary",
+ "placeholder": "{PerformanceSummary}",
+
+ // Context and guidance
+ "templateId": "template-abc123", // Optional: for context
+ "aiHint": "Generate a professional summary of company performance",
+
+ // Output settings
+ "richTextEnabled": "true" // or "false"
+}
+```
+
+#### Request Parameters
+
+| Parameter | Type | Required | Description |
+| ---------------------- | ------ | ----------- | ---------------------------------------------------- |
+| `FileResource-{uuid}` | file | No | Binary file data for AI analysis |
+| `fileResourceMetadata` | string | Conditional | JSON metadata for attached files |
+| `name` | string | Yes | Display name for the variable |
+| `placeholder` | string | Yes | Template placeholder (e.g., `{VariableName}`) |
+| `templateId` | string | No | Template ID for context-aware generation |
+| `aiHint` | string | Yes | Instructions for AI content generation |
+| `richTextEnabled` | string | No | Enable HTML/rich text output (`"true"` or `"false"`) |
+
+#### File Metadata Structure
+
+When attaching files, provide metadata to guide AI processing:
+
+```json
+{
+ "file-uuid-here": {
+ "selectedSheet": "Q4 Results", // For spreadsheets: specific sheet
+ "hasMultipleSheets": true, // Whether file has multiple sheets
+ "dataRange": "A1:D100", // Optional: specific cell range
+ "contentType": "financial-data" // Optional: content classification
+ }
+}
+```
+
+#### Response
+
+```json
+{
+ "data": {
+ "mimeType": "text|html|markdown",
+ "text": "Generated variable content based on AI analysis"
+ }
+}
+```
+
+#### Response Fields
+
+| Field | Type | Description |
+| --------------- | ------ | ------------------------------------------- |
+| `data.mimeType` | string | Content format (`text`, `html`, `markdown`) |
+| `data.text` | string | Generated variable content |
+
+## Advanced Features
+
+### File Attachment Workflows
+
+#### Excel/Spreadsheet Processing
+
+When working with spreadsheets, the AI can analyze specific sheets and data ranges:
+
+```bash
+# Example: Financial data analysis
+curl 'https://api.turbodocx.com/ai/generate/variable/one' \
+ -H 'Authorization: Bearer YOUR_API_TOKEN' \
+ -H 'x-rapiddocx-org-id: YOUR_ORG_ID' \
+ -H 'Content-Type: multipart/form-data' \
+ -F 'FileResource-fin123=@quarterly-financials.xlsx' \
+ -F 'fileResourceMetadata={"fin123":{"selectedSheet":"Income Statement","hasMultipleSheets":true,"dataRange":"A1:F50"}}' \
+ -F 'name=Revenue Analysis' \
+ -F 'placeholder={RevenueAnalysis}' \
+ -F 'aiHint=Analyze the quarterly revenue trends and provide insights on growth patterns, highlighting key metrics and year-over-year changes' \
+ -F 'richTextEnabled=true'
+```
+
+#### Document Content Extraction
+
+For text documents, the AI can extract and synthesize key information:
+
+```bash
+# Example: Contract analysis
+curl 'https://api.turbodocx.com/ai/generate/variable/one' \
+ -H 'Authorization: Bearer YOUR_API_TOKEN' \
+ -H 'x-rapiddocx-org-id: YOUR_ORG_ID' \
+ -H 'Content-Type: multipart/form-data' \
+ -F 'FileResource-doc456=@contract-draft.docx' \
+ -F 'fileResourceMetadata={"doc456":{"contentType":"legal-document"}}' \
+ -F 'name=Contract Key Terms' \
+ -F 'placeholder={KeyTerms}' \
+ -F 'aiHint=Extract and summarize the key terms, obligations, and important dates from this contract document' \
+ -F 'richTextEnabled=false'
+```
+
+### Context-Aware Generation
+
+Leverage existing template context for more accurate content generation:
+
+```bash
+# Using template context
+curl 'https://api.turbodocx.com/ai/generate/variable/one' \
+ -H 'Authorization: Bearer YOUR_API_TOKEN' \
+ -H 'x-rapiddocx-org-id: YOUR_ORG_ID' \
+ -H 'Content-Type: multipart/form-data' \
+ -F 'name=Project Scope Description' \
+ -F 'placeholder={ProjectScope}' \
+ -F 'templateId=project-template-789' \
+ -F 'aiHint=Generate a detailed project scope description that aligns with the project template structure and includes deliverables, timeline, and success criteria' \
+ -F 'richTextEnabled=true'
+```
+
+### Rich Text Generation
+
+Enable rich text for formatted output with HTML styling:
+
+```bash
+# Rich text example
+curl 'https://api.turbodocx.com/ai/generate/variable/one' \
+ -H 'Authorization: Bearer YOUR_API_TOKEN' \
+ -H 'x-rapiddocx-org-id: YOUR_ORG_ID' \
+ -H 'Content-Type: multipart/form-data' \
+ -F 'name=Executive Summary' \
+ -F 'placeholder={ExecutiveSummary}' \
+ -F 'aiHint=Create a comprehensive executive summary with bullet points, key metrics, and strategic recommendations formatted for presentation' \
+ -F 'richTextEnabled=true'
+```
+
+**Rich Text Response Example:**
+
+```json
+{
+ "data": {
+ "mimeType": "html",
+ "text": "Executive Summary
Overview: Q4 2024 delivered exceptional results across all key performance indicators.
- Revenue Growth: 23% increase year-over-year
- Market Expansion: Successfully entered 3 new geographic markets
- Operational Efficiency: 15% improvement in cost optimization
Strategic Recommendations: Continue aggressive growth strategy while maintaining operational excellence.
"
+ }
+}
+```
+
+## Code Examples
+
+### Complete Implementation Examples
+
+
+
+## Use Cases & Examples
+
+### 1. Financial Report Analysis
+
+**Scenario**: Generate executive summaries from quarterly financial spreadsheets
+
+```bash
+curl 'https://api.turbodocx.com/ai/generate/variable/one' \
+ -H 'Authorization: Bearer YOUR_API_TOKEN' \
+ -H 'x-rapiddocx-org-id: YOUR_ORG_ID' \
+ -H 'Content-Type: multipart/form-data' \
+ -F 'FileResource-12345=@Q4-financials.xlsx' \
+ -F 'fileResourceMetadata={"12345":{"selectedSheet":"Summary","hasMultipleSheets":true}}' \
+ -F 'name=Financial Performance Summary' \
+ -F 'placeholder={FinancialSummary}' \
+ -F 'aiHint=Create a concise executive summary highlighting revenue growth, profit margins, and key financial metrics from the Q4 data' \
+ -F 'richTextEnabled=true'
+```
+
+### 2. Contract Key Terms Extraction
+
+**Scenario**: Extract important terms and dates from legal documents
+
+```bash
+curl 'https://api.turbodocx.com/ai/generate/variable/one' \
+ -H 'Authorization: Bearer YOUR_API_TOKEN' \
+ -H 'x-rapiddocx-org-id: YOUR_ORG_ID' \
+ -H 'Content-Type: multipart/form-data' \
+ -F 'FileResource-67890=@service-agreement.pdf' \
+ -F 'name=Contract Terms' \
+ -F 'placeholder={ContractTerms}' \
+ -F 'aiHint=Extract contract duration, payment terms, key obligations, and important deadlines in a structured format' \
+ -F 'richTextEnabled=false'
+```
+
+### 3. Project Proposal Generation
+
+**Scenario**: Create project descriptions based on scope documents
+
+```bash
+curl 'https://api.turbodocx.com/ai/generate/variable/one' \
+ -H 'Authorization: Bearer YOUR_API_TOKEN' \
+ -H 'x-rapiddocx-org-id: YOUR_ORG_ID' \
+ -H 'Content-Type: multipart/form-data' \
+ -F 'FileResource-abcde=@project-requirements.docx' \
+ -F 'name=Project Description' \
+ -F 'placeholder={ProjectDescription}' \
+ -F 'templateId=proposal-template-123' \
+ -F 'aiHint=Generate a professional project description including objectives, deliverables, timeline, and success criteria based on the requirements document' \
+ -F 'richTextEnabled=true'
+```
+
+### 4. Data-Driven Insights
+
+**Scenario**: Generate insights from research data and surveys
+
+```bash
+curl 'https://api.turbodocx.com/ai/generate/variable/one' \
+ -H 'Authorization: Bearer YOUR_API_TOKEN' \
+ -H 'x-rapiddocx-org-id: YOUR_ORG_ID' \
+ -H 'Content-Type: multipart/form-data' \
+ -F 'FileResource-xyz789=@market-research.xlsx' \
+ -F 'fileResourceMetadata={"xyz789":{"selectedSheet":"Survey Results","hasMultipleSheets":true}}' \
+ -F 'name=Market Insights' \
+ -F 'placeholder={MarketInsights}' \
+ -F 'aiHint=Analyze the survey data and generate key market insights, trends, and actionable recommendations for product strategy' \
+ -F 'richTextEnabled=true'
+```
+
+## AI Prompt Engineering
+
+### Writing Effective AI Hints
+
+The quality of generated content depends heavily on your AI prompts. Follow these best practices:
+
+#### ✅ Do: Be Specific and Clear
+
+```bash
+# Good prompt
+'aiHint=Generate a professional project timeline with 5 key milestones, including dates, deliverables, and success criteria for a 6-month software development project'
+
+# Poor prompt
+'aiHint=make a timeline'
+```
+
+#### ✅ Do: Provide Context and Format Requirements
+
+```bash
+# Good prompt
+'aiHint=Create an executive summary in bullet point format highlighting Q4 revenue (target: $2M), customer acquisition metrics, and year-over-year growth percentages'
+
+# Poor prompt
+'aiHint=summarize the data'
+```
+
+#### ✅ Do: Specify Tone and Audience
+
+```bash
+# Good prompt
+'aiHint=Write a formal, executive-level summary suitable for board presentation, focusing on strategic implications and ROI metrics'
+
+# Poor prompt
+'aiHint=write a summary'
+```
+
+### Advanced Prompt Techniques
+
+#### 1. Role-Based Prompts
+
+```bash
+'aiHint=Acting as a senior financial analyst, review the quarterly data and provide insights on revenue trends, cost optimization opportunities, and market positioning recommendations'
+```
+
+#### 2. Structured Output Prompts
+
+```bash
+'aiHint=Generate a risk assessment with three sections: 1) High-priority risks with mitigation strategies, 2) Medium-priority risks with monitoring plans, 3) Risk summary and overall assessment'
+```
+
+#### 3. Data-Driven Prompts
+
+```bash
+'aiHint=Based on the attached sales data, calculate month-over-month growth rates, identify top-performing products, and recommend strategies for underperforming segments'
+```
+
+## Best Practices
+
+### File Preparation
+
+#### Excel/Spreadsheet Files
+
+- **Clean Data**: Remove empty rows, merged cells, and formatting inconsistencies
+- **Clear Headers**: Use descriptive column headers in the first row
+- **Consistent Formatting**: Use consistent date formats, number formats, and text casing
+- **Specific Sheets**: Select the most relevant sheet containing the target data
+
+#### Document Files
+
+- **Clear Structure**: Use headings, bullet points, and logical organization
+- **Relevant Content**: Include only content relevant to the AI task
+- **Text Format**: Ensure text is selectable (not embedded images)
+- **File Size**: Keep files under 25MB for optimal processing
+
+### Performance Optimization
+
+#### Efficient File Usage
+
+```bash
+# Good: Specific sheet selection
+'fileResourceMetadata={"uuid":{"selectedSheet":"Revenue Data","dataRange":"A1:E100"}}'
+
+# Poor: Processing entire workbook
+'fileResourceMetadata={"uuid":{"hasMultipleSheets":true}}'
+```
+
+#### Smart Prompting
+
+```bash
+# Good: Specific, actionable prompt
+'aiHint=Extract the top 5 revenue-generating products from the sales data and provide a brief analysis of their performance trends'
+
+# Poor: Vague prompt
+'aiHint=tell me about the sales'
+```
+
+### Error Handling
+
+#### File Processing Errors
+
+- **Check File Format**: Ensure files are in supported formats
+- **Verify File Size**: Keep attachments under the size limit
+- **Test File Access**: Ensure files are not corrupted or password-protected
+
+#### AI Generation Errors
+
+- **Simplify Prompts**: Break complex requests into smaller, specific tasks
+- **Provide Context**: Include relevant background information in prompts
+- **Iterate and Refine**: Test prompts and refine based on output quality
+
+### Security Considerations
+
+#### Data Privacy
+
+- **Sensitive Information**: Review files for confidential data before upload
+- **Access Controls**: Ensure proper API token management and access restrictions
+- **Data Retention**: Understand how uploaded files are processed and stored
+
+#### API Security
+
+- **Token Protection**: Store API tokens securely in environment variables
+- **HTTPS Only**: Always use HTTPS for API communication
+- **Rate Limiting**: Implement appropriate rate limiting for production use
+
+## Error Handling & Troubleshooting
+
+### Common HTTP Status Codes
+
+| Status Code | Description | Solution |
+| ----------- | --------------------- | ----------------------------------------------------------- |
+| `200` | Success | Request completed successfully |
+| `400` | Bad Request | Check request format, file attachments, and required fields |
+| `401` | Unauthorized | Verify API token and authentication headers |
+| `403` | Forbidden | Check organization ID and API permissions |
+| `413` | Payload Too Large | Reduce file size or compress attachments |
+| `422` | Unprocessable Entity | Validate AI prompt, file metadata, and parameters |
+| `429` | Too Many Requests | Implement rate limiting and retry logic |
+| `500` | Internal Server Error | Contact support if persistent |
+
+### Common Issues
+
+#### File Upload Problems
+
+**Symptoms**: Files not processing or upload errors
+
+**Solutions**:
+
+- Verify file format is supported (Excel, Word, PDF, etc.)
+- Check file size is under 25MB
+- Ensure file is not corrupted or password-protected
+- Validate file metadata JSON format
+
+#### AI Generation Quality Issues
+
+**Symptoms**: Generated content is not relevant or useful
+
+**Solutions**:
+
+- Provide more specific and detailed AI prompts
+- Include relevant context in the aiHint parameter
+- Use templateId for additional context
+- Break complex requests into smaller, focused tasks
+
+#### Context Recognition Problems
+
+**Symptoms**: AI not understanding file content correctly
+
+**Solutions**:
+
+- Use selectedSheet parameter for Excel files
+- Specify relevant data ranges in file metadata
+- Ensure file content is clearly structured
+- Provide additional context in AI prompts
+
+### Debugging Tips
+
+1. **Start Simple**: Test with basic prompts before adding complexity
+2. **Validate Files**: Ensure uploaded files are properly formatted and accessible
+3. **Check Metadata**: Verify file metadata JSON is properly structured
+4. **Monitor Responses**: Review mimeType and content format in responses
+5. **Iterate Prompts**: Refine AI hints based on output quality
+
+## Integration Patterns
+
+### Template Workflow Integration
+
+Combine AI variable generation with template processing for complete automation:
+
+```javascript
+// 1. Generate AI content
+const aiResponse = await generateAIVariable({
+ file: "financial-data.xlsx",
+ aiHint: "Generate Q4 performance summary",
+ richText: true,
+});
+
+// 2. Use in template generation
+const templateData = {
+ templateId: "quarterly-report-template",
+ variables: [
+ {
+ name: "Q4 Performance",
+ placeholder: "{Q4Performance}",
+ text: aiResponse.data.text,
+ mimeType: aiResponse.data.mimeType,
+ },
+ ],
+};
+
+// 3. Generate final document
+const deliverable = await generateDeliverable(templateData);
+```
+
+### Batch Processing Pattern
+
+Process multiple variables with AI for comprehensive content generation:
+
+```javascript
+const aiVariables = [
+ { name: "Executive Summary", hint: "Create executive summary" },
+ { name: "Financial Analysis", hint: "Analyze financial metrics" },
+ { name: "Market Insights", hint: "Generate market insights" },
+];
+
+const generatedContent = await Promise.all(
+ aiVariables.map((variable) =>
+ generateAIVariable({
+ file: "company-data.xlsx",
+ aiHint: variable.hint,
+ name: variable.name,
+ })
+ )
+);
+```
+
+## Next Steps
+
+### Advanced AI Features to Explore
+
+📖 **[Template Generation API →](/docs/TurboDocx%20Templating/API%20Templates)**
+📖 **[Webhook Integration →](/docs/Webhooks/webhook-configuration)**
+📖 **[Bulk Processing →](/docs/Templates/bulk-generation)**
+📖 **[API Authentication →](/docs/API/turbodocx-api-documentation)**
+
+### Related Documentation
+
+- [Template Management Guide](/docs/Templates/template-management)
+- [Variable Types and Formatting](/docs/Templates/variable-types)
+- [Integration Examples](/docs/Integrations)
+- [Best Practices Guide](/docs/Templates/best-practices)
+
+## Support
+
+Need help with AI-powered variable generation? We're here to help:
+
+- **Discord Community**: [Join our Discord server](https://discord.gg/NYKwz4BcpX) for real-time support
+- **Documentation**: [https://docs.turbodocx.com](https://docs.turbodocx.com)
+- **AI Examples**: Browse our example gallery for inspiration
+
+---
+
+Ready to revolutionize your document workflows with AI-powered content generation? Start creating intelligent, context-aware variables that transform how you build documents! 🤖✨
diff --git a/static/img/template-generation-api/banner.gif b/static/img/template-generation-api/banner.gif
new file mode 100644
index 0000000..c67ac30
Binary files /dev/null and b/static/img/template-generation-api/banner.gif differ
diff --git a/static/img/template-generation-api/options.png b/static/img/template-generation-api/options.png
new file mode 100644
index 0000000..8552456
Binary files /dev/null and b/static/img/template-generation-api/options.png differ
diff --git a/static/scripts/ai/variable-generation/curl.sh b/static/scripts/ai/variable-generation/curl.sh
new file mode 100644
index 0000000..ffb3a21
--- /dev/null
+++ b/static/scripts/ai/variable-generation/curl.sh
@@ -0,0 +1,103 @@
+#!/bin/bash
+
+# Configuration - Update these values
+API_TOKEN="YOUR_API_TOKEN"
+ORG_ID="YOUR_ORGANIZATION_ID"
+BASE_URL="https://api.turbodocx.com"
+
+##
+# AI-Powered Variable Generation Examples
+# Generate intelligent content for template variables using AI with optional file attachments
+##
+
+# Example 1: Basic AI Variable Generation (no file attachment)
+echo "=== Example 1: Basic AI Variable Generation ==="
+curl "${BASE_URL}/ai/generate/variable/one" \
+ -H "Authorization: Bearer ${API_TOKEN}" \
+ -H "x-rapiddocx-org-id: ${ORG_ID}" \
+ -H "User-Agent: TurboDocx AI Client" \
+ -H "Content-Type: multipart/form-data" \
+ -F "name=Company Overview" \
+ -F "placeholder={CompanyOverview}" \
+ -F "aiHint=Generate a professional company overview for a technology consulting firm specializing in digital transformation" \
+ -F "richTextEnabled=false"
+
+echo -e "\n=== Example 2: AI Generation with Excel File Attachment ==="
+# Example 2: AI Variable Generation with Excel File
+curl "${BASE_URL}/ai/generate/variable/one" \
+ -H "Authorization: Bearer ${API_TOKEN}" \
+ -H "x-rapiddocx-org-id: ${ORG_ID}" \
+ -H "User-Agent: TurboDocx AI Client" \
+ -H "Content-Type: multipart/form-data" \
+ -F "FileResource-e0f12963-10ff-496a-9703-06df14f171af=@financial-report.xlsx" \
+ -F "fileResourceMetadata={\"e0f12963-10ff-496a-9703-06df14f171af\":{\"selectedSheet\":\"Q4 Results\",\"hasMultipleSheets\":true,\"dataRange\":\"A1:F50\"}}" \
+ -F "name=Financial Performance Summary" \
+ -F "placeholder={FinancialSummary}" \
+ -F "templateId=quarterly-report-template-123" \
+ -F "aiHint=Analyze the Q4 financial data and generate a comprehensive executive summary highlighting revenue growth, profit margins, and key performance indicators" \
+ -F "richTextEnabled=true"
+
+echo -e "\n=== Example 3: AI Generation with Word Document ==="
+# Example 3: AI Variable Generation with Word Document
+curl "${BASE_URL}/ai/generate/variable/one" \
+ -H "Authorization: Bearer ${API_TOKEN}" \
+ -H "x-rapiddocx-org-id: ${ORG_ID}" \
+ -H "User-Agent: TurboDocx AI Client" \
+ -H "Content-Type: multipart/form-data" \
+ -F "FileResource-abc12345-def6-789a-bcde-123456789abc=@project-requirements.docx" \
+ -F "fileResourceMetadata={\"abc12345-def6-789a-bcde-123456789abc\":{\"contentType\":\"project-document\"}}" \
+ -F "name=Project Scope" \
+ -F "placeholder={ProjectScope}" \
+ -F "templateId=project-proposal-template-456" \
+ -F "aiHint=Based on the project requirements document, create a detailed project scope including objectives, deliverables, timeline, and success criteria" \
+ -F "richTextEnabled=true"
+
+echo -e "\n=== Example 4: Contract Analysis ==="
+# Example 4: Legal Document Analysis
+curl "${BASE_URL}/ai/generate/variable/one" \
+ -H "Authorization: Bearer ${API_TOKEN}" \
+ -H "x-rapiddocx-org-id: ${ORG_ID}" \
+ -H "User-Agent: TurboDocx AI Client" \
+ -H "Content-Type: multipart/form-data" \
+ -F "FileResource-legal123-456a-789b-cdef-987654321abc=@service-agreement.pdf" \
+ -F "fileResourceMetadata={\"legal123-456a-789b-cdef-987654321abc\":{\"contentType\":\"legal-document\"}}" \
+ -F "name=Contract Key Terms" \
+ -F "placeholder={KeyTerms}" \
+ -F "aiHint=Extract and summarize the key terms, payment obligations, contract duration, and important deadlines from this service agreement" \
+ -F "richTextEnabled=false"
+
+echo -e "\n=== Example 5: Rich Text Generation ==="
+# Example 5: Rich Text Content Generation
+curl "${BASE_URL}/ai/generate/variable/one" \
+ -H "Authorization: Bearer ${API_TOKEN}" \
+ -H "x-rapiddocx-org-id: ${ORG_ID}" \
+ -H "User-Agent: TurboDocx AI Client" \
+ -H "Content-Type: multipart/form-data" \
+ -F "name=Marketing Campaign Summary" \
+ -F "placeholder={CampaignSummary}" \
+ -F "templateId=marketing-report-template-789" \
+ -F "aiHint=Create a comprehensive marketing campaign summary with bullet points for key metrics, formatted sections for strategy overview, and highlighted call-to-action recommendations" \
+ -F "richTextEnabled=true"
+
+echo -e "\n=== Example 6: Data Analysis with CSV ==="
+# Example 6: CSV Data Analysis
+curl "${BASE_URL}/ai/generate/variable/one" \
+ -H "Authorization: Bearer ${API_TOKEN}" \
+ -H "x-rapiddocx-org-id: ${ORG_ID}" \
+ -H "User-Agent: TurboDocx AI Client" \
+ -H "Content-Type: multipart/form-data" \
+ -F "FileResource-data789-abc1-2345-6def-abcdef123456=@sales-data.csv" \
+ -F "fileResourceMetadata={\"data789-abc1-2345-6def-abcdef123456\":{\"contentType\":\"sales-data\",\"hasHeaders\":true}}" \
+ -F "name=Sales Performance Analysis" \
+ -F "placeholder={SalesAnalysis}" \
+ -F "aiHint=Analyze the sales data to identify top-performing products, seasonal trends, and growth opportunities. Provide actionable insights for sales strategy" \
+ -F "richTextEnabled=true"
+
+echo -e "\n=== AI Variable Generation Examples Complete ==="
+echo "All examples demonstrate different aspects of AI-powered variable generation:"
+echo "1. Basic text generation without file attachments"
+echo "2. Excel spreadsheet analysis with sheet selection"
+echo "3. Word document content extraction"
+echo "4. Legal document term extraction"
+echo "5. Rich text formatting for presentation"
+echo "6. CSV data analysis and insights"
\ No newline at end of file
diff --git a/static/scripts/ai/variable-generation/javascript.js b/static/scripts/ai/variable-generation/javascript.js
new file mode 100644
index 0000000..3b3bca8
--- /dev/null
+++ b/static/scripts/ai/variable-generation/javascript.js
@@ -0,0 +1,364 @@
+/**
+ * AI-Powered Variable Generation - JavaScript Examples
+ * Generate intelligent content for template variables using AI with file attachments
+ */
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+/**
+ * Generate AI-powered variable content with optional file attachment
+ */
+async function generateAIVariable(options) {
+ const {
+ file,
+ fileMetadata,
+ name,
+ placeholder,
+ templateId,
+ aiHint,
+ richTextEnabled = false
+ } = options;
+
+ // Create FormData for multipart request
+ const formData = new FormData();
+
+ // Add file if provided
+ if (file) {
+ const fileUuid = generateUUID();
+ formData.append(`FileResource-${fileUuid}`, file);
+
+ // Add file metadata
+ const metadata = {
+ [fileUuid]: {
+ selectedSheet: fileMetadata?.selectedSheet || "Sheet1",
+ hasMultipleSheets: fileMetadata?.hasMultipleSheets || false,
+ contentType: fileMetadata?.contentType || "document",
+ dataRange: fileMetadata?.dataRange
+ }
+ };
+ formData.append('fileResourceMetadata', JSON.stringify(metadata));
+ }
+
+ // Add variable parameters
+ formData.append('name', name);
+ formData.append('placeholder', placeholder);
+ formData.append('aiHint', aiHint);
+ formData.append('richTextEnabled', richTextEnabled.toString());
+
+ if (templateId) {
+ formData.append('templateId', templateId);
+ }
+
+ try {
+ const response = await fetch(`${BASE_URL}/ai/generate/variable/one`, {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx AI Client'
+ },
+ body: formData
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error ${response.status}: ${response.statusText}`);
+ }
+
+ const result = await response.json();
+
+ console.log('✅ AI Variable generated successfully!');
+ console.log(`Variable: ${name}`);
+ console.log(`Content Type: ${result.data.mimeType}`);
+ console.log(`Generated Content: ${result.data.text.substring(0, 100)}...`);
+
+ return result;
+
+ } catch (error) {
+ console.error('❌ AI Variable generation failed:', error.message);
+ throw error;
+ }
+}
+
+/**
+ * Generate UUID for file resource identification
+ */
+function generateUUID() {
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+ const r = Math.random() * 16 | 0;
+ const v = c == 'x' ? r : (r & 0x3 | 0x8);
+ return v.toString(16);
+ });
+}
+
+/**
+ * Example 1: Basic AI Variable Generation (no file)
+ */
+async function example1_BasicGeneration() {
+ console.log('=== Example 1: Basic AI Variable Generation ===');
+
+ try {
+ const result = await generateAIVariable({
+ name: 'Company Overview',
+ placeholder: '{CompanyOverview}',
+ aiHint: 'Generate a professional company overview for a technology consulting firm specializing in digital transformation and cloud solutions',
+ richTextEnabled: false
+ });
+
+ console.log('Generated content:', result.data.text);
+ return result;
+
+ } catch (error) {
+ console.error('Example 1 failed:', error.message);
+ }
+}
+
+/**
+ * Example 2: Excel File Analysis
+ */
+async function example2_ExcelAnalysis(excelFile) {
+ console.log('=== Example 2: Excel File Analysis ===');
+
+ try {
+ const result = await generateAIVariable({
+ file: excelFile,
+ fileMetadata: {
+ selectedSheet: 'Q4 Results',
+ hasMultipleSheets: true,
+ dataRange: 'A1:F50',
+ contentType: 'financial-data'
+ },
+ name: 'Financial Performance Summary',
+ placeholder: '{FinancialSummary}',
+ templateId: 'quarterly-report-template-123',
+ aiHint: 'Analyze the Q4 financial data and generate a comprehensive executive summary highlighting revenue growth, profit margins, key performance indicators, and strategic recommendations',
+ richTextEnabled: true
+ });
+
+ console.log('Financial analysis generated:', result.data.text);
+ return result;
+
+ } catch (error) {
+ console.error('Example 2 failed:', error.message);
+ }
+}
+
+/**
+ * Example 3: Word Document Processing
+ */
+async function example3_DocumentAnalysis(wordFile) {
+ console.log('=== Example 3: Word Document Analysis ===');
+
+ try {
+ const result = await generateAIVariable({
+ file: wordFile,
+ fileMetadata: {
+ contentType: 'project-document'
+ },
+ name: 'Project Scope',
+ placeholder: '{ProjectScope}',
+ templateId: 'project-proposal-template-456',
+ aiHint: 'Based on the project requirements document, create a detailed project scope including objectives, key deliverables, timeline milestones, and success criteria',
+ richTextEnabled: true
+ });
+
+ console.log('Project scope generated:', result.data.text);
+ return result;
+
+ } catch (error) {
+ console.error('Example 3 failed:', error.message);
+ }
+}
+
+/**
+ * Example 4: Legal Document Analysis
+ */
+async function example4_LegalAnalysis(pdfFile) {
+ console.log('=== Example 4: Legal Document Analysis ===');
+
+ try {
+ const result = await generateAIVariable({
+ file: pdfFile,
+ fileMetadata: {
+ contentType: 'legal-document'
+ },
+ name: 'Contract Key Terms',
+ placeholder: '{KeyTerms}',
+ aiHint: 'Extract and summarize the key terms, payment obligations, contract duration, termination clauses, and important deadlines from this service agreement',
+ richTextEnabled: false
+ });
+
+ console.log('Contract analysis generated:', result.data.text);
+ return result;
+
+ } catch (error) {
+ console.error('Example 4 failed:', error.message);
+ }
+}
+
+/**
+ * Example 5: Rich Text Content Generation
+ */
+async function example5_RichTextGeneration() {
+ console.log('=== Example 5: Rich Text Content Generation ===');
+
+ try {
+ const result = await generateAIVariable({
+ name: 'Marketing Campaign Summary',
+ placeholder: '{CampaignSummary}',
+ templateId: 'marketing-report-template-789',
+ aiHint: 'Create a comprehensive marketing campaign summary with structured sections: Executive Overview, Key Metrics (with specific numbers), Strategic Insights, and Action Items. Format with appropriate headings and bullet points.',
+ richTextEnabled: true
+ });
+
+ console.log('Rich text content generated:', result.data.text);
+ return result;
+
+ } catch (error) {
+ console.error('Example 5 failed:', error.message);
+ }
+}
+
+/**
+ * Example 6: Batch AI Variable Generation
+ */
+async function example6_BatchGeneration(dataFile) {
+ console.log('=== Example 6: Batch AI Variable Generation ===');
+
+ const variables = [
+ {
+ name: 'Executive Summary',
+ placeholder: '{ExecutiveSummary}',
+ aiHint: 'Create a high-level executive summary focusing on strategic outcomes and business impact'
+ },
+ {
+ name: 'Key Metrics',
+ placeholder: '{KeyMetrics}',
+ aiHint: 'Extract and present the most important quantitative metrics and KPIs'
+ },
+ {
+ name: 'Recommendations',
+ placeholder: '{Recommendations}',
+ aiHint: 'Provide actionable recommendations based on data analysis and insights'
+ }
+ ];
+
+ try {
+ const results = await Promise.all(
+ variables.map(variable => generateAIVariable({
+ file: dataFile,
+ fileMetadata: {
+ contentType: 'business-data',
+ hasHeaders: true
+ },
+ name: variable.name,
+ placeholder: variable.placeholder,
+ aiHint: variable.aiHint,
+ richTextEnabled: true
+ }))
+ );
+
+ console.log('Batch generation completed successfully!');
+ results.forEach((result, index) => {
+ console.log(`${variables[index].name}: ${result.data.text.substring(0, 100)}...`);
+ });
+
+ return results;
+
+ } catch (error) {
+ console.error('Example 6 failed:', error.message);
+ }
+}
+
+/**
+ * File Upload Helper
+ */
+function handleFileUpload(inputId, callback) {
+ const fileInput = document.getElementById(inputId);
+
+ fileInput.addEventListener('change', (event) => {
+ const file = event.target.files[0];
+ if (file) {
+ console.log(`File selected: ${file.name} (${file.size} bytes)`);
+ callback(file);
+ }
+ });
+}
+
+/**
+ * Complete Workflow Integration Example
+ */
+async function completeWorkflowExample(sourceFile) {
+ console.log('=== Complete Workflow: AI + Template Generation ===');
+
+ try {
+ // Step 1: Generate AI content
+ const aiResult = await generateAIVariable({
+ file: sourceFile,
+ fileMetadata: {
+ selectedSheet: 'Data',
+ hasMultipleSheets: true
+ },
+ name: 'Business Analysis',
+ placeholder: '{BusinessAnalysis}',
+ aiHint: 'Generate a comprehensive business analysis including market trends, performance metrics, and strategic recommendations',
+ richTextEnabled: true
+ });
+
+ console.log('AI content generated successfully');
+
+ // Step 2: Use AI content in template (example integration)
+ const templateVariables = [
+ {
+ name: 'Business Analysis',
+ placeholder: '{BusinessAnalysis}',
+ text: aiResult.data.text,
+ mimeType: aiResult.data.mimeType,
+ allowRichTextInjection: aiResult.data.mimeType === 'html' ? 1 : 0
+ }
+ ];
+
+ console.log('Template variables prepared with AI content');
+
+ // Note: This would integrate with the Template Generation API
+ // for complete document creation workflow
+
+ return {
+ aiContent: aiResult,
+ templateVariables: templateVariables
+ };
+
+ } catch (error) {
+ console.error('Complete workflow failed:', error.message);
+ throw error;
+ }
+}
+
+// Example usage and demonstrations
+if (typeof window !== 'undefined') {
+ // Browser environment
+ console.log('🤖 AI Variable Generation Examples Loaded');
+ console.log('Available functions:');
+ console.log('- example1_BasicGeneration()');
+ console.log('- example2_ExcelAnalysis(file)');
+ console.log('- example3_DocumentAnalysis(file)');
+ console.log('- example4_LegalAnalysis(file)');
+ console.log('- example5_RichTextGeneration()');
+ console.log('- example6_BatchGeneration(file)');
+ console.log('- completeWorkflowExample(file)');
+
+} else {
+ // Node.js environment
+ module.exports = {
+ generateAIVariable,
+ example1_BasicGeneration,
+ example2_ExcelAnalysis,
+ example3_DocumentAnalysis,
+ example4_LegalAnalysis,
+ example5_RichTextGeneration,
+ example6_BatchGeneration,
+ completeWorkflowExample
+ };
+}
\ No newline at end of file
diff --git a/static/scripts/ai/variable-generation/nodejs/express.js b/static/scripts/ai/variable-generation/nodejs/express.js
new file mode 100644
index 0000000..41f8bde
--- /dev/null
+++ b/static/scripts/ai/variable-generation/nodejs/express.js
@@ -0,0 +1,395 @@
+const express = require('express');
+const multer = require('multer');
+const FormData = require('form-data');
+const axios = require('axios');
+const fs = require('fs');
+const { v4: uuidv4 } = require('uuid');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+const app = express();
+const upload = multer({ dest: 'uploads/' });
+
+// Middleware
+app.use(express.json());
+app.use(express.static('public'));
+
+/**
+ * AI-Powered Variable Generation Service
+ */
+class AIVariableService {
+ constructor(apiToken, orgId, baseUrl = BASE_URL) {
+ this.apiToken = apiToken;
+ this.orgId = orgId;
+ this.baseUrl = baseUrl;
+ }
+
+ /**
+ * Generate AI-powered variable content with optional file attachment
+ */
+ async generateVariable(options) {
+ const {
+ file,
+ fileMetadata,
+ name,
+ placeholder,
+ templateId,
+ aiHint,
+ richTextEnabled = false
+ } = options;
+
+ const form = new FormData();
+
+ // Add file if provided
+ if (file) {
+ const fileUuid = uuidv4();
+ form.append(`FileResource-${fileUuid}`, fs.createReadStream(file.path), {
+ filename: file.originalname,
+ contentType: this.getContentType(file.originalname)
+ });
+
+ // Add file metadata
+ const metadata = {
+ [fileUuid]: {
+ selectedSheet: fileMetadata?.selectedSheet || "Sheet1",
+ hasMultipleSheets: fileMetadata?.hasMultipleSheets || false,
+ contentType: fileMetadata?.contentType || "document",
+ dataRange: fileMetadata?.dataRange,
+ hasHeaders: fileMetadata?.hasHeaders
+ }
+ };
+ form.append('fileResourceMetadata', JSON.stringify(metadata));
+ }
+
+ // Add variable parameters
+ form.append('name', name);
+ form.append('placeholder', placeholder);
+ form.append('aiHint', aiHint);
+ form.append('richTextEnabled', richTextEnabled.toString());
+
+ if (templateId) {
+ form.append('templateId', templateId);
+ }
+
+ try {
+ console.log(`Generating AI variable: ${name}`);
+ console.log(`AI Hint: ${aiHint.substring(0, 100)}...`);
+
+ const response = await axios.post(`${this.baseUrl}/ai/generate/variable/one`, form, {
+ headers: {
+ 'Authorization': `Bearer ${this.apiToken}`,
+ 'x-rapiddocx-org-id': this.orgId,
+ 'User-Agent': 'TurboDocx AI Client',
+ ...form.getHeaders()
+ }
+ });
+
+ console.log('✅ AI Variable generated successfully!');
+ console.log(`Content Type: ${response.data.data.mimeType}`);
+ console.log(`Generated Content: ${response.data.data.text.substring(0, 100)}...`);
+
+ // Clean up uploaded file
+ if (file && fs.existsSync(file.path)) {
+ fs.unlinkSync(file.path);
+ }
+
+ return response.data;
+
+ } catch (error) {
+ console.error('❌ AI Variable generation failed:', error.response?.data || error.message);
+
+ // Clean up on error
+ if (file && fs.existsSync(file.path)) {
+ fs.unlinkSync(file.path);
+ }
+
+ throw error;
+ }
+ }
+
+ /**
+ * Get content type based on file extension
+ */
+ getContentType(filename) {
+ const ext = filename.toLowerCase().split('.').pop();
+ const contentTypes = {
+ 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xls': 'application/vnd.ms-excel',
+ 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'doc': 'application/msword',
+ 'pdf': 'application/pdf',
+ 'csv': 'text/csv',
+ 'txt': 'text/plain',
+ 'png': 'image/png',
+ 'jpg': 'image/jpeg',
+ 'jpeg': 'image/jpeg'
+ };
+ return contentTypes[ext] || 'application/octet-stream';
+ }
+}
+
+// Initialize service
+const aiService = new AIVariableService(API_TOKEN, ORG_ID);
+
+// Routes
+
+/**
+ * Generate AI variable without file attachment
+ */
+app.post('/ai/generate-basic', async (req, res) => {
+ try {
+ const { name, placeholder, aiHint, templateId, richTextEnabled } = req.body;
+
+ if (!name || !placeholder || !aiHint) {
+ return res.status(400).json({
+ error: 'Missing required fields: name, placeholder, aiHint'
+ });
+ }
+
+ const result = await aiService.generateVariable({
+ name,
+ placeholder,
+ aiHint,
+ templateId,
+ richTextEnabled: richTextEnabled === 'true' || richTextEnabled === true
+ });
+
+ res.json({
+ success: true,
+ message: 'AI variable generated successfully',
+ data: result
+ });
+
+ } catch (error) {
+ console.error('Error in basic generation:', error);
+ res.status(500).json({
+ error: 'AI variable generation failed',
+ message: error.message
+ });
+ }
+});
+
+/**
+ * Generate AI variable with file attachment
+ */
+app.post('/ai/generate-with-file', upload.single('file'), async (req, res) => {
+ try {
+ const { name, placeholder, aiHint, templateId, richTextEnabled } = req.body;
+ const file = req.file;
+
+ if (!name || !placeholder || !aiHint) {
+ return res.status(400).json({
+ error: 'Missing required fields: name, placeholder, aiHint'
+ });
+ }
+
+ // Parse file metadata if provided
+ let fileMetadata = {};
+ if (req.body.fileMetadata) {
+ try {
+ fileMetadata = JSON.parse(req.body.fileMetadata);
+ } catch (e) {
+ console.warn('Invalid file metadata JSON, using defaults');
+ }
+ }
+
+ const result = await aiService.generateVariable({
+ file,
+ fileMetadata,
+ name,
+ placeholder,
+ aiHint,
+ templateId,
+ richTextEnabled: richTextEnabled === 'true' || richTextEnabled === true
+ });
+
+ res.json({
+ success: true,
+ message: 'AI variable generated successfully with file',
+ data: result
+ });
+
+ } catch (error) {
+ console.error('Error in file-based generation:', error);
+ res.status(500).json({
+ error: 'AI variable generation with file failed',
+ message: error.message
+ });
+ }
+});
+
+/**
+ * Batch AI variable generation
+ */
+app.post('/ai/generate-batch', upload.single('file'), async (req, res) => {
+ try {
+ const { variables } = req.body;
+ const file = req.file;
+
+ if (!variables) {
+ return res.status(400).json({
+ error: 'Missing variables array'
+ });
+ }
+
+ const variableList = JSON.parse(variables);
+
+ // Parse file metadata if provided
+ let fileMetadata = {};
+ if (req.body.fileMetadata) {
+ try {
+ fileMetadata = JSON.parse(req.body.fileMetadata);
+ } catch (e) {
+ console.warn('Invalid file metadata JSON, using defaults');
+ }
+ }
+
+ const results = [];
+ for (const variable of variableList) {
+ try {
+ const result = await aiService.generateVariable({
+ file: file ? { ...file, path: file.path } : null,
+ fileMetadata,
+ name: variable.name,
+ placeholder: variable.placeholder,
+ aiHint: variable.aiHint,
+ templateId: variable.templateId,
+ richTextEnabled: variable.richTextEnabled || false
+ });
+ results.push({ success: true, variable: variable.name, data: result });
+ } catch (error) {
+ results.push({ success: false, variable: variable.name, error: error.message });
+ }
+ }
+
+ res.json({
+ success: true,
+ message: 'Batch AI variable generation completed',
+ results: results
+ });
+
+ } catch (error) {
+ console.error('Error in batch generation:', error);
+ res.status(500).json({
+ error: 'Batch AI variable generation failed',
+ message: error.message
+ });
+ }
+});
+
+/**
+ * Health check endpoint
+ */
+app.get('/health', (req, res) => {
+ res.json({
+ status: 'healthy',
+ service: 'ai-variable-generation',
+ timestamp: new Date().toISOString()
+ });
+});
+
+/**
+ * Service information endpoint
+ */
+app.get('/ai/info', (req, res) => {
+ res.json({
+ service: 'TurboDocx AI Variable Generation Service',
+ endpoints: {
+ 'POST /ai/generate-basic': 'Generate AI variable without file attachment',
+ 'POST /ai/generate-with-file': 'Generate AI variable with file attachment',
+ 'POST /ai/generate-batch': 'Batch generate multiple AI variables',
+ 'GET /health': 'Service health check',
+ 'GET /ai/info': 'Service information'
+ },
+ configuration: {
+ baseUrl: BASE_URL,
+ hasToken: !!API_TOKEN && API_TOKEN !== 'YOUR_API_TOKEN',
+ hasOrgId: !!ORG_ID && ORG_ID !== 'YOUR_ORGANIZATION_ID'
+ },
+ supportedFileTypes: [
+ 'Excel (.xlsx, .xls)',
+ 'Word (.docx, .doc)',
+ 'PDF (.pdf)',
+ 'CSV (.csv)',
+ 'Text (.txt)',
+ 'Images (.png, .jpg, .jpeg)'
+ ]
+ });
+});
+
+/**
+ * Example usage endpoint
+ */
+app.get('/ai/examples', (req, res) => {
+ res.json({
+ examples: [
+ {
+ name: 'Basic Generation',
+ endpoint: 'POST /ai/generate-basic',
+ payload: {
+ name: 'Company Overview',
+ placeholder: '{CompanyOverview}',
+ aiHint: 'Generate a professional company overview for a technology consulting firm',
+ richTextEnabled: false
+ }
+ },
+ {
+ name: 'Excel Analysis',
+ endpoint: 'POST /ai/generate-with-file',
+ payload: {
+ name: 'Financial Summary',
+ placeholder: '{FinancialSummary}',
+ aiHint: 'Analyze Q4 financial data and generate executive summary',
+ fileMetadata: JSON.stringify({
+ selectedSheet: 'Q4 Results',
+ hasMultipleSheets: true
+ }),
+ richTextEnabled: true
+ },
+ note: 'Include Excel file in multipart form data'
+ },
+ {
+ name: 'Document Analysis',
+ endpoint: 'POST /ai/generate-with-file',
+ payload: {
+ name: 'Project Scope',
+ placeholder: '{ProjectScope}',
+ aiHint: 'Extract project scope from requirements document',
+ fileMetadata: JSON.stringify({
+ contentType: 'project-document'
+ }),
+ richTextEnabled: true
+ },
+ note: 'Include Word/PDF file in multipart form data'
+ }
+ ]
+ });
+});
+
+// Error handling middleware
+app.use((error, req, res, next) => {
+ console.error('Unhandled error:', error);
+ res.status(500).json({
+ error: 'Internal server error',
+ message: error.message
+ });
+});
+
+// Start server
+const PORT = process.env.PORT || 3001;
+app.listen(PORT, () => {
+ console.log('🤖 TurboDocx AI Variable Generation Service started');
+ console.log(`📡 Server listening on http://localhost:${PORT}`);
+ console.log('\nAvailable endpoints:');
+ console.log(` POST http://localhost:${PORT}/ai/generate-basic`);
+ console.log(` POST http://localhost:${PORT}/ai/generate-with-file`);
+ console.log(` POST http://localhost:${PORT}/ai/generate-batch`);
+ console.log(` GET http://localhost:${PORT}/health`);
+ console.log(` GET http://localhost:${PORT}/ai/info`);
+ console.log(` GET http://localhost:${PORT}/ai/examples`);
+});
+
+module.exports = app;
\ No newline at end of file
diff --git a/static/scripts/ai/variable-generation/nodejs/fastify.js b/static/scripts/ai/variable-generation/nodejs/fastify.js
new file mode 100644
index 0000000..8ee590a
--- /dev/null
+++ b/static/scripts/ai/variable-generation/nodejs/fastify.js
@@ -0,0 +1,571 @@
+const fastify = require('fastify')({ logger: true });
+const FormData = require('form-data');
+const axios = require('axios');
+const fs = require('fs');
+const { v4: uuidv4 } = require('uuid');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+/**
+ * AI-Powered Variable Generation Service
+ */
+class AIVariableService {
+ constructor(apiToken, orgId, baseUrl = BASE_URL) {
+ this.apiToken = apiToken;
+ this.orgId = orgId;
+ this.baseUrl = baseUrl;
+ }
+
+ /**
+ * Generate AI-powered variable content with optional file attachment
+ */
+ async generateVariable(options) {
+ const {
+ file,
+ fileMetadata,
+ name,
+ placeholder,
+ templateId,
+ aiHint,
+ richTextEnabled = false
+ } = options;
+
+ const form = new FormData();
+
+ // Add file if provided
+ if (file) {
+ const fileUuid = uuidv4();
+ const fileBuffer = await file.toBuffer();
+
+ form.append(`FileResource-${fileUuid}`, fileBuffer, {
+ filename: file.filename,
+ contentType: this.getContentType(file.filename)
+ });
+
+ // Add file metadata
+ const metadata = {
+ [fileUuid]: {
+ selectedSheet: fileMetadata?.selectedSheet || "Sheet1",
+ hasMultipleSheets: fileMetadata?.hasMultipleSheets || false,
+ contentType: fileMetadata?.contentType || "document",
+ dataRange: fileMetadata?.dataRange,
+ hasHeaders: fileMetadata?.hasHeaders
+ }
+ };
+ form.append('fileResourceMetadata', JSON.stringify(metadata));
+ }
+
+ // Add variable parameters
+ form.append('name', name);
+ form.append('placeholder', placeholder);
+ form.append('aiHint', aiHint);
+ form.append('richTextEnabled', richTextEnabled.toString());
+
+ if (templateId) {
+ form.append('templateId', templateId);
+ }
+
+ try {
+ console.log(`Generating AI variable: ${name}`);
+ console.log(`AI Hint: ${aiHint.substring(0, 100)}...`);
+
+ const response = await axios.post(`${this.baseUrl}/ai/generate/variable/one`, form, {
+ headers: {
+ 'Authorization': `Bearer ${this.apiToken}`,
+ 'x-rapiddocx-org-id': this.orgId,
+ 'User-Agent': 'TurboDocx AI Client',
+ ...form.getHeaders()
+ }
+ });
+
+ console.log('✅ AI Variable generated successfully!');
+ console.log(`Content Type: ${response.data.data.mimeType}`);
+ console.log(`Generated Content: ${response.data.data.text.substring(0, 100)}...`);
+
+ return response.data;
+
+ } catch (error) {
+ console.error('❌ AI Variable generation failed:', error.response?.data || error.message);
+ throw error;
+ }
+ }
+
+ /**
+ * Get content type based on file extension
+ */
+ getContentType(filename) {
+ const ext = filename.toLowerCase().split('.').pop();
+ const contentTypes = {
+ 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xls': 'application/vnd.ms-excel',
+ 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'doc': 'application/msword',
+ 'pdf': 'application/pdf',
+ 'csv': 'text/csv',
+ 'txt': 'text/plain',
+ 'png': 'image/png',
+ 'jpg': 'image/jpeg',
+ 'jpeg': 'image/jpeg'
+ };
+ return contentTypes[ext] || 'application/octet-stream';
+ }
+}
+
+// Initialize service
+const aiService = new AIVariableService(API_TOKEN, ORG_ID);
+
+// Register multipart content parsing
+fastify.register(require('@fastify/multipart'));
+
+// Routes
+
+/**
+ * Generate AI variable without file attachment
+ */
+fastify.post('/ai/generate-basic', async (request, reply) => {
+ try {
+ const { name, placeholder, aiHint, templateId, richTextEnabled } = request.body;
+
+ if (!name || !placeholder || !aiHint) {
+ return reply.code(400).send({
+ error: 'Missing required fields: name, placeholder, aiHint'
+ });
+ }
+
+ const result = await aiService.generateVariable({
+ name,
+ placeholder,
+ aiHint,
+ templateId,
+ richTextEnabled: richTextEnabled === 'true' || richTextEnabled === true
+ });
+
+ reply.send({
+ success: true,
+ message: 'AI variable generated successfully',
+ data: result
+ });
+
+ } catch (error) {
+ fastify.log.error('Error in basic generation:', error);
+ reply.code(500).send({
+ error: 'AI variable generation failed',
+ message: error.message
+ });
+ }
+});
+
+/**
+ * Generate AI variable with file attachment
+ */
+fastify.post('/ai/generate-with-file', async (request, reply) => {
+ try {
+ const parts = request.parts();
+ let file = null;
+ let fileMetadata = {};
+ let name, placeholder, aiHint, templateId, richTextEnabled;
+
+ // Process multipart data
+ for await (const part of parts) {
+ if (part.file) {
+ file = part;
+ } else {
+ const value = part.value;
+ switch (part.fieldname) {
+ case 'name':
+ name = value;
+ break;
+ case 'placeholder':
+ placeholder = value;
+ break;
+ case 'aiHint':
+ aiHint = value;
+ break;
+ case 'templateId':
+ templateId = value;
+ break;
+ case 'richTextEnabled':
+ richTextEnabled = value;
+ break;
+ case 'fileMetadata':
+ try {
+ fileMetadata = JSON.parse(value);
+ } catch (e) {
+ fastify.log.warn('Invalid file metadata JSON, using defaults');
+ }
+ break;
+ }
+ }
+ }
+
+ if (!name || !placeholder || !aiHint) {
+ return reply.code(400).send({
+ error: 'Missing required fields: name, placeholder, aiHint'
+ });
+ }
+
+ const result = await aiService.generateVariable({
+ file,
+ fileMetadata,
+ name,
+ placeholder,
+ aiHint,
+ templateId,
+ richTextEnabled: richTextEnabled === 'true' || richTextEnabled === true
+ });
+
+ reply.send({
+ success: true,
+ message: 'AI variable generated successfully with file',
+ data: result
+ });
+
+ } catch (error) {
+ fastify.log.error('Error in file-based generation:', error);
+ reply.code(500).send({
+ error: 'AI variable generation with file failed',
+ message: error.message
+ });
+ }
+});
+
+/**
+ * Batch AI variable generation
+ */
+fastify.post('/ai/generate-batch', async (request, reply) => {
+ try {
+ const parts = request.parts();
+ let file = null;
+ let fileMetadata = {};
+ let variables;
+
+ // Process multipart data
+ for await (const part of parts) {
+ if (part.file) {
+ file = part;
+ } else {
+ const value = part.value;
+ switch (part.fieldname) {
+ case 'variables':
+ try {
+ variables = JSON.parse(value);
+ } catch (e) {
+ return reply.code(400).send({
+ error: 'Invalid variables JSON format'
+ });
+ }
+ break;
+ case 'fileMetadata':
+ try {
+ fileMetadata = JSON.parse(value);
+ } catch (e) {
+ fastify.log.warn('Invalid file metadata JSON, using defaults');
+ }
+ break;
+ }
+ }
+ }
+
+ if (!variables || !Array.isArray(variables)) {
+ return reply.code(400).send({
+ error: 'Missing or invalid variables array'
+ });
+ }
+
+ const results = [];
+ for (const variable of variables) {
+ try {
+ const result = await aiService.generateVariable({
+ file,
+ fileMetadata,
+ name: variable.name,
+ placeholder: variable.placeholder,
+ aiHint: variable.aiHint,
+ templateId: variable.templateId,
+ richTextEnabled: variable.richTextEnabled || false
+ });
+ results.push({ success: true, variable: variable.name, data: result });
+ } catch (error) {
+ results.push({ success: false, variable: variable.name, error: error.message });
+ }
+ }
+
+ reply.send({
+ success: true,
+ message: 'Batch AI variable generation completed',
+ results: results
+ });
+
+ } catch (error) {
+ fastify.log.error('Error in batch generation:', error);
+ reply.code(500).send({
+ error: 'Batch AI variable generation failed',
+ message: error.message
+ });
+ }
+});
+
+/**
+ * Complete workflow: AI generation + template integration
+ */
+fastify.post('/ai/complete-workflow', async (request, reply) => {
+ try {
+ const parts = request.parts();
+ let file = null;
+ let fileMetadata = {};
+ let templateId, aiHint, variableName, placeholder;
+
+ // Process multipart data
+ for await (const part of parts) {
+ if (part.file) {
+ file = part;
+ } else {
+ const value = part.value;
+ switch (part.fieldname) {
+ case 'templateId':
+ templateId = value;
+ break;
+ case 'aiHint':
+ aiHint = value;
+ break;
+ case 'variableName':
+ variableName = value;
+ break;
+ case 'placeholder':
+ placeholder = value;
+ break;
+ case 'fileMetadata':
+ try {
+ fileMetadata = JSON.parse(value);
+ } catch (e) {
+ fastify.log.warn('Invalid file metadata JSON, using defaults');
+ }
+ break;
+ }
+ }
+ }
+
+ if (!variableName || !placeholder || !aiHint) {
+ return reply.code(400).send({
+ error: 'Missing required fields: variableName, placeholder, aiHint'
+ });
+ }
+
+ // Step 1: Generate AI content
+ const aiResult = await aiService.generateVariable({
+ file,
+ fileMetadata,
+ name: variableName,
+ placeholder,
+ aiHint,
+ templateId,
+ richTextEnabled: true
+ });
+
+ // Step 2: Prepare template variables
+ const templateVariables = [{
+ name: variableName,
+ placeholder: placeholder,
+ text: aiResult.data.text,
+ mimeType: aiResult.data.mimeType,
+ allowRichTextInjection: aiResult.data.mimeType === 'html' ? 1 : 0
+ }];
+
+ reply.send({
+ success: true,
+ message: 'Complete AI workflow executed successfully',
+ data: {
+ aiContent: aiResult,
+ templateVariables: templateVariables,
+ summary: {
+ variableName: variableName,
+ contentType: aiResult.data.mimeType,
+ contentLength: aiResult.data.text.length
+ }
+ }
+ });
+
+ } catch (error) {
+ fastify.log.error('Error in complete workflow:', error);
+ reply.code(500).send({
+ error: 'Complete AI workflow failed',
+ message: error.message
+ });
+ }
+});
+
+/**
+ * Health check endpoint
+ */
+fastify.get('/health', async (request, reply) => {
+ reply.send({
+ status: 'healthy',
+ service: 'ai-variable-generation',
+ timestamp: new Date().toISOString()
+ });
+});
+
+/**
+ * Service information endpoint
+ */
+fastify.get('/ai/info', async (request, reply) => {
+ reply.send({
+ service: 'TurboDocx AI Variable Generation Service (Fastify)',
+ endpoints: {
+ 'POST /ai/generate-basic': 'Generate AI variable without file attachment',
+ 'POST /ai/generate-with-file': 'Generate AI variable with file attachment',
+ 'POST /ai/generate-batch': 'Batch generate multiple AI variables',
+ 'POST /ai/complete-workflow': 'Complete AI generation and template integration',
+ 'GET /health': 'Service health check',
+ 'GET /ai/info': 'Service information',
+ 'GET /ai/examples': 'Usage examples'
+ },
+ configuration: {
+ baseUrl: BASE_URL,
+ hasToken: !!API_TOKEN && API_TOKEN !== 'YOUR_API_TOKEN',
+ hasOrgId: !!ORG_ID && ORG_ID !== 'YOUR_ORGANIZATION_ID'
+ },
+ supportedFileTypes: [
+ 'Excel (.xlsx, .xls)',
+ 'Word (.docx, .doc)',
+ 'PDF (.pdf)',
+ 'CSV (.csv)',
+ 'Text (.txt)',
+ 'Images (.png, .jpg, .jpeg)'
+ ]
+ });
+});
+
+/**
+ * Example usage endpoint
+ */
+fastify.get('/ai/examples', async (request, reply) => {
+ reply.send({
+ examples: [
+ {
+ name: 'Basic Generation',
+ endpoint: 'POST /ai/generate-basic',
+ payload: {
+ name: 'Company Overview',
+ placeholder: '{CompanyOverview}',
+ aiHint: 'Generate a professional company overview for a technology consulting firm',
+ richTextEnabled: false
+ }
+ },
+ {
+ name: 'Excel Analysis',
+ endpoint: 'POST /ai/generate-with-file',
+ description: 'Upload Excel file with form data fields',
+ formFields: {
+ name: 'Financial Summary',
+ placeholder: '{FinancialSummary}',
+ aiHint: 'Analyze Q4 financial data and generate executive summary',
+ fileMetadata: '{"selectedSheet":"Q4 Results","hasMultipleSheets":true}',
+ richTextEnabled: 'true',
+ file: '[Excel file binary data]'
+ }
+ },
+ {
+ name: 'Batch Generation',
+ endpoint: 'POST /ai/generate-batch',
+ description: 'Generate multiple variables from single file',
+ formFields: {
+ variables: JSON.stringify([
+ {
+ name: 'Executive Summary',
+ placeholder: '{ExecutiveSummary}',
+ aiHint: 'Create high-level executive summary'
+ },
+ {
+ name: 'Key Metrics',
+ placeholder: '{KeyMetrics}',
+ aiHint: 'Extract important KPIs and metrics'
+ }
+ ]),
+ fileMetadata: '{"contentType":"business-data"}',
+ file: '[Data file binary data]'
+ }
+ },
+ {
+ name: 'Complete Workflow',
+ endpoint: 'POST /ai/complete-workflow',
+ description: 'AI generation with template integration',
+ formFields: {
+ variableName: 'Business Analysis',
+ placeholder: '{BusinessAnalysis}',
+ aiHint: 'Generate comprehensive business analysis with recommendations',
+ templateId: 'template-123',
+ fileMetadata: '{"selectedSheet":"Data"}',
+ file: '[Business data file]'
+ }
+ }
+ ],
+ curlExamples: [
+ {
+ name: 'Basic Generation',
+ curl: `curl -X POST http://localhost:3001/ai/generate-basic \\
+ -H "Content-Type: application/json" \\
+ -d '{
+ "name": "Company Overview",
+ "placeholder": "{CompanyOverview}",
+ "aiHint": "Generate a professional company overview",
+ "richTextEnabled": false
+ }'`
+ },
+ {
+ name: 'File Upload',
+ curl: `curl -X POST http://localhost:3001/ai/generate-with-file \\
+ -F "name=Financial Summary" \\
+ -F "placeholder={FinancialSummary}" \\
+ -F "aiHint=Analyze financial data" \\
+ -F "richTextEnabled=true" \\
+ -F "fileMetadata={\\"selectedSheet\\":\\"Q4 Results\\"}" \\
+ -F "file=@financial-data.xlsx"`
+ }
+ ]
+ });
+});
+
+// Error handler
+fastify.setErrorHandler((error, request, reply) => {
+ fastify.log.error(error);
+ reply.status(500).send({
+ error: 'Internal server error',
+ message: error.message
+ });
+});
+
+// Start server
+const start = async () => {
+ try {
+ const port = process.env.PORT || 3001;
+ const host = process.env.HOST || '0.0.0.0';
+
+ await fastify.listen({ port, host });
+
+ console.log('🤖 TurboDocx AI Variable Generation Service (Fastify) started');
+ console.log(`📡 Server listening on http://${host}:${port}`);
+ console.log('\nAvailable endpoints:');
+ console.log(` POST http://${host}:${port}/ai/generate-basic`);
+ console.log(` POST http://${host}:${port}/ai/generate-with-file`);
+ console.log(` POST http://${host}:${port}/ai/generate-batch`);
+ console.log(` POST http://${host}:${port}/ai/complete-workflow`);
+ console.log(` GET http://${host}:${port}/health`);
+ console.log(` GET http://${host}:${port}/ai/info`);
+ console.log(` GET http://${host}:${port}/ai/examples`);
+
+ } catch (err) {
+ fastify.log.error(err);
+ process.exit(1);
+ }
+};
+
+// Check if this file is being run directly
+if (require.main === module) {
+ start();
+}
+
+module.exports = fastify;
\ No newline at end of file
diff --git a/static/scripts/ai/variable-generation/python/flask.py b/static/scripts/ai/variable-generation/python/flask.py
new file mode 100644
index 0000000..a5574ea
--- /dev/null
+++ b/static/scripts/ai/variable-generation/python/flask.py
@@ -0,0 +1,546 @@
+#!/usr/bin/env python3
+
+import os
+import requests
+import json
+import uuid
+from flask import Flask, request, jsonify
+from werkzeug.utils import secure_filename
+from pathlib import Path
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+app = Flask(__name__)
+app.config['MAX_CONTENT_LENGTH'] = 25 * 1024 * 1024 # 25MB max file size
+
+class AIVariableService:
+ """AI-Powered Variable Generation Service"""
+
+ def __init__(self, api_token: str, org_id: str, base_url: str = BASE_URL):
+ self.api_token = api_token
+ self.org_id = org_id
+ self.base_url = base_url
+
+ def generate_variable(self, **kwargs):
+ """Generate AI-powered variable content with optional file attachment"""
+
+ file_path = kwargs.get('file_path')
+ file_metadata = kwargs.get('file_metadata', {})
+ name = kwargs.get('name')
+ placeholder = kwargs.get('placeholder')
+ template_id = kwargs.get('template_id')
+ ai_hint = kwargs.get('ai_hint')
+ rich_text_enabled = kwargs.get('rich_text_enabled', False)
+
+ url = f"{self.base_url}/ai/generate/variable/one"
+
+ # Prepare headers
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx AI Client (Flask)'
+ }
+
+ # Prepare form data
+ data = {
+ 'name': name,
+ 'placeholder': placeholder,
+ 'aiHint': ai_hint,
+ 'richTextEnabled': str(rich_text_enabled).lower()
+ }
+
+ if template_id:
+ data['templateId'] = template_id
+
+ files = {}
+
+ # Handle file attachment
+ if file_path and os.path.exists(file_path):
+ file_uuid = str(uuid.uuid4())
+ file_path_obj = Path(file_path)
+
+ # Open file for upload
+ files[f'FileResource-{file_uuid}'] = (
+ file_path_obj.name,
+ open(file_path_obj, 'rb'),
+ self._get_content_type(file_path_obj)
+ )
+
+ # Prepare file metadata
+ default_metadata = {
+ file_uuid: {
+ 'contentType': 'document',
+ 'hasMultipleSheets': False
+ }
+ }
+
+ default_metadata[file_uuid].update(file_metadata)
+ data['fileResourceMetadata'] = json.dumps(default_metadata)
+
+ try:
+ print(f"Generating AI variable: {name}")
+ print(f"AI Hint: {ai_hint[:100]}...")
+
+ response = requests.post(url, headers=headers, data=data, files=files)
+ response.raise_for_status()
+
+ result = response.json()
+
+ print("✅ AI Variable generated successfully!")
+ print(f"Content Type: {result['data']['mimeType']}")
+ print(f"Generated Content: {result['data']['text'][:100]}...")
+
+ return result
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"AI Variable generation failed: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(f"❌ {error_msg}")
+ raise
+
+ finally:
+ # Close file handles
+ for file_handle in files.values():
+ if hasattr(file_handle[1], 'close'):
+ file_handle[1].close()
+
+ def _get_content_type(self, file_path: Path) -> str:
+ """Get appropriate content type based on file extension"""
+ extension = file_path.suffix.lower()
+ content_types = {
+ '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ '.xls': 'application/vnd.ms-excel',
+ '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ '.doc': 'application/msword',
+ '.pdf': 'application/pdf',
+ '.csv': 'text/csv',
+ '.txt': 'text/plain',
+ '.png': 'image/png',
+ '.jpg': 'image/jpeg',
+ '.jpeg': 'image/jpeg'
+ }
+ return content_types.get(extension, 'application/octet-stream')
+
+# Initialize service
+ai_service = AIVariableService(API_TOKEN, ORG_ID)
+
+# Routes
+
+@app.route('/ai/generate-basic', methods=['POST'])
+def generate_basic():
+ """Generate AI variable without file attachment"""
+ try:
+ data = request.get_json()
+
+ if not data:
+ return jsonify({'error': 'JSON payload required'}), 400
+
+ required_fields = ['name', 'placeholder', 'aiHint']
+ missing_fields = [field for field in required_fields if not data.get(field)]
+
+ if missing_fields:
+ return jsonify({
+ 'error': f'Missing required fields: {", ".join(missing_fields)}'
+ }), 400
+
+ result = ai_service.generate_variable(
+ name=data['name'],
+ placeholder=data['placeholder'],
+ ai_hint=data['aiHint'],
+ template_id=data.get('templateId'),
+ rich_text_enabled=data.get('richTextEnabled', False)
+ )
+
+ return jsonify({
+ 'success': True,
+ 'message': 'AI variable generated successfully',
+ 'data': result
+ })
+
+ except Exception as e:
+ app.logger.error(f'Error in basic generation: {str(e)}')
+ return jsonify({
+ 'error': 'AI variable generation failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/ai/generate-with-file', methods=['POST'])
+def generate_with_file():
+ """Generate AI variable with file attachment"""
+ try:
+ # Check for required form fields
+ required_fields = ['name', 'placeholder', 'aiHint']
+ missing_fields = [field for field in required_fields if not request.form.get(field)]
+
+ if missing_fields:
+ return jsonify({
+ 'error': f'Missing required fields: {", ".join(missing_fields)}'
+ }), 400
+
+ # Handle file upload
+ file_path = None
+ if 'file' in request.files:
+ file = request.files['file']
+ if file.filename:
+ filename = secure_filename(file.filename)
+ file_path = os.path.join('/tmp', filename)
+ file.save(file_path)
+
+ # Parse file metadata
+ file_metadata = {}
+ if request.form.get('fileMetadata'):
+ try:
+ file_metadata = json.loads(request.form.get('fileMetadata'))
+ except json.JSONDecodeError:
+ app.logger.warning('Invalid file metadata JSON, using defaults')
+
+ result = ai_service.generate_variable(
+ file_path=file_path,
+ file_metadata=file_metadata,
+ name=request.form['name'],
+ placeholder=request.form['placeholder'],
+ ai_hint=request.form['aiHint'],
+ template_id=request.form.get('templateId'),
+ rich_text_enabled=request.form.get('richTextEnabled', 'false').lower() == 'true'
+ )
+
+ # Clean up uploaded file
+ if file_path and os.path.exists(file_path):
+ os.remove(file_path)
+
+ return jsonify({
+ 'success': True,
+ 'message': 'AI variable generated successfully with file',
+ 'data': result
+ })
+
+ except Exception as e:
+ # Clean up on error
+ if 'file_path' in locals() and file_path and os.path.exists(file_path):
+ os.remove(file_path)
+
+ app.logger.error(f'Error in file-based generation: {str(e)}')
+ return jsonify({
+ 'error': 'AI variable generation with file failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/ai/generate-batch', methods=['POST'])
+def generate_batch():
+ """Batch generate multiple AI variables"""
+ try:
+ # Parse variables from form or JSON
+ if request.content_type and 'application/json' in request.content_type:
+ data = request.get_json()
+ variables = data.get('variables', [])
+ file_path = None
+ else:
+ variables_json = request.form.get('variables')
+ if not variables_json:
+ return jsonify({'error': 'Missing variables field'}), 400
+
+ try:
+ variables = json.loads(variables_json)
+ except json.JSONDecodeError:
+ return jsonify({'error': 'Invalid variables JSON format'}), 400
+
+ # Handle file upload
+ file_path = None
+ if 'file' in request.files:
+ file = request.files['file']
+ if file.filename:
+ filename = secure_filename(file.filename)
+ file_path = os.path.join('/tmp', filename)
+ file.save(file_path)
+
+ if not isinstance(variables, list):
+ return jsonify({'error': 'Variables must be an array'}), 400
+
+ # Parse file metadata
+ file_metadata = {}
+ metadata_str = request.form.get('fileMetadata') if request.form else None
+ if metadata_str:
+ try:
+ file_metadata = json.loads(metadata_str)
+ except json.JSONDecodeError:
+ app.logger.warning('Invalid file metadata JSON, using defaults')
+
+ results = []
+ for variable in variables:
+ try:
+ result = ai_service.generate_variable(
+ file_path=file_path,
+ file_metadata=file_metadata,
+ name=variable.get('name'),
+ placeholder=variable.get('placeholder'),
+ ai_hint=variable.get('aiHint'),
+ template_id=variable.get('templateId'),
+ rich_text_enabled=variable.get('richTextEnabled', False)
+ )
+ results.append({
+ 'success': True,
+ 'variable': variable.get('name'),
+ 'data': result
+ })
+ except Exception as e:
+ results.append({
+ 'success': False,
+ 'variable': variable.get('name'),
+ 'error': str(e)
+ })
+
+ # Clean up uploaded file
+ if file_path and os.path.exists(file_path):
+ os.remove(file_path)
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Batch AI variable generation completed',
+ 'results': results
+ })
+
+ except Exception as e:
+ # Clean up on error
+ if 'file_path' in locals() and file_path and os.path.exists(file_path):
+ os.remove(file_path)
+
+ app.logger.error(f'Error in batch generation: {str(e)}')
+ return jsonify({
+ 'error': 'Batch AI variable generation failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/ai/complete-workflow', methods=['POST'])
+def complete_workflow():
+ """Complete AI generation and template integration workflow"""
+ try:
+ # Check for required form fields
+ required_fields = ['variableName', 'placeholder', 'aiHint']
+ missing_fields = [field for field in required_fields if not request.form.get(field)]
+
+ if missing_fields:
+ return jsonify({
+ 'error': f'Missing required fields: {", ".join(missing_fields)}'
+ }), 400
+
+ # Handle file upload
+ file_path = None
+ if 'file' in request.files:
+ file = request.files['file']
+ if file.filename:
+ filename = secure_filename(file.filename)
+ file_path = os.path.join('/tmp', filename)
+ file.save(file_path)
+
+ # Parse file metadata
+ file_metadata = {}
+ if request.form.get('fileMetadata'):
+ try:
+ file_metadata = json.loads(request.form.get('fileMetadata'))
+ except json.JSONDecodeError:
+ app.logger.warning('Invalid file metadata JSON, using defaults')
+
+ # Step 1: Generate AI content
+ ai_result = ai_service.generate_variable(
+ file_path=file_path,
+ file_metadata=file_metadata,
+ name=request.form['variableName'],
+ placeholder=request.form['placeholder'],
+ ai_hint=request.form['aiHint'],
+ template_id=request.form.get('templateId'),
+ rich_text_enabled=True
+ )
+
+ # Step 2: Prepare template variables
+ template_variables = [{
+ 'name': request.form['variableName'],
+ 'placeholder': request.form['placeholder'],
+ 'text': ai_result['data']['text'],
+ 'mimeType': ai_result['data']['mimeType'],
+ 'allowRichTextInjection': 1 if ai_result['data']['mimeType'] == 'html' else 0
+ }]
+
+ # Clean up uploaded file
+ if file_path and os.path.exists(file_path):
+ os.remove(file_path)
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Complete AI workflow executed successfully',
+ 'data': {
+ 'aiContent': ai_result,
+ 'templateVariables': template_variables,
+ 'summary': {
+ 'variableName': request.form['variableName'],
+ 'contentType': ai_result['data']['mimeType'],
+ 'contentLength': len(ai_result['data']['text'])
+ }
+ }
+ })
+
+ except Exception as e:
+ # Clean up on error
+ if 'file_path' in locals() and file_path and os.path.exists(file_path):
+ os.remove(file_path)
+
+ app.logger.error(f'Error in complete workflow: {str(e)}')
+ return jsonify({
+ 'error': 'Complete AI workflow failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/health', methods=['GET'])
+def health_check():
+ """Health check endpoint"""
+ return jsonify({
+ 'status': 'healthy',
+ 'service': 'ai-variable-generation-flask',
+ 'timestamp': app.logger.handlers[0].formatter.formatTime(None) if app.logger.handlers else None
+ })
+
+@app.route('/ai/info', methods=['GET'])
+def service_info():
+ """Service information endpoint"""
+ return jsonify({
+ 'service': 'TurboDocx AI Variable Generation Service (Flask)',
+ 'endpoints': {
+ 'POST /ai/generate-basic': 'Generate AI variable without file attachment',
+ 'POST /ai/generate-with-file': 'Generate AI variable with file attachment',
+ 'POST /ai/generate-batch': 'Batch generate multiple AI variables',
+ 'POST /ai/complete-workflow': 'Complete AI generation and template integration',
+ 'GET /health': 'Service health check',
+ 'GET /ai/info': 'Service information',
+ 'GET /ai/examples': 'Usage examples'
+ },
+ 'configuration': {
+ 'baseUrl': BASE_URL,
+ 'hasToken': bool(API_TOKEN and API_TOKEN != 'YOUR_API_TOKEN'),
+ 'hasOrgId': bool(ORG_ID and ORG_ID != 'YOUR_ORGANIZATION_ID'),
+ 'maxFileSize': '25MB'
+ },
+ 'supportedFileTypes': [
+ 'Excel (.xlsx, .xls)',
+ 'Word (.docx, .doc)',
+ 'PDF (.pdf)',
+ 'CSV (.csv)',
+ 'Text (.txt)',
+ 'Images (.png, .jpg, .jpeg)'
+ ]
+ })
+
+@app.route('/ai/examples', methods=['GET'])
+def usage_examples():
+ """Usage examples endpoint"""
+ return jsonify({
+ 'examples': [
+ {
+ 'name': 'Basic Generation',
+ 'endpoint': 'POST /ai/generate-basic',
+ 'contentType': 'application/json',
+ 'payload': {
+ 'name': 'Company Overview',
+ 'placeholder': '{CompanyOverview}',
+ 'aiHint': 'Generate a professional company overview for a technology consulting firm',
+ 'richTextEnabled': False
+ }
+ },
+ {
+ 'name': 'Excel Analysis',
+ 'endpoint': 'POST /ai/generate-with-file',
+ 'contentType': 'multipart/form-data',
+ 'formFields': {
+ 'name': 'Financial Summary',
+ 'placeholder': '{FinancialSummary}',
+ 'aiHint': 'Analyze Q4 financial data and generate executive summary',
+ 'fileMetadata': '{"selectedSheet":"Q4 Results","hasMultipleSheets":true}',
+ 'richTextEnabled': 'true',
+ 'file': '[Excel file upload]'
+ }
+ },
+ {
+ 'name': 'Batch Generation',
+ 'endpoint': 'POST /ai/generate-batch',
+ 'contentType': 'multipart/form-data',
+ 'formFields': {
+ 'variables': json.dumps([
+ {
+ 'name': 'Executive Summary',
+ 'placeholder': '{ExecutiveSummary}',
+ 'aiHint': 'Create high-level executive summary'
+ },
+ {
+ 'name': 'Key Metrics',
+ 'placeholder': '{KeyMetrics}',
+ 'aiHint': 'Extract important KPIs and metrics'
+ }
+ ]),
+ 'fileMetadata': '{"contentType":"business-data"}',
+ 'file': '[Data file upload]'
+ }
+ }
+ ],
+ 'curlExamples': [
+ {
+ 'name': 'Basic Generation',
+ 'curl': '''curl -X POST http://localhost:5001/ai/generate-basic \\
+ -H "Content-Type: application/json" \\
+ -d '{
+ "name": "Company Overview",
+ "placeholder": "{CompanyOverview}",
+ "aiHint": "Generate a professional company overview",
+ "richTextEnabled": false
+ }\'
+'''
+ },
+ {
+ 'name': 'File Upload',
+ 'curl': '''curl -X POST http://localhost:5001/ai/generate-with-file \\
+ -F "name=Financial Summary" \\
+ -F "placeholder={FinancialSummary}" \\
+ -F "aiHint=Analyze financial data and create summary" \\
+ -F "richTextEnabled=true" \\
+ -F "fileMetadata={\\"selectedSheet\\":\\"Q4 Results\\"}" \\
+ -F "file=@financial-data.xlsx"'''
+ }
+ ]
+ })
+
+# Error handlers
+@app.errorhandler(413)
+def file_too_large(e):
+ return jsonify({
+ 'error': 'File too large',
+ 'message': 'Maximum file size is 25MB'
+ }), 413
+
+@app.errorhandler(500)
+def internal_error(e):
+ return jsonify({
+ 'error': 'Internal server error',
+ 'message': str(e)
+ }), 500
+
+if __name__ == '__main__':
+ port = int(os.environ.get('PORT', 5001))
+ host = os.environ.get('HOST', '0.0.0.0')
+
+ print('🤖 TurboDocx AI Variable Generation Service (Flask) started')
+ print(f'📡 Server listening on http://{host}:{port}')
+ print('\nAvailable endpoints:')
+ print(f' POST http://{host}:{port}/ai/generate-basic')
+ print(f' POST http://{host}:{port}/ai/generate-with-file')
+ print(f' POST http://{host}:{port}/ai/generate-batch')
+ print(f' POST http://{host}:{port}/ai/complete-workflow')
+ print(f' GET http://{host}:{port}/health')
+ print(f' GET http://{host}:{port}/ai/info')
+ print(f' GET http://{host}:{port}/ai/examples')
+
+ app.run(host=host, port=port, debug=False)
\ No newline at end of file
diff --git a/static/scripts/ai/variable-generation/python/requests.py b/static/scripts/ai/variable-generation/python/requests.py
new file mode 100644
index 0000000..94d3246
--- /dev/null
+++ b/static/scripts/ai/variable-generation/python/requests.py
@@ -0,0 +1,378 @@
+#!/usr/bin/env python3
+
+import requests
+import json
+import uuid
+from pathlib import Path
+from typing import Optional, Dict, Any, Union
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+class AIVariableGenerator:
+ """
+ AI-Powered Variable Generation Client
+ Generate intelligent content for template variables using AI with file attachments
+ """
+
+ def __init__(self, api_token: str, org_id: str, base_url: str = BASE_URL):
+ self.api_token = api_token
+ self.org_id = org_id
+ self.base_url = base_url
+
+ def generate_variable(
+ self,
+ name: str,
+ placeholder: str,
+ ai_hint: str,
+ file_path: Optional[str] = None,
+ file_metadata: Optional[Dict[str, Any]] = None,
+ template_id: Optional[str] = None,
+ rich_text_enabled: bool = False
+ ) -> Dict[str, Any]:
+ """
+ Generate AI-powered variable content with optional file attachment
+
+ Args:
+ name: Variable display name
+ placeholder: Template placeholder (e.g., '{VariableName}')
+ ai_hint: Instructions for AI content generation
+ file_path: Path to file for AI analysis (optional)
+ file_metadata: File-specific metadata (optional)
+ template_id: Template ID for context (optional)
+ rich_text_enabled: Enable HTML/rich text output
+
+ Returns:
+ Dict containing generated content and metadata
+ """
+ url = f"{self.base_url}/ai/generate/variable/one"
+
+ # Prepare headers
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx AI Client'
+ }
+
+ # Prepare form data
+ data = {
+ 'name': name,
+ 'placeholder': placeholder,
+ 'aiHint': ai_hint,
+ 'richTextEnabled': str(rich_text_enabled).lower()
+ }
+
+ if template_id:
+ data['templateId'] = template_id
+
+ files = {}
+
+ # Handle file attachment
+ if file_path:
+ file_uuid = str(uuid.uuid4())
+ file_path_obj = Path(file_path)
+
+ if not file_path_obj.exists():
+ raise FileNotFoundError(f"File not found: {file_path}")
+
+ # Open file for upload
+ files[f'FileResource-{file_uuid}'] = (
+ file_path_obj.name,
+ open(file_path_obj, 'rb'),
+ self._get_content_type(file_path_obj)
+ )
+
+ # Prepare file metadata
+ default_metadata = {
+ file_uuid: {
+ 'contentType': 'document',
+ 'hasMultipleSheets': False
+ }
+ }
+
+ if file_metadata:
+ default_metadata[file_uuid].update(file_metadata)
+
+ data['fileResourceMetadata'] = json.dumps(default_metadata)
+
+ try:
+ print(f"Generating AI variable: {name}")
+ print(f"AI Hint: {ai_hint[:100]}...")
+
+ response = requests.post(url, headers=headers, data=data, files=files)
+ response.raise_for_status()
+
+ result = response.json()
+
+ print("✅ AI Variable generated successfully!")
+ print(f"Content Type: {result['data']['mimeType']}")
+ print(f"Generated Content: {result['data']['text'][:100]}...")
+
+ return result
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"AI Variable generation failed: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(f"❌ {error_msg}")
+ raise
+
+ finally:
+ # Close file handles
+ for file_handle in files.values():
+ if hasattr(file_handle[1], 'close'):
+ file_handle[1].close()
+
+ def _get_content_type(self, file_path: Path) -> str:
+ """Get appropriate content type based on file extension"""
+ extension = file_path.suffix.lower()
+ content_types = {
+ '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ '.xls': 'application/vnd.ms-excel',
+ '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ '.doc': 'application/msword',
+ '.pdf': 'application/pdf',
+ '.csv': 'text/csv',
+ '.txt': 'text/plain',
+ '.png': 'image/png',
+ '.jpg': 'image/jpeg',
+ '.jpeg': 'image/jpeg'
+ }
+ return content_types.get(extension, 'application/octet-stream')
+
+def example1_basic_generation():
+ """Example 1: Basic AI Variable Generation (no file)"""
+ print('=== Example 1: Basic AI Variable Generation ===')
+
+ generator = AIVariableGenerator(API_TOKEN, ORG_ID)
+
+ try:
+ result = generator.generate_variable(
+ name='Company Overview',
+ placeholder='{CompanyOverview}',
+ ai_hint='Generate a professional company overview for a technology consulting firm specializing in digital transformation and cloud solutions',
+ rich_text_enabled=False
+ )
+
+ print(f"Generated content: {result['data']['text']}")
+ return result
+
+ except Exception as e:
+ print(f"Example 1 failed: {str(e)}")
+
+def example2_excel_analysis(file_path: str):
+ """Example 2: Excel File Analysis"""
+ print('=== Example 2: Excel File Analysis ===')
+
+ generator = AIVariableGenerator(API_TOKEN, ORG_ID)
+
+ try:
+ result = generator.generate_variable(
+ name='Financial Performance Summary',
+ placeholder='{FinancialSummary}',
+ ai_hint='Analyze the Q4 financial data and generate a comprehensive executive summary highlighting revenue growth, profit margins, key performance indicators, and strategic recommendations',
+ file_path=file_path,
+ file_metadata={
+ 'selectedSheet': 'Q4 Results',
+ 'hasMultipleSheets': True,
+ 'dataRange': 'A1:F50',
+ 'contentType': 'financial-data'
+ },
+ template_id='quarterly-report-template-123',
+ rich_text_enabled=True
+ )
+
+ print(f"Financial analysis: {result['data']['text']}")
+ return result
+
+ except Exception as e:
+ print(f"Example 2 failed: {str(e)}")
+
+def example3_document_analysis(file_path: str):
+ """Example 3: Word Document Analysis"""
+ print('=== Example 3: Word Document Analysis ===')
+
+ generator = AIVariableGenerator(API_TOKEN, ORG_ID)
+
+ try:
+ result = generator.generate_variable(
+ name='Project Scope',
+ placeholder='{ProjectScope}',
+ ai_hint='Based on the project requirements document, create a detailed project scope including objectives, key deliverables, timeline milestones, and success criteria',
+ file_path=file_path,
+ file_metadata={
+ 'contentType': 'project-document'
+ },
+ template_id='project-proposal-template-456',
+ rich_text_enabled=True
+ )
+
+ print(f"Project scope: {result['data']['text']}")
+ return result
+
+ except Exception as e:
+ print(f"Example 3 failed: {str(e)}")
+
+def example4_legal_analysis(file_path: str):
+ """Example 4: Legal Document Analysis"""
+ print('=== Example 4: Legal Document Analysis ===')
+
+ generator = AIVariableGenerator(API_TOKEN, ORG_ID)
+
+ try:
+ result = generator.generate_variable(
+ name='Contract Key Terms',
+ placeholder='{KeyTerms}',
+ ai_hint='Extract and summarize the key terms, payment obligations, contract duration, termination clauses, and important deadlines from this service agreement',
+ file_path=file_path,
+ file_metadata={
+ 'contentType': 'legal-document'
+ },
+ rich_text_enabled=False
+ )
+
+ print(f"Contract analysis: {result['data']['text']}")
+ return result
+
+ except Exception as e:
+ print(f"Example 4 failed: {str(e)}")
+
+def example5_rich_text_generation():
+ """Example 5: Rich Text Content Generation"""
+ print('=== Example 5: Rich Text Content Generation ===')
+
+ generator = AIVariableGenerator(API_TOKEN, ORG_ID)
+
+ try:
+ result = generator.generate_variable(
+ name='Marketing Campaign Summary',
+ placeholder='{CampaignSummary}',
+ ai_hint='Create a comprehensive marketing campaign summary with structured sections: Executive Overview, Key Metrics (with specific numbers), Strategic Insights, and Action Items. Format with appropriate headings and bullet points.',
+ template_id='marketing-report-template-789',
+ rich_text_enabled=True
+ )
+
+ print(f"Rich text content: {result['data']['text']}")
+ return result
+
+ except Exception as e:
+ print(f"Example 5 failed: {str(e)}")
+
+def example6_batch_generation(file_path: str):
+ """Example 6: Batch AI Variable Generation"""
+ print('=== Example 6: Batch AI Variable Generation ===')
+
+ generator = AIVariableGenerator(API_TOKEN, ORG_ID)
+
+ variables = [
+ {
+ 'name': 'Executive Summary',
+ 'placeholder': '{ExecutiveSummary}',
+ 'ai_hint': 'Create a high-level executive summary focusing on strategic outcomes and business impact'
+ },
+ {
+ 'name': 'Key Metrics',
+ 'placeholder': '{KeyMetrics}',
+ 'ai_hint': 'Extract and present the most important quantitative metrics and KPIs'
+ },
+ {
+ 'name': 'Recommendations',
+ 'placeholder': '{Recommendations}',
+ 'ai_hint': 'Provide actionable recommendations based on data analysis and insights'
+ }
+ ]
+
+ try:
+ results = []
+ for variable in variables:
+ result = generator.generate_variable(
+ name=variable['name'],
+ placeholder=variable['placeholder'],
+ ai_hint=variable['ai_hint'],
+ file_path=file_path,
+ file_metadata={
+ 'contentType': 'business-data',
+ 'hasHeaders': True
+ },
+ rich_text_enabled=True
+ )
+ results.append(result)
+
+ print('Batch generation completed successfully!')
+ for i, result in enumerate(results):
+ print(f"{variables[i]['name']}: {result['data']['text'][:100]}...")
+
+ return results
+
+ except Exception as e:
+ print(f"Example 6 failed: {str(e)}")
+
+def complete_workflow_example(file_path: str):
+ """Complete Workflow: AI + Template Generation Integration"""
+ print('=== Complete Workflow: AI + Template Generation ===')
+
+ generator = AIVariableGenerator(API_TOKEN, ORG_ID)
+
+ try:
+ # Step 1: Generate AI content
+ ai_result = generator.generate_variable(
+ name='Business Analysis',
+ placeholder='{BusinessAnalysis}',
+ ai_hint='Generate a comprehensive business analysis including market trends, performance metrics, and strategic recommendations',
+ file_path=file_path,
+ file_metadata={
+ 'selectedSheet': 'Data',
+ 'hasMultipleSheets': True
+ },
+ rich_text_enabled=True
+ )
+
+ print('AI content generated successfully')
+
+ # Step 2: Prepare template variables with AI content
+ template_variables = [{
+ 'name': 'Business Analysis',
+ 'placeholder': '{BusinessAnalysis}',
+ 'text': ai_result['data']['text'],
+ 'mimeType': ai_result['data']['mimeType'],
+ 'allowRichTextInjection': 1 if ai_result['data']['mimeType'] == 'html' else 0
+ }]
+
+ print('Template variables prepared with AI content')
+
+ # Note: This would integrate with the Template Generation API
+ # for complete document creation workflow
+
+ return {
+ 'ai_content': ai_result,
+ 'template_variables': template_variables
+ }
+
+ except Exception as e:
+ print(f"Complete workflow failed: {str(e)}")
+ raise
+
+# Example usage and demonstrations
+if __name__ == '__main__':
+ print('🤖 AI Variable Generation Examples')
+ print('Available functions:')
+ print('- example1_basic_generation()')
+ print('- example2_excel_analysis(file_path)')
+ print('- example3_document_analysis(file_path)')
+ print('- example4_legal_analysis(file_path)')
+ print('- example5_rich_text_generation()')
+ print('- example6_batch_generation(file_path)')
+ print('- complete_workflow_example(file_path)')
+
+ # Run basic example
+ try:
+ example1_basic_generation()
+ except Exception as e:
+ print(f"Demo failed: {str(e)}")
+ print("Please update API_TOKEN and ORG_ID with your credentials")
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/csharp/controller.cs b/static/scripts/templates/api/browse-templates/csharp/controller.cs
new file mode 100644
index 0000000..5913d62
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/csharp/controller.cs
@@ -0,0 +1,196 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+using System.Text.Json;
+using System.Web;
+
+/**
+ * Path B: Browse and Select Existing Templates
+ */
+class TemplateBrowser
+{
+ // Configuration - Update these values
+ private const string API_TOKEN = "YOUR_API_TOKEN";
+ private const string ORG_ID = "YOUR_ORGANIZATION_ID";
+ private const string BASE_URL = "https://api.turbodocx.com";
+
+ static async Task Main(string[] args)
+ {
+ try
+ {
+ Console.WriteLine("=== Path B: Browse and Select Template ===");
+
+ // Step 1: Browse templates
+ Console.WriteLine("\n1. Browsing templates...");
+ var browseResult = await BrowseTemplates(10, 0, "contract", true, null);
+
+ using var browseDoc = JsonDocument.Parse(browseResult);
+ var results = browseDoc.RootElement.GetProperty("data").GetProperty("results");
+
+ // Find a template (not a folder)
+ JsonElement? selectedTemplate = null;
+ foreach (var item in results.EnumerateArray())
+ {
+ if (item.GetProperty("type").GetString() == "template")
+ {
+ selectedTemplate = item;
+ break;
+ }
+ }
+
+ if (!selectedTemplate.HasValue)
+ {
+ Console.WriteLine("No templates found in browse results");
+ return;
+ }
+
+ var template = selectedTemplate.Value;
+ Console.WriteLine($"\nSelected template: {template.GetProperty("name").GetString()} ({template.GetProperty("id").GetString()})");
+
+ // Step 2: Get detailed template information
+ Console.WriteLine("\n2. Getting template details...");
+ var templateDetails = await GetTemplateDetails(template.GetProperty("id").GetString());
+
+ // Step 3: Get PDF preview (optional)
+ Console.WriteLine("\n3. Getting PDF preview...");
+ var pdfPreview = await GetTemplatePDFPreview(template.GetProperty("id").GetString());
+
+ using var detailsDoc = JsonDocument.Parse(templateDetails);
+ var templateInfo = detailsDoc.RootElement.GetProperty("data").GetProperty("results");
+
+ Console.WriteLine("\n=== Template Ready for Generation ===");
+ Console.WriteLine($"Template ID: {templateInfo.GetProperty("id").GetString()}");
+
+ var variableCount = 0;
+ if (templateInfo.TryGetProperty("variables", out var variables) &&
+ variables.ValueKind != JsonValueKind.Null)
+ {
+ variableCount = variables.GetArrayLength();
+ }
+ Console.WriteLine($"Variables available: {variableCount}");
+ Console.WriteLine($"PDF Preview: {pdfPreview}");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Browsing workflow failed: {ex.Message}");
+ }
+ }
+
+ /**
+ * Step 1: Browse Templates and Folders
+ */
+ private static async Task BrowseTemplates(int limit, int offset, string query,
+ bool showTags, string[] selectedTags)
+ {
+ using var client = new HttpClient();
+
+ // Set headers
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ // Build query parameters
+ var queryParams = $"limit={limit}&offset={offset}&showTags={showTags.ToString().ToLower()}";
+
+ if (!string.IsNullOrEmpty(query))
+ {
+ queryParams += $"&query={HttpUtility.UrlEncode(query)}";
+ }
+
+ if (selectedTags != null)
+ {
+ foreach (var tag in selectedTags)
+ {
+ queryParams += $"&selectedTags[]={HttpUtility.UrlEncode(tag)}";
+ }
+ }
+
+ var url = $"{BASE_URL}/template-item?{queryParams}";
+
+ var response = await client.GetAsync(url);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"HTTP error {response.StatusCode}: {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var totalRecords = document.RootElement.GetProperty("data").GetProperty("totalRecords").GetInt32();
+ Console.WriteLine($"Found {totalRecords} templates/folders");
+
+ return result;
+ }
+
+ /**
+ * Step 2: Get Template Details by ID
+ */
+ private static async Task GetTemplateDetails(string templateId)
+ {
+ using var client = new HttpClient();
+
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ var response = await client.GetAsync($"{BASE_URL}/template/{templateId}");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"HTTP error {response.StatusCode}: {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var template = document.RootElement.GetProperty("data").GetProperty("results");
+
+ Console.WriteLine($"Template: {template.GetProperty("name").GetString()}");
+
+ var variableCount = 0;
+ if (template.TryGetProperty("variables", out var variables) &&
+ variables.ValueKind != JsonValueKind.Null)
+ {
+ variableCount = variables.GetArrayLength();
+ }
+ Console.WriteLine($"Variables: {variableCount}");
+
+ var defaultFont = template.TryGetProperty("defaultFont", out var font) ? font.GetString() : "N/A";
+ Console.WriteLine($"Default font: {defaultFont}");
+
+ return result;
+ }
+
+ /**
+ * Step 3: Get PDF Preview Link (Optional)
+ */
+ private static async Task GetTemplatePDFPreview(string templateId)
+ {
+ using var client = new HttpClient();
+
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ var response = await client.GetAsync($"{BASE_URL}/template/{templateId}/previewpdflink");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"HTTP error {response.StatusCode}: {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var pdfUrl = document.RootElement.GetProperty("results").GetString();
+
+ Console.WriteLine($"PDF Preview: {pdfUrl}");
+
+ return pdfUrl;
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/csharp/minimal.cs b/static/scripts/templates/api/browse-templates/csharp/minimal.cs
new file mode 100644
index 0000000..5913d62
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/csharp/minimal.cs
@@ -0,0 +1,196 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+using System.Text.Json;
+using System.Web;
+
+/**
+ * Path B: Browse and Select Existing Templates
+ */
+class TemplateBrowser
+{
+ // Configuration - Update these values
+ private const string API_TOKEN = "YOUR_API_TOKEN";
+ private const string ORG_ID = "YOUR_ORGANIZATION_ID";
+ private const string BASE_URL = "https://api.turbodocx.com";
+
+ static async Task Main(string[] args)
+ {
+ try
+ {
+ Console.WriteLine("=== Path B: Browse and Select Template ===");
+
+ // Step 1: Browse templates
+ Console.WriteLine("\n1. Browsing templates...");
+ var browseResult = await BrowseTemplates(10, 0, "contract", true, null);
+
+ using var browseDoc = JsonDocument.Parse(browseResult);
+ var results = browseDoc.RootElement.GetProperty("data").GetProperty("results");
+
+ // Find a template (not a folder)
+ JsonElement? selectedTemplate = null;
+ foreach (var item in results.EnumerateArray())
+ {
+ if (item.GetProperty("type").GetString() == "template")
+ {
+ selectedTemplate = item;
+ break;
+ }
+ }
+
+ if (!selectedTemplate.HasValue)
+ {
+ Console.WriteLine("No templates found in browse results");
+ return;
+ }
+
+ var template = selectedTemplate.Value;
+ Console.WriteLine($"\nSelected template: {template.GetProperty("name").GetString()} ({template.GetProperty("id").GetString()})");
+
+ // Step 2: Get detailed template information
+ Console.WriteLine("\n2. Getting template details...");
+ var templateDetails = await GetTemplateDetails(template.GetProperty("id").GetString());
+
+ // Step 3: Get PDF preview (optional)
+ Console.WriteLine("\n3. Getting PDF preview...");
+ var pdfPreview = await GetTemplatePDFPreview(template.GetProperty("id").GetString());
+
+ using var detailsDoc = JsonDocument.Parse(templateDetails);
+ var templateInfo = detailsDoc.RootElement.GetProperty("data").GetProperty("results");
+
+ Console.WriteLine("\n=== Template Ready for Generation ===");
+ Console.WriteLine($"Template ID: {templateInfo.GetProperty("id").GetString()}");
+
+ var variableCount = 0;
+ if (templateInfo.TryGetProperty("variables", out var variables) &&
+ variables.ValueKind != JsonValueKind.Null)
+ {
+ variableCount = variables.GetArrayLength();
+ }
+ Console.WriteLine($"Variables available: {variableCount}");
+ Console.WriteLine($"PDF Preview: {pdfPreview}");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Browsing workflow failed: {ex.Message}");
+ }
+ }
+
+ /**
+ * Step 1: Browse Templates and Folders
+ */
+ private static async Task BrowseTemplates(int limit, int offset, string query,
+ bool showTags, string[] selectedTags)
+ {
+ using var client = new HttpClient();
+
+ // Set headers
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ // Build query parameters
+ var queryParams = $"limit={limit}&offset={offset}&showTags={showTags.ToString().ToLower()}";
+
+ if (!string.IsNullOrEmpty(query))
+ {
+ queryParams += $"&query={HttpUtility.UrlEncode(query)}";
+ }
+
+ if (selectedTags != null)
+ {
+ foreach (var tag in selectedTags)
+ {
+ queryParams += $"&selectedTags[]={HttpUtility.UrlEncode(tag)}";
+ }
+ }
+
+ var url = $"{BASE_URL}/template-item?{queryParams}";
+
+ var response = await client.GetAsync(url);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"HTTP error {response.StatusCode}: {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var totalRecords = document.RootElement.GetProperty("data").GetProperty("totalRecords").GetInt32();
+ Console.WriteLine($"Found {totalRecords} templates/folders");
+
+ return result;
+ }
+
+ /**
+ * Step 2: Get Template Details by ID
+ */
+ private static async Task GetTemplateDetails(string templateId)
+ {
+ using var client = new HttpClient();
+
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ var response = await client.GetAsync($"{BASE_URL}/template/{templateId}");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"HTTP error {response.StatusCode}: {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var template = document.RootElement.GetProperty("data").GetProperty("results");
+
+ Console.WriteLine($"Template: {template.GetProperty("name").GetString()}");
+
+ var variableCount = 0;
+ if (template.TryGetProperty("variables", out var variables) &&
+ variables.ValueKind != JsonValueKind.Null)
+ {
+ variableCount = variables.GetArrayLength();
+ }
+ Console.WriteLine($"Variables: {variableCount}");
+
+ var defaultFont = template.TryGetProperty("defaultFont", out var font) ? font.GetString() : "N/A";
+ Console.WriteLine($"Default font: {defaultFont}");
+
+ return result;
+ }
+
+ /**
+ * Step 3: Get PDF Preview Link (Optional)
+ */
+ private static async Task GetTemplatePDFPreview(string templateId)
+ {
+ using var client = new HttpClient();
+
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ var response = await client.GetAsync($"{BASE_URL}/template/{templateId}/previewpdflink");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"HTTP error {response.StatusCode}: {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var pdfUrl = document.RootElement.GetProperty("results").GetString();
+
+ Console.WriteLine($"PDF Preview: {pdfUrl}");
+
+ return pdfUrl;
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/curl.sh b/static/scripts/templates/api/browse-templates/curl.sh
new file mode 100644
index 0000000..8c81cd8
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/curl.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+# Configuration - Update these values
+API_TOKEN="YOUR_API_TOKEN"
+ORG_ID="YOUR_ORGANIZATION_ID"
+BASE_URL="https://api.turbodocx.com"
+
+# Path B: Browse and Select Existing Templates
+
+echo "=== Path B: Browse and Select Template ==="
+
+# Step 1: Browse Templates and Folders
+echo -e "\n1. Browsing templates..."
+
+BROWSE_RESPONSE=$(curl -s -X GET "$BASE_URL/template-item?limit=10&offset=0&query=contract&showTags=true" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client")
+
+echo "Browse Results:"
+echo "$BROWSE_RESPONSE" | jq '.'
+
+# Extract first template ID from response
+TEMPLATE_ID=$(echo "$BROWSE_RESPONSE" | jq -r '.data.results[] | select(.type == "template") | .id' | head -1)
+
+if [ "$TEMPLATE_ID" = "null" ] || [ -z "$TEMPLATE_ID" ]; then
+ echo "No templates found in browse results"
+ exit 1
+fi
+
+echo -e "\nSelected template ID: $TEMPLATE_ID"
+
+# Step 2: Get Template Details
+echo -e "\n2. Getting template details..."
+
+TEMPLATE_DETAILS=$(curl -s -X GET "$BASE_URL/template/$TEMPLATE_ID" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client")
+
+echo "Template Details:"
+echo "$TEMPLATE_DETAILS" | jq '.'
+
+# Extract template info
+TEMPLATE_NAME=$(echo "$TEMPLATE_DETAILS" | jq -r '.data.results.name')
+VARIABLE_COUNT=$(echo "$TEMPLATE_DETAILS" | jq '.data.results.variables | length')
+
+echo -e "\nTemplate: $TEMPLATE_NAME"
+echo "Variables: $VARIABLE_COUNT"
+
+# Step 3: Get PDF Preview (Optional)
+echo -e "\n3. Getting PDF preview..."
+
+PDF_PREVIEW=$(curl -s -X GET "$BASE_URL/template/$TEMPLATE_ID/previewpdflink" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client")
+
+echo "PDF Preview Response:"
+echo "$PDF_PREVIEW" | jq '.'
+
+PDF_URL=$(echo "$PDF_PREVIEW" | jq -r '.results')
+echo -e "\nPDF Preview URL: $PDF_URL"
+
+echo -e "\n=== Template Ready for Generation ==="
+echo "Template ID: $TEMPLATE_ID"
+echo "Template Name: $TEMPLATE_NAME"
+echo "Variables available: $VARIABLE_COUNT"
+echo "PDF Preview: $PDF_URL"
+
+# Optional: Browse a specific folder
+echo -e "\n--- Optional: Browse Folder Contents ---"
+echo "To browse a specific folder, use:"
+echo "curl -X GET \"$BASE_URL/template-item/FOLDER_ID?limit=25&offset=0\" \\"
+echo " -H \"Authorization: Bearer $API_TOKEN\" \\"
+echo " -H \"x-rapiddocx-org-id: $ORG_ID\" \\"
+echo " -H \"User-Agent: TurboDocx API Client\""
+
+# Optional: Search with filters
+echo -e "\n--- Optional: Advanced Search ---"
+echo "Search with tags:"
+echo "curl -X GET \"$BASE_URL/template-item?query=contract&selectedTags[]=hr&selectedTags[]=template\" \\"
+echo " -H \"Authorization: Bearer $API_TOKEN\" \\"
+echo " -H \"x-rapiddocx-org-id: $ORG_ID\" \\"
+echo " -H \"User-Agent: TurboDocx API Client\""
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/fastapi.py b/static/scripts/templates/api/browse-templates/fastapi.py
new file mode 100644
index 0000000..bffd43e
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/fastapi.py
@@ -0,0 +1,386 @@
+#!/usr/bin/env python3
+
+import requests
+import json
+from typing import Optional, List
+from urllib.parse import urlencode
+from fastapi import FastAPI, HTTPException, Query
+from pydantic import BaseModel
+import uvicorn
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+app = FastAPI(
+ title="TurboDocx Template Browser Service",
+ description="FastAPI service for browsing and selecting templates from TurboDocx API",
+ version="1.0.0"
+)
+
+class BrowseRequest(BaseModel):
+ limit: Optional[int] = 10
+ offset: Optional[int] = 0
+ query: Optional[str] = 'contract'
+ showTags: Optional[bool] = True
+
+class BrowseResponse(BaseModel):
+ success: bool
+ message: str
+ data: dict
+
+class TemplateResponse(BaseModel):
+ success: bool
+ message: str
+ data: dict
+
+class PreviewResponse(BaseModel):
+ success: bool
+ message: str
+ data: dict
+
+class ConfigurationInfo(BaseModel):
+ baseUrl: str
+ hasToken: bool
+ hasOrgId: bool
+
+class ServiceInfo(BaseModel):
+ service: str
+ endpoints: dict
+ configuration: ConfigurationInfo
+
+def browse_templates(limit: int = 25, offset: int = 0, query: str = '',
+ show_tags: bool = True, selected_tags: Optional[List[str]] = None) -> dict:
+ """
+ Path B: Browse and Select Existing Templates
+ """
+ # Build query parameters
+ params = {
+ 'limit': str(limit),
+ 'offset': str(offset),
+ 'showTags': str(show_tags).lower()
+ }
+
+ if query:
+ params['query'] = query
+
+ if selected_tags:
+ for tag in selected_tags:
+ # Handle multiple values for selectedTags[]
+ if 'selectedTags[]' not in params:
+ params['selectedTags[]'] = []
+ if isinstance(params['selectedTags[]'], list):
+ params['selectedTags[]'].append(tag)
+ else:
+ params['selectedTags[]'] = [params['selectedTags[]'], tag]
+
+ query_string = urlencode(params, doseq=True)
+ url = f"{BASE_URL}/template-item?{query_string}"
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ try:
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+
+ # Parse response
+ result = response.json()
+ data = result['data']
+
+ print(f"Found {data['totalRecords']} templates/folders")
+
+ return data
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Browse failed: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+def get_template_details(template_id: str) -> dict:
+ """Get detailed template information"""
+ url = f"{BASE_URL}/template/{template_id}"
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ try:
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+
+ result = response.json()
+ template = result['data']['results']
+
+ print(f"Template: {template['name']}")
+
+ variable_count = len(template['variables']) if template.get('variables') else 0
+ print(f"Variables: {variable_count}")
+
+ default_font = template.get('defaultFont', 'N/A')
+ print(f"Default font: {default_font}")
+
+ return template
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Failed to get template details: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+def get_template_pdf_preview(template_id: str) -> str:
+ """Get template PDF preview link"""
+ url = f"{BASE_URL}/template/{template_id}/previewpdflink"
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ try:
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+
+ result = response.json()
+ pdf_url = result['results']
+
+ print(f"PDF Preview: {pdf_url}")
+
+ return pdf_url
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Failed to get PDF preview: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+# FastAPI route handlers
+@app.get("/browse-templates", response_model=BrowseResponse)
+async def browse_templates_endpoint(
+ limit: int = Query(25, ge=1, le=100),
+ offset: int = Query(0, ge=0),
+ query: str = Query(''),
+ showTags: bool = Query(True),
+ selectedTags: Optional[List[str]] = Query(None)
+):
+ """Browse templates with filtering options"""
+ try:
+ result = browse_templates(limit, offset, query, showTags, selectedTags)
+
+ return BrowseResponse(
+ success=True,
+ message="Templates retrieved successfully",
+ data=result
+ )
+
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Template browsing failed: {str(e)}")
+
+@app.get("/template/{template_id}", response_model=TemplateResponse)
+async def get_template_details_endpoint(template_id: str):
+ """Get detailed template information"""
+ try:
+ template = get_template_details(template_id)
+
+ return TemplateResponse(
+ success=True,
+ message="Template details retrieved successfully",
+ data=template
+ )
+
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Failed to get template details: {str(e)}")
+
+@app.get("/template/{template_id}/preview", response_model=PreviewResponse)
+async def get_template_pdf_preview_endpoint(template_id: str):
+ """Get template PDF preview URL"""
+ try:
+ pdf_url = get_template_pdf_preview(template_id)
+
+ return PreviewResponse(
+ success=True,
+ message="PDF preview URL retrieved successfully",
+ data={"pdfUrl": pdf_url}
+ )
+
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Failed to get PDF preview: {str(e)}")
+
+@app.post("/browse-workflow", response_model=BrowseResponse)
+async def browse_workflow_endpoint(request: BrowseRequest):
+ """Complete browse and select workflow"""
+ try:
+ # Step 1: Browse templates
+ print('1. Browsing templates...')
+ browse_result = browse_templates(request.limit, request.offset, request.query, request.showTags)
+
+ # Find a template (not a folder)
+ selected_template = None
+ for item in browse_result['results']:
+ if item.get('type') == 'template':
+ selected_template = item
+ break
+
+ if not selected_template:
+ raise HTTPException(
+ status_code=404,
+ detail="No templates found in browse results"
+ )
+
+ print(f"Selected template: {selected_template['name']} ({selected_template['id']})")
+
+ # Step 2: Get detailed template information
+ print('2. Getting template details...')
+ template_details = get_template_details(selected_template['id'])
+
+ # Step 3: Get PDF preview (optional)
+ print('3. Getting PDF preview...')
+ pdf_preview = get_template_pdf_preview(selected_template['id'])
+
+ result = {
+ 'selectedTemplate': selected_template,
+ 'templateDetails': template_details,
+ 'pdfPreview': pdf_preview,
+ 'summary': {
+ 'templateId': template_details['id'],
+ 'variableCount': len(template_details['variables']) if template_details.get('variables') else 0,
+ 'pdfPreviewUrl': pdf_preview
+ }
+ }
+
+ return BrowseResponse(
+ success=True,
+ message="Browse workflow completed successfully",
+ data=result
+ )
+
+ except HTTPException:
+ raise
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Browse workflow failed: {str(e)}")
+
+@app.get("/health")
+async def health_check():
+ """Health check endpoint"""
+ return {
+ "status": "healthy",
+ "service": "template-browser"
+ }
+
+@app.get("/browse-info", response_model=ServiceInfo)
+async def browse_info():
+ """Service information endpoint"""
+ return ServiceInfo(
+ service="TurboDocx Template Browser Service",
+ endpoints={
+ "GET /browse-templates": "Browse available templates with filtering",
+ "GET /template/{template_id}": "Get detailed template information",
+ "GET /template/{template_id}/preview": "Get template PDF preview URL",
+ "POST /browse-workflow": "Complete browse and select workflow",
+ "GET /health": "Service health check",
+ "GET /browse-info": "Service information",
+ "GET /docs": "Interactive API documentation",
+ "GET /redoc": "Alternative API documentation"
+ },
+ configuration=ConfigurationInfo(
+ baseUrl=BASE_URL,
+ hasToken=bool(API_TOKEN and API_TOKEN != 'YOUR_API_TOKEN'),
+ hasOrgId=bool(ORG_ID and ORG_ID != 'YOUR_ORGANIZATION_ID')
+ )
+ )
+
+def demonstrate_browse_workflow():
+ """Example usage function"""
+ try:
+ print('=== Path B: Browse and Select Template ===')
+
+ # Step 1: Browse all templates
+ print('\n1. Browsing templates...')
+ browse_result = browse_templates(10, 0, 'contract', True)
+
+ # Find a template (not a folder)
+ selected_template = None
+ for item in browse_result['results']:
+ if item.get('type') == 'template':
+ selected_template = item
+ break
+
+ if not selected_template:
+ print('No templates found in browse results')
+ exit(1)
+
+ print(f"\nSelected template: {selected_template['name']} ({selected_template['id']})")
+
+ # Step 2: Get detailed template information
+ print('\n2. Getting template details...')
+ template_details = get_template_details(selected_template['id'])
+
+ # Step 3: Get PDF preview (optional)
+ print('\n3. Getting PDF preview...')
+ pdf_preview = get_template_pdf_preview(selected_template['id'])
+
+ print('\n=== Template Ready for Generation ===')
+ print(f"Template ID: {template_details['id']}")
+
+ variable_count = len(template_details['variables']) if template_details.get('variables') else 0
+ print(f"Variables available: {variable_count}")
+ print(f"PDF Preview: {pdf_preview}")
+
+ return {
+ 'templateId': template_details['id'],
+ 'templateDetails': template_details,
+ 'pdfPreview': pdf_preview
+ }
+
+ except Exception as e:
+ print(f'Browsing workflow failed: {str(e)}')
+ exit(1)
+
+if __name__ == '__main__':
+ import sys
+ import os
+
+ if '--demo' in sys.argv:
+ # Run demonstration
+ demonstrate_browse_workflow()
+ else:
+ # Start FastAPI server
+ port = int(os.environ.get('PORT', 8002))
+ host = os.environ.get('HOST', '0.0.0.0')
+
+ print('🚀 TurboDocx Template Browser Service started')
+ print(f'📡 Server listening on http://{host}:{port}')
+ print('\nAvailable endpoints:')
+ print(f' GET http://{host}:{port}/browse-templates')
+ print(f' GET http://{host}:{port}/template/{{template_id}}')
+ print(f' GET http://{host}:{port}/template/{{template_id}}/preview')
+ print(f' POST http://{host}:{port}/browse-workflow')
+ print(f' GET http://{host}:{port}/health')
+ print(f' GET http://{host}:{port}/browse-info')
+ print(f' GET http://{host}:{port}/docs (Interactive API docs)')
+ print(f' GET http://{host}:{port}/redoc (Alternative API docs)')
+
+ uvicorn.run(app, host=host, port=port)
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/fastify.js b/static/scripts/templates/api/browse-templates/fastify.js
new file mode 100644
index 0000000..185e829
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/fastify.js
@@ -0,0 +1,374 @@
+const fastify = require('fastify')({ logger: true });
+const axios = require('axios');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+/**
+ * Path B: Browse and Select Existing Templates
+ */
+
+/**
+ * Browse templates with filtering options
+ */
+async function browseTemplates(limit = 25, offset = 0, query = '', showTags = true, selectedTags = null) {
+ // Build query parameters
+ const params = new URLSearchParams({
+ limit: limit.toString(),
+ offset: offset.toString(),
+ showTags: showTags.toString()
+ });
+
+ if (query) {
+ params.append('query', query);
+ }
+
+ if (selectedTags && Array.isArray(selectedTags)) {
+ selectedTags.forEach(tag => {
+ params.append('selectedTags[]', tag);
+ });
+ }
+
+ const url = `${BASE_URL}/template-item?${params.toString()}`;
+
+ try {
+ const response = await axios.get(url, {
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ // Parse response
+ const data = response.data.data;
+
+ console.log(`Found ${data.totalRecords} templates/folders`);
+
+ return data;
+ } catch (error) {
+ console.error('Browse failed:', error.response?.data || error.message);
+ throw error;
+ }
+}
+
+/**
+ * Get detailed template information
+ */
+async function getTemplateDetails(templateId) {
+ const url = `${BASE_URL}/template/${templateId}`;
+
+ try {
+ const response = await axios.get(url, {
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ const template = response.data.data.results;
+
+ console.log(`Template: ${template.name}`);
+
+ const variableCount = template.variables ? template.variables.length : 0;
+ console.log(`Variables: ${variableCount}`);
+
+ const defaultFont = template.defaultFont || 'N/A';
+ console.log(`Default font: ${defaultFont}`);
+
+ return template;
+ } catch (error) {
+ console.error('Failed to get template details:', error.response?.data || error.message);
+ throw error;
+ }
+}
+
+/**
+ * Get template PDF preview link
+ */
+async function getTemplatePdfPreview(templateId) {
+ const url = `${BASE_URL}/template/${templateId}/previewpdflink`;
+
+ try {
+ const response = await axios.get(url, {
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ const pdfUrl = response.data.results;
+
+ console.log(`PDF Preview: ${pdfUrl}`);
+
+ return pdfUrl;
+ } catch (error) {
+ console.error('Failed to get PDF preview:', error.response?.data || error.message);
+ throw error;
+ }
+}
+
+// Fastify route handlers
+async function registerRoutes() {
+ // Browse templates route
+ fastify.get('/browse-templates', async (request, reply) => {
+ try {
+ const {
+ limit = 25,
+ offset = 0,
+ query = '',
+ showTags = true,
+ selectedTags
+ } = request.query;
+
+ const parsedLimit = parseInt(limit);
+ const parsedOffset = parseInt(offset);
+ const parsedShowTags = showTags === 'true' || showTags === true;
+ const parsedSelectedTags = selectedTags ?
+ (Array.isArray(selectedTags) ? selectedTags : [selectedTags]) : null;
+
+ const result = await browseTemplates(
+ parsedLimit,
+ parsedOffset,
+ query,
+ parsedShowTags,
+ parsedSelectedTags
+ );
+
+ reply.send({
+ success: true,
+ message: 'Templates retrieved successfully',
+ data: result
+ });
+ } catch (error) {
+ console.error('Error browsing templates:', error);
+ reply.code(500).send({
+ error: 'Template browsing failed',
+ message: error.message
+ });
+ }
+ });
+
+ // Get template details route
+ fastify.get('/template/:templateId', async (request, reply) => {
+ try {
+ const { templateId } = request.params;
+
+ const template = await getTemplateDetails(templateId);
+
+ reply.send({
+ success: true,
+ message: 'Template details retrieved successfully',
+ data: template
+ });
+ } catch (error) {
+ console.error('Error getting template details:', error);
+ reply.code(500).send({
+ error: 'Failed to get template details',
+ message: error.message
+ });
+ }
+ });
+
+ // Get template PDF preview route
+ fastify.get('/template/:templateId/preview', async (request, reply) => {
+ try {
+ const { templateId } = request.params;
+
+ const pdfUrl = await getTemplatePdfPreview(templateId);
+
+ reply.send({
+ success: true,
+ message: 'PDF preview URL retrieved successfully',
+ data: { pdfUrl }
+ });
+ } catch (error) {
+ console.error('Error getting PDF preview:', error);
+ reply.code(500).send({
+ error: 'Failed to get PDF preview',
+ message: error.message
+ });
+ }
+ });
+
+ // Complete browse workflow route
+ fastify.post('/browse-workflow', async (request, reply) => {
+ try {
+ const {
+ limit = 10,
+ offset = 0,
+ query = 'contract',
+ showTags = true
+ } = request.body;
+
+ // Step 1: Browse templates
+ console.log('1. Browsing templates...');
+ const browseResult = await browseTemplates(limit, offset, query, showTags);
+
+ // Find a template (not a folder)
+ const selectedTemplate = browseResult.results.find(item => item.type === 'template');
+
+ if (!selectedTemplate) {
+ return reply.code(404).send({
+ error: 'No templates found',
+ message: 'No templates found in browse results'
+ });
+ }
+
+ console.log(`Selected template: ${selectedTemplate.name} (${selectedTemplate.id})`);
+
+ // Step 2: Get detailed template information
+ console.log('2. Getting template details...');
+ const templateDetails = await getTemplateDetails(selectedTemplate.id);
+
+ // Step 3: Get PDF preview (optional)
+ console.log('3. Getting PDF preview...');
+ const pdfPreview = await getTemplatePdfPreview(selectedTemplate.id);
+
+ const result = {
+ selectedTemplate,
+ templateDetails,
+ pdfPreview,
+ summary: {
+ templateId: templateDetails.id,
+ variableCount: templateDetails.variables ? templateDetails.variables.length : 0,
+ pdfPreviewUrl: pdfPreview
+ }
+ };
+
+ reply.send({
+ success: true,
+ message: 'Browse workflow completed successfully',
+ data: result
+ });
+ } catch (error) {
+ console.error('Error in browse workflow:', error);
+ reply.code(500).send({
+ error: 'Browse workflow failed',
+ message: error.message
+ });
+ }
+ });
+
+ // Health check route
+ fastify.get('/health', async (request, reply) => {
+ reply.send({ status: 'healthy', service: 'template-browser' });
+ });
+
+ // Service info route
+ fastify.get('/browse-info', async (request, reply) => {
+ reply.send({
+ service: 'TurboDocx Template Browser Service',
+ endpoints: {
+ 'GET /browse-templates': 'Browse available templates with filtering',
+ 'GET /template/:templateId': 'Get detailed template information',
+ 'GET /template/:templateId/preview': 'Get template PDF preview URL',
+ 'POST /browse-workflow': 'Complete browse and select workflow',
+ 'GET /health': 'Service health check',
+ 'GET /browse-info': 'Service information'
+ },
+ configuration: {
+ baseUrl: BASE_URL,
+ hasToken: !!API_TOKEN && API_TOKEN !== 'YOUR_API_TOKEN',
+ hasOrgId: !!ORG_ID && ORG_ID !== 'YOUR_ORGANIZATION_ID'
+ }
+ });
+ });
+}
+
+// Example usage function
+async function demonstrateBrowseWorkflow() {
+ try {
+ console.log('=== Path B: Browse and Select Template ===');
+
+ // Step 1: Browse all templates
+ console.log('\n1. Browsing templates...');
+ const browseResult = await browseTemplates(10, 0, 'contract', true);
+
+ // Find a template (not a folder)
+ const selectedTemplate = browseResult.results.find(item => item.type === 'template');
+
+ if (!selectedTemplate) {
+ console.log('No templates found in browse results');
+ process.exit(1);
+ }
+
+ console.log(`\nSelected template: ${selectedTemplate.name} (${selectedTemplate.id})`);
+
+ // Step 2: Get detailed template information
+ console.log('\n2. Getting template details...');
+ const templateDetails = await getTemplateDetails(selectedTemplate.id);
+
+ // Step 3: Get PDF preview (optional)
+ console.log('\n3. Getting PDF preview...');
+ const pdfPreview = await getTemplatePdfPreview(selectedTemplate.id);
+
+ console.log('\n=== Template Ready for Generation ===');
+ console.log(`Template ID: ${templateDetails.id}`);
+
+ const variableCount = templateDetails.variables ? templateDetails.variables.length : 0;
+ console.log(`Variables available: ${variableCount}`);
+ console.log(`PDF Preview: ${pdfPreview}`);
+
+ return {
+ templateId: templateDetails.id,
+ templateDetails,
+ pdfPreview
+ };
+ } catch (error) {
+ console.error('Browsing workflow failed:', error.message);
+ process.exit(1);
+ }
+}
+
+// Server startup
+async function startServer() {
+ try {
+ await registerRoutes();
+
+ const port = process.env.PORT || 3002;
+ const host = process.env.HOST || '0.0.0.0';
+
+ await fastify.listen({ port, host });
+
+ console.log('🚀 TurboDocx Template Browser Service started');
+ console.log(`📡 Server listening on http://${host}:${port}`);
+ console.log('\nAvailable endpoints:');
+ console.log(` GET http://${host}:${port}/browse-templates`);
+ console.log(` GET http://${host}:${port}/template/:templateId`);
+ console.log(` GET http://${host}:${port}/template/:templateId/preview`);
+ console.log(` POST http://${host}:${port}/browse-workflow`);
+ console.log(` GET http://${host}:${port}/health`);
+ console.log(` GET http://${host}:${port}/browse-info`);
+
+ } catch (error) {
+ fastify.log.error(error);
+ process.exit(1);
+ }
+}
+
+// Check if this file is being run directly
+if (require.main === module) {
+ const args = process.argv.slice(2);
+
+ if (args.includes('--demo')) {
+ // Run demonstration
+ demonstrateBrowseWorkflow();
+ } else {
+ // Start server
+ startServer();
+ }
+}
+
+module.exports = {
+ browseTemplates,
+ getTemplateDetails,
+ getTemplatePdfPreview,
+ demonstrateBrowseWorkflow,
+ startServer,
+ fastify
+};
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/flask.py b/static/scripts/templates/api/browse-templates/flask.py
new file mode 100644
index 0000000..2f031d6
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/flask.py
@@ -0,0 +1,364 @@
+#!/usr/bin/env python3
+
+import requests
+import json
+from urllib.parse import urlencode
+from flask import Flask, request, jsonify
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+app = Flask(__name__)
+
+def browse_templates(limit=25, offset=0, query='', show_tags=True, selected_tags=None):
+ """
+ Path B: Browse and Select Existing Templates
+ """
+ # Build query parameters
+ params = {
+ 'limit': str(limit),
+ 'offset': str(offset),
+ 'showTags': str(show_tags).lower()
+ }
+
+ if query:
+ params['query'] = query
+
+ if selected_tags:
+ for tag in selected_tags:
+ # Handle multiple values for selectedTags[]
+ if 'selectedTags[]' not in params:
+ params['selectedTags[]'] = []
+ if isinstance(params['selectedTags[]'], list):
+ params['selectedTags[]'].append(tag)
+ else:
+ params['selectedTags[]'] = [params['selectedTags[]'], tag]
+
+ query_string = urlencode(params, doseq=True)
+ url = f"{BASE_URL}/template-item?{query_string}"
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ try:
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+
+ # Parse response
+ result = response.json()
+ data = result['data']
+
+ print(f"Found {data['totalRecords']} templates/folders")
+
+ return data
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Browse failed: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+def get_template_details(template_id):
+ """Get detailed template information"""
+ url = f"{BASE_URL}/template/{template_id}"
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ try:
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+
+ result = response.json()
+ template = result['data']['results']
+
+ print(f"Template: {template['name']}")
+
+ variable_count = len(template['variables']) if template.get('variables') else 0
+ print(f"Variables: {variable_count}")
+
+ default_font = template.get('defaultFont', 'N/A')
+ print(f"Default font: {default_font}")
+
+ return template
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Failed to get template details: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+def get_template_pdf_preview(template_id):
+ """Get template PDF preview link"""
+ url = f"{BASE_URL}/template/{template_id}/previewpdflink"
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ try:
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+
+ result = response.json()
+ pdf_url = result['results']
+
+ print(f"PDF Preview: {pdf_url}")
+
+ return pdf_url
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Failed to get PDF preview: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+# Flask route handlers
+@app.route('/browse-templates', methods=['GET'])
+def browse_templates_endpoint():
+ """Browse templates endpoint"""
+ try:
+ # Get query parameters
+ limit = int(request.args.get('limit', 25))
+ offset = int(request.args.get('offset', 0))
+ query = request.args.get('query', '')
+ show_tags = request.args.get('showTags', 'true').lower() == 'true'
+ selected_tags = request.args.getlist('selectedTags[]')
+
+ result = browse_templates(limit, offset, query, show_tags, selected_tags or None)
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Templates retrieved successfully',
+ 'data': result
+ })
+
+ except Exception as e:
+ app.logger.error(f'Error browsing templates: {str(e)}')
+ return jsonify({
+ 'error': 'Template browsing failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/template/', methods=['GET'])
+def get_template_details_endpoint(template_id):
+ """Get template details endpoint"""
+ try:
+ template = get_template_details(template_id)
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Template details retrieved successfully',
+ 'data': template
+ })
+
+ except Exception as e:
+ app.logger.error(f'Error getting template details: {str(e)}')
+ return jsonify({
+ 'error': 'Failed to get template details',
+ 'message': str(e)
+ }), 500
+
+@app.route('/template//preview', methods=['GET'])
+def get_template_pdf_preview_endpoint(template_id):
+ """Get template PDF preview endpoint"""
+ try:
+ pdf_url = get_template_pdf_preview(template_id)
+
+ return jsonify({
+ 'success': True,
+ 'message': 'PDF preview URL retrieved successfully',
+ 'data': {'pdfUrl': pdf_url}
+ })
+
+ except Exception as e:
+ app.logger.error(f'Error getting PDF preview: {str(e)}')
+ return jsonify({
+ 'error': 'Failed to get PDF preview',
+ 'message': str(e)
+ }), 500
+
+@app.route('/browse-workflow', methods=['POST'])
+def browse_workflow_endpoint():
+ """Complete browse workflow endpoint"""
+ try:
+ data = request.get_json() or {}
+ limit = data.get('limit', 10)
+ offset = data.get('offset', 0)
+ query = data.get('query', 'contract')
+ show_tags = data.get('showTags', True)
+
+ # Step 1: Browse templates
+ print('1. Browsing templates...')
+ browse_result = browse_templates(limit, offset, query, show_tags)
+
+ # Find a template (not a folder)
+ selected_template = None
+ for item in browse_result['results']:
+ if item.get('type') == 'template':
+ selected_template = item
+ break
+
+ if not selected_template:
+ return jsonify({
+ 'error': 'No templates found',
+ 'message': 'No templates found in browse results'
+ }), 404
+
+ print(f"Selected template: {selected_template['name']} ({selected_template['id']})")
+
+ # Step 2: Get detailed template information
+ print('2. Getting template details...')
+ template_details = get_template_details(selected_template['id'])
+
+ # Step 3: Get PDF preview (optional)
+ print('3. Getting PDF preview...')
+ pdf_preview = get_template_pdf_preview(selected_template['id'])
+
+ result = {
+ 'selectedTemplate': selected_template,
+ 'templateDetails': template_details,
+ 'pdfPreview': pdf_preview,
+ 'summary': {
+ 'templateId': template_details['id'],
+ 'variableCount': len(template_details['variables']) if template_details.get('variables') else 0,
+ 'pdfPreviewUrl': pdf_preview
+ }
+ }
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Browse workflow completed successfully',
+ 'data': result
+ })
+
+ except Exception as e:
+ app.logger.error(f'Error in browse workflow: {str(e)}')
+ return jsonify({
+ 'error': 'Browse workflow failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/health', methods=['GET'])
+def health_check():
+ """Health check endpoint"""
+ return jsonify({
+ 'status': 'healthy',
+ 'service': 'template-browser'
+ })
+
+@app.route('/browse-info', methods=['GET'])
+def browse_info():
+ """Service information endpoint"""
+ return jsonify({
+ 'service': 'TurboDocx Template Browser Service',
+ 'endpoints': {
+ 'GET /browse-templates': 'Browse available templates with filtering',
+ 'GET /template/': 'Get detailed template information',
+ 'GET /template//preview': 'Get template PDF preview URL',
+ 'POST /browse-workflow': 'Complete browse and select workflow',
+ 'GET /health': 'Service health check',
+ 'GET /browse-info': 'Service information'
+ },
+ 'configuration': {
+ 'baseUrl': BASE_URL,
+ 'hasToken': bool(API_TOKEN and API_TOKEN != 'YOUR_API_TOKEN'),
+ 'hasOrgId': bool(ORG_ID and ORG_ID != 'YOUR_ORGANIZATION_ID')
+ }
+ })
+
+def demonstrate_browse_workflow():
+ """Example usage function"""
+ try:
+ print('=== Path B: Browse and Select Template ===')
+
+ # Step 1: Browse all templates
+ print('\n1. Browsing templates...')
+ browse_result = browse_templates(10, 0, 'contract', True)
+
+ # Find a template (not a folder)
+ selected_template = None
+ for item in browse_result['results']:
+ if item.get('type') == 'template':
+ selected_template = item
+ break
+
+ if not selected_template:
+ print('No templates found in browse results')
+ exit(1)
+
+ print(f"\nSelected template: {selected_template['name']} ({selected_template['id']})")
+
+ # Step 2: Get detailed template information
+ print('\n2. Getting template details...')
+ template_details = get_template_details(selected_template['id'])
+
+ # Step 3: Get PDF preview (optional)
+ print('\n3. Getting PDF preview...')
+ pdf_preview = get_template_pdf_preview(selected_template['id'])
+
+ print('\n=== Template Ready for Generation ===')
+ print(f"Template ID: {template_details['id']}")
+
+ variable_count = len(template_details['variables']) if template_details.get('variables') else 0
+ print(f"Variables available: {variable_count}")
+ print(f"PDF Preview: {pdf_preview}")
+
+ return {
+ 'templateId': template_details['id'],
+ 'templateDetails': template_details,
+ 'pdfPreview': pdf_preview
+ }
+
+ except Exception as e:
+ print(f'Browsing workflow failed: {str(e)}')
+ exit(1)
+
+if __name__ == '__main__':
+ import sys
+
+ if '--demo' in sys.argv:
+ # Run demonstration
+ demonstrate_browse_workflow()
+ else:
+ # Start Flask server
+ import os
+ port = int(os.environ.get('PORT', 5002))
+ host = os.environ.get('HOST', '0.0.0.0')
+
+ print('🚀 TurboDocx Template Browser Service started')
+ print(f'📡 Server listening on http://{host}:{port}')
+ print('\nAvailable endpoints:')
+ print(f' GET http://{host}:{port}/browse-templates')
+ print(f' GET http://{host}:{port}/template/')
+ print(f' GET http://{host}:{port}/template//preview')
+ print(f' POST http://{host}:{port}/browse-workflow')
+ print(f' GET http://{host}:{port}/health')
+ print(f' GET http://{host}:{port}/browse-info')
+
+ app.run(host=host, port=port, debug=False)
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/go.go b/static/scripts/templates/api/browse-templates/go.go
new file mode 100644
index 0000000..c7b4261
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/go.go
@@ -0,0 +1,279 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+)
+
+// Configuration - Update these values
+const (
+ API_TOKEN = "YOUR_API_TOKEN"
+ ORG_ID = "YOUR_ORGANIZATION_ID"
+ BASE_URL = "https://api.turbodocx.com"
+)
+
+// BrowseResponse represents the browse API response structure
+type BrowseResponse struct {
+ Data struct {
+ Results []struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Type string `json:"type"`
+ CreatedOn string `json:"createdOn"`
+ Email string `json:"email"`
+ } `json:"results"`
+ TotalRecords int `json:"totalRecords"`
+ } `json:"data"`
+}
+
+// TemplateDetailsResponse represents the template details API response
+type TemplateDetailsResponse struct {
+ Data struct {
+ Results struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ DefaultFont string `json:"defaultFont"`
+ Variables []struct {
+ Name string `json:"name"`
+ Placeholder string `json:"placeholder"`
+ } `json:"variables"`
+ } `json:"results"`
+ } `json:"data"`
+}
+
+// PDFPreviewResponse represents the PDF preview API response
+type PDFPreviewResponse struct {
+ Results string `json:"results"`
+}
+
+/**
+ * Path B: Browse and Select Existing Templates
+ */
+func main() {
+ fmt.Println("=== Path B: Browse and Select Template ===")
+
+ // Step 1: Browse templates
+ fmt.Println("\n1. Browsing templates...")
+ browseResult, err := browseTemplates(10, 0, "contract", true, nil)
+ if err != nil {
+ fmt.Printf("Browse failed: %v\n", err)
+ return
+ }
+
+ // Find a template (not a folder)
+ var selectedTemplate *struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Type string `json:"type"`
+ CreatedOn string `json:"createdOn"`
+ Email string `json:"email"`
+ }
+
+ for _, item := range browseResult.Data.Results {
+ if item.Type == "template" {
+ selectedTemplate = &item
+ break
+ }
+ }
+
+ if selectedTemplate == nil {
+ fmt.Println("No templates found in browse results")
+ return
+ }
+
+ fmt.Printf("\nSelected template: %s (%s)\n", selectedTemplate.Name, selectedTemplate.ID)
+
+ // Step 2: Get detailed template information
+ fmt.Println("\n2. Getting template details...")
+ templateDetails, err := getTemplateDetails(selectedTemplate.ID)
+ if err != nil {
+ fmt.Printf("Failed to get template details: %v\n", err)
+ return
+ }
+
+ // Step 3: Get PDF preview (optional)
+ fmt.Println("\n3. Getting PDF preview...")
+ pdfPreview, err := getTemplatePDFPreview(selectedTemplate.ID)
+ if err != nil {
+ fmt.Printf("Failed to get PDF preview: %v\n", err)
+ return
+ }
+
+ fmt.Println("\n=== Template Ready for Generation ===")
+ fmt.Printf("Template ID: %s\n", templateDetails.Data.Results.ID)
+
+ variableCount := 0
+ if templateDetails.Data.Results.Variables != nil {
+ variableCount = len(templateDetails.Data.Results.Variables)
+ }
+ fmt.Printf("Variables available: %d\n", variableCount)
+ fmt.Printf("PDF Preview: %s\n", pdfPreview)
+}
+
+/**
+ * Step 1: Browse Templates and Folders
+ */
+func browseTemplates(limit, offset int, query string, showTags bool, selectedTags []string) (*BrowseResponse, error) {
+ // Build query parameters
+ params := url.Values{}
+ params.Set("limit", fmt.Sprintf("%d", limit))
+ params.Set("offset", fmt.Sprintf("%d", offset))
+ params.Set("showTags", fmt.Sprintf("%t", showTags))
+
+ if query != "" {
+ params.Set("query", query)
+ }
+
+ if selectedTags != nil {
+ for _, tag := range selectedTags {
+ params.Add("selectedTags[]", tag)
+ }
+ }
+
+ requestURL := fmt.Sprintf("%s/template-item?%s", BASE_URL, params.Encode())
+
+ // Create request
+ req, err := http.NewRequest("GET", requestURL, nil)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create request: %v", err)
+ }
+
+ // Set headers
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+
+ // Make request
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, fmt.Errorf("HTTP error %d: %s", resp.StatusCode, string(body))
+ }
+
+ // Parse response
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %v", err)
+ }
+
+ var result BrowseResponse
+ err = json.Unmarshal(body, &result)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse JSON: %v", err)
+ }
+
+ fmt.Printf("Found %d templates/folders\n", result.Data.TotalRecords)
+
+ return &result, nil
+}
+
+/**
+ * Step 2: Get Template Details by ID
+ */
+func getTemplateDetails(templateID string) (*TemplateDetailsResponse, error) {
+ requestURL := fmt.Sprintf("%s/template/%s", BASE_URL, templateID)
+
+ req, err := http.NewRequest("GET", requestURL, nil)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create request: %v", err)
+ }
+
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, fmt.Errorf("HTTP error %d: %s", resp.StatusCode, string(body))
+ }
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %v", err)
+ }
+
+ var result TemplateDetailsResponse
+ err = json.Unmarshal(body, &result)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse JSON: %v", err)
+ }
+
+ template := result.Data.Results
+ fmt.Printf("Template: %s\n", template.Name)
+
+ variableCount := 0
+ if template.Variables != nil {
+ variableCount = len(template.Variables)
+ }
+ fmt.Printf("Variables: %d\n", variableCount)
+
+ defaultFont := template.DefaultFont
+ if defaultFont == "" {
+ defaultFont = "N/A"
+ }
+ fmt.Printf("Default font: %s\n", defaultFont)
+
+ return &result, nil
+}
+
+/**
+ * Step 3: Get PDF Preview Link (Optional)
+ */
+func getTemplatePDFPreview(templateID string) (string, error) {
+ requestURL := fmt.Sprintf("%s/template/%s/previewpdflink", BASE_URL, templateID)
+
+ req, err := http.NewRequest("GET", requestURL, nil)
+ if err != nil {
+ return "", fmt.Errorf("failed to create request: %v", err)
+ }
+
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return "", fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, _ := io.ReadAll(resp.Body)
+ return "", fmt.Errorf("HTTP error %d: %s", resp.StatusCode, string(body))
+ }
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return "", fmt.Errorf("failed to read response: %v", err)
+ }
+
+ var result PDFPreviewResponse
+ err = json.Unmarshal(body, &result)
+ if err != nil {
+ return "", fmt.Errorf("failed to parse JSON: %v", err)
+ }
+
+ fmt.Printf("PDF Preview: %s\n", result.Results)
+
+ return result.Results, nil
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/java.java b/static/scripts/templates/api/browse-templates/java.java
new file mode 100644
index 0000000..993eedb
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/java.java
@@ -0,0 +1,177 @@
+import java.io.*;
+import java.net.URI;
+import java.net.http.*;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Path B: Browse and Select Existing Templates
+ */
+public class TemplateBrowser {
+ // Configuration - Update these values
+ private static final String API_TOKEN = "YOUR_API_TOKEN";
+ private static final String ORG_ID = "YOUR_ORGANIZATION_ID";
+ private static final String BASE_URL = "https://api.turbodocx.com";
+
+ public static void main(String[] args) throws Exception {
+ try {
+ System.out.println("=== Path B: Browse and Select Template ===");
+
+ // Step 1: Browse templates
+ System.out.println("\n1. Browsing templates...");
+ JsonNode browseResult = browseTemplates(10, 0, "contract", true, null);
+
+ // Find a template (not a folder)
+ JsonNode selectedTemplate = null;
+ for (JsonNode item : browseResult.get("results")) {
+ if ("template".equals(item.get("type").asText())) {
+ selectedTemplate = item;
+ break;
+ }
+ }
+
+ if (selectedTemplate == null) {
+ System.out.println("No templates found in browse results");
+ return;
+ }
+
+ System.out.println("\nSelected template: " + selectedTemplate.get("name").asText() +
+ " (" + selectedTemplate.get("id").asText() + ")");
+
+ // Step 2: Get detailed template information
+ System.out.println("\n2. Getting template details...");
+ JsonNode templateDetails = getTemplateDetails(selectedTemplate.get("id").asText());
+
+ // Step 3: Get PDF preview (optional)
+ System.out.println("\n3. Getting PDF preview...");
+ String pdfPreview = getTemplatePDFPreview(selectedTemplate.get("id").asText());
+
+ System.out.println("\n=== Template Ready for Generation ===");
+ System.out.println("Template ID: " + templateDetails.get("id").asText());
+
+ JsonNode variables = templateDetails.get("variables");
+ int variableCount = (variables != null && !variables.isNull()) ? variables.size() : 0;
+ System.out.println("Variables available: " + variableCount);
+ System.out.println("PDF Preview: " + pdfPreview);
+
+ } catch (Exception e) {
+ System.err.println("Browsing workflow failed: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Step 1: Browse Templates and Folders
+ */
+ private static JsonNode browseTemplates(int limit, int offset, String query,
+ boolean showTags, String[] selectedTags) throws Exception {
+ HttpClient client = HttpClient.newHttpClient();
+
+ // Build query parameters
+ StringBuilder params = new StringBuilder();
+ params.append("limit=").append(limit);
+ params.append("&offset=").append(offset);
+ params.append("&showTags=").append(showTags);
+
+ if (query != null && !query.isEmpty()) {
+ params.append("&query=").append(URLEncoder.encode(query, StandardCharsets.UTF_8));
+ }
+
+ if (selectedTags != null) {
+ for (String tag : selectedTags) {
+ params.append("&selectedTags[]=").append(URLEncoder.encode(tag, StandardCharsets.UTF_8));
+ }
+ }
+
+ String url = BASE_URL + "/template-item?" + params.toString();
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(url))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("HTTP error " + response.statusCode() + ": " + response.body());
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode result = mapper.readTree(response.body());
+ JsonNode data = result.get("data");
+
+ System.out.println("Found " + data.get("totalRecords").asInt() + " templates/folders");
+
+ return data;
+ }
+
+ /**
+ * Step 2: Get Template Details by ID
+ */
+ private static JsonNode getTemplateDetails(String templateId) throws Exception {
+ HttpClient client = HttpClient.newHttpClient();
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(BASE_URL + "/template/" + templateId))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("HTTP error " + response.statusCode() + ": " + response.body());
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode result = mapper.readTree(response.body());
+ JsonNode template = result.get("data").get("results");
+
+ System.out.println("Template: " + template.get("name").asText());
+
+ JsonNode variables = template.get("variables");
+ int variableCount = (variables != null && !variables.isNull()) ? variables.size() : 0;
+ System.out.println("Variables: " + variableCount);
+
+ String defaultFont = template.has("defaultFont") ? template.get("defaultFont").asText() : "N/A";
+ System.out.println("Default font: " + defaultFont);
+
+ return template;
+ }
+
+ /**
+ * Step 3: Get PDF Preview Link (Optional)
+ */
+ private static String getTemplatePDFPreview(String templateId) throws Exception {
+ HttpClient client = HttpClient.newHttpClient();
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(BASE_URL + "/template/" + templateId + "/previewpdflink"))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("HTTP error " + response.statusCode() + ": " + response.body());
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode result = mapper.readTree(response.body());
+ String pdfUrl = result.get("results").asText();
+
+ System.out.println("PDF Preview: " + pdfUrl);
+
+ return pdfUrl;
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/nodejs/express.js b/static/scripts/templates/api/browse-templates/nodejs/express.js
new file mode 100644
index 0000000..4f26e34
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/nodejs/express.js
@@ -0,0 +1,218 @@
+const fetch = require('node-fetch');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+// Path B: Browse and Select Existing Templates
+
+/**
+ * Step 1: Browse Templates and Folders
+ */
+async function browseTemplates(options = {}) {
+ try {
+ const {
+ limit = 25,
+ offset = 0,
+ query = '',
+ showTags = true,
+ selectedTags = []
+ } = options;
+
+ // Build query parameters
+ const params = new URLSearchParams({
+ limit: limit.toString(),
+ offset: offset.toString(),
+ showTags: showTags.toString()
+ });
+
+ if (query) params.append('query', query);
+
+ // Add selected tags (multiple values)
+ selectedTags.forEach(tag => {
+ params.append('selectedTags[]', tag);
+ });
+
+ const url = `${BASE_URL}/template-item?${params.toString()}`;
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const result = await response.json();
+ console.log(`Found ${result.data.totalRecords} templates/folders`);
+
+ return result.data;
+ } catch (error) {
+ console.error('Error browsing templates:', error);
+ throw error;
+ }
+}
+
+/**
+ * Step 2: Get Template Details by ID
+ */
+async function getTemplateDetails(templateId) {
+ try {
+ const url = `${BASE_URL}/template/${templateId}`;
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const result = await response.json();
+ const template = result.data.results;
+
+ console.log(`Template: ${template.name}`);
+ console.log(`Variables: ${template.variables.length}`);
+ console.log(`Default font: ${template.defaultFont}`);
+
+ return template;
+ } catch (error) {
+ console.error('Error getting template details:', error);
+ throw error;
+ }
+}
+
+/**
+ * Step 3: Get PDF Preview Link (Optional)
+ */
+async function getTemplatePDFPreview(templateId) {
+ try {
+ const url = `${BASE_URL}/template/${templateId}/previewpdflink`;
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const result = await response.json();
+ console.log(`PDF Preview: ${result.results}`);
+
+ return result.results;
+ } catch (error) {
+ console.error('Error getting PDF preview:', error);
+ throw error;
+ }
+}
+
+/**
+ * Browse Folder Contents
+ */
+async function browseFolderContents(folderId, options = {}) {
+ try {
+ const {
+ limit = 25,
+ offset = 0,
+ query = ''
+ } = options;
+
+ const params = new URLSearchParams({
+ limit: limit.toString(),
+ offset: offset.toString()
+ });
+
+ if (query) params.append('query', query);
+
+ const url = `${BASE_URL}/template-item/${folderId}?${params.toString()}`;
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const result = await response.json();
+ const folderData = result.data.results;
+
+ console.log(`Folder: ${folderData.name}`);
+ console.log(`Templates in folder: ${folderData.templateCount}`);
+
+ return folderData;
+ } catch (error) {
+ console.error('Error browsing folder:', error);
+ throw error;
+ }
+}
+
+// Example usage - Complete browsing workflow
+async function exampleBrowsingWorkflow() {
+ try {
+ console.log('=== Path B: Browse and Select Template ===');
+
+ // Step 1: Browse all templates
+ console.log('\n1. Browsing templates...');
+ const browseResult = await browseTemplates({
+ limit: 10,
+ query: 'contract',
+ showTags: true
+ });
+
+ // Find a template (not a folder)
+ const template = browseResult.results.find(item => item.type === 'template');
+ if (!template) {
+ console.log('No templates found in browse results');
+ return;
+ }
+
+ console.log(`\nSelected template: ${template.name} (${template.id})`);
+
+ // Step 2: Get detailed template information
+ console.log('\n2. Getting template details...');
+ const templateDetails = await getTemplateDetails(template.id);
+
+ // Step 3: Get PDF preview (optional)
+ console.log('\n3. Getting PDF preview...');
+ const pdfPreview = await getTemplatePDFPreview(template.id);
+
+ console.log('\n=== Template Ready for Generation ===');
+ console.log(`Template ID: ${templateDetails.id}`);
+ console.log(`Variables available: ${templateDetails.variables.length}`);
+ console.log(`PDF Preview: ${pdfPreview}`);
+
+ return {
+ template: templateDetails,
+ pdfPreview
+ };
+
+ } catch (error) {
+ console.error('Browsing workflow failed:', error.message);
+ }
+}
+
+// Run the example
+exampleBrowsingWorkflow();
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/nodejs/fastify.js b/static/scripts/templates/api/browse-templates/nodejs/fastify.js
new file mode 100644
index 0000000..4f26e34
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/nodejs/fastify.js
@@ -0,0 +1,218 @@
+const fetch = require('node-fetch');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+// Path B: Browse and Select Existing Templates
+
+/**
+ * Step 1: Browse Templates and Folders
+ */
+async function browseTemplates(options = {}) {
+ try {
+ const {
+ limit = 25,
+ offset = 0,
+ query = '',
+ showTags = true,
+ selectedTags = []
+ } = options;
+
+ // Build query parameters
+ const params = new URLSearchParams({
+ limit: limit.toString(),
+ offset: offset.toString(),
+ showTags: showTags.toString()
+ });
+
+ if (query) params.append('query', query);
+
+ // Add selected tags (multiple values)
+ selectedTags.forEach(tag => {
+ params.append('selectedTags[]', tag);
+ });
+
+ const url = `${BASE_URL}/template-item?${params.toString()}`;
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const result = await response.json();
+ console.log(`Found ${result.data.totalRecords} templates/folders`);
+
+ return result.data;
+ } catch (error) {
+ console.error('Error browsing templates:', error);
+ throw error;
+ }
+}
+
+/**
+ * Step 2: Get Template Details by ID
+ */
+async function getTemplateDetails(templateId) {
+ try {
+ const url = `${BASE_URL}/template/${templateId}`;
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const result = await response.json();
+ const template = result.data.results;
+
+ console.log(`Template: ${template.name}`);
+ console.log(`Variables: ${template.variables.length}`);
+ console.log(`Default font: ${template.defaultFont}`);
+
+ return template;
+ } catch (error) {
+ console.error('Error getting template details:', error);
+ throw error;
+ }
+}
+
+/**
+ * Step 3: Get PDF Preview Link (Optional)
+ */
+async function getTemplatePDFPreview(templateId) {
+ try {
+ const url = `${BASE_URL}/template/${templateId}/previewpdflink`;
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const result = await response.json();
+ console.log(`PDF Preview: ${result.results}`);
+
+ return result.results;
+ } catch (error) {
+ console.error('Error getting PDF preview:', error);
+ throw error;
+ }
+}
+
+/**
+ * Browse Folder Contents
+ */
+async function browseFolderContents(folderId, options = {}) {
+ try {
+ const {
+ limit = 25,
+ offset = 0,
+ query = ''
+ } = options;
+
+ const params = new URLSearchParams({
+ limit: limit.toString(),
+ offset: offset.toString()
+ });
+
+ if (query) params.append('query', query);
+
+ const url = `${BASE_URL}/template-item/${folderId}?${params.toString()}`;
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const result = await response.json();
+ const folderData = result.data.results;
+
+ console.log(`Folder: ${folderData.name}`);
+ console.log(`Templates in folder: ${folderData.templateCount}`);
+
+ return folderData;
+ } catch (error) {
+ console.error('Error browsing folder:', error);
+ throw error;
+ }
+}
+
+// Example usage - Complete browsing workflow
+async function exampleBrowsingWorkflow() {
+ try {
+ console.log('=== Path B: Browse and Select Template ===');
+
+ // Step 1: Browse all templates
+ console.log('\n1. Browsing templates...');
+ const browseResult = await browseTemplates({
+ limit: 10,
+ query: 'contract',
+ showTags: true
+ });
+
+ // Find a template (not a folder)
+ const template = browseResult.results.find(item => item.type === 'template');
+ if (!template) {
+ console.log('No templates found in browse results');
+ return;
+ }
+
+ console.log(`\nSelected template: ${template.name} (${template.id})`);
+
+ // Step 2: Get detailed template information
+ console.log('\n2. Getting template details...');
+ const templateDetails = await getTemplateDetails(template.id);
+
+ // Step 3: Get PDF preview (optional)
+ console.log('\n3. Getting PDF preview...');
+ const pdfPreview = await getTemplatePDFPreview(template.id);
+
+ console.log('\n=== Template Ready for Generation ===');
+ console.log(`Template ID: ${templateDetails.id}`);
+ console.log(`Variables available: ${templateDetails.variables.length}`);
+ console.log(`PDF Preview: ${pdfPreview}`);
+
+ return {
+ template: templateDetails,
+ pdfPreview
+ };
+
+ } catch (error) {
+ console.error('Browsing workflow failed:', error.message);
+ }
+}
+
+// Run the example
+exampleBrowsingWorkflow();
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/powershell.ps1 b/static/scripts/templates/api/browse-templates/powershell.ps1
new file mode 100644
index 0000000..bb75381
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/powershell.ps1
@@ -0,0 +1,171 @@
+# Configuration - Update these values
+$API_TOKEN = "YOUR_API_TOKEN"
+$ORG_ID = "YOUR_ORGANIZATION_ID"
+$BASE_URL = "https://api.turbodocx.com"
+
+##
+# Path B: Browse and Select Existing Templates
+##
+
+function Browse-Templates {
+ param(
+ [int]$Limit = 25,
+ [int]$Offset = 0,
+ [string]$Query = '',
+ [bool]$ShowTags = $true,
+ [string[]]$SelectedTags = $null
+ )
+
+ # Build query parameters
+ $params = @{
+ 'limit' = $Limit
+ 'offset' = $Offset
+ 'showTags' = $ShowTags.ToString().ToLower()
+ }
+
+ if ($Query -ne '') {
+ $params['query'] = $Query
+ }
+
+ if ($SelectedTags) {
+ foreach ($tag in $SelectedTags) {
+ $params["selectedTags[]"] = $tag
+ }
+ }
+
+ # Build query string
+ $queryString = ($params.GetEnumerator() | ForEach-Object {
+ "$([System.Web.HttpUtility]::UrlEncode($_.Key))=$([System.Web.HttpUtility]::UrlEncode($_.Value))"
+ }) -join '&'
+
+ $uri = "$BASE_URL/template-item?$queryString"
+
+ try {
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $API_TOKEN"
+ 'x-rapiddocx-org-id' = $ORG_ID
+ 'User-Agent' = 'TurboDocx API Client'
+ }
+
+ # Make request
+ $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
+
+ # Parse response
+ $data = $response.data
+
+ Write-Host "Found $($data.totalRecords) templates/folders"
+
+ return $data
+ }
+ catch {
+ Write-Error "Browse failed: $($_.Exception.Message)"
+ throw
+ }
+}
+
+function Get-TemplateDetails {
+ param(
+ [Parameter(Mandatory=$true)]
+ [string]$TemplateId
+ )
+
+ $uri = "$BASE_URL/template/$TemplateId"
+
+ try {
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $API_TOKEN"
+ 'x-rapiddocx-org-id' = $ORG_ID
+ 'User-Agent' = 'TurboDocx API Client'
+ }
+
+ # Make request
+ $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
+
+ $template = $response.data.results
+
+ Write-Host "Template: $($template.name)"
+
+ $variableCount = if ($template.variables) { $template.variables.Count } else { 0 }
+ Write-Host "Variables: $variableCount"
+
+ $defaultFont = if ($template.defaultFont) { $template.defaultFont } else { 'N/A' }
+ Write-Host "Default font: $defaultFont"
+
+ return $template
+ }
+ catch {
+ Write-Error "Failed to get template details: $($_.Exception.Message)"
+ throw
+ }
+}
+
+function Get-TemplatePdfPreview {
+ param(
+ [Parameter(Mandatory=$true)]
+ [string]$TemplateId
+ )
+
+ $uri = "$BASE_URL/template/$TemplateId/previewpdflink"
+
+ try {
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $API_TOKEN"
+ 'x-rapiddocx-org-id' = $ORG_ID
+ 'User-Agent' = 'TurboDocx API Client'
+ }
+
+ # Make request
+ $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
+
+ $pdfUrl = $response.results
+
+ Write-Host "PDF Preview: $pdfUrl"
+
+ return $pdfUrl
+ }
+ catch {
+ Write-Error "Failed to get PDF preview: $($_.Exception.Message)"
+ throw
+ }
+}
+
+# Example usage - Complete browsing workflow
+try {
+ Write-Host "=== Path B: Browse and Select Template ===" -ForegroundColor Cyan
+
+ # Step 1: Browse all templates
+ Write-Host "`n1. Browsing templates..." -ForegroundColor Yellow
+ $browseResult = Browse-Templates -Limit 10 -Offset 0 -Query 'contract' -ShowTags $true
+
+ # Find a template (not a folder)
+ $selectedTemplate = $browseResult.results | Where-Object { $_.type -eq 'template' } | Select-Object -First 1
+
+ if ($null -eq $selectedTemplate) {
+ Write-Host "No templates found in browse results" -ForegroundColor Red
+ exit 1
+ }
+
+ Write-Host "`nSelected template: $($selectedTemplate.name) ($($selectedTemplate.id))"
+
+ # Step 2: Get detailed template information
+ Write-Host "`n2. Getting template details..." -ForegroundColor Yellow
+ $templateDetails = Get-TemplateDetails -TemplateId $selectedTemplate.id
+
+ # Step 3: Get PDF preview (optional)
+ Write-Host "`n3. Getting PDF preview..." -ForegroundColor Yellow
+ $pdfPreview = Get-TemplatePdfPreview -TemplateId $selectedTemplate.id
+
+ Write-Host "`n=== Template Ready for Generation ===" -ForegroundColor Green
+ Write-Host "Template ID: $($templateDetails.id)"
+
+ $variableCount = if ($templateDetails.variables) { $templateDetails.variables.Count } else { 0 }
+ Write-Host "Variables available: $variableCount"
+ Write-Host "PDF Preview: $pdfPreview"
+}
+catch {
+ Write-Error "Browsing workflow failed: $($_.Exception.Message)"
+ exit 1
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/python/fastapi.py b/static/scripts/templates/api/browse-templates/python/fastapi.py
new file mode 100644
index 0000000..6f373c1
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/python/fastapi.py
@@ -0,0 +1,180 @@
+import requests
+import json
+from urllib.parse import urlencode
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+class TemplateBrowser:
+ """Path B: Browse and Select Existing Templates"""
+
+ def __init__(self, api_token, org_id, base_url):
+ self.api_token = api_token
+ self.org_id = org_id
+ self.base_url = base_url
+ self.headers = {
+ 'Authorization': f'Bearer {api_token}',
+ 'x-rapiddocx-org-id': org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ def browse_templates(self, limit=25, offset=0, query='', show_tags=True, selected_tags=None):
+ """Step 1: Browse Templates and Folders"""
+ try:
+ url = f"{self.base_url}/template-item"
+
+ params = {
+ 'limit': limit,
+ 'offset': offset,
+ 'showTags': str(show_tags).lower()
+ }
+
+ if query:
+ params['query'] = query
+
+ # Handle multiple selectedTags parameters
+ if selected_tags:
+ # For requests library, we need to handle multiple values manually
+ param_string = urlencode(params)
+ for tag in selected_tags:
+ param_string += f"&selectedTags[]={tag}"
+ url += f"?{param_string}"
+ else:
+ url += f"?{urlencode(params)}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ data = result['data']
+
+ print(f"Found {data['totalRecords']} templates/folders")
+
+ return data
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error browsing templates: {e}")
+ raise
+
+ def get_template_details(self, template_id):
+ """Step 2: Get Template Details by ID"""
+ try:
+ url = f"{self.base_url}/template/{template_id}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ template = result['data']['results']
+
+ print(f"Template: {template['name']}")
+ print(f"Variables: {len(template['variables'])}")
+ print(f"Default font: {template.get('defaultFont', 'N/A')}")
+
+ return template
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error getting template details: {e}")
+ raise
+
+ def get_template_pdf_preview(self, template_id):
+ """Step 3: Get PDF Preview Link (Optional)"""
+ try:
+ url = f"{self.base_url}/template/{template_id}/previewpdflink"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ pdf_url = result['results']
+
+ print(f"PDF Preview: {pdf_url}")
+
+ return pdf_url
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error getting PDF preview: {e}")
+ raise
+
+ def browse_folder_contents(self, folder_id, limit=25, offset=0, query=''):
+ """Browse Folder Contents"""
+ try:
+ params = {
+ 'limit': limit,
+ 'offset': offset
+ }
+
+ if query:
+ params['query'] = query
+
+ url = f"{self.base_url}/template-item/{folder_id}?{urlencode(params)}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ folder_data = result['data']['results']
+
+ print(f"Folder: {folder_data['name']}")
+ print(f"Templates in folder: {folder_data.get('templateCount', 0)}")
+
+ return folder_data
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error browsing folder: {e}")
+ raise
+
+def example_browsing_workflow():
+ """Example usage - Complete browsing workflow"""
+ try:
+ print("=== Path B: Browse and Select Template ===")
+
+ browser = TemplateBrowser(API_TOKEN, ORG_ID, BASE_URL)
+
+ # Step 1: Browse all templates
+ print("\n1. Browsing templates...")
+ browse_result = browser.browse_templates(
+ limit=10,
+ query='contract',
+ show_tags=True
+ )
+
+ # Find a template (not a folder)
+ template = None
+ for item in browse_result['results']:
+ if item['type'] == 'template':
+ template = item
+ break
+
+ if not template:
+ print("No templates found in browse results")
+ return
+
+ print(f"\nSelected template: {template['name']} ({template['id']})")
+
+ # Step 2: Get detailed template information
+ print("\n2. Getting template details...")
+ template_details = browser.get_template_details(template['id'])
+
+ # Step 3: Get PDF preview (optional)
+ print("\n3. Getting PDF preview...")
+ pdf_preview = browser.get_template_pdf_preview(template['id'])
+
+ print("\n=== Template Ready for Generation ===")
+ print(f"Template ID: {template_details['id']}")
+ print(f"Variables available: {len(template_details['variables'])}")
+ print(f"PDF Preview: {pdf_preview}")
+
+ return {
+ 'template': template_details,
+ 'pdf_preview': pdf_preview
+ }
+
+ except Exception as error:
+ print(f"Browsing workflow failed: {error}")
+
+# Example usage
+if __name__ == "__main__":
+ example_browsing_workflow()
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/python/flask.py b/static/scripts/templates/api/browse-templates/python/flask.py
new file mode 100644
index 0000000..6f373c1
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/python/flask.py
@@ -0,0 +1,180 @@
+import requests
+import json
+from urllib.parse import urlencode
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+class TemplateBrowser:
+ """Path B: Browse and Select Existing Templates"""
+
+ def __init__(self, api_token, org_id, base_url):
+ self.api_token = api_token
+ self.org_id = org_id
+ self.base_url = base_url
+ self.headers = {
+ 'Authorization': f'Bearer {api_token}',
+ 'x-rapiddocx-org-id': org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ def browse_templates(self, limit=25, offset=0, query='', show_tags=True, selected_tags=None):
+ """Step 1: Browse Templates and Folders"""
+ try:
+ url = f"{self.base_url}/template-item"
+
+ params = {
+ 'limit': limit,
+ 'offset': offset,
+ 'showTags': str(show_tags).lower()
+ }
+
+ if query:
+ params['query'] = query
+
+ # Handle multiple selectedTags parameters
+ if selected_tags:
+ # For requests library, we need to handle multiple values manually
+ param_string = urlencode(params)
+ for tag in selected_tags:
+ param_string += f"&selectedTags[]={tag}"
+ url += f"?{param_string}"
+ else:
+ url += f"?{urlencode(params)}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ data = result['data']
+
+ print(f"Found {data['totalRecords']} templates/folders")
+
+ return data
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error browsing templates: {e}")
+ raise
+
+ def get_template_details(self, template_id):
+ """Step 2: Get Template Details by ID"""
+ try:
+ url = f"{self.base_url}/template/{template_id}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ template = result['data']['results']
+
+ print(f"Template: {template['name']}")
+ print(f"Variables: {len(template['variables'])}")
+ print(f"Default font: {template.get('defaultFont', 'N/A')}")
+
+ return template
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error getting template details: {e}")
+ raise
+
+ def get_template_pdf_preview(self, template_id):
+ """Step 3: Get PDF Preview Link (Optional)"""
+ try:
+ url = f"{self.base_url}/template/{template_id}/previewpdflink"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ pdf_url = result['results']
+
+ print(f"PDF Preview: {pdf_url}")
+
+ return pdf_url
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error getting PDF preview: {e}")
+ raise
+
+ def browse_folder_contents(self, folder_id, limit=25, offset=0, query=''):
+ """Browse Folder Contents"""
+ try:
+ params = {
+ 'limit': limit,
+ 'offset': offset
+ }
+
+ if query:
+ params['query'] = query
+
+ url = f"{self.base_url}/template-item/{folder_id}?{urlencode(params)}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ folder_data = result['data']['results']
+
+ print(f"Folder: {folder_data['name']}")
+ print(f"Templates in folder: {folder_data.get('templateCount', 0)}")
+
+ return folder_data
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error browsing folder: {e}")
+ raise
+
+def example_browsing_workflow():
+ """Example usage - Complete browsing workflow"""
+ try:
+ print("=== Path B: Browse and Select Template ===")
+
+ browser = TemplateBrowser(API_TOKEN, ORG_ID, BASE_URL)
+
+ # Step 1: Browse all templates
+ print("\n1. Browsing templates...")
+ browse_result = browser.browse_templates(
+ limit=10,
+ query='contract',
+ show_tags=True
+ )
+
+ # Find a template (not a folder)
+ template = None
+ for item in browse_result['results']:
+ if item['type'] == 'template':
+ template = item
+ break
+
+ if not template:
+ print("No templates found in browse results")
+ return
+
+ print(f"\nSelected template: {template['name']} ({template['id']})")
+
+ # Step 2: Get detailed template information
+ print("\n2. Getting template details...")
+ template_details = browser.get_template_details(template['id'])
+
+ # Step 3: Get PDF preview (optional)
+ print("\n3. Getting PDF preview...")
+ pdf_preview = browser.get_template_pdf_preview(template['id'])
+
+ print("\n=== Template Ready for Generation ===")
+ print(f"Template ID: {template_details['id']}")
+ print(f"Variables available: {len(template_details['variables'])}")
+ print(f"PDF Preview: {pdf_preview}")
+
+ return {
+ 'template': template_details,
+ 'pdf_preview': pdf_preview
+ }
+
+ except Exception as error:
+ print(f"Browsing workflow failed: {error}")
+
+# Example usage
+if __name__ == "__main__":
+ example_browsing_workflow()
\ No newline at end of file
diff --git a/static/scripts/templates/api/browse-templates/ruby.rb b/static/scripts/templates/api/browse-templates/ruby.rb
new file mode 100644
index 0000000..b7176e3
--- /dev/null
+++ b/static/scripts/templates/api/browse-templates/ruby.rb
@@ -0,0 +1,167 @@
+require 'net/http'
+require 'uri'
+require 'json'
+require 'cgi'
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+##
+# Path B: Browse and Select Existing Templates
+##
+
+def browse_templates(limit = 25, offset = 0, query = '', show_tags = true, selected_tags = nil)
+ # Build query parameters
+ params = {
+ 'limit' => limit.to_s,
+ 'offset' => offset.to_s,
+ 'showTags' => show_tags.to_s
+ }
+
+ params['query'] = query unless query.empty?
+
+ if selected_tags
+ selected_tags.each do |tag|
+ params["selectedTags[]"] = tag
+ end
+ end
+
+ query_string = params.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v)}" }.join('&')
+ uri = URI("#{BASE_URL}/template-item?#{query_string}")
+
+ # Create HTTP connection
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ # Create request
+ request = Net::HTTP::Get.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+
+ # Make request
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "HTTP error #{response.code}: #{response.body}"
+ end
+
+ # Parse JSON response
+ result = JSON.parse(response.body)
+ data = result['data']
+
+ puts "Found #{data['totalRecords']} templates/folders"
+
+ data
+rescue JSON::ParserError => e
+ raise "Failed to parse JSON response: #{e.message}"
+rescue => e
+ puts "Browse failed: #{e.message}"
+ raise
+end
+
+def get_template_details(template_id)
+ uri = URI("#{BASE_URL}/template/#{template_id}")
+
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ request = Net::HTTP::Get.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "HTTP error #{response.code}: #{response.body}"
+ end
+
+ result = JSON.parse(response.body)
+ template = result['data']['results']
+
+ puts "Template: #{template['name']}"
+
+ variable_count = template['variables'] ? template['variables'].length : 0
+ puts "Variables: #{variable_count}"
+
+ default_font = template['defaultFont'] || 'N/A'
+ puts "Default font: #{default_font}"
+
+ template
+rescue JSON::ParserError => e
+ raise "Failed to parse JSON response: #{e.message}"
+rescue => e
+ puts "Failed to get template details: #{e.message}"
+ raise
+end
+
+def get_template_pdf_preview(template_id)
+ uri = URI("#{BASE_URL}/template/#{template_id}/previewpdflink")
+
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ request = Net::HTTP::Get.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "HTTP error #{response.code}: #{response.body}"
+ end
+
+ result = JSON.parse(response.body)
+ pdf_url = result['results']
+
+ puts "PDF Preview: #{pdf_url}"
+
+ pdf_url
+rescue JSON::ParserError => e
+ raise "Failed to parse JSON response: #{e.message}"
+rescue => e
+ puts "Failed to get PDF preview: #{e.message}"
+ raise
+end
+
+# Example usage - Complete browsing workflow
+begin
+ puts "=== Path B: Browse and Select Template ==="
+
+ # Step 1: Browse all templates
+ puts "\n1. Browsing templates..."
+ browse_result = browse_templates(10, 0, 'contract', true)
+
+ # Find a template (not a folder)
+ selected_template = browse_result['results'].find { |item| item['type'] == 'template' }
+
+ if selected_template.nil?
+ puts "No templates found in browse results"
+ exit 1
+ end
+
+ puts "\nSelected template: #{selected_template['name']} (#{selected_template['id']})"
+
+ # Step 2: Get detailed template information
+ puts "\n2. Getting template details..."
+ template_details = get_template_details(selected_template['id'])
+
+ # Step 3: Get PDF preview (optional)
+ puts "\n3. Getting PDF preview..."
+ pdf_preview = get_template_pdf_preview(selected_template['id'])
+
+ puts "\n=== Template Ready for Generation ==="
+ puts "Template ID: #{template_details['id']}"
+
+ variable_count = template_details['variables'] ? template_details['variables'].length : 0
+ puts "Variables available: #{variable_count}"
+ puts "PDF Preview: #{pdf_preview}"
+
+rescue => e
+ puts "Browsing workflow failed: #{e.message}"
+ exit 1
+end
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/csharp/controller.cs b/static/scripts/templates/api/complete-workflows/csharp/controller.cs
new file mode 100644
index 0000000..43846db
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/csharp/controller.cs
@@ -0,0 +1,468 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+using System.Text.Json;
+using System.Text;
+using System.Web;
+
+/**
+ * Complete Template Generation Workflows
+ * Demonstrates both Path A (Upload) and Path B (Browse/Select) followed by generation
+ */
+class TemplateWorkflowManager
+{
+ // Configuration - Update these values
+ private const string API_TOKEN = "YOUR_API_TOKEN";
+ private const string ORG_ID = "YOUR_ORGANIZATION_ID";
+ private const string BASE_URL = "https://api.turbodocx.com";
+
+ private readonly HttpClient client;
+
+ public TemplateWorkflowManager()
+ {
+ client = new HttpClient();
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+ }
+
+ static async Task Main(string[] args)
+ {
+ var workflow = new TemplateWorkflowManager();
+
+ try
+ {
+ // Demo Path B (Browse existing templates)
+ await workflow.DemoPathB();
+
+ // Uncomment to demo Path A (requires template file):
+ // await workflow.DemoPathA("./path/to/your/template.docx");
+
+ // Uncomment to run full comparison:
+ // await workflow.DemoComparison();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Workflow demo failed: {ex.Message}");
+ }
+ finally
+ {
+ workflow.client?.Dispose();
+ }
+ }
+
+ // ===============================
+ // PATH A: Upload New Template
+ // ===============================
+
+ /**
+ * Complete Path A workflow: Upload → Generate
+ */
+ public async Task PathA_UploadAndGenerate(string templateFilePath, string deliverableName)
+ {
+ Console.WriteLine("🔄 PATH A: Upload New Template → Generate Deliverable");
+ Console.WriteLine(new string('=', 48));
+
+ try
+ {
+ // Step 1: Upload and create template
+ Console.WriteLine("\n📤 Step 1: Uploading template...");
+ var template = await UploadTemplate(templateFilePath);
+
+ // Step 2: Generate deliverable using uploaded template
+ Console.WriteLine("\n📝 Step 2: Generating deliverable...");
+ using var templateDoc = JsonDocument.Parse(template);
+ var templateInfo = templateDoc.RootElement.GetProperty("data").GetProperty("results").GetProperty("template");
+
+ var deliverable = await GenerateDeliverable(
+ templateInfo.GetProperty("id").GetString(),
+ deliverableName,
+ $"Generated from uploaded template: {templateInfo.GetProperty("name").GetString()}"
+ );
+
+ Console.WriteLine("\n✅ PATH A COMPLETE!");
+ Console.WriteLine($"Template ID: {templateInfo.GetProperty("id").GetString()}");
+
+ using var deliverableDoc = JsonDocument.Parse(deliverable);
+ var deliverableInfo = deliverableDoc.RootElement.GetProperty("data").GetProperty("results").GetProperty("deliverable");
+ Console.WriteLine($"Deliverable ID: {deliverableInfo.GetProperty("id").GetString()}");
+
+ // Download the generated file
+ await DownloadDeliverable(
+ deliverableInfo.GetProperty("id").GetString(),
+ $"{deliverableInfo.GetProperty("name").GetString()}.docx"
+ );
+
+ return new TemplateWorkflowResult(template, deliverable, null);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"❌ Path A failed: {ex.Message}");
+ throw;
+ }
+ }
+
+ private async Task UploadTemplate(string templateFilePath)
+ {
+ if (!File.Exists(templateFilePath))
+ {
+ throw new FileNotFoundException($"Template file not found: {templateFilePath}");
+ }
+
+ using var content = new MultipartFormDataContent();
+
+ var fileContent = new ByteArrayContent(File.ReadAllBytes(templateFilePath));
+ fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+ content.Add(fileContent, "templateFile", Path.GetFileName(templateFilePath));
+
+ content.Add(new StringContent("API Upload Template"), "name");
+ content.Add(new StringContent("Template uploaded via API for testing"), "description");
+ content.Add(new StringContent("[]"), "variables");
+ content.Add(new StringContent("[\"api\", \"test\", \"upload\"]"), "tags");
+
+ var response = await client.PostAsync($"{BASE_URL}/template/upload-and-create", content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"Upload failed: {response.StatusCode} - {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var template = document.RootElement.GetProperty("data").GetProperty("results").GetProperty("template");
+
+ Console.WriteLine($"✅ Template uploaded: {template.GetProperty("name").GetString()} ({template.GetProperty("id").GetString()})");
+
+ var variableCount = 0;
+ if (template.TryGetProperty("variables", out var variables) && variables.ValueKind != JsonValueKind.Null)
+ {
+ variableCount = variables.GetArrayLength();
+ }
+ Console.WriteLine($"📊 Variables extracted: {variableCount}");
+
+ Console.WriteLine($"🔤 Default font: {template.GetProperty("defaultFont").GetString()}");
+
+ var fontCount = 0;
+ if (template.TryGetProperty("fonts", out var fonts) && fonts.ValueKind != JsonValueKind.Null)
+ {
+ fontCount = fonts.GetArrayLength();
+ }
+ Console.WriteLine($"📝 Fonts used: {fontCount}");
+
+ return result;
+ }
+
+ // ===============================
+ // PATH B: Browse and Select
+ // ===============================
+
+ /**
+ * Complete Path B workflow: Browse → Select → Generate
+ */
+ public async Task PathB_BrowseAndGenerate(string searchQuery, string deliverableName)
+ {
+ Console.WriteLine("🔍 PATH B: Browse Existing Templates → Generate Deliverable");
+ Console.WriteLine(new string('=', 56));
+
+ try
+ {
+ // Step 1: Browse templates
+ Console.WriteLine("\n🔍 Step 1: Browsing templates...");
+ var browseResult = await BrowseTemplates(searchQuery);
+
+ // Step 2: Select first available template
+ using var browseDoc = JsonDocument.Parse(browseResult);
+ var results = browseDoc.RootElement.GetProperty("data").GetProperty("results");
+
+ JsonElement? selectedTemplate = null;
+ foreach (var item in results.EnumerateArray())
+ {
+ if (item.GetProperty("type").GetString() == "template")
+ {
+ selectedTemplate = item;
+ break;
+ }
+ }
+
+ if (!selectedTemplate.HasValue)
+ {
+ throw new Exception("No templates found in browse results");
+ }
+
+ var template = selectedTemplate.Value;
+ Console.WriteLine($"📋 Selected: {template.GetProperty("name").GetString()} ({template.GetProperty("id").GetString()})");
+
+ // Step 3: Get template details
+ Console.WriteLine("\n📖 Step 2: Getting template details...");
+ var templateDetails = await GetTemplateDetails(template.GetProperty("id").GetString());
+
+ // Step 4: Get PDF preview (optional)
+ Console.WriteLine("\n🖼️ Step 3: Getting PDF preview...");
+ var pdfPreview = await GetTemplatePDFPreview(template.GetProperty("id").GetString());
+
+ // Step 5: Generate deliverable
+ Console.WriteLine("\n📝 Step 4: Generating deliverable...");
+ using var detailsDoc = JsonDocument.Parse(templateDetails);
+ var templateInfo = detailsDoc.RootElement.GetProperty("data").GetProperty("results");
+
+ var deliverable = await GenerateDeliverable(
+ templateInfo.GetProperty("id").GetString(),
+ deliverableName,
+ $"Generated from existing template: {templateInfo.GetProperty("name").GetString()}"
+ );
+
+ Console.WriteLine("\n✅ PATH B COMPLETE!");
+ Console.WriteLine($"Template ID: {templateInfo.GetProperty("id").GetString()}");
+
+ using var deliverableDoc = JsonDocument.Parse(deliverable);
+ var deliverableInfo = deliverableDoc.RootElement.GetProperty("data").GetProperty("results").GetProperty("deliverable");
+ Console.WriteLine($"Deliverable ID: {deliverableInfo.GetProperty("id").GetString()}");
+ Console.WriteLine($"PDF Preview: {pdfPreview}");
+
+ // Download the generated file
+ Console.WriteLine("\n📥 Step 5: Downloading file...");
+ await DownloadDeliverable(
+ deliverableInfo.GetProperty("id").GetString(),
+ $"{deliverableInfo.GetProperty("name").GetString()}.docx"
+ );
+
+ return new TemplateWorkflowResult(templateDetails, deliverable, pdfPreview);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"❌ Path B failed: {ex.Message}");
+ throw;
+ }
+ }
+
+ private async Task BrowseTemplates(string query)
+ {
+ var queryParams = "limit=25&offset=0&showTags=true";
+
+ if (!string.IsNullOrEmpty(query))
+ {
+ queryParams += $"&query={HttpUtility.UrlEncode(query)}";
+ }
+
+ var response = await client.GetAsync($"{BASE_URL}/template-item?{queryParams}");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"Browse failed: {response.StatusCode} - {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var totalRecords = document.RootElement.GetProperty("data").GetProperty("totalRecords").GetInt32();
+ Console.WriteLine($"🔍 Found {totalRecords} templates/folders");
+
+ return result;
+ }
+
+ private async Task GetTemplateDetails(string templateId)
+ {
+ var response = await client.GetAsync($"{BASE_URL}/template/{templateId}");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"Template details failed: {response.StatusCode} - {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var template = document.RootElement.GetProperty("data").GetProperty("results");
+
+ var variableCount = 0;
+ if (template.TryGetProperty("variables", out var variables) && variables.ValueKind != JsonValueKind.Null)
+ {
+ variableCount = variables.GetArrayLength();
+ }
+ Console.WriteLine($"📊 Variables: {variableCount}");
+
+ var defaultFont = template.TryGetProperty("defaultFont", out var font) ? font.GetString() : "N/A";
+ Console.WriteLine($"🔤 Default font: {defaultFont}");
+
+ return result;
+ }
+
+ private async Task GetTemplatePDFPreview(string templateId)
+ {
+ var response = await client.GetAsync($"{BASE_URL}/template/{templateId}/previewpdflink");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"PDF preview failed: {response.StatusCode} - {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var pdfUrl = document.RootElement.GetProperty("results").GetString();
+
+ Console.WriteLine($"🖼️ PDF Preview available: {pdfUrl}");
+
+ return pdfUrl;
+ }
+
+ // ===============================
+ // COMMON: Generate Deliverable
+ // ===============================
+
+ private async Task GenerateDeliverable(string templateId, string name, string description)
+ {
+ var payload = $$"""
+ {
+ "templateId": "{{templateId}}",
+ "name": "{{name}}",
+ "description": "{{description}}",
+ "variables": [
+ {
+ "mimeType": "text",
+ "name": "Sample Variable",
+ "placeholder": "{SampleVariable}",
+ "text": "Sample Content from C# Workflow",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 1,
+ "order": 1,
+ "subvariables": [],
+ "metadata": {
+ "generatedBy": "C# Workflow"
+ },
+ "aiPrompt": ""
+ }
+ ],
+ "tags": ["api-generated"],
+ "fonts": "[]",
+ "defaultFont": "Arial",
+ "replaceFonts": true,
+ "metadata": {
+ "sessions": [
+ {
+ "id": "{{Guid.NewGuid()}}",
+ "starttime": "{{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}}",
+ "endtime": "{{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}}"
+ }
+ ],
+ "workflow": "C# Complete Workflow",
+ "generated": "{{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}}"
+ }
+ }
+ """;
+
+ var content = new StringContent(payload, Encoding.UTF8, "application/json");
+ var response = await client.PostAsync($"{BASE_URL}/deliverable", content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"Deliverable generation failed: {response.StatusCode} - {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var deliverable = document.RootElement.GetProperty("data").GetProperty("results").GetProperty("deliverable");
+
+ Console.WriteLine($"✅ Generated: {deliverable.GetProperty("name").GetString()}");
+ Console.WriteLine($"📄 Created by: {deliverable.GetProperty("createdBy").GetString()}");
+ Console.WriteLine($"📅 Created on: {deliverable.GetProperty("createdOn").GetString()}");
+
+ return result;
+ }
+
+ private async Task DownloadDeliverable(string deliverableId, string filename)
+ {
+ Console.WriteLine($"📥 Downloading file: {filename}");
+
+ var response = await client.GetAsync($"{BASE_URL}/deliverable/file/{deliverableId}");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ throw new HttpRequestException($"Download failed: {response.StatusCode}");
+ }
+
+ Console.WriteLine($"✅ File ready for download: {filename}");
+
+ var contentType = response.Content.Headers.ContentType?.ToString() ?? "N/A";
+ var contentLength = response.Content.Headers.ContentLength?.ToString() ?? "N/A";
+
+ Console.WriteLine($"📁 Content-Type: {contentType}");
+ Console.WriteLine($"📊 Content-Length: {contentLength} bytes");
+
+ // In a real application, you would save the file
+ // var fileBytes = await response.Content.ReadAsByteArrayAsync();
+ // await File.WriteAllBytesAsync(filename, fileBytes);
+ }
+
+ // ===============================
+ // DEMO FUNCTIONS
+ // ===============================
+
+ public async Task DemoPathA(string templateFilePath)
+ {
+ Console.WriteLine("🚀 DEMO: Path A - Upload New Template Workflow");
+ Console.WriteLine(new string('=', 45));
+ Console.WriteLine();
+
+ return await PathA_UploadAndGenerate(templateFilePath, "Contract Generated via Path A - API Upload");
+ }
+
+ public async Task DemoPathB()
+ {
+ Console.WriteLine("🚀 DEMO: Path B - Browse Existing Template Workflow");
+ Console.WriteLine(new string('=', 51));
+ Console.WriteLine();
+
+ return await PathB_BrowseAndGenerate("contract", "Contract Generated via Path B - Browse & Select");
+ }
+
+ public async Task DemoComparison()
+ {
+ Console.WriteLine("🚀 DEMO: Complete Workflow Comparison");
+ Console.WriteLine(new string('=', 36));
+ Console.WriteLine();
+
+ try
+ {
+ Console.WriteLine("Testing both paths with the same template type...\n");
+
+ // Run Path B first (browse existing)
+ var pathBResult = await DemoPathB();
+
+ Console.WriteLine("\n" + new string('=', 60) + "\n");
+
+ // For Path A, we'd need a template file
+ Console.WriteLine("📝 Path A requires a template file to upload.");
+ Console.WriteLine(" Example: await workflow.DemoPathA(\"./contract-template.docx\")");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Demo comparison failed: {ex.Message}");
+ }
+ }
+
+ // Result container class
+ public class TemplateWorkflowResult
+ {
+ public string Template { get; }
+ public string Deliverable { get; }
+ public string PdfPreview { get; }
+
+ public TemplateWorkflowResult(string template, string deliverable, string pdfPreview)
+ {
+ Template = template;
+ Deliverable = deliverable;
+ PdfPreview = pdfPreview;
+ }
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/csharp/minimal.cs b/static/scripts/templates/api/complete-workflows/csharp/minimal.cs
new file mode 100644
index 0000000..43846db
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/csharp/minimal.cs
@@ -0,0 +1,468 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+using System.Text.Json;
+using System.Text;
+using System.Web;
+
+/**
+ * Complete Template Generation Workflows
+ * Demonstrates both Path A (Upload) and Path B (Browse/Select) followed by generation
+ */
+class TemplateWorkflowManager
+{
+ // Configuration - Update these values
+ private const string API_TOKEN = "YOUR_API_TOKEN";
+ private const string ORG_ID = "YOUR_ORGANIZATION_ID";
+ private const string BASE_URL = "https://api.turbodocx.com";
+
+ private readonly HttpClient client;
+
+ public TemplateWorkflowManager()
+ {
+ client = new HttpClient();
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+ }
+
+ static async Task Main(string[] args)
+ {
+ var workflow = new TemplateWorkflowManager();
+
+ try
+ {
+ // Demo Path B (Browse existing templates)
+ await workflow.DemoPathB();
+
+ // Uncomment to demo Path A (requires template file):
+ // await workflow.DemoPathA("./path/to/your/template.docx");
+
+ // Uncomment to run full comparison:
+ // await workflow.DemoComparison();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Workflow demo failed: {ex.Message}");
+ }
+ finally
+ {
+ workflow.client?.Dispose();
+ }
+ }
+
+ // ===============================
+ // PATH A: Upload New Template
+ // ===============================
+
+ /**
+ * Complete Path A workflow: Upload → Generate
+ */
+ public async Task PathA_UploadAndGenerate(string templateFilePath, string deliverableName)
+ {
+ Console.WriteLine("🔄 PATH A: Upload New Template → Generate Deliverable");
+ Console.WriteLine(new string('=', 48));
+
+ try
+ {
+ // Step 1: Upload and create template
+ Console.WriteLine("\n📤 Step 1: Uploading template...");
+ var template = await UploadTemplate(templateFilePath);
+
+ // Step 2: Generate deliverable using uploaded template
+ Console.WriteLine("\n📝 Step 2: Generating deliverable...");
+ using var templateDoc = JsonDocument.Parse(template);
+ var templateInfo = templateDoc.RootElement.GetProperty("data").GetProperty("results").GetProperty("template");
+
+ var deliverable = await GenerateDeliverable(
+ templateInfo.GetProperty("id").GetString(),
+ deliverableName,
+ $"Generated from uploaded template: {templateInfo.GetProperty("name").GetString()}"
+ );
+
+ Console.WriteLine("\n✅ PATH A COMPLETE!");
+ Console.WriteLine($"Template ID: {templateInfo.GetProperty("id").GetString()}");
+
+ using var deliverableDoc = JsonDocument.Parse(deliverable);
+ var deliverableInfo = deliverableDoc.RootElement.GetProperty("data").GetProperty("results").GetProperty("deliverable");
+ Console.WriteLine($"Deliverable ID: {deliverableInfo.GetProperty("id").GetString()}");
+
+ // Download the generated file
+ await DownloadDeliverable(
+ deliverableInfo.GetProperty("id").GetString(),
+ $"{deliverableInfo.GetProperty("name").GetString()}.docx"
+ );
+
+ return new TemplateWorkflowResult(template, deliverable, null);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"❌ Path A failed: {ex.Message}");
+ throw;
+ }
+ }
+
+ private async Task UploadTemplate(string templateFilePath)
+ {
+ if (!File.Exists(templateFilePath))
+ {
+ throw new FileNotFoundException($"Template file not found: {templateFilePath}");
+ }
+
+ using var content = new MultipartFormDataContent();
+
+ var fileContent = new ByteArrayContent(File.ReadAllBytes(templateFilePath));
+ fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+ content.Add(fileContent, "templateFile", Path.GetFileName(templateFilePath));
+
+ content.Add(new StringContent("API Upload Template"), "name");
+ content.Add(new StringContent("Template uploaded via API for testing"), "description");
+ content.Add(new StringContent("[]"), "variables");
+ content.Add(new StringContent("[\"api\", \"test\", \"upload\"]"), "tags");
+
+ var response = await client.PostAsync($"{BASE_URL}/template/upload-and-create", content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"Upload failed: {response.StatusCode} - {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var template = document.RootElement.GetProperty("data").GetProperty("results").GetProperty("template");
+
+ Console.WriteLine($"✅ Template uploaded: {template.GetProperty("name").GetString()} ({template.GetProperty("id").GetString()})");
+
+ var variableCount = 0;
+ if (template.TryGetProperty("variables", out var variables) && variables.ValueKind != JsonValueKind.Null)
+ {
+ variableCount = variables.GetArrayLength();
+ }
+ Console.WriteLine($"📊 Variables extracted: {variableCount}");
+
+ Console.WriteLine($"🔤 Default font: {template.GetProperty("defaultFont").GetString()}");
+
+ var fontCount = 0;
+ if (template.TryGetProperty("fonts", out var fonts) && fonts.ValueKind != JsonValueKind.Null)
+ {
+ fontCount = fonts.GetArrayLength();
+ }
+ Console.WriteLine($"📝 Fonts used: {fontCount}");
+
+ return result;
+ }
+
+ // ===============================
+ // PATH B: Browse and Select
+ // ===============================
+
+ /**
+ * Complete Path B workflow: Browse → Select → Generate
+ */
+ public async Task PathB_BrowseAndGenerate(string searchQuery, string deliverableName)
+ {
+ Console.WriteLine("🔍 PATH B: Browse Existing Templates → Generate Deliverable");
+ Console.WriteLine(new string('=', 56));
+
+ try
+ {
+ // Step 1: Browse templates
+ Console.WriteLine("\n🔍 Step 1: Browsing templates...");
+ var browseResult = await BrowseTemplates(searchQuery);
+
+ // Step 2: Select first available template
+ using var browseDoc = JsonDocument.Parse(browseResult);
+ var results = browseDoc.RootElement.GetProperty("data").GetProperty("results");
+
+ JsonElement? selectedTemplate = null;
+ foreach (var item in results.EnumerateArray())
+ {
+ if (item.GetProperty("type").GetString() == "template")
+ {
+ selectedTemplate = item;
+ break;
+ }
+ }
+
+ if (!selectedTemplate.HasValue)
+ {
+ throw new Exception("No templates found in browse results");
+ }
+
+ var template = selectedTemplate.Value;
+ Console.WriteLine($"📋 Selected: {template.GetProperty("name").GetString()} ({template.GetProperty("id").GetString()})");
+
+ // Step 3: Get template details
+ Console.WriteLine("\n📖 Step 2: Getting template details...");
+ var templateDetails = await GetTemplateDetails(template.GetProperty("id").GetString());
+
+ // Step 4: Get PDF preview (optional)
+ Console.WriteLine("\n🖼️ Step 3: Getting PDF preview...");
+ var pdfPreview = await GetTemplatePDFPreview(template.GetProperty("id").GetString());
+
+ // Step 5: Generate deliverable
+ Console.WriteLine("\n📝 Step 4: Generating deliverable...");
+ using var detailsDoc = JsonDocument.Parse(templateDetails);
+ var templateInfo = detailsDoc.RootElement.GetProperty("data").GetProperty("results");
+
+ var deliverable = await GenerateDeliverable(
+ templateInfo.GetProperty("id").GetString(),
+ deliverableName,
+ $"Generated from existing template: {templateInfo.GetProperty("name").GetString()}"
+ );
+
+ Console.WriteLine("\n✅ PATH B COMPLETE!");
+ Console.WriteLine($"Template ID: {templateInfo.GetProperty("id").GetString()}");
+
+ using var deliverableDoc = JsonDocument.Parse(deliverable);
+ var deliverableInfo = deliverableDoc.RootElement.GetProperty("data").GetProperty("results").GetProperty("deliverable");
+ Console.WriteLine($"Deliverable ID: {deliverableInfo.GetProperty("id").GetString()}");
+ Console.WriteLine($"PDF Preview: {pdfPreview}");
+
+ // Download the generated file
+ Console.WriteLine("\n📥 Step 5: Downloading file...");
+ await DownloadDeliverable(
+ deliverableInfo.GetProperty("id").GetString(),
+ $"{deliverableInfo.GetProperty("name").GetString()}.docx"
+ );
+
+ return new TemplateWorkflowResult(templateDetails, deliverable, pdfPreview);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"❌ Path B failed: {ex.Message}");
+ throw;
+ }
+ }
+
+ private async Task BrowseTemplates(string query)
+ {
+ var queryParams = "limit=25&offset=0&showTags=true";
+
+ if (!string.IsNullOrEmpty(query))
+ {
+ queryParams += $"&query={HttpUtility.UrlEncode(query)}";
+ }
+
+ var response = await client.GetAsync($"{BASE_URL}/template-item?{queryParams}");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"Browse failed: {response.StatusCode} - {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var totalRecords = document.RootElement.GetProperty("data").GetProperty("totalRecords").GetInt32();
+ Console.WriteLine($"🔍 Found {totalRecords} templates/folders");
+
+ return result;
+ }
+
+ private async Task GetTemplateDetails(string templateId)
+ {
+ var response = await client.GetAsync($"{BASE_URL}/template/{templateId}");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"Template details failed: {response.StatusCode} - {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var template = document.RootElement.GetProperty("data").GetProperty("results");
+
+ var variableCount = 0;
+ if (template.TryGetProperty("variables", out var variables) && variables.ValueKind != JsonValueKind.Null)
+ {
+ variableCount = variables.GetArrayLength();
+ }
+ Console.WriteLine($"📊 Variables: {variableCount}");
+
+ var defaultFont = template.TryGetProperty("defaultFont", out var font) ? font.GetString() : "N/A";
+ Console.WriteLine($"🔤 Default font: {defaultFont}");
+
+ return result;
+ }
+
+ private async Task GetTemplatePDFPreview(string templateId)
+ {
+ var response = await client.GetAsync($"{BASE_URL}/template/{templateId}/previewpdflink");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"PDF preview failed: {response.StatusCode} - {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var pdfUrl = document.RootElement.GetProperty("results").GetString();
+
+ Console.WriteLine($"🖼️ PDF Preview available: {pdfUrl}");
+
+ return pdfUrl;
+ }
+
+ // ===============================
+ // COMMON: Generate Deliverable
+ // ===============================
+
+ private async Task GenerateDeliverable(string templateId, string name, string description)
+ {
+ var payload = $$"""
+ {
+ "templateId": "{{templateId}}",
+ "name": "{{name}}",
+ "description": "{{description}}",
+ "variables": [
+ {
+ "mimeType": "text",
+ "name": "Sample Variable",
+ "placeholder": "{SampleVariable}",
+ "text": "Sample Content from C# Workflow",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 1,
+ "order": 1,
+ "subvariables": [],
+ "metadata": {
+ "generatedBy": "C# Workflow"
+ },
+ "aiPrompt": ""
+ }
+ ],
+ "tags": ["api-generated"],
+ "fonts": "[]",
+ "defaultFont": "Arial",
+ "replaceFonts": true,
+ "metadata": {
+ "sessions": [
+ {
+ "id": "{{Guid.NewGuid()}}",
+ "starttime": "{{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}}",
+ "endtime": "{{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}}"
+ }
+ ],
+ "workflow": "C# Complete Workflow",
+ "generated": "{{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}}"
+ }
+ }
+ """;
+
+ var content = new StringContent(payload, Encoding.UTF8, "application/json");
+ var response = await client.PostAsync($"{BASE_URL}/deliverable", content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"Deliverable generation failed: {response.StatusCode} - {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var document = JsonDocument.Parse(result);
+ var deliverable = document.RootElement.GetProperty("data").GetProperty("results").GetProperty("deliverable");
+
+ Console.WriteLine($"✅ Generated: {deliverable.GetProperty("name").GetString()}");
+ Console.WriteLine($"📄 Created by: {deliverable.GetProperty("createdBy").GetString()}");
+ Console.WriteLine($"📅 Created on: {deliverable.GetProperty("createdOn").GetString()}");
+
+ return result;
+ }
+
+ private async Task DownloadDeliverable(string deliverableId, string filename)
+ {
+ Console.WriteLine($"📥 Downloading file: {filename}");
+
+ var response = await client.GetAsync($"{BASE_URL}/deliverable/file/{deliverableId}");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ throw new HttpRequestException($"Download failed: {response.StatusCode}");
+ }
+
+ Console.WriteLine($"✅ File ready for download: {filename}");
+
+ var contentType = response.Content.Headers.ContentType?.ToString() ?? "N/A";
+ var contentLength = response.Content.Headers.ContentLength?.ToString() ?? "N/A";
+
+ Console.WriteLine($"📁 Content-Type: {contentType}");
+ Console.WriteLine($"📊 Content-Length: {contentLength} bytes");
+
+ // In a real application, you would save the file
+ // var fileBytes = await response.Content.ReadAsByteArrayAsync();
+ // await File.WriteAllBytesAsync(filename, fileBytes);
+ }
+
+ // ===============================
+ // DEMO FUNCTIONS
+ // ===============================
+
+ public async Task DemoPathA(string templateFilePath)
+ {
+ Console.WriteLine("🚀 DEMO: Path A - Upload New Template Workflow");
+ Console.WriteLine(new string('=', 45));
+ Console.WriteLine();
+
+ return await PathA_UploadAndGenerate(templateFilePath, "Contract Generated via Path A - API Upload");
+ }
+
+ public async Task DemoPathB()
+ {
+ Console.WriteLine("🚀 DEMO: Path B - Browse Existing Template Workflow");
+ Console.WriteLine(new string('=', 51));
+ Console.WriteLine();
+
+ return await PathB_BrowseAndGenerate("contract", "Contract Generated via Path B - Browse & Select");
+ }
+
+ public async Task DemoComparison()
+ {
+ Console.WriteLine("🚀 DEMO: Complete Workflow Comparison");
+ Console.WriteLine(new string('=', 36));
+ Console.WriteLine();
+
+ try
+ {
+ Console.WriteLine("Testing both paths with the same template type...\n");
+
+ // Run Path B first (browse existing)
+ var pathBResult = await DemoPathB();
+
+ Console.WriteLine("\n" + new string('=', 60) + "\n");
+
+ // For Path A, we'd need a template file
+ Console.WriteLine("📝 Path A requires a template file to upload.");
+ Console.WriteLine(" Example: await workflow.DemoPathA(\"./contract-template.docx\")");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Demo comparison failed: {ex.Message}");
+ }
+ }
+
+ // Result container class
+ public class TemplateWorkflowResult
+ {
+ public string Template { get; }
+ public string Deliverable { get; }
+ public string PdfPreview { get; }
+
+ public TemplateWorkflowResult(string template, string deliverable, string pdfPreview)
+ {
+ Template = template;
+ Deliverable = deliverable;
+ PdfPreview = pdfPreview;
+ }
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/curl.sh b/static/scripts/templates/api/complete-workflows/curl.sh
new file mode 100644
index 0000000..8080ae2
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/curl.sh
@@ -0,0 +1,397 @@
+#!/bin/bash
+
+# Configuration - Update these values
+API_TOKEN="YOUR_API_TOKEN"
+ORG_ID="YOUR_ORGANIZATION_ID"
+BASE_URL="https://api.turbodocx.com"
+
+# Colors for output formatting
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+BLUE='\033[0;34m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+echo -e "${BLUE}🚀 COMPLETE TEMPLATE GENERATION WORKFLOWS${NC}"
+echo -e "${BLUE}===========================================${NC}"
+echo
+
+# Function to generate session ID
+generate_session_id() {
+ echo "session-$(date +%s)-$(shuf -i 1000-9999 -n 1)"
+}
+
+# Function to get current timestamp
+get_timestamp() {
+ date -u +"%Y-%m-%dT%H:%M:%S.%3NZ"
+}
+
+# Function to download deliverable file
+download_deliverable() {
+ local deliverable_id="$1"
+ local filename="$2"
+
+ echo "Downloading file: $filename"
+
+ DOWNLOAD_RESPONSE=$(curl -s -X GET "$BASE_URL/deliverable/file/$deliverable_id" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client" \
+ --output "$filename" \
+ --write-out "HTTP_CODE:%{http_code};CONTENT_TYPE:%{content_type};SIZE:%{size_download}")
+
+ HTTP_CODE=$(echo "$DOWNLOAD_RESPONSE" | grep -o 'HTTP_CODE:[0-9]*' | cut -d: -f2)
+ CONTENT_TYPE=$(echo "$DOWNLOAD_RESPONSE" | grep -o 'CONTENT_TYPE:[^;]*' | cut -d: -f2)
+ FILE_SIZE=$(echo "$DOWNLOAD_RESPONSE" | grep -o 'SIZE:[0-9]*' | cut -d: -f2)
+
+ if [ "$HTTP_CODE" = "200" ]; then
+ echo -e "${GREEN}✅ File downloaded successfully: $filename${NC}"
+ echo -e "${GREEN}📁 Content-Type: $CONTENT_TYPE${NC}"
+ echo -e "${GREEN}📊 File Size: $FILE_SIZE bytes${NC}"
+ else
+ echo -e "${RED}❌ Download failed with HTTP $HTTP_CODE${NC}"
+ return 1
+ fi
+}
+
+# ===============================
+# PATH A: Upload New Template
+# ===============================
+
+path_a_upload_and_generate() {
+ local template_file="$1"
+ local deliverable_name="$2"
+
+ echo -e "${YELLOW}🔄 PATH A: Upload New Template → Generate Deliverable${NC}"
+ echo -e "${YELLOW}================================================${NC}"
+ echo
+
+ if [ ! -f "$template_file" ]; then
+ echo -e "${RED}❌ Error: Template file '$template_file' not found${NC}"
+ echo "Please provide a valid .docx or .pptx file path"
+ return 1
+ fi
+
+ # Step 1: Upload and create template
+ echo -e "${BLUE}📤 Step 1: Uploading template...${NC}"
+
+ UPLOAD_RESPONSE=$(curl -s -X POST "$BASE_URL/template/upload-and-create" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client" \
+ -F "templateFile=@$template_file" \
+ -F "name=API Upload Template" \
+ -F "description=Template uploaded via API for testing" \
+ -F 'variables=[]' \
+ -F 'tags=["api", "test", "upload"]')
+
+ if [ $? -ne 0 ]; then
+ echo -e "${RED}❌ Template upload failed${NC}"
+ return 1
+ fi
+
+ echo "Upload Response:"
+ echo "$UPLOAD_RESPONSE" | jq '.'
+
+ # Extract template ID and details
+ TEMPLATE_ID=$(echo "$UPLOAD_RESPONSE" | jq -r '.data.results.template.id')
+ TEMPLATE_NAME=$(echo "$UPLOAD_RESPONSE" | jq -r '.data.results.template.name')
+ VARIABLE_COUNT=$(echo "$UPLOAD_RESPONSE" | jq '.data.results.template.variables | length // 0')
+ DEFAULT_FONT=$(echo "$UPLOAD_RESPONSE" | jq -r '.data.results.template.defaultFont')
+ FONT_COUNT=$(echo "$UPLOAD_RESPONSE" | jq '.data.results.template.fonts | length // 0')
+
+ if [ "$TEMPLATE_ID" = "null" ] || [ -z "$TEMPLATE_ID" ]; then
+ echo -e "${RED}❌ Failed to extract template ID from upload response${NC}"
+ return 1
+ fi
+
+ echo -e "${GREEN}✅ Template uploaded: $TEMPLATE_NAME ($TEMPLATE_ID)${NC}"
+ echo -e "${GREEN}📊 Variables extracted: $VARIABLE_COUNT${NC}"
+ echo -e "${GREEN}🔤 Default font: $DEFAULT_FONT${NC}"
+ echo -e "${GREEN}📝 Fonts used: $FONT_COUNT${NC}"
+
+ # Step 2: Generate deliverable using uploaded template
+ echo -e "\n${BLUE}📝 Step 2: Generating deliverable...${NC}"
+
+ GENERATE_RESPONSE=$(curl -s -X POST "$BASE_URL/deliverable" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "templateId": "'$TEMPLATE_ID'",
+ "name": "'$deliverable_name'",
+ "description": "Generated from uploaded template: '$TEMPLATE_NAME'",
+ "variables": [
+ {
+ "mimeType": "text",
+ "name": "Sample Variable",
+ "placeholder": "{SampleVariable}",
+ "text": "Sample Content from Path A",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 1,
+ "order": 1,
+ "subvariables": [],
+ "metadata": {
+ "generatedBy": "Path A Workflow"
+ },
+ "aiPrompt": ""
+ }
+ ],
+ "tags": ["api-generated", "path-a"],
+ "fonts": "[]",
+ "defaultFont": "Arial",
+ "replaceFonts": true,
+ "metadata": {
+ "sessions": [
+ {
+ "id": "'$(generate_session_id)'",
+ "starttime": "'$(get_timestamp)'",
+ "endtime": "'$(get_timestamp)'"
+ }
+ ],
+ "workflow": "Path A - Upload and Generate",
+ "generated": "'$(get_timestamp)'"
+ }
+ }')
+
+ echo "Generation Response:"
+ echo "$GENERATE_RESPONSE" | jq '.'
+
+ # Extract deliverable details
+ DELIVERABLE_ID=$(echo "$GENERATE_RESPONSE" | jq -r '.data.results.deliverable.id')
+ DELIVERABLE_NAME=$(echo "$GENERATE_RESPONSE" | jq -r '.data.results.deliverable.name')
+ CREATED_BY=$(echo "$GENERATE_RESPONSE" | jq -r '.data.results.deliverable.createdBy')
+
+ echo -e "\n${GREEN}✅ PATH A COMPLETE!${NC}"
+ echo -e "${GREEN}Template ID: $TEMPLATE_ID${NC}"
+ echo -e "${GREEN}Deliverable ID: $DELIVERABLE_ID${NC}"
+ echo -e "${GREEN}Created by: $CREATED_BY${NC}"
+
+ # Download the generated file
+ echo -e "\n${BLUE}📥 Step 3: Downloading file...${NC}"
+ download_deliverable "$DELIVERABLE_ID" "$DELIVERABLE_NAME.docx"
+}
+
+# ===============================
+# PATH B: Browse and Select
+# ===============================
+
+path_b_browse_and_generate() {
+ local search_query="$1"
+ local deliverable_name="$2"
+
+ echo -e "${YELLOW}🔍 PATH B: Browse Existing Templates → Generate Deliverable${NC}"
+ echo -e "${YELLOW}======================================================${NC}"
+ echo
+
+ # Step 1: Browse templates
+ echo -e "${BLUE}🔍 Step 1: Browsing templates...${NC}"
+
+ BROWSE_RESPONSE=$(curl -s -X GET "$BASE_URL/template-item?limit=10&offset=0&query=$search_query&showTags=true" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client")
+
+ echo "Browse Results:"
+ echo "$BROWSE_RESPONSE" | jq '.'
+
+ # Extract first template ID
+ TEMPLATE_ID=$(echo "$BROWSE_RESPONSE" | jq -r '.data.results[] | select(.type == "template") | .id' | head -1)
+
+ if [ "$TEMPLATE_ID" = "null" ] || [ -z "$TEMPLATE_ID" ]; then
+ echo -e "${RED}❌ No templates found in browse results${NC}"
+ return 1
+ fi
+
+ TEMPLATE_NAME=$(echo "$BROWSE_RESPONSE" | jq -r '.data.results[] | select(.id == "'$TEMPLATE_ID'") | .name')
+ echo -e "${GREEN}📋 Selected: $TEMPLATE_NAME ($TEMPLATE_ID)${NC}"
+
+ # Step 2: Get template details
+ echo -e "\n${BLUE}📖 Step 2: Getting template details...${NC}"
+
+ TEMPLATE_DETAILS=$(curl -s -X GET "$BASE_URL/template/$TEMPLATE_ID" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client")
+
+ echo "Template Details:"
+ echo "$TEMPLATE_DETAILS" | jq '.'
+
+ VARIABLE_COUNT=$(echo "$TEMPLATE_DETAILS" | jq '.data.results.variables | length')
+ DEFAULT_FONT=$(echo "$TEMPLATE_DETAILS" | jq -r '.data.results.defaultFont // "N/A"')
+
+ echo -e "${GREEN}📊 Variables: $VARIABLE_COUNT${NC}"
+ echo -e "${GREEN}🔤 Default font: $DEFAULT_FONT${NC}"
+
+ # Step 3: Get PDF preview (optional)
+ echo -e "\n${BLUE}🖼️ Step 3: Getting PDF preview...${NC}"
+
+ PDF_PREVIEW=$(curl -s -X GET "$BASE_URL/template/$TEMPLATE_ID/previewpdflink" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client")
+
+ echo "PDF Preview Response:"
+ echo "$PDF_PREVIEW" | jq '.'
+
+ PDF_URL=$(echo "$PDF_PREVIEW" | jq -r '.results')
+ echo -e "${GREEN}🖼️ PDF Preview available: $PDF_URL${NC}"
+
+ # Step 4: Generate deliverable
+ echo -e "\n${BLUE}📝 Step 4: Generating deliverable...${NC}"
+
+ GENERATE_RESPONSE=$(curl -s -X POST "$BASE_URL/deliverable" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "templateId": "'$TEMPLATE_ID'",
+ "name": "'$deliverable_name'",
+ "description": "Generated from existing template: '$TEMPLATE_NAME'",
+ "variables": [
+ {
+ "mimeType": "text",
+ "name": "Sample Variable",
+ "placeholder": "{SampleVariable}",
+ "text": "Sample Content from Path B",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 1,
+ "order": 1,
+ "subvariables": [
+ {
+ "placeholder": "{SampleVariable.SubItem}",
+ "text": "Sub-content from browse workflow"
+ }
+ ],
+ "metadata": {
+ "generatedBy": "Path B Workflow",
+ "sourceTemplate": "'$TEMPLATE_NAME'"
+ },
+ "aiPrompt": "Generate content appropriate for this selected template"
+ }
+ ],
+ "tags": ["api-generated", "path-b", "browse-selected"],
+ "fonts": "[]",
+ "defaultFont": "'$DEFAULT_FONT'",
+ "replaceFonts": true,
+ "metadata": {
+ "sessions": [
+ {
+ "id": "'$(generate_session_id)'",
+ "starttime": "'$(get_timestamp)'",
+ "endtime": "'$(get_timestamp)'"
+ }
+ ],
+ "workflow": "Path B - Browse and Generate",
+ "generated": "'$(get_timestamp)'",
+ "pdfPreview": "'$PDF_URL'"
+ }
+ }')
+
+ echo "Generation Response:"
+ echo "$GENERATE_RESPONSE" | jq '.'
+
+ # Extract deliverable details
+ DELIVERABLE_ID=$(echo "$GENERATE_RESPONSE" | jq -r '.data.results.deliverable.id')
+ DELIVERABLE_NAME=$(echo "$GENERATE_RESPONSE" | jq -r '.data.results.deliverable.name')
+ CREATED_BY=$(echo "$GENERATE_RESPONSE" | jq -r '.data.results.deliverable.createdBy')
+
+ echo -e "\n${GREEN}✅ PATH B COMPLETE!${NC}"
+ echo -e "${GREEN}Template ID: $TEMPLATE_ID${NC}"
+ echo -e "${GREEN}Deliverable ID: $DELIVERABLE_ID${NC}"
+ echo -e "${GREEN}Created by: $CREATED_BY${NC}"
+ echo -e "${GREEN}PDF Preview: $PDF_URL${NC}"
+
+ # Download the generated file
+ echo -e "\n${BLUE}📥 Step 5: Downloading file...${NC}"
+ download_deliverable "$DELIVERABLE_ID" "$DELIVERABLE_NAME.docx"
+}
+
+# ===============================
+# DEMO FUNCTIONS
+# ===============================
+
+demo_path_a() {
+ local template_file="$1"
+ echo -e "${BLUE}🚀 DEMO: Path A - Upload New Template Workflow${NC}"
+ echo -e "${BLUE}==============================================${NC}"
+ echo
+
+ if [ -z "$template_file" ]; then
+ echo -e "${YELLOW}📝 Path A requires a template file to upload.${NC}"
+ echo "Usage: demo_path_a './path/to/your/template.docx'"
+ echo "Example: demo_path_a './contract-template.docx'"
+ return 1
+ fi
+
+ path_a_upload_and_generate "$template_file" "Contract Generated via Path A - API Upload"
+}
+
+demo_path_b() {
+ echo -e "${BLUE}🚀 DEMO: Path B - Browse Existing Template Workflow${NC}"
+ echo -e "${BLUE}==================================================${NC}"
+ echo
+
+ path_b_browse_and_generate "contract" "Contract Generated via Path B - Browse & Select"
+}
+
+demo_comparison() {
+ echo -e "${BLUE}🚀 DEMO: Complete Workflow Comparison${NC}"
+ echo -e "${BLUE}====================================${NC}"
+ echo
+
+ echo "Testing both paths with the same template type..."
+ echo
+
+ # Run Path B first (browse existing)
+ demo_path_b
+
+ echo
+ echo -e "${BLUE}${'='*60}${NC}"
+ echo
+
+ # For Path A, we'd need a template file
+ echo -e "${YELLOW}📝 Path A requires a template file to upload.${NC}"
+ echo " Example: demo_path_a './contract-template.docx'"
+ echo
+ echo "To test Path A, run:"
+ echo " $0 path-a ./path/to/your/template.docx"
+}
+
+# ===============================
+# MAIN EXECUTION
+# ===============================
+
+case "${1:-demo}" in
+ "path-a")
+ demo_path_a "$2"
+ ;;
+ "path-b")
+ demo_path_b
+ ;;
+ "comparison")
+ demo_comparison
+ ;;
+ "demo"|*)
+ echo -e "${BLUE}Template Generation API - Complete Workflows${NC}"
+ echo -e "${BLUE}===========================================${NC}"
+ echo
+ echo "Available commands:"
+ echo " $0 path-a - Demo Path A (upload new template)"
+ echo " $0 path-b - Demo Path B (browse existing templates)"
+ echo " $0 comparison - Compare both workflows"
+ echo
+ echo "Examples:"
+ echo " $0 path-a ./contract-template.docx"
+ echo " $0 path-b"
+ echo " $0 comparison"
+ echo
+ echo "Running Path B demo by default..."
+ echo
+ demo_path_b
+ ;;
+esac
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/fastapi.py b/static/scripts/templates/api/complete-workflows/fastapi.py
new file mode 100644
index 0000000..2ab3875
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/fastapi.py
@@ -0,0 +1,541 @@
+#!/usr/bin/env python3
+
+import os
+import requests
+import json
+import uuid
+from datetime import datetime
+from typing import Optional, List, Dict, Any
+from fastapi import FastAPI, HTTPException
+from pydantic import BaseModel
+import uvicorn
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+app = FastAPI(
+ title="TurboDocx Complete Workflow Manager Service",
+ description="FastAPI service demonstrating complete template workflows using TurboDocx API",
+ version="1.0.0"
+)
+
+class UploadWorkflowRequest(BaseModel):
+ templateFilePath: Optional[str] = "./contract-template.docx"
+
+class WorkflowResponse(BaseModel):
+ success: bool
+ message: str
+ data: dict
+
+class ConfigurationInfo(BaseModel):
+ baseUrl: str
+ hasToken: bool
+ hasOrgId: bool
+
+class ServiceInfo(BaseModel):
+ service: str
+ endpoints: dict
+ configuration: ConfigurationInfo
+ description: str
+
+class TemplateWorkflowManager:
+ """
+ Complete Template Workflow Manager
+ Demonstrates both upload and browse/select paths
+ """
+
+ def __init__(self, api_token: str, org_id: str, base_url: str):
+ self.api_token = api_token
+ self.org_id = org_id
+ self.base_url = base_url
+ print('=== TurboDocx Template Generation Workflow Manager ===')
+
+ async def demonstrate_complete_workflow(self) -> dict:
+ print('\nSelect workflow path:')
+ print('A) Upload new template')
+ print('B) Browse and select existing template')
+
+ # For this example, we'll demonstrate both paths
+ print('\n=== Demonstrating Path A: Upload Template ===')
+ template_id_a = await self.demonstrate_upload_workflow()
+
+ print('\n=== Demonstrating Path B: Browse Templates ===')
+ template_id_b = await self.demonstrate_browse_workflow()
+
+ # Generate deliverables for both templates if successful
+ results = {}
+
+ if template_id_a:
+ print('\n=== Generating Deliverable from Uploaded Template ===')
+ results['uploadPath'] = await self.generate_and_download_deliverable(template_id_a, 'A')
+
+ if template_id_b:
+ print('\n=== Generating Deliverable from Selected Template ===')
+ results['browsePath'] = await self.generate_and_download_deliverable(template_id_b, 'B')
+
+ return {
+ 'uploadedTemplateId': template_id_a,
+ 'selectedTemplateId': template_id_b,
+ 'results': results
+ }
+
+ async def demonstrate_upload_workflow(self) -> Optional[str]:
+ try:
+ print('\n--- Path A: Upload and Create Template ---')
+
+ # Check for template file
+ template_file = './contract-template.docx'
+ if not os.path.exists(template_file):
+ print(f'⚠️ Template file not found: {template_file}')
+ print('Creating a placeholder message for demonstration')
+ return None
+
+ result = await self.upload_template(template_file)
+ template = result['data']['results']['template']
+
+ print('✅ Upload workflow completed')
+ print(f'Template ID: {template["id"]}')
+ print('Ready for deliverable generation')
+
+ return template['id']
+
+ except Exception as e:
+ print(f'❌ Upload workflow failed: {str(e)}')
+ return None
+
+ async def demonstrate_browse_workflow(self) -> Optional[str]:
+ try:
+ print('\n--- Path B: Browse and Select Template ---')
+
+ # Browse templates
+ browse_result = await self.browse_templates(10, 0, 'contract', True)
+
+ # Find first template (not folder)
+ selected_template = None
+ for item in browse_result['results']:
+ if item.get('type') == 'template':
+ selected_template = item
+ break
+
+ if not selected_template:
+ print('⚠️ No templates found in browse results')
+ return None
+
+ print(f'Selected: {selected_template["name"]}')
+
+ # Get detailed information
+ template_details = await self.get_template_details(selected_template['id'])
+
+ # Optionally get PDF preview
+ pdf_preview = await self.get_template_pdf_preview(selected_template['id'])
+
+ print('✅ Browse workflow completed')
+ print(f'Template ID: {template_details["id"]}')
+ print(f'PDF Preview: {pdf_preview}')
+ print('Ready for deliverable generation')
+
+ return template_details['id']
+
+ except Exception as e:
+ print(f'❌ Browse workflow failed: {str(e)}')
+ return None
+
+ async def generate_and_download_deliverable(self, template_id: str, path_label: str) -> dict:
+ try:
+ print(f'\n--- Generating Deliverable (Path {path_label}) ---')
+
+ deliverable_data = self.create_deliverable_data(template_id, path_label)
+ deliverable = await self.generate_deliverable(template_id, deliverable_data)
+
+ # Download the file
+ download_result = await self.download_deliverable(
+ deliverable['id'],
+ f'{deliverable["name"]}_path_{path_label}.docx'
+ )
+
+ print(f'✅ Complete workflow finished successfully for Path {path_label}')
+ print(f'Deliverable ID: {deliverable["id"]}')
+ print(f'Download info: {json.dumps(download_result, indent=2)}')
+
+ return {
+ 'deliverable': deliverable,
+ 'downloadResult': download_result
+ }
+
+ except Exception as e:
+ print(f'❌ Deliverable generation failed for Path {path_label}: {str(e)}')
+ raise
+
+ async def upload_template(self, template_file_path: str) -> dict:
+ url = f"{self.base_url}/template/upload-and-create"
+
+ with open(template_file_path, 'rb') as file:
+ files = {
+ 'templateFile': (os.path.basename(template_file_path), file,
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')
+ }
+
+ data = {
+ 'name': 'Employee Contract Template',
+ 'description': 'Standard employee contract with variable placeholders',
+ 'variables': '[]',
+ 'tags': '["hr", "contract", "template"]'
+ }
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ response = requests.post(url, files=files, data=data, headers=headers)
+ response.raise_for_status()
+ return response.json()
+
+ async def browse_templates(self, limit: int, offset: int, query: str, show_tags: bool) -> dict:
+ from urllib.parse import urlencode
+
+ params = {
+ 'limit': str(limit),
+ 'offset': str(offset),
+ 'showTags': str(show_tags).lower()
+ }
+
+ if query:
+ params['query'] = query
+
+ query_string = urlencode(params)
+ url = f"{self.base_url}/template-item?{query_string}"
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()['data']
+
+ async def get_template_details(self, template_id: str) -> dict:
+ url = f"{self.base_url}/template/{template_id}"
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()['data']['results']
+
+ async def get_template_pdf_preview(self, template_id: str) -> str:
+ url = f"{self.base_url}/template/{template_id}/previewpdflink"
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()['results']
+
+ async def generate_deliverable(self, template_id: str, deliverable_data: dict) -> dict:
+ url = f"{self.base_url}/deliverable"
+
+ print('Generating deliverable...')
+ print(f'Template ID: {template_id}')
+ print(f'Deliverable Name: {deliverable_data["name"]}')
+ print(f'Variables: {len(deliverable_data["variables"])}')
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client',
+ 'Content-Type': 'application/json'
+ }
+
+ response = requests.post(url, json=deliverable_data, headers=headers)
+ response.raise_for_status()
+
+ # Parse JSON response
+ result = response.json()
+ deliverable = result['data']['results']['deliverable']
+
+ print('✅ Deliverable generated successfully!')
+ print(f'Deliverable ID: {deliverable["id"]}')
+ print(f'Created by: {deliverable["createdBy"]}')
+ print(f'Created on: {deliverable["createdOn"]}')
+ print(f'Template ID: {deliverable["templateId"]}')
+
+ return deliverable
+
+ async def download_deliverable(self, deliverable_id: str, filename: str) -> dict:
+ print(f'Downloading file: {filename}')
+
+ url = f"{self.base_url}/deliverable/file/{deliverable_id}"
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ response = requests.get(url, headers=headers, stream=True)
+ response.raise_for_status()
+
+ print(f'✅ File ready for download: {filename}')
+
+ content_type = response.headers.get('Content-Type', 'N/A')
+ content_length = response.headers.get('Content-Length', 'N/A')
+
+ print(f'📁 Content-Type: {content_type}')
+ print(f'📊 Content-Length: {content_length} bytes')
+
+ # In a real application, you would save the file
+ # with open(filename, 'wb') as f:
+ # for chunk in response.iter_content(chunk_size=8192):
+ # f.write(chunk)
+
+ return {
+ 'filename': filename,
+ 'contentType': content_type,
+ 'contentLength': content_length
+ }
+
+ def create_deliverable_data(self, template_id: str, path_label: str) -> dict:
+ now = datetime.utcnow().isoformat() + 'Z'
+
+ return {
+ 'templateId': template_id,
+ 'name': f'Contract Document - Path {path_label}',
+ 'description': f'Employment contract generated via workflow path {path_label}',
+ 'variables': self.create_complex_variables(),
+ 'tags': ['hr', 'contract', 'employee', 'engineering'],
+ 'fonts': '[{"name":"Arial","usage":269}]',
+ 'defaultFont': 'Arial',
+ 'replaceFonts': True,
+ 'metadata': {
+ 'sessions': [
+ {
+ 'id': str(uuid.uuid4()),
+ 'starttime': now,
+ 'endtime': now
+ }
+ ],
+ 'createdBy': 'Python FastAPI Workflow Manager',
+ 'documentType': 'Employment Contract',
+ 'version': 'v1.0',
+ 'workflowPath': path_label
+ }
+ }
+
+ def create_complex_variables(self) -> List[dict]:
+ return [
+ {
+ 'mimeType': 'text',
+ 'name': 'Employee Name',
+ 'placeholder': '{EmployeeName}',
+ 'text': 'John Smith',
+ 'allowRichTextInjection': 0,
+ 'autogenerated': False,
+ 'count': 1,
+ 'order': 1,
+ 'subvariables': [
+ {
+ 'placeholder': '{EmployeeName.Title}',
+ 'text': 'Senior Software Engineer'
+ },
+ {
+ 'placeholder': '{EmployeeName.StartDate}',
+ 'text': 'January 15, 2024'
+ }
+ ],
+ 'metadata': {
+ 'department': 'Engineering',
+ 'level': 'Senior'
+ },
+ 'aiPrompt': 'Generate a professional job description for a senior software engineer role'
+ },
+ {
+ 'mimeType': 'text',
+ 'name': 'Company Information',
+ 'placeholder': '{CompanyInfo}',
+ 'text': 'TechCorp Solutions Inc.',
+ 'allowRichTextInjection': 1,
+ 'autogenerated': False,
+ 'count': 1,
+ 'order': 2,
+ 'subvariables': [
+ {
+ 'placeholder': '{CompanyInfo.Address}',
+ 'text': '123 Innovation Drive, Tech City, TC 12345'
+ },
+ {
+ 'placeholder': '{CompanyInfo.Phone}',
+ 'text': '(555) 123-4567'
+ }
+ ],
+ 'metadata': {},
+ 'aiPrompt': ''
+ }
+ ]
+
+# FastAPI route handlers
+@app.post("/complete-workflow", response_model=WorkflowResponse)
+async def complete_workflow_endpoint():
+ """Complete workflow demonstration endpoint"""
+ try:
+ print('Starting complete workflow demonstration...')
+
+ workflow_manager = TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL)
+ result = await workflow_manager.demonstrate_complete_workflow()
+
+ return WorkflowResponse(
+ success=True,
+ message="Complete workflow demonstration finished",
+ data=result
+ )
+
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Complete workflow failed: {str(e)}")
+
+@app.post("/upload-workflow", response_model=WorkflowResponse)
+async def upload_workflow_endpoint(request: UploadWorkflowRequest):
+ """Upload workflow endpoint"""
+ try:
+ workflow_manager = TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL)
+ template_id = await workflow_manager.demonstrate_upload_workflow()
+
+ if not template_id:
+ raise HTTPException(
+ status_code=404,
+ detail="Template file not found or upload failed"
+ )
+
+ # Generate deliverable
+ deliverable_result = await workflow_manager.generate_and_download_deliverable(template_id, 'Upload')
+
+ return WorkflowResponse(
+ success=True,
+ message="Upload workflow completed successfully",
+ data={
+ 'templateId': template_id,
+ **deliverable_result
+ }
+ )
+
+ except HTTPException:
+ raise
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Upload workflow failed: {str(e)}")
+
+@app.post("/browse-workflow", response_model=WorkflowResponse)
+async def browse_workflow_endpoint():
+ """Browse workflow endpoint"""
+ try:
+ workflow_manager = TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL)
+ template_id = await workflow_manager.demonstrate_browse_workflow()
+
+ if not template_id:
+ raise HTTPException(
+ status_code=404,
+ detail="No templates found or selection failed"
+ )
+
+ # Generate deliverable
+ deliverable_result = await workflow_manager.generate_and_download_deliverable(template_id, 'Browse')
+
+ return WorkflowResponse(
+ success=True,
+ message="Browse workflow completed successfully",
+ data={
+ 'templateId': template_id,
+ **deliverable_result
+ }
+ )
+
+ except HTTPException:
+ raise
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Browse workflow failed: {str(e)}")
+
+@app.get("/health")
+async def health_check():
+ """Health check endpoint"""
+ return {
+ "status": "healthy",
+ "service": "workflow-manager"
+ }
+
+@app.get("/workflow-info", response_model=ServiceInfo)
+async def workflow_info():
+ """Service information endpoint"""
+ return ServiceInfo(
+ service="TurboDocx Complete Workflow Manager Service",
+ endpoints={
+ "POST /complete-workflow": "Demonstrate both upload and browse workflows",
+ "POST /upload-workflow": "Execute upload workflow only",
+ "POST /browse-workflow": "Execute browse workflow only",
+ "GET /health": "Service health check",
+ "GET /workflow-info": "Service information",
+ "GET /docs": "Interactive API documentation",
+ "GET /redoc": "Alternative API documentation"
+ },
+ configuration=ConfigurationInfo(
+ baseUrl=BASE_URL,
+ hasToken=bool(API_TOKEN and API_TOKEN != 'YOUR_API_TOKEN'),
+ hasOrgId=bool(ORG_ID and ORG_ID != 'YOUR_ORGANIZATION_ID')
+ ),
+ description="Complete workflow manager that demonstrates both template upload and browse/select paths, followed by deliverable generation and download."
+ )
+
+async def demonstrate_complete_workflow():
+ """Example usage function"""
+ try:
+ print('=== Complete Template Workflow Demonstration ===')
+
+ workflow_manager = TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL)
+ result = await workflow_manager.demonstrate_complete_workflow()
+
+ print('\n=== Workflow Demonstration Complete ===')
+ print('Both upload and browse/select paths have been demonstrated.')
+ print('Choose the appropriate path for your use case:')
+ print('- Upload path: When you have new templates to create')
+ print('- Browse path: When you want to use existing templates')
+
+ return result
+
+ except Exception as e:
+ print(f'Workflow demonstration failed: {str(e)}')
+ exit(1)
+
+if __name__ == '__main__':
+ import sys
+
+ if '--demo' in sys.argv:
+ # Run demonstration
+ import asyncio
+ asyncio.run(demonstrate_complete_workflow())
+ else:
+ # Start FastAPI server
+ port = int(os.environ.get('PORT', 8004))
+ host = os.environ.get('HOST', '0.0.0.0')
+
+ print('🚀 TurboDocx Complete Workflow Manager Service started')
+ print(f'📡 Server listening on http://{host}:{port}')
+ print('\nAvailable endpoints:')
+ print(f' POST http://{host}:{port}/complete-workflow')
+ print(f' POST http://{host}:{port}/upload-workflow')
+ print(f' POST http://{host}:{port}/browse-workflow')
+ print(f' GET http://{host}:{port}/health')
+ print(f' GET http://{host}:{port}/workflow-info')
+ print(f' GET http://{host}:{port}/docs (Interactive API docs)')
+ print(f' GET http://{host}:{port}/redoc (Alternative API docs)')
+
+ uvicorn.run(app, host=host, port=port)
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/fastify.js b/static/scripts/templates/api/complete-workflows/fastify.js
new file mode 100644
index 0000000..d091c78
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/fastify.js
@@ -0,0 +1,556 @@
+const fastify = require('fastify')({ logger: true });
+const fs = require('fs');
+const path = require('path');
+const FormData = require('form-data');
+const axios = require('axios');
+const { v4: uuidv4 } = require('uuid');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+/**
+ * Complete Template Workflow Manager
+ * Demonstrates both upload and browse/select paths
+ */
+
+class TemplateWorkflowManager {
+ constructor(apiToken, orgId, baseUrl) {
+ this.apiToken = apiToken;
+ this.orgId = orgId;
+ this.baseUrl = baseUrl;
+ console.log('=== TurboDocx Template Generation Workflow Manager ===');
+ }
+
+ async demonstrateCompleteWorkflow() {
+ console.log('\nSelect workflow path:');
+ console.log('A) Upload new template');
+ console.log('B) Browse and select existing template');
+
+ // For this example, we'll demonstrate both paths
+ console.log('\n=== Demonstrating Path A: Upload Template ===');
+ const templateIdA = await this.demonstrateUploadWorkflow();
+
+ console.log('\n=== Demonstrating Path B: Browse Templates ===');
+ const templateIdB = await this.demonstrateBrowseWorkflow();
+
+ // Generate deliverables for both templates if successful
+ if (templateIdA) {
+ console.log('\n=== Generating Deliverable from Uploaded Template ===');
+ await this.generateAndDownloadDeliverable(templateIdA, 'A');
+ }
+
+ if (templateIdB) {
+ console.log('\n=== Generating Deliverable from Selected Template ===');
+ await this.generateAndDownloadDeliverable(templateIdB, 'B');
+ }
+
+ return {
+ uploadedTemplateId: templateIdA,
+ selectedTemplateId: templateIdB
+ };
+ }
+
+ async demonstrateUploadWorkflow() {
+ try {
+ console.log('\n--- Path A: Upload and Create Template ---');
+
+ // Check for template file
+ const templateFile = './contract-template.docx';
+ if (!fs.existsSync(templateFile)) {
+ console.log(`⚠️ Template file not found: ${templateFile}`);
+ console.log('Creating a placeholder message for demonstration');
+ return null;
+ }
+
+ const result = await this.uploadTemplate(templateFile);
+ const template = result.data.results.template;
+
+ console.log('✅ Upload workflow completed');
+ console.log(`Template ID: ${template.id}`);
+ console.log('Ready for deliverable generation');
+
+ return template.id;
+ } catch (error) {
+ console.error(`❌ Upload workflow failed: ${error.message}`);
+ return null;
+ }
+ }
+
+ async demonstrateBrowseWorkflow() {
+ try {
+ console.log('\n--- Path B: Browse and Select Template ---');
+
+ // Browse templates
+ const browseResult = await this.browseTemplates(10, 0, 'contract', true);
+
+ // Find first template (not folder)
+ const selectedTemplate = browseResult.results.find(item => item.type === 'template');
+
+ if (!selectedTemplate) {
+ console.log('⚠️ No templates found in browse results');
+ return null;
+ }
+
+ console.log(`Selected: ${selectedTemplate.name}`);
+
+ // Get detailed information
+ const templateDetails = await this.getTemplateDetails(selectedTemplate.id);
+
+ // Optionally get PDF preview
+ const pdfPreview = await this.getTemplatePdfPreview(selectedTemplate.id);
+
+ console.log('✅ Browse workflow completed');
+ console.log(`Template ID: ${templateDetails.id}`);
+ console.log(`PDF Preview: ${pdfPreview}`);
+ console.log('Ready for deliverable generation');
+
+ return templateDetails.id;
+ } catch (error) {
+ console.error(`❌ Browse workflow failed: ${error.message}`);
+ return null;
+ }
+ }
+
+ async generateAndDownloadDeliverable(templateId, pathLabel) {
+ try {
+ console.log(`\n--- Generating Deliverable (Path ${pathLabel}) ---`);
+
+ const deliverableData = this.createDeliverableData(templateId, pathLabel);
+ const deliverable = await this.generateDeliverable(templateId, deliverableData);
+
+ // Download the file
+ const downloadResult = await this.downloadDeliverable(
+ deliverable.id,
+ `${deliverable.name}_path_${pathLabel}.docx`
+ );
+
+ console.log(`✅ Complete workflow finished successfully for Path ${pathLabel}`);
+ console.log(`Deliverable ID: ${deliverable.id}`);
+ console.log(`Download info: ${JSON.stringify(downloadResult, null, 2)}`);
+
+ return {
+ deliverable,
+ downloadResult
+ };
+ } catch (error) {
+ console.error(`❌ Deliverable generation failed for Path ${pathLabel}: ${error.message}`);
+ throw error;
+ }
+ }
+
+ async uploadTemplate(templateFilePath) {
+ const url = `${this.baseUrl}/template/upload-and-create`;
+
+ // Create form data
+ const form = new FormData();
+
+ // Add template file
+ form.append('templateFile', fs.createReadStream(templateFilePath), {
+ filename: path.basename(templateFilePath),
+ contentType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+ });
+
+ // Add metadata fields
+ form.append('name', 'Employee Contract Template');
+ form.append('description', 'Standard employee contract with variable placeholders');
+ form.append('variables', '[]');
+ form.append('tags', '["hr", "contract", "template"]');
+
+ const response = await axios.post(url, form, {
+ headers: {
+ 'Authorization': `Bearer ${this.apiToken}`,
+ 'x-rapiddocx-org-id': this.orgId,
+ 'User-Agent': 'TurboDocx API Client',
+ ...form.getHeaders()
+ }
+ });
+
+ return response.data;
+ }
+
+ async browseTemplates(limit, offset, query, showTags) {
+ // Build query parameters
+ const params = new URLSearchParams({
+ limit: limit.toString(),
+ offset: offset.toString(),
+ showTags: showTags.toString()
+ });
+
+ if (query) {
+ params.append('query', query);
+ }
+
+ const url = `${this.baseUrl}/template-item?${params.toString()}`;
+
+ const response = await axios.get(url, {
+ headers: {
+ 'Authorization': `Bearer ${this.apiToken}`,
+ 'x-rapiddocx-org-id': this.orgId,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ return response.data.data;
+ }
+
+ async getTemplateDetails(templateId) {
+ const url = `${this.baseUrl}/template/${templateId}`;
+
+ const response = await axios.get(url, {
+ headers: {
+ 'Authorization': `Bearer ${this.apiToken}`,
+ 'x-rapiddocx-org-id': this.orgId,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ return response.data.data.results;
+ }
+
+ async getTemplatePdfPreview(templateId) {
+ const url = `${this.baseUrl}/template/${templateId}/previewpdflink`;
+
+ const response = await axios.get(url, {
+ headers: {
+ 'Authorization': `Bearer ${this.apiToken}`,
+ 'x-rapiddocx-org-id': this.orgId,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ return response.data.results;
+ }
+
+ async generateDeliverable(templateId, deliverableData) {
+ const url = `${this.baseUrl}/deliverable`;
+
+ console.log('Generating deliverable...');
+ console.log(`Template ID: ${templateId}`);
+ console.log(`Deliverable Name: ${deliverableData.name}`);
+ console.log(`Variables: ${deliverableData.variables.length}`);
+
+ const response = await axios.post(url, deliverableData, {
+ headers: {
+ 'Authorization': `Bearer ${this.apiToken}`,
+ 'x-rapiddocx-org-id': this.orgId,
+ 'User-Agent': 'TurboDocx API Client',
+ 'Content-Type': 'application/json'
+ }
+ });
+
+ // Parse JSON response
+ const deliverable = response.data.data.results.deliverable;
+
+ console.log('✅ Deliverable generated successfully!');
+ console.log(`Deliverable ID: ${deliverable.id}`);
+ console.log(`Created by: ${deliverable.createdBy}`);
+ console.log(`Created on: ${deliverable.createdOn}`);
+ console.log(`Template ID: ${deliverable.templateId}`);
+
+ return deliverable;
+ }
+
+ async downloadDeliverable(deliverableId, filename) {
+ console.log(`Downloading file: ${filename}`);
+
+ const url = `${this.baseUrl}/deliverable/file/${deliverableId}`;
+
+ const response = await axios.get(url, {
+ headers: {
+ 'Authorization': `Bearer ${this.apiToken}`,
+ 'x-rapiddocx-org-id': this.orgId,
+ 'User-Agent': 'TurboDocx API Client'
+ },
+ responseType: 'stream'
+ });
+
+ console.log(`✅ File ready for download: ${filename}`);
+
+ const contentType = response.headers['content-type'] || 'N/A';
+ const contentLength = response.headers['content-length'] || 'N/A';
+
+ console.log(`📁 Content-Type: ${contentType}`);
+ console.log(`📊 Content-Length: ${contentLength} bytes`);
+
+ // In a real application, you would save the file
+ // const writer = fs.createWriteStream(filename);
+ // response.data.pipe(writer);
+
+ return {
+ filename,
+ contentType,
+ contentLength
+ };
+ }
+
+ createDeliverableData(templateId, pathLabel) {
+ const now = new Date().toISOString();
+
+ return {
+ templateId,
+ name: `Contract Document - Path ${pathLabel}`,
+ description: `Employment contract generated via workflow path ${pathLabel}`,
+ variables: this.createComplexVariables(),
+ tags: ['hr', 'contract', 'employee', 'engineering'],
+ fonts: '[{"name":"Arial","usage":269}]',
+ defaultFont: 'Arial',
+ replaceFonts: true,
+ metadata: {
+ sessions: [
+ {
+ id: uuidv4(),
+ starttime: now,
+ endtime: now
+ }
+ ],
+ createdBy: 'Node.js Workflow Manager',
+ documentType: 'Employment Contract',
+ version: 'v1.0',
+ workflowPath: pathLabel
+ }
+ };
+ }
+
+ createComplexVariables() {
+ return [
+ {
+ mimeType: 'text',
+ name: 'Employee Name',
+ placeholder: '{EmployeeName}',
+ text: 'John Smith',
+ allowRichTextInjection: 0,
+ autogenerated: false,
+ count: 1,
+ order: 1,
+ subvariables: [
+ {
+ placeholder: '{EmployeeName.Title}',
+ text: 'Senior Software Engineer'
+ },
+ {
+ placeholder: '{EmployeeName.StartDate}',
+ text: 'January 15, 2024'
+ }
+ ],
+ metadata: {
+ department: 'Engineering',
+ level: 'Senior'
+ },
+ aiPrompt: 'Generate a professional job description for a senior software engineer role'
+ },
+ {
+ mimeType: 'text',
+ name: 'Company Information',
+ placeholder: '{CompanyInfo}',
+ text: 'TechCorp Solutions Inc.',
+ allowRichTextInjection: 1,
+ autogenerated: false,
+ count: 1,
+ order: 2,
+ subvariables: [
+ {
+ placeholder: '{CompanyInfo.Address}',
+ text: '123 Innovation Drive, Tech City, TC 12345'
+ },
+ {
+ placeholder: '{CompanyInfo.Phone}',
+ text: '(555) 123-4567'
+ }
+ ],
+ metadata: {},
+ aiPrompt: ''
+ }
+ ];
+ }
+}
+
+// Fastify route handlers
+async function registerRoutes() {
+ // Complete workflow demonstration route
+ fastify.post('/complete-workflow', async (request, reply) => {
+ try {
+ console.log('Starting complete workflow demonstration...');
+
+ const workflowManager = new TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL);
+ const result = await workflowManager.demonstrateCompleteWorkflow();
+
+ reply.send({
+ success: true,
+ message: 'Complete workflow demonstration finished',
+ data: result
+ });
+ } catch (error) {
+ console.error('Error in complete workflow:', error);
+ reply.code(500).send({
+ error: 'Complete workflow failed',
+ message: error.message
+ });
+ }
+ });
+
+ // Individual workflow paths
+ fastify.post('/upload-workflow', async (request, reply) => {
+ try {
+ const { templateFilePath } = request.body;
+
+ if (!templateFilePath) {
+ return reply.code(400).send({
+ error: 'templateFilePath is required'
+ });
+ }
+
+ const workflowManager = new TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL);
+ const templateId = await workflowManager.demonstrateUploadWorkflow();
+
+ if (!templateId) {
+ return reply.code(404).send({
+ error: 'Upload workflow failed',
+ message: 'Template file not found or upload failed'
+ });
+ }
+
+ // Generate deliverable
+ const deliverableResult = await workflowManager.generateAndDownloadDeliverable(templateId, 'Upload');
+
+ reply.send({
+ success: true,
+ message: 'Upload workflow completed successfully',
+ data: {
+ templateId,
+ ...deliverableResult
+ }
+ });
+ } catch (error) {
+ console.error('Error in upload workflow:', error);
+ reply.code(500).send({
+ error: 'Upload workflow failed',
+ message: error.message
+ });
+ }
+ });
+
+ fastify.post('/browse-workflow', async (request, reply) => {
+ try {
+ const workflowManager = new TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL);
+ const templateId = await workflowManager.demonstrateBrowseWorkflow();
+
+ if (!templateId) {
+ return reply.code(404).send({
+ error: 'Browse workflow failed',
+ message: 'No templates found or selection failed'
+ });
+ }
+
+ // Generate deliverable
+ const deliverableResult = await workflowManager.generateAndDownloadDeliverable(templateId, 'Browse');
+
+ reply.send({
+ success: true,
+ message: 'Browse workflow completed successfully',
+ data: {
+ templateId,
+ ...deliverableResult
+ }
+ });
+ } catch (error) {
+ console.error('Error in browse workflow:', error);
+ reply.code(500).send({
+ error: 'Browse workflow failed',
+ message: error.message
+ });
+ }
+ });
+
+ // Health check route
+ fastify.get('/health', async (request, reply) => {
+ reply.send({ status: 'healthy', service: 'workflow-manager' });
+ });
+
+ // Service info route
+ fastify.get('/workflow-info', async (request, reply) => {
+ reply.send({
+ service: 'TurboDocx Complete Workflow Manager Service',
+ endpoints: {
+ 'POST /complete-workflow': 'Demonstrate both upload and browse workflows',
+ 'POST /upload-workflow': 'Execute upload workflow only',
+ 'POST /browse-workflow': 'Execute browse workflow only',
+ 'GET /health': 'Service health check',
+ 'GET /workflow-info': 'Service information'
+ },
+ configuration: {
+ baseUrl: BASE_URL,
+ hasToken: !!API_TOKEN && API_TOKEN !== 'YOUR_API_TOKEN',
+ hasOrgId: !!ORG_ID && ORG_ID !== 'YOUR_ORGANIZATION_ID'
+ },
+ description: 'Complete workflow manager that demonstrates both template upload and browse/select paths, followed by deliverable generation and download.'
+ });
+ });
+}
+
+// Example usage function
+async function demonstrateCompleteWorkflow() {
+ try {
+ console.log('=== Complete Template Workflow Demonstration ===');
+
+ const workflowManager = new TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL);
+ const result = await workflowManager.demonstrateCompleteWorkflow();
+
+ console.log('\n=== Workflow Demonstration Complete ===');
+ console.log('Both upload and browse/select paths have been demonstrated.');
+ console.log('Choose the appropriate path for your use case:');
+ console.log('- Upload path: When you have new templates to create');
+ console.log('- Browse path: When you want to use existing templates');
+
+ return result;
+ } catch (error) {
+ console.error('Workflow demonstration failed:', error.message);
+ process.exit(1);
+ }
+}
+
+// Server startup
+async function startServer() {
+ try {
+ await registerRoutes();
+
+ const port = process.env.PORT || 3004;
+ const host = process.env.HOST || '0.0.0.0';
+
+ await fastify.listen({ port, host });
+
+ console.log('🚀 TurboDocx Complete Workflow Manager Service started');
+ console.log(`📡 Server listening on http://${host}:${port}`);
+ console.log('\nAvailable endpoints:');
+ console.log(` POST http://${host}:${port}/complete-workflow`);
+ console.log(` POST http://${host}:${port}/upload-workflow`);
+ console.log(` POST http://${host}:${port}/browse-workflow`);
+ console.log(` GET http://${host}:${port}/health`);
+ console.log(` GET http://${host}:${port}/workflow-info`);
+
+ } catch (error) {
+ fastify.log.error(error);
+ process.exit(1);
+ }
+}
+
+// Check if this file is being run directly
+if (require.main === module) {
+ const args = process.argv.slice(2);
+
+ if (args.includes('--demo')) {
+ // Run demonstration
+ demonstrateCompleteWorkflow();
+ } else {
+ // Start server
+ startServer();
+ }
+}
+
+module.exports = {
+ TemplateWorkflowManager,
+ demonstrateCompleteWorkflow,
+ startServer,
+ fastify
+};
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/flask.py b/static/scripts/templates/api/complete-workflows/flask.py
new file mode 100644
index 0000000..d5dccbd
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/flask.py
@@ -0,0 +1,521 @@
+#!/usr/bin/env python3
+
+import os
+import requests
+import json
+import uuid
+from datetime import datetime
+from flask import Flask, request, jsonify
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+app = Flask(__name__)
+
+class TemplateWorkflowManager:
+ """
+ Complete Template Workflow Manager
+ Demonstrates both upload and browse/select paths
+ """
+
+ def __init__(self, api_token, org_id, base_url):
+ self.api_token = api_token
+ self.org_id = org_id
+ self.base_url = base_url
+ print('=== TurboDocx Template Generation Workflow Manager ===')
+
+ def demonstrate_complete_workflow(self):
+ print('\nSelect workflow path:')
+ print('A) Upload new template')
+ print('B) Browse and select existing template')
+
+ # For this example, we'll demonstrate both paths
+ print('\n=== Demonstrating Path A: Upload Template ===')
+ template_id_a = self.demonstrate_upload_workflow()
+
+ print('\n=== Demonstrating Path B: Browse Templates ===')
+ template_id_b = self.demonstrate_browse_workflow()
+
+ # Generate deliverables for both templates if successful
+ results = {}
+
+ if template_id_a:
+ print('\n=== Generating Deliverable from Uploaded Template ===')
+ results['uploadPath'] = self.generate_and_download_deliverable(template_id_a, 'A')
+
+ if template_id_b:
+ print('\n=== Generating Deliverable from Selected Template ===')
+ results['browsePath'] = self.generate_and_download_deliverable(template_id_b, 'B')
+
+ return {
+ 'uploadedTemplateId': template_id_a,
+ 'selectedTemplateId': template_id_b,
+ 'results': results
+ }
+
+ def demonstrate_upload_workflow(self):
+ try:
+ print('\n--- Path A: Upload and Create Template ---')
+
+ # Check for template file
+ template_file = './contract-template.docx'
+ if not os.path.exists(template_file):
+ print(f'⚠️ Template file not found: {template_file}')
+ print('Creating a placeholder message for demonstration')
+ return None
+
+ result = self.upload_template(template_file)
+ template = result['data']['results']['template']
+
+ print('✅ Upload workflow completed')
+ print(f'Template ID: {template["id"]}')
+ print('Ready for deliverable generation')
+
+ return template['id']
+
+ except Exception as e:
+ print(f'❌ Upload workflow failed: {str(e)}')
+ return None
+
+ def demonstrate_browse_workflow(self):
+ try:
+ print('\n--- Path B: Browse and Select Template ---')
+
+ # Browse templates
+ browse_result = self.browse_templates(10, 0, 'contract', True)
+
+ # Find first template (not folder)
+ selected_template = None
+ for item in browse_result['results']:
+ if item.get('type') == 'template':
+ selected_template = item
+ break
+
+ if not selected_template:
+ print('⚠️ No templates found in browse results')
+ return None
+
+ print(f'Selected: {selected_template["name"]}')
+
+ # Get detailed information
+ template_details = self.get_template_details(selected_template['id'])
+
+ # Optionally get PDF preview
+ pdf_preview = self.get_template_pdf_preview(selected_template['id'])
+
+ print('✅ Browse workflow completed')
+ print(f'Template ID: {template_details["id"]}')
+ print(f'PDF Preview: {pdf_preview}')
+ print('Ready for deliverable generation')
+
+ return template_details['id']
+
+ except Exception as e:
+ print(f'❌ Browse workflow failed: {str(e)}')
+ return None
+
+ def generate_and_download_deliverable(self, template_id, path_label):
+ try:
+ print(f'\n--- Generating Deliverable (Path {path_label}) ---')
+
+ deliverable_data = self.create_deliverable_data(template_id, path_label)
+ deliverable = self.generate_deliverable(template_id, deliverable_data)
+
+ # Download the file
+ download_result = self.download_deliverable(
+ deliverable['id'],
+ f'{deliverable["name"]}_path_{path_label}.docx'
+ )
+
+ print(f'✅ Complete workflow finished successfully for Path {path_label}')
+ print(f'Deliverable ID: {deliverable["id"]}')
+ print(f'Download info: {json.dumps(download_result, indent=2)}')
+
+ return {
+ 'deliverable': deliverable,
+ 'downloadResult': download_result
+ }
+
+ except Exception as e:
+ print(f'❌ Deliverable generation failed for Path {path_label}: {str(e)}')
+ raise
+
+ def upload_template(self, template_file_path):
+ url = f"{self.base_url}/template/upload-and-create"
+
+ with open(template_file_path, 'rb') as file:
+ files = {
+ 'templateFile': (os.path.basename(template_file_path), file,
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')
+ }
+
+ data = {
+ 'name': 'Employee Contract Template',
+ 'description': 'Standard employee contract with variable placeholders',
+ 'variables': '[]',
+ 'tags': '["hr", "contract", "template"]'
+ }
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ response = requests.post(url, files=files, data=data, headers=headers)
+ response.raise_for_status()
+ return response.json()
+
+ def browse_templates(self, limit, offset, query, show_tags):
+ from urllib.parse import urlencode
+
+ params = {
+ 'limit': str(limit),
+ 'offset': str(offset),
+ 'showTags': str(show_tags).lower()
+ }
+
+ if query:
+ params['query'] = query
+
+ query_string = urlencode(params)
+ url = f"{self.base_url}/template-item?{query_string}"
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()['data']
+
+ def get_template_details(self, template_id):
+ url = f"{self.base_url}/template/{template_id}"
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()['data']['results']
+
+ def get_template_pdf_preview(self, template_id):
+ url = f"{self.base_url}/template/{template_id}/previewpdflink"
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ response = requests.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()['results']
+
+ def generate_deliverable(self, template_id, deliverable_data):
+ url = f"{self.base_url}/deliverable"
+
+ print('Generating deliverable...')
+ print(f'Template ID: {template_id}')
+ print(f'Deliverable Name: {deliverable_data["name"]}')
+ print(f'Variables: {len(deliverable_data["variables"])}')
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client',
+ 'Content-Type': 'application/json'
+ }
+
+ response = requests.post(url, json=deliverable_data, headers=headers)
+ response.raise_for_status()
+
+ # Parse JSON response
+ result = response.json()
+ deliverable = result['data']['results']['deliverable']
+
+ print('✅ Deliverable generated successfully!')
+ print(f'Deliverable ID: {deliverable["id"]}')
+ print(f'Created by: {deliverable["createdBy"]}')
+ print(f'Created on: {deliverable["createdOn"]}')
+ print(f'Template ID: {deliverable["templateId"]}')
+
+ return deliverable
+
+ def download_deliverable(self, deliverable_id, filename):
+ print(f'Downloading file: {filename}')
+
+ url = f"{self.base_url}/deliverable/file/{deliverable_id}"
+
+ headers = {
+ 'Authorization': f'Bearer {self.api_token}',
+ 'x-rapiddocx-org-id': self.org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ response = requests.get(url, headers=headers, stream=True)
+ response.raise_for_status()
+
+ print(f'✅ File ready for download: {filename}')
+
+ content_type = response.headers.get('Content-Type', 'N/A')
+ content_length = response.headers.get('Content-Length', 'N/A')
+
+ print(f'📁 Content-Type: {content_type}')
+ print(f'📊 Content-Length: {content_length} bytes')
+
+ # In a real application, you would save the file
+ # with open(filename, 'wb') as f:
+ # for chunk in response.iter_content(chunk_size=8192):
+ # f.write(chunk)
+
+ return {
+ 'filename': filename,
+ 'contentType': content_type,
+ 'contentLength': content_length
+ }
+
+ def create_deliverable_data(self, template_id, path_label):
+ now = datetime.utcnow().isoformat() + 'Z'
+
+ return {
+ 'templateId': template_id,
+ 'name': f'Contract Document - Path {path_label}',
+ 'description': f'Employment contract generated via workflow path {path_label}',
+ 'variables': self.create_complex_variables(),
+ 'tags': ['hr', 'contract', 'employee', 'engineering'],
+ 'fonts': '[{"name":"Arial","usage":269}]',
+ 'defaultFont': 'Arial',
+ 'replaceFonts': True,
+ 'metadata': {
+ 'sessions': [
+ {
+ 'id': str(uuid.uuid4()),
+ 'starttime': now,
+ 'endtime': now
+ }
+ ],
+ 'createdBy': 'Python Workflow Manager',
+ 'documentType': 'Employment Contract',
+ 'version': 'v1.0',
+ 'workflowPath': path_label
+ }
+ }
+
+ def create_complex_variables(self):
+ return [
+ {
+ 'mimeType': 'text',
+ 'name': 'Employee Name',
+ 'placeholder': '{EmployeeName}',
+ 'text': 'John Smith',
+ 'allowRichTextInjection': 0,
+ 'autogenerated': False,
+ 'count': 1,
+ 'order': 1,
+ 'subvariables': [
+ {
+ 'placeholder': '{EmployeeName.Title}',
+ 'text': 'Senior Software Engineer'
+ },
+ {
+ 'placeholder': '{EmployeeName.StartDate}',
+ 'text': 'January 15, 2024'
+ }
+ ],
+ 'metadata': {
+ 'department': 'Engineering',
+ 'level': 'Senior'
+ },
+ 'aiPrompt': 'Generate a professional job description for a senior software engineer role'
+ },
+ {
+ 'mimeType': 'text',
+ 'name': 'Company Information',
+ 'placeholder': '{CompanyInfo}',
+ 'text': 'TechCorp Solutions Inc.',
+ 'allowRichTextInjection': 1,
+ 'autogenerated': False,
+ 'count': 1,
+ 'order': 2,
+ 'subvariables': [
+ {
+ 'placeholder': '{CompanyInfo.Address}',
+ 'text': '123 Innovation Drive, Tech City, TC 12345'
+ },
+ {
+ 'placeholder': '{CompanyInfo.Phone}',
+ 'text': '(555) 123-4567'
+ }
+ ],
+ 'metadata': {},
+ 'aiPrompt': ''
+ }
+ ]
+
+# Flask route handlers
+@app.route('/complete-workflow', methods=['POST'])
+def complete_workflow_endpoint():
+ """Complete workflow demonstration endpoint"""
+ try:
+ print('Starting complete workflow demonstration...')
+
+ workflow_manager = TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL)
+ result = workflow_manager.demonstrate_complete_workflow()
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Complete workflow demonstration finished',
+ 'data': result
+ })
+
+ except Exception as e:
+ app.logger.error(f'Error in complete workflow: {str(e)}')
+ return jsonify({
+ 'error': 'Complete workflow failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/upload-workflow', methods=['POST'])
+def upload_workflow_endpoint():
+ """Upload workflow endpoint"""
+ try:
+ data = request.get_json() or {}
+ template_file_path = data.get('templateFilePath', './contract-template.docx')
+
+ workflow_manager = TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL)
+ template_id = workflow_manager.demonstrate_upload_workflow()
+
+ if not template_id:
+ return jsonify({
+ 'error': 'Upload workflow failed',
+ 'message': 'Template file not found or upload failed'
+ }), 404
+
+ # Generate deliverable
+ deliverable_result = workflow_manager.generate_and_download_deliverable(template_id, 'Upload')
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Upload workflow completed successfully',
+ 'data': {
+ 'templateId': template_id,
+ **deliverable_result
+ }
+ })
+
+ except Exception as e:
+ app.logger.error(f'Error in upload workflow: {str(e)}')
+ return jsonify({
+ 'error': 'Upload workflow failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/browse-workflow', methods=['POST'])
+def browse_workflow_endpoint():
+ """Browse workflow endpoint"""
+ try:
+ workflow_manager = TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL)
+ template_id = workflow_manager.demonstrate_browse_workflow()
+
+ if not template_id:
+ return jsonify({
+ 'error': 'Browse workflow failed',
+ 'message': 'No templates found or selection failed'
+ }), 404
+
+ # Generate deliverable
+ deliverable_result = workflow_manager.generate_and_download_deliverable(template_id, 'Browse')
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Browse workflow completed successfully',
+ 'data': {
+ 'templateId': template_id,
+ **deliverable_result
+ }
+ })
+
+ except Exception as e:
+ app.logger.error(f'Error in browse workflow: {str(e)}')
+ return jsonify({
+ 'error': 'Browse workflow failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/health', methods=['GET'])
+def health_check():
+ """Health check endpoint"""
+ return jsonify({
+ 'status': 'healthy',
+ 'service': 'workflow-manager'
+ })
+
+@app.route('/workflow-info', methods=['GET'])
+def workflow_info():
+ """Service information endpoint"""
+ return jsonify({
+ 'service': 'TurboDocx Complete Workflow Manager Service',
+ 'endpoints': {
+ 'POST /complete-workflow': 'Demonstrate both upload and browse workflows',
+ 'POST /upload-workflow': 'Execute upload workflow only',
+ 'POST /browse-workflow': 'Execute browse workflow only',
+ 'GET /health': 'Service health check',
+ 'GET /workflow-info': 'Service information'
+ },
+ 'configuration': {
+ 'baseUrl': BASE_URL,
+ 'hasToken': bool(API_TOKEN and API_TOKEN != 'YOUR_API_TOKEN'),
+ 'hasOrgId': bool(ORG_ID and ORG_ID != 'YOUR_ORGANIZATION_ID')
+ },
+ 'description': 'Complete workflow manager that demonstrates both template upload and browse/select paths, followed by deliverable generation and download.'
+ })
+
+def demonstrate_complete_workflow():
+ """Example usage function"""
+ try:
+ print('=== Complete Template Workflow Demonstration ===')
+
+ workflow_manager = TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL)
+ result = workflow_manager.demonstrate_complete_workflow()
+
+ print('\n=== Workflow Demonstration Complete ===')
+ print('Both upload and browse/select paths have been demonstrated.')
+ print('Choose the appropriate path for your use case:')
+ print('- Upload path: When you have new templates to create')
+ print('- Browse path: When you want to use existing templates')
+
+ return result
+
+ except Exception as e:
+ print(f'Workflow demonstration failed: {str(e)}')
+ exit(1)
+
+if __name__ == '__main__':
+ import sys
+
+ if '--demo' in sys.argv:
+ # Run demonstration
+ demonstrate_complete_workflow()
+ else:
+ # Start Flask server
+ port = int(os.environ.get('PORT', 5004))
+ host = os.environ.get('HOST', '0.0.0.0')
+
+ print('🚀 TurboDocx Complete Workflow Manager Service started')
+ print(f'📡 Server listening on http://{host}:{port}')
+ print('\nAvailable endpoints:')
+ print(f' POST http://{host}:{port}/complete-workflow')
+ print(f' POST http://{host}:{port}/upload-workflow')
+ print(f' POST http://{host}:{port}/browse-workflow')
+ print(f' GET http://{host}:{port}/health')
+ print(f' GET http://{host}:{port}/workflow-info')
+
+ app.run(host=host, port=port, debug=False)
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/go.go b/static/scripts/templates/api/complete-workflows/go.go
new file mode 100644
index 0000000..fd6a16e
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/go.go
@@ -0,0 +1,613 @@
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "mime/multipart"
+ "net/http"
+ "net/url"
+ "os"
+ "time"
+)
+
+// Configuration - Update these values
+const (
+ API_TOKEN = "YOUR_API_TOKEN"
+ ORG_ID = "YOUR_ORGANIZATION_ID"
+ BASE_URL = "https://api.turbodocx.com"
+)
+
+// Response structures
+type UploadResponse struct {
+ Data struct {
+ Results struct {
+ Template struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ DefaultFont string `json:"defaultFont"`
+ Variables []struct {
+ Name string `json:"name"`
+ } `json:"variables"`
+ Fonts []struct {
+ Name string `json:"name"`
+ } `json:"fonts"`
+ } `json:"template"`
+ } `json:"results"`
+ } `json:"data"`
+}
+
+type BrowseResponse struct {
+ Data struct {
+ Results []struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Type string `json:"type"`
+ } `json:"results"`
+ TotalRecords int `json:"totalRecords"`
+ } `json:"data"`
+}
+
+type TemplateDetailsResponse struct {
+ Data struct {
+ Results struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Variables []struct {
+ Name string `json:"name"`
+ } `json:"variables"`
+ DefaultFont string `json:"defaultFont"`
+ } `json:"results"`
+ } `json:"data"`
+}
+
+type PDFPreviewResponse struct {
+ Results string `json:"results"`
+}
+
+type DeliverableResponse struct {
+ Data struct {
+ Results struct {
+ Deliverable struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ CreatedBy string `json:"createdBy"`
+ CreatedOn string `json:"createdOn"`
+ } `json:"deliverable"`
+ } `json:"results"`
+ } `json:"data"`
+}
+
+/**
+ * Complete Template Generation Workflows
+ * Demonstrates both Path A (Upload) and Path B (Browse/Select) followed by generation
+ */
+type TemplateWorkflowManager struct {
+ client *http.Client
+}
+
+func NewTemplateWorkflowManager() *TemplateWorkflowManager {
+ return &TemplateWorkflowManager{
+ client: &http.Client{},
+ }
+}
+
+func main() {
+ workflow := NewTemplateWorkflowManager()
+
+ // Demo Path B (Browse existing templates)
+ err := workflow.DemoPathB()
+ if err != nil {
+ fmt.Printf("Workflow demo failed: %v\n", err)
+ return
+ }
+
+ // Uncomment to demo Path A (requires template file):
+ // err = workflow.DemoPathA("./path/to/your/template.docx")
+
+ // Uncomment to run full comparison:
+ // err = workflow.DemoComparison()
+}
+
+// ===============================
+// PATH A: Upload New Template
+// ===============================
+
+/**
+ * Complete Path A workflow: Upload → Generate
+ */
+func (tm *TemplateWorkflowManager) PathA_UploadAndGenerate(templateFilePath, deliverableName string) error {
+ fmt.Println("🔄 PATH A: Upload New Template → Generate Deliverable")
+ fmt.Println(fmt.Sprintf("%s", fmt.Sprintf("%48s", "").ReplaceAll(" ", "=")))
+
+ // Step 1: Upload and create template
+ fmt.Println("\n📤 Step 1: Uploading template...")
+ template, err := tm.uploadTemplate(templateFilePath)
+ if err != nil {
+ fmt.Printf("❌ Path A failed: %v\n", err)
+ return err
+ }
+
+ // Step 2: Generate deliverable using uploaded template
+ fmt.Println("\n📝 Step 2: Generating deliverable...")
+ deliverable, err := tm.generateDeliverable(template.Data.Results.Template.ID, deliverableName,
+ fmt.Sprintf("Generated from uploaded template: %s", template.Data.Results.Template.Name))
+ if err != nil {
+ fmt.Printf("❌ Path A failed: %v\n", err)
+ return err
+ }
+
+ fmt.Println("\n✅ PATH A COMPLETE!")
+ fmt.Printf("Template ID: %s\n", template.Data.Results.Template.ID)
+ fmt.Printf("Deliverable ID: %s\n", deliverable.Data.Results.Deliverable.ID)
+
+ // Download the generated file
+ return tm.downloadDeliverable(deliverable.Data.Results.Deliverable.ID,
+ deliverable.Data.Results.Deliverable.Name+".docx")
+}
+
+func (tm *TemplateWorkflowManager) uploadTemplate(templateFilePath string) (*UploadResponse, error) {
+ if _, err := os.Stat(templateFilePath); os.IsNotExist(err) {
+ return nil, fmt.Errorf("template file not found: %s", templateFilePath)
+ }
+
+ var buf bytes.Buffer
+ writer := multipart.NewWriter(&buf)
+
+ file, err := os.Open(templateFilePath)
+ if err != nil {
+ return nil, fmt.Errorf("failed to open file: %v", err)
+ }
+ defer file.Close()
+
+ part, err := writer.CreateFormFile("templateFile", templateFilePath)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create form file: %v", err)
+ }
+
+ _, err = io.Copy(part, file)
+ if err != nil {
+ return nil, fmt.Errorf("failed to copy file: %v", err)
+ }
+
+ writer.WriteField("name", "API Upload Template")
+ writer.WriteField("description", "Template uploaded via API for testing")
+ writer.WriteField("variables", "[]")
+ writer.WriteField("tags", `["api", "test", "upload"]`)
+
+ writer.Close()
+
+ req, err := http.NewRequest("POST", BASE_URL+"/template/upload-and-create", &buf)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create request: %v", err)
+ }
+
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+ req.Header.Set("Content-Type", writer.FormDataContentType())
+
+ resp, err := tm.client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, fmt.Errorf("upload failed: %d - %s", resp.StatusCode, string(body))
+ }
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %v", err)
+ }
+
+ var result UploadResponse
+ err = json.Unmarshal(body, &result)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse JSON: %v", err)
+ }
+
+ template := result.Data.Results.Template
+ fmt.Printf("✅ Template uploaded: %s (%s)\n", template.Name, template.ID)
+
+ variableCount := 0
+ if template.Variables != nil {
+ variableCount = len(template.Variables)
+ }
+ fmt.Printf("📊 Variables extracted: %d\n", variableCount)
+
+ fmt.Printf("🔤 Default font: %s\n", template.DefaultFont)
+
+ fontCount := 0
+ if template.Fonts != nil {
+ fontCount = len(template.Fonts)
+ }
+ fmt.Printf("📝 Fonts used: %d\n", fontCount)
+
+ return &result, nil
+}
+
+// ===============================
+// PATH B: Browse and Select
+// ===============================
+
+/**
+ * Complete Path B workflow: Browse → Select → Generate
+ */
+func (tm *TemplateWorkflowManager) PathB_BrowseAndGenerate(searchQuery, deliverableName string) error {
+ fmt.Println("🔍 PATH B: Browse Existing Templates → Generate Deliverable")
+ fmt.Println(fmt.Sprintf("%56s", "").ReplaceAll(" ", "="))
+
+ // Step 1: Browse templates
+ fmt.Println("\n🔍 Step 1: Browsing templates...")
+ browseResult, err := tm.browseTemplates(searchQuery)
+ if err != nil {
+ fmt.Printf("❌ Path B failed: %v\n", err)
+ return err
+ }
+
+ // Step 2: Select first available template
+ var selectedTemplate *struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Type string `json:"type"`
+ }
+
+ for _, item := range browseResult.Data.Results {
+ if item.Type == "template" {
+ selectedTemplate = &item
+ break
+ }
+ }
+
+ if selectedTemplate == nil {
+ err := fmt.Errorf("no templates found in browse results")
+ fmt.Printf("❌ Path B failed: %v\n", err)
+ return err
+ }
+
+ fmt.Printf("📋 Selected: %s (%s)\n", selectedTemplate.Name, selectedTemplate.ID)
+
+ // Step 3: Get template details
+ fmt.Println("\n📖 Step 2: Getting template details...")
+ templateDetails, err := tm.getTemplateDetails(selectedTemplate.ID)
+ if err != nil {
+ fmt.Printf("❌ Path B failed: %v\n", err)
+ return err
+ }
+
+ // Step 4: Get PDF preview (optional)
+ fmt.Println("\n🖼️ Step 3: Getting PDF preview...")
+ pdfPreview, err := tm.getTemplatePDFPreview(selectedTemplate.ID)
+ if err != nil {
+ fmt.Printf("❌ Path B failed: %v\n", err)
+ return err
+ }
+
+ // Step 5: Generate deliverable
+ fmt.Println("\n📝 Step 4: Generating deliverable...")
+ deliverable, err := tm.generateDeliverable(templateDetails.Data.Results.ID, deliverableName,
+ fmt.Sprintf("Generated from existing template: %s", templateDetails.Data.Results.Name))
+ if err != nil {
+ fmt.Printf("❌ Path B failed: %v\n", err)
+ return err
+ }
+
+ fmt.Println("\n✅ PATH B COMPLETE!")
+ fmt.Printf("Template ID: %s\n", templateDetails.Data.Results.ID)
+ fmt.Printf("Deliverable ID: %s\n", deliverable.Data.Results.Deliverable.ID)
+ fmt.Printf("PDF Preview: %s\n", pdfPreview)
+
+ // Download the generated file
+ fmt.Println("\n📥 Step 5: Downloading file...")
+ return tm.downloadDeliverable(deliverable.Data.Results.Deliverable.ID,
+ deliverable.Data.Results.Deliverable.Name+".docx")
+}
+
+func (tm *TemplateWorkflowManager) browseTemplates(query string) (*BrowseResponse, error) {
+ params := url.Values{}
+ params.Set("limit", "25")
+ params.Set("offset", "0")
+ params.Set("showTags", "true")
+
+ if query != "" {
+ params.Set("query", query)
+ }
+
+ requestURL := fmt.Sprintf("%s/template-item?%s", BASE_URL, params.Encode())
+
+ req, err := http.NewRequest("GET", requestURL, nil)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create request: %v", err)
+ }
+
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+
+ resp, err := tm.client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, fmt.Errorf("browse failed: %d - %s", resp.StatusCode, string(body))
+ }
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %v", err)
+ }
+
+ var result BrowseResponse
+ err = json.Unmarshal(body, &result)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse JSON: %v", err)
+ }
+
+ fmt.Printf("🔍 Found %d templates/folders\n", result.Data.TotalRecords)
+
+ return &result, nil
+}
+
+func (tm *TemplateWorkflowManager) getTemplateDetails(templateID string) (*TemplateDetailsResponse, error) {
+ req, err := http.NewRequest("GET", BASE_URL+"/template/"+templateID, nil)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create request: %v", err)
+ }
+
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+
+ resp, err := tm.client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, fmt.Errorf("template details failed: %d - %s", resp.StatusCode, string(body))
+ }
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %v", err)
+ }
+
+ var result TemplateDetailsResponse
+ err = json.Unmarshal(body, &result)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse JSON: %v", err)
+ }
+
+ template := result.Data.Results
+ variableCount := 0
+ if template.Variables != nil {
+ variableCount = len(template.Variables)
+ }
+ fmt.Printf("📊 Variables: %d\n", variableCount)
+
+ defaultFont := template.DefaultFont
+ if defaultFont == "" {
+ defaultFont = "N/A"
+ }
+ fmt.Printf("🔤 Default font: %s\n", defaultFont)
+
+ return &result, nil
+}
+
+func (tm *TemplateWorkflowManager) getTemplatePDFPreview(templateID string) (string, error) {
+ req, err := http.NewRequest("GET", BASE_URL+"/template/"+templateID+"/previewpdflink", nil)
+ if err != nil {
+ return "", fmt.Errorf("failed to create request: %v", err)
+ }
+
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+
+ resp, err := tm.client.Do(req)
+ if err != nil {
+ return "", fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, _ := io.ReadAll(resp.Body)
+ return "", fmt.Errorf("PDF preview failed: %d - %s", resp.StatusCode, string(body))
+ }
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return "", fmt.Errorf("failed to read response: %v", err)
+ }
+
+ var result PDFPreviewResponse
+ err = json.Unmarshal(body, &result)
+ if err != nil {
+ return "", fmt.Errorf("failed to parse JSON: %v", err)
+ }
+
+ fmt.Printf("🖼️ PDF Preview available: %s\n", result.Results)
+
+ return result.Results, nil
+}
+
+// ===============================
+// COMMON: Generate Deliverable
+// ===============================
+
+func (tm *TemplateWorkflowManager) generateDeliverable(templateID, name, description string) (*DeliverableResponse, error) {
+ now := time.Now().UTC().Format(time.RFC3339)
+
+ payload := map[string]interface{}{
+ "templateId": templateID,
+ "name": name,
+ "description": description,
+ "variables": []map[string]interface{}{
+ {
+ "mimeType": "text",
+ "name": "Sample Variable",
+ "placeholder": "{SampleVariable}",
+ "text": "Sample Content from Go Workflow",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 1,
+ "order": 1,
+ "subvariables": []interface{}{},
+ "metadata": map[string]interface{}{
+ "generatedBy": "Go Workflow",
+ },
+ "aiPrompt": "",
+ },
+ },
+ "tags": []string{"api-generated"},
+ "fonts": "[]",
+ "defaultFont": "Arial",
+ "replaceFonts": true,
+ "metadata": map[string]interface{}{
+ "sessions": []map[string]interface{}{
+ {
+ "id": fmt.Sprintf("go-session-%d", time.Now().Unix()),
+ "starttime": now,
+ "endtime": now,
+ },
+ },
+ "workflow": "Go Complete Workflow",
+ "generated": now,
+ },
+ }
+
+ jsonData, err := json.Marshal(payload)
+ if err != nil {
+ return nil, fmt.Errorf("failed to marshal JSON: %v", err)
+ }
+
+ req, err := http.NewRequest("POST", BASE_URL+"/deliverable", bytes.NewBuffer(jsonData))
+ if err != nil {
+ return nil, fmt.Errorf("failed to create request: %v", err)
+ }
+
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+ req.Header.Set("Content-Type", "application/json")
+
+ resp, err := tm.client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, fmt.Errorf("deliverable generation failed: %d - %s", resp.StatusCode, string(body))
+ }
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %v", err)
+ }
+
+ var result DeliverableResponse
+ err = json.Unmarshal(body, &result)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse JSON: %v", err)
+ }
+
+ deliverable := result.Data.Results.Deliverable
+ fmt.Printf("✅ Generated: %s\n", deliverable.Name)
+ fmt.Printf("📄 Created by: %s\n", deliverable.CreatedBy)
+ fmt.Printf("📅 Created on: %s\n", deliverable.CreatedOn)
+
+ return &result, nil
+}
+
+func (tm *TemplateWorkflowManager) downloadDeliverable(deliverableID, filename string) error {
+ fmt.Printf("📥 Downloading file: %s\n", filename)
+
+ req, err := http.NewRequest("GET", BASE_URL+"/deliverable/file/"+deliverableID, nil)
+ if err != nil {
+ return fmt.Errorf("failed to create request: %v", err)
+ }
+
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+
+ resp, err := tm.client.Do(req)
+ if err != nil {
+ return fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("download failed: %d", resp.StatusCode)
+ }
+
+ fmt.Printf("✅ File ready for download: %s\n", filename)
+
+ contentType := resp.Header.Get("Content-Type")
+ if contentType == "" {
+ contentType = "N/A"
+ }
+
+ contentLength := resp.Header.Get("Content-Length")
+ if contentLength == "" {
+ contentLength = "N/A"
+ }
+
+ fmt.Printf("📁 Content-Type: %s\n", contentType)
+ fmt.Printf("📊 Content-Length: %s bytes\n", contentLength)
+
+ return nil
+}
+
+// ===============================
+// DEMO FUNCTIONS
+// ===============================
+
+func (tm *TemplateWorkflowManager) DemoPathA(templateFilePath string) error {
+ fmt.Println("🚀 DEMO: Path A - Upload New Template Workflow")
+ fmt.Println(fmt.Sprintf("%45s", "").ReplaceAll(" ", "="))
+ fmt.Println()
+
+ return tm.PathA_UploadAndGenerate(templateFilePath, "Contract Generated via Path A - API Upload")
+}
+
+func (tm *TemplateWorkflowManager) DemoPathB() error {
+ fmt.Println("🚀 DEMO: Path B - Browse Existing Template Workflow")
+ fmt.Println(fmt.Sprintf("%51s", "").ReplaceAll(" ", "="))
+ fmt.Println()
+
+ return tm.PathB_BrowseAndGenerate("contract", "Contract Generated via Path B - Browse & Select")
+}
+
+func (tm *TemplateWorkflowManager) DemoComparison() error {
+ fmt.Println("🚀 DEMO: Complete Workflow Comparison")
+ fmt.Println(fmt.Sprintf("%36s", "").ReplaceAll(" ", "="))
+ fmt.Println()
+
+ fmt.Println("Testing both paths with the same template type...\n")
+
+ // Run Path B first (browse existing)
+ err := tm.DemoPathB()
+ if err != nil {
+ return fmt.Errorf("demo comparison failed: %v", err)
+ }
+
+ fmt.Println("\n" + fmt.Sprintf("%60s", "").ReplaceAll(" ", "=") + "\n")
+
+ // For Path A, we'd need a template file
+ fmt.Println("📝 Path A requires a template file to upload.")
+ fmt.Println(" Example: workflow.DemoPathA(\"./contract-template.docx\")")
+
+ return nil
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/java.java b/static/scripts/templates/api/complete-workflows/java.java
new file mode 100644
index 0000000..ea457f2
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/java.java
@@ -0,0 +1,477 @@
+import java.io.*;
+import java.net.URI;
+import java.net.http.*;
+import java.nio.file.*;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.util.UUID;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+/**
+ * Complete Template Generation Workflows
+ * Demonstrates both Path A (Upload) and Path B (Browse/Select) followed by generation
+ */
+public class TemplateWorkflowManager {
+ // Configuration - Update these values
+ private static final String API_TOKEN = "YOUR_API_TOKEN";
+ private static final String ORG_ID = "YOUR_ORGANIZATION_ID";
+ private static final String BASE_URL = "https://api.turbodocx.com";
+
+ private final HttpClient client;
+ private final ObjectMapper mapper;
+
+ public TemplateWorkflowManager() {
+ this.client = HttpClient.newHttpClient();
+ this.mapper = new ObjectMapper();
+ }
+
+ public static void main(String[] args) throws Exception {
+ TemplateWorkflowManager workflow = new TemplateWorkflowManager();
+
+ try {
+ // Demo Path B (Browse existing templates)
+ workflow.demoPathB();
+
+ // Uncomment to demo Path A (requires template file):
+ // workflow.demoPathA("./path/to/your/template.docx");
+
+ // Uncomment to run full comparison:
+ // workflow.demoComparison();
+
+ } catch (Exception e) {
+ System.err.println("Workflow demo failed: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ // ===============================
+ // PATH A: Upload New Template
+ // ===============================
+
+ /**
+ * Complete Path A workflow: Upload → Generate
+ */
+ public TemplateWorkflowResult pathA_UploadAndGenerate(String templateFilePath, String deliverableName) throws Exception {
+ System.out.println("🔄 PATH A: Upload New Template → Generate Deliverable");
+ System.out.println("=".repeat(48));
+
+ try {
+ // Step 1: Upload and create template
+ System.out.println("\n📤 Step 1: Uploading template...");
+ JsonNode template = uploadTemplate(templateFilePath);
+
+ // Step 2: Generate deliverable using uploaded template
+ System.out.println("\n📝 Step 2: Generating deliverable...");
+ JsonNode deliverable = generateDeliverable(template.get("id").asText(),
+ createDeliverableData(deliverableName, "Generated from uploaded template: " + template.get("name").asText()));
+
+ System.out.println("\n✅ PATH A COMPLETE!");
+ System.out.println("Template ID: " + template.get("id").asText());
+ System.out.println("Deliverable ID: " + deliverable.get("id").asText());
+
+ // Download the generated file
+ downloadDeliverable(deliverable.get("id").asText(), deliverable.get("name").asText() + ".docx");
+
+ return new TemplateWorkflowResult(template, deliverable, null);
+
+ } catch (Exception e) {
+ System.err.println("❌ Path A failed: " + e.getMessage());
+ throw e;
+ }
+ }
+
+ private JsonNode uploadTemplate(String templateFilePath) throws Exception {
+ Path filePath = Paths.get(templateFilePath);
+ if (!Files.exists(filePath)) {
+ throw new FileNotFoundException("Template file not found: " + templateFilePath);
+ }
+
+ String boundary = "----JavaBoundary" + System.currentTimeMillis();
+ byte[] fileBytes = Files.readAllBytes(filePath);
+
+ // Build multipart form data
+ StringBuilder formData = new StringBuilder();
+ formData.append("--").append(boundary).append("\r\n");
+ formData.append("Content-Disposition: form-data; name=\"templateFile\"; filename=\"")
+ .append(filePath.getFileName().toString()).append("\"\r\n");
+ formData.append("Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document\r\n\r\n");
+
+ String additionalFields = "\r\n--" + boundary + "\r\n" +
+ "Content-Disposition: form-data; name=\"name\"\r\n\r\n" +
+ "API Upload Template" +
+ "\r\n--" + boundary + "\r\n" +
+ "Content-Disposition: form-data; name=\"description\"\r\n\r\n" +
+ "Template uploaded via API for testing" +
+ "\r\n--" + boundary + "\r\n" +
+ "Content-Disposition: form-data; name=\"variables\"\r\n\r\n" +
+ "[]" +
+ "\r\n--" + boundary + "\r\n" +
+ "Content-Disposition: form-data; name=\"tags\"\r\n\r\n" +
+ "[\"api\", \"test\", \"upload\"]" +
+ "\r\n--" + boundary + "--\r\n";
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(formData.toString().getBytes());
+ baos.write(fileBytes);
+ baos.write(additionalFields.getBytes());
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(BASE_URL + "/template/upload-and-create"))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .header("Content-Type", "multipart/form-data; boundary=" + boundary)
+ .POST(HttpRequest.BodyPublishers.ofByteArray(baos.toByteArray()))
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("Upload failed: " + response.statusCode());
+ }
+
+ JsonNode result = mapper.readTree(response.body());
+ JsonNode template = result.get("data").get("results").get("template");
+
+ System.out.println("✅ Template uploaded: " + template.get("name").asText() + " (" + template.get("id").asText() + ")");
+
+ JsonNode variables = template.get("variables");
+ int variableCount = (variables != null && !variables.isNull()) ? variables.size() : 0;
+ System.out.println("📊 Variables extracted: " + variableCount);
+
+ System.out.println("🔤 Default font: " + template.get("defaultFont").asText());
+
+ JsonNode fonts = template.get("fonts");
+ int fontCount = (fonts != null && !fonts.isNull()) ? fonts.size() : 0;
+ System.out.println("📝 Fonts used: " + fontCount);
+
+ return template;
+ }
+
+ // ===============================
+ // PATH B: Browse and Select
+ // ===============================
+
+ /**
+ * Complete Path B workflow: Browse → Select → Generate
+ */
+ public TemplateWorkflowResult pathB_BrowseAndGenerate(String searchQuery, String deliverableName) throws Exception {
+ System.out.println("🔍 PATH B: Browse Existing Templates → Generate Deliverable");
+ System.out.println("=".repeat(56));
+
+ try {
+ // Step 1: Browse templates
+ System.out.println("\n🔍 Step 1: Browsing templates...");
+ JsonNode browseResult = browseTemplates(searchQuery);
+
+ // Step 2: Select first available template
+ JsonNode selectedTemplate = null;
+ for (JsonNode item : browseResult.get("results")) {
+ if ("template".equals(item.get("type").asText())) {
+ selectedTemplate = item;
+ break;
+ }
+ }
+
+ if (selectedTemplate == null) {
+ throw new RuntimeException("No templates found in browse results");
+ }
+
+ System.out.println("📋 Selected: " + selectedTemplate.get("name").asText() +
+ " (" + selectedTemplate.get("id").asText() + ")");
+
+ // Step 3: Get template details
+ System.out.println("\n📖 Step 2: Getting template details...");
+ JsonNode templateDetails = getTemplateDetails(selectedTemplate.get("id").asText());
+
+ // Step 4: Get PDF preview (optional)
+ System.out.println("\n🖼️ Step 3: Getting PDF preview...");
+ String pdfPreview = getTemplatePDFPreview(selectedTemplate.get("id").asText());
+
+ // Step 5: Generate deliverable
+ System.out.println("\n📝 Step 4: Generating deliverable...");
+ JsonNode deliverable = generateDeliverable(templateDetails.get("id").asText(),
+ createDeliverableData(deliverableName, "Generated from existing template: " + templateDetails.get("name").asText()));
+
+ System.out.println("\n✅ PATH B COMPLETE!");
+ System.out.println("Template ID: " + templateDetails.get("id").asText());
+ System.out.println("Deliverable ID: " + deliverable.get("id").asText());
+ System.out.println("PDF Preview: " + pdfPreview);
+
+ // Download the generated file
+ System.out.println("\n📥 Step 5: Downloading file...");
+ downloadDeliverable(deliverable.get("id").asText(), deliverable.get("name").asText() + ".docx");
+
+ return new TemplateWorkflowResult(templateDetails, deliverable, pdfPreview);
+
+ } catch (Exception e) {
+ System.err.println("❌ Path B failed: " + e.getMessage());
+ throw e;
+ }
+ }
+
+ private JsonNode browseTemplates(String query) throws Exception {
+ StringBuilder params = new StringBuilder();
+ params.append("limit=25&offset=0&showTags=true");
+
+ if (query != null && !query.isEmpty()) {
+ params.append("&query=").append(URLEncoder.encode(query, StandardCharsets.UTF_8));
+ }
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(BASE_URL + "/template-item?" + params.toString()))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("Browse failed: " + response.statusCode());
+ }
+
+ JsonNode result = mapper.readTree(response.body());
+ JsonNode data = result.get("data");
+
+ System.out.println("🔍 Found " + data.get("totalRecords").asInt() + " templates/folders");
+
+ return data;
+ }
+
+ private JsonNode getTemplateDetails(String templateId) throws Exception {
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(BASE_URL + "/template/" + templateId))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("Template details failed: " + response.statusCode());
+ }
+
+ JsonNode result = mapper.readTree(response.body());
+ JsonNode template = result.get("data").get("results");
+
+ JsonNode variables = template.get("variables");
+ int variableCount = (variables != null && !variables.isNull()) ? variables.size() : 0;
+ System.out.println("📊 Variables: " + variableCount);
+
+ String defaultFont = template.has("defaultFont") ? template.get("defaultFont").asText() : "N/A";
+ System.out.println("🔤 Default font: " + defaultFont);
+
+ return template;
+ }
+
+ private String getTemplatePDFPreview(String templateId) throws Exception {
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(BASE_URL + "/template/" + templateId + "/previewpdflink"))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("PDF preview failed: " + response.statusCode());
+ }
+
+ JsonNode result = mapper.readTree(response.body());
+ String pdfUrl = result.get("results").asText();
+
+ System.out.println("🖼️ PDF Preview available: " + pdfUrl);
+
+ return pdfUrl;
+ }
+
+ // ===============================
+ // COMMON: Generate Deliverable
+ // ===============================
+
+ private JsonNode generateDeliverable(String templateId, ObjectNode deliverableData) throws Exception {
+ ObjectNode payload = mapper.createObjectNode();
+ payload.put("templateId", templateId);
+ payload.put("name", deliverableData.get("name").asText());
+ payload.put("description", deliverableData.get("description").asText());
+ payload.set("variables", deliverableData.get("variables"));
+ payload.set("tags", deliverableData.get("tags"));
+ payload.put("fonts", "[]");
+ payload.put("defaultFont", "Arial");
+ payload.put("replaceFonts", true);
+ payload.set("metadata", createMetadata());
+
+ String jsonBody = mapper.writeValueAsString(payload);
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(BASE_URL + "/deliverable"))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .header("Content-Type", "application/json")
+ .POST(HttpRequest.BodyPublishers.ofString(jsonBody))
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("Deliverable generation failed: " + response.statusCode() + " - " + response.body());
+ }
+
+ JsonNode result = mapper.readTree(response.body());
+ JsonNode deliverable = result.get("data").get("results").get("deliverable");
+
+ System.out.println("✅ Generated: " + deliverable.get("name").asText());
+ System.out.println("📄 Created by: " + deliverable.get("createdBy").asText());
+ System.out.println("📅 Created on: " + deliverable.get("createdOn").asText());
+
+ return deliverable;
+ }
+
+ private void downloadDeliverable(String deliverableId, String filename) throws Exception {
+ System.out.println("📥 Downloading file: " + filename);
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(BASE_URL + "/deliverable/file/" + deliverableId))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("Download failed: " + response.statusCode());
+ }
+
+ System.out.println("✅ File ready for download: " + filename);
+ String contentType = response.headers().firstValue("content-type").orElse("N/A");
+ String contentLength = response.headers().firstValue("content-length").orElse("N/A");
+ System.out.println("📁 Content-Type: " + contentType);
+ System.out.println("📊 Content-Length: " + contentLength + " bytes");
+ }
+
+ // ===============================
+ // UTILITY FUNCTIONS
+ // ===============================
+
+ private ObjectNode createDeliverableData(String name, String description) {
+ ObjectNode data = mapper.createObjectNode();
+ data.put("name", name);
+ data.put("description", description);
+ data.set("variables", createSampleVariables());
+
+ ArrayNode tags = mapper.createArrayNode();
+ tags.add("api-generated");
+ data.set("tags", tags);
+
+ return data;
+ }
+
+ private ArrayNode createSampleVariables() {
+ ArrayNode variables = mapper.createArrayNode();
+
+ ObjectNode variable = mapper.createObjectNode();
+ variable.put("mimeType", "text");
+ variable.put("name", "Sample Variable");
+ variable.put("placeholder", "{SampleVariable}");
+ variable.put("text", "Sample Content from Java Workflow");
+ variable.put("allowRichTextInjection", 0);
+ variable.put("autogenerated", false);
+ variable.put("count", 1);
+ variable.put("order", 1);
+ variable.set("subvariables", mapper.createArrayNode());
+
+ ObjectNode metadata = mapper.createObjectNode();
+ metadata.put("generatedBy", "Java Workflow");
+ variable.set("metadata", metadata);
+
+ variable.put("aiPrompt", "");
+
+ variables.add(variable);
+ return variables;
+ }
+
+ private ObjectNode createMetadata() {
+ ObjectNode metadata = mapper.createObjectNode();
+
+ ArrayNode sessions = mapper.createArrayNode();
+ ObjectNode session = mapper.createObjectNode();
+ session.put("id", UUID.randomUUID().toString());
+ session.put("starttime", Instant.now().toString());
+ session.put("endtime", Instant.now().toString());
+ sessions.add(session);
+
+ metadata.set("sessions", sessions);
+ metadata.put("workflow", "Java Complete Workflow");
+ metadata.put("generated", Instant.now().toString());
+
+ return metadata;
+ }
+
+ // ===============================
+ // DEMO FUNCTIONS
+ // ===============================
+
+ public TemplateWorkflowResult demoPathA(String templateFilePath) throws Exception {
+ System.out.println("🚀 DEMO: Path A - Upload New Template Workflow");
+ System.out.println("=".repeat(45));
+ System.out.println();
+
+ return pathA_UploadAndGenerate(templateFilePath, "Contract Generated via Path A - API Upload");
+ }
+
+ public TemplateWorkflowResult demoPathB() throws Exception {
+ System.out.println("🚀 DEMO: Path B - Browse Existing Template Workflow");
+ System.out.println("=".repeat(51));
+ System.out.println();
+
+ return pathB_BrowseAndGenerate("contract", "Contract Generated via Path B - Browse & Select");
+ }
+
+ public void demoComparison() throws Exception {
+ System.out.println("🚀 DEMO: Complete Workflow Comparison");
+ System.out.println("=".repeat(36));
+ System.out.println();
+
+ try {
+ System.out.println("Testing both paths with the same template type...\\n");
+
+ // Run Path B first (browse existing)
+ TemplateWorkflowResult pathBResult = demoPathB();
+
+ System.out.println("\\n" + "=".repeat(60) + "\\n");
+
+ // For Path A, we'd need a template file
+ System.out.println("📝 Path A requires a template file to upload.");
+ System.out.println(" Example: workflow.demoPathA(\"./contract-template.docx\")");
+
+ } catch (Exception e) {
+ System.err.println("Demo comparison failed: " + e.getMessage());
+ }
+ }
+
+ // Result container class
+ public static class TemplateWorkflowResult {
+ public final JsonNode template;
+ public final JsonNode deliverable;
+ public final String pdfPreview;
+
+ public TemplateWorkflowResult(JsonNode template, JsonNode deliverable, String pdfPreview) {
+ this.template = template;
+ this.deliverable = deliverable;
+ this.pdfPreview = pdfPreview;
+ }
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/nodejs/express.js b/static/scripts/templates/api/complete-workflows/nodejs/express.js
new file mode 100644
index 0000000..fa6539e
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/nodejs/express.js
@@ -0,0 +1,436 @@
+const FormData = require('form-data');
+const fs = require('fs');
+const fetch = require('node-fetch');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+/**
+ * Complete Template Generation Workflows
+ * Demonstrates both Path A (Upload) and Path B (Browse/Select) followed by generation
+ */
+
+class TemplateWorkflowManager {
+ constructor(apiToken, orgId, baseUrl) {
+ this.apiToken = apiToken;
+ this.orgId = orgId;
+ this.baseUrl = baseUrl;
+ this.headers = {
+ 'Authorization': `Bearer ${apiToken}`,
+ 'x-rapiddocx-org-id': orgId,
+ 'User-Agent': 'TurboDocx API Client'
+ };
+ }
+
+ // ===============================
+ // PATH A: Upload New Template
+ // ===============================
+
+ async pathA_UploadAndGenerate(templateFilePath, deliverableName) {
+ console.log('🔄 PATH A: Upload New Template → Generate Deliverable');
+ console.log('================================');
+
+ try {
+ // Step 1: Upload and create template
+ console.log('\n📤 Step 1: Uploading template...');
+ const template = await this.uploadTemplate(templateFilePath);
+
+ // Step 2: Generate deliverable using uploaded template
+ console.log('\n📝 Step 2: Generating deliverable...');
+ const deliverable = await this.generateDeliverable(template.id, {
+ name: deliverableName,
+ description: `Generated from uploaded template: ${template.name}`,
+ variables: this.createVariablesFromTemplate(template.variables)
+ });
+
+ console.log('\n✅ PATH A COMPLETE!');
+ console.log(`Template ID: ${template.id}`);
+ console.log(`Deliverable ID: ${deliverable.id}`);
+
+ // Download the generated file
+ await this.downloadDeliverable(deliverable.id, `${deliverable.name}.docx`);
+
+ return { template, deliverable };
+
+ } catch (error) {
+ console.error('❌ Path A failed:', error.message);
+ throw error;
+ }
+ }
+
+ async uploadTemplate(templateFilePath) {
+ const formData = new FormData();
+ formData.append('templateFile', fs.createReadStream(templateFilePath));
+ formData.append('name', 'API Upload Template');
+ formData.append('description', 'Template uploaded via API for testing');
+ formData.append('variables', '[]');
+ formData.append('tags', '["api", "test", "upload"]');
+
+ const response = await fetch(`${this.baseUrl}/template/upload-and-create`, {
+ method: 'POST',
+ headers: {
+ ...this.headers,
+ ...formData.getHeaders()
+ },
+ body: formData
+ });
+
+ if (!response.ok) {
+ throw new Error(`Upload failed: ${response.status}`);
+ }
+
+ const result = await response.json();
+ const template = result.data.results.template;
+
+ console.log(`✅ Template uploaded: ${template.name} (${template.id})`);
+ console.log(`📊 Variables extracted: ${template.variables ? template.variables.length : 0}`);
+ console.log(`🔤 Default font: ${template.defaultFont}`);
+ console.log(`📝 Fonts used: ${template.fonts ? template.fonts.length : 0}`);
+
+ return template;
+ }
+
+ // ===============================
+ // PATH B: Browse and Select
+ // ===============================
+
+ async pathB_BrowseAndGenerate(searchQuery, deliverableName) {
+ console.log('🔍 PATH B: Browse Existing Templates → Generate Deliverable');
+ console.log('==================================================');
+
+ try {
+ // Step 1: Browse templates
+ console.log('\n🔍 Step 1: Browsing templates...');
+ const browseResult = await this.browseTemplates({ query: searchQuery });
+
+ // Step 2: Select first available template
+ const selectedTemplate = browseResult.results.find(item => item.type === 'template');
+ if (!selectedTemplate) {
+ throw new Error('No templates found in browse results');
+ }
+
+ console.log(`📋 Selected: ${selectedTemplate.name} (${selectedTemplate.id})`);
+
+ // Step 3: Get template details
+ console.log('\n📖 Step 2: Getting template details...');
+ const templateDetails = await this.getTemplateDetails(selectedTemplate.id);
+
+ // Step 4: Get PDF preview (optional)
+ console.log('\n🖼️ Step 3: Getting PDF preview...');
+ const pdfPreview = await this.getTemplatePDFPreview(selectedTemplate.id);
+
+ // Step 5: Generate deliverable
+ console.log('\n📝 Step 4: Generating deliverable...');
+ const deliverable = await this.generateDeliverable(templateDetails.id, {
+ name: deliverableName,
+ description: `Generated from existing template: ${templateDetails.name}`,
+ variables: this.createVariablesFromTemplate(templateDetails.variables)
+ });
+
+ console.log('\n✅ PATH B COMPLETE!');
+ console.log(`Template ID: ${templateDetails.id}`);
+ console.log(`Deliverable ID: ${deliverable.id}`);
+
+ // Download the generated file
+ await this.downloadDeliverable(deliverable.id, `${deliverable.name}.docx`);
+
+ return { template: templateDetails, deliverable, pdfPreview };
+
+ } catch (error) {
+ console.error('❌ Path B failed:', error.message);
+ throw error;
+ }
+ }
+
+ async browseTemplates(options = {}) {
+ const {
+ limit = 25,
+ offset = 0,
+ query = '',
+ showTags = true
+ } = options;
+
+ const params = new URLSearchParams({
+ limit: limit.toString(),
+ offset: offset.toString(),
+ showTags: showTags.toString()
+ });
+
+ if (query) params.append('query', query);
+
+ const response = await fetch(`${this.baseUrl}/template-item?${params.toString()}`, {
+ method: 'GET',
+ headers: this.headers
+ });
+
+ if (!response.ok) {
+ throw new Error(`Browse failed: ${response.status}`);
+ }
+
+ const result = await response.json();
+ console.log(`🔍 Found ${result.data.totalRecords} templates/folders`);
+
+ return result.data;
+ }
+
+ async getTemplateDetails(templateId) {
+ const response = await fetch(`${this.baseUrl}/template/${templateId}`, {
+ method: 'GET',
+ headers: this.headers
+ });
+
+ if (!response.ok) {
+ throw new Error(`Template details failed: ${response.status}`);
+ }
+
+ const result = await response.json();
+ const template = result.data.results;
+
+ console.log(`📊 Variables: ${template.variables.length}`);
+ console.log(`🔤 Default font: ${template.defaultFont || 'N/A'}`);
+
+ return template;
+ }
+
+ async getTemplatePDFPreview(templateId) {
+ const response = await fetch(`${this.baseUrl}/template/${templateId}/previewpdflink`, {
+ method: 'GET',
+ headers: this.headers
+ });
+
+ if (!response.ok) {
+ throw new Error(`PDF preview failed: ${response.status}`);
+ }
+
+ const result = await response.json();
+ console.log(`🖼️ PDF Preview available: ${result.results}`);
+
+ return result.results;
+ }
+
+ // ===============================
+ // COMMON: Generate Deliverable
+ // ===============================
+
+ async generateDeliverable(templateId, deliverableData) {
+ const payload = {
+ templateId: templateId,
+ name: deliverableData.name,
+ description: deliverableData.description || '',
+ variables: deliverableData.variables,
+ tags: deliverableData.tags || ['api-generated'],
+ fonts: deliverableData.fonts || '[]',
+ defaultFont: deliverableData.defaultFont || 'Arial',
+ replaceFonts: deliverableData.replaceFonts !== undefined ? deliverableData.replaceFonts : true,
+ metadata: deliverableData.metadata || {
+ sessions: [{
+ id: this.generateSessionId(),
+ starttime: new Date().toISOString(),
+ endtime: new Date().toISOString()
+ }],
+ workflow: 'API Complete Workflow',
+ generated: new Date().toISOString()
+ }
+ };
+
+ const response = await fetch(`${this.baseUrl}/deliverable`, {
+ method: 'POST',
+ headers: {
+ ...this.headers,
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(payload)
+ });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+ throw new Error(`Deliverable generation failed: ${response.status} - ${errorText}`);
+ }
+
+ const result = await response.json();
+ const deliverable = result.data.results.deliverable;
+
+ console.log(`✅ Generated: ${deliverable.name}`);
+ console.log(`📄 Created by: ${deliverable.createdBy}`);
+ console.log(`📅 Created on: ${deliverable.createdOn}`);
+
+ return deliverable;
+ }
+
+ // ===============================
+ // UTILITY FUNCTIONS
+ // ===============================
+
+ createVariablesFromTemplate(templateVariables) {
+ return templateVariables.map((variable, index) => ({
+ mimeType: variable.mimeType || "text",
+ name: variable.name,
+ placeholder: variable.placeholder,
+ text: this.generateSampleText(variable.name),
+ allowRichTextInjection: variable.allowRichTextInjection || 0,
+ autogenerated: false,
+ count: 1,
+ order: index + 1,
+ subvariables: this.createSampleSubvariables(variable.placeholder),
+ metadata: {
+ generatedBy: "API Workflow",
+ variableType: variable.mimeType || "text"
+ },
+ aiPrompt: `Generate appropriate content for ${variable.name}`
+ }));
+ }
+
+ generateSampleText(variableName) {
+ const sampleData = {
+ 'Company': 'TechCorp Solutions Inc.',
+ 'Employee': 'John Smith',
+ 'Date': new Date().toLocaleDateString(),
+ 'Title': 'Senior Software Engineer',
+ 'Department': 'Engineering',
+ 'Salary': '$95,000',
+ 'Address': '123 Main Street, Tech City, TC 12345',
+ 'Phone': '(555) 123-4567',
+ 'Email': 'john.smith@techcorp.com'
+ };
+
+ // Find matching sample data or generate generic text
+ for (const [key, value] of Object.entries(sampleData)) {
+ if (variableName.toLowerCase().includes(key.toLowerCase())) {
+ return value;
+ }
+ }
+
+ return `Sample ${variableName} Content`;
+ }
+
+ createSampleSubvariables(placeholder) {
+ // Create relevant subvariables based on placeholder name
+ if (placeholder.toLowerCase().includes('employee')) {
+ return [
+ { placeholder: "{Employee.Title}", text: "Senior Software Engineer" },
+ { placeholder: "{Employee.StartDate}", text: new Date().toLocaleDateString() }
+ ];
+ } else if (placeholder.toLowerCase().includes('company')) {
+ return [
+ { placeholder: "{Company.Address}", text: "123 Main Street, Tech City, TC 12345" },
+ { placeholder: "{Company.Phone}", text: "(555) 123-4567" }
+ ];
+ }
+
+ return [];
+ }
+
+ generateSessionId() {
+ return Math.random().toString(36).substr(2, 9) + '-' +
+ Math.random().toString(36).substr(2, 9) + '-' +
+ Math.random().toString(36).substr(2, 9);
+ }
+
+ async downloadDeliverable(deliverableId, filename) {
+ console.log(`\n📥 Downloading file: ${filename}`);
+
+ const response = await fetch(`${this.baseUrl}/deliverable/file/${deliverableId}`, {
+ method: 'GET',
+ headers: this.headers
+ });
+
+ if (!response.ok) {
+ throw new Error(`Download failed: ${response.status}`);
+ }
+
+ console.log(`✅ File ready for download: ${filename}`);
+ console.log(`📁 Content-Type: ${response.headers.get('content-type')}`);
+ console.log(`📊 Content-Length: ${response.headers.get('content-length')} bytes`);
+
+ // In a real application, you would save the file or return the buffer
+ // const buffer = await response.buffer();
+ // fs.writeFileSync(filename, buffer);
+
+ return {
+ filename,
+ contentType: response.headers.get('content-type'),
+ contentLength: response.headers.get('content-length')
+ };
+ }
+
+ // ===============================
+ // DEMO FUNCTIONS
+ // ===============================
+
+ async demoPathA(templateFilePath) {
+ console.log('🚀 DEMO: Path A - Upload New Template Workflow');
+ console.log('===============================================\n');
+
+ return await this.pathA_UploadAndGenerate(
+ templateFilePath,
+ 'Contract Generated via Path A - API Upload'
+ );
+ }
+
+ async demoPathB() {
+ console.log('🚀 DEMO: Path B - Browse Existing Template Workflow');
+ console.log('=================================================\n');
+
+ return await this.pathB_BrowseAndGenerate(
+ 'contract',
+ 'Contract Generated via Path B - Browse & Select'
+ );
+ }
+
+ async demoComparison() {
+ console.log('🚀 DEMO: Complete Workflow Comparison');
+ console.log('====================================\n');
+
+ try {
+ console.log('Testing both paths with the same template type...\n');
+
+ // Run Path B first (browse existing)
+ const pathBResult = await this.demoPathB();
+
+ console.log('\n' + '='.repeat(60) + '\n');
+
+ // For Path A, we'd need a template file
+ console.log('📝 Path A requires a template file to upload.');
+ console.log(' Example: await workflow.demoPathA("./contract-template.docx")');
+
+ return { pathB: pathBResult };
+
+ } catch (error) {
+ console.error('Demo comparison failed:', error.message);
+ }
+ }
+}
+
+// ===============================
+// EXAMPLE USAGE
+// ===============================
+
+async function runExamples() {
+ const workflow = new TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL);
+
+ try {
+ // Demo Path B (Browse existing templates)
+ await workflow.demoPathB();
+
+ // Uncomment to demo Path A (requires template file):
+ // await workflow.demoPathA('./path/to/your/template.docx');
+
+ // Uncomment to run full comparison:
+ // await workflow.demoComparison();
+
+ } catch (error) {
+ console.error('Workflow demo failed:', error.message);
+ }
+}
+
+// Export for use in other modules
+module.exports = {
+ TemplateWorkflowManager
+};
+
+// Run examples if script is executed directly
+if (require.main === module) {
+ runExamples();
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/nodejs/fastify.js b/static/scripts/templates/api/complete-workflows/nodejs/fastify.js
new file mode 100644
index 0000000..fa6539e
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/nodejs/fastify.js
@@ -0,0 +1,436 @@
+const FormData = require('form-data');
+const fs = require('fs');
+const fetch = require('node-fetch');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+/**
+ * Complete Template Generation Workflows
+ * Demonstrates both Path A (Upload) and Path B (Browse/Select) followed by generation
+ */
+
+class TemplateWorkflowManager {
+ constructor(apiToken, orgId, baseUrl) {
+ this.apiToken = apiToken;
+ this.orgId = orgId;
+ this.baseUrl = baseUrl;
+ this.headers = {
+ 'Authorization': `Bearer ${apiToken}`,
+ 'x-rapiddocx-org-id': orgId,
+ 'User-Agent': 'TurboDocx API Client'
+ };
+ }
+
+ // ===============================
+ // PATH A: Upload New Template
+ // ===============================
+
+ async pathA_UploadAndGenerate(templateFilePath, deliverableName) {
+ console.log('🔄 PATH A: Upload New Template → Generate Deliverable');
+ console.log('================================');
+
+ try {
+ // Step 1: Upload and create template
+ console.log('\n📤 Step 1: Uploading template...');
+ const template = await this.uploadTemplate(templateFilePath);
+
+ // Step 2: Generate deliverable using uploaded template
+ console.log('\n📝 Step 2: Generating deliverable...');
+ const deliverable = await this.generateDeliverable(template.id, {
+ name: deliverableName,
+ description: `Generated from uploaded template: ${template.name}`,
+ variables: this.createVariablesFromTemplate(template.variables)
+ });
+
+ console.log('\n✅ PATH A COMPLETE!');
+ console.log(`Template ID: ${template.id}`);
+ console.log(`Deliverable ID: ${deliverable.id}`);
+
+ // Download the generated file
+ await this.downloadDeliverable(deliverable.id, `${deliverable.name}.docx`);
+
+ return { template, deliverable };
+
+ } catch (error) {
+ console.error('❌ Path A failed:', error.message);
+ throw error;
+ }
+ }
+
+ async uploadTemplate(templateFilePath) {
+ const formData = new FormData();
+ formData.append('templateFile', fs.createReadStream(templateFilePath));
+ formData.append('name', 'API Upload Template');
+ formData.append('description', 'Template uploaded via API for testing');
+ formData.append('variables', '[]');
+ formData.append('tags', '["api", "test", "upload"]');
+
+ const response = await fetch(`${this.baseUrl}/template/upload-and-create`, {
+ method: 'POST',
+ headers: {
+ ...this.headers,
+ ...formData.getHeaders()
+ },
+ body: formData
+ });
+
+ if (!response.ok) {
+ throw new Error(`Upload failed: ${response.status}`);
+ }
+
+ const result = await response.json();
+ const template = result.data.results.template;
+
+ console.log(`✅ Template uploaded: ${template.name} (${template.id})`);
+ console.log(`📊 Variables extracted: ${template.variables ? template.variables.length : 0}`);
+ console.log(`🔤 Default font: ${template.defaultFont}`);
+ console.log(`📝 Fonts used: ${template.fonts ? template.fonts.length : 0}`);
+
+ return template;
+ }
+
+ // ===============================
+ // PATH B: Browse and Select
+ // ===============================
+
+ async pathB_BrowseAndGenerate(searchQuery, deliverableName) {
+ console.log('🔍 PATH B: Browse Existing Templates → Generate Deliverable');
+ console.log('==================================================');
+
+ try {
+ // Step 1: Browse templates
+ console.log('\n🔍 Step 1: Browsing templates...');
+ const browseResult = await this.browseTemplates({ query: searchQuery });
+
+ // Step 2: Select first available template
+ const selectedTemplate = browseResult.results.find(item => item.type === 'template');
+ if (!selectedTemplate) {
+ throw new Error('No templates found in browse results');
+ }
+
+ console.log(`📋 Selected: ${selectedTemplate.name} (${selectedTemplate.id})`);
+
+ // Step 3: Get template details
+ console.log('\n📖 Step 2: Getting template details...');
+ const templateDetails = await this.getTemplateDetails(selectedTemplate.id);
+
+ // Step 4: Get PDF preview (optional)
+ console.log('\n🖼️ Step 3: Getting PDF preview...');
+ const pdfPreview = await this.getTemplatePDFPreview(selectedTemplate.id);
+
+ // Step 5: Generate deliverable
+ console.log('\n📝 Step 4: Generating deliverable...');
+ const deliverable = await this.generateDeliverable(templateDetails.id, {
+ name: deliverableName,
+ description: `Generated from existing template: ${templateDetails.name}`,
+ variables: this.createVariablesFromTemplate(templateDetails.variables)
+ });
+
+ console.log('\n✅ PATH B COMPLETE!');
+ console.log(`Template ID: ${templateDetails.id}`);
+ console.log(`Deliverable ID: ${deliverable.id}`);
+
+ // Download the generated file
+ await this.downloadDeliverable(deliverable.id, `${deliverable.name}.docx`);
+
+ return { template: templateDetails, deliverable, pdfPreview };
+
+ } catch (error) {
+ console.error('❌ Path B failed:', error.message);
+ throw error;
+ }
+ }
+
+ async browseTemplates(options = {}) {
+ const {
+ limit = 25,
+ offset = 0,
+ query = '',
+ showTags = true
+ } = options;
+
+ const params = new URLSearchParams({
+ limit: limit.toString(),
+ offset: offset.toString(),
+ showTags: showTags.toString()
+ });
+
+ if (query) params.append('query', query);
+
+ const response = await fetch(`${this.baseUrl}/template-item?${params.toString()}`, {
+ method: 'GET',
+ headers: this.headers
+ });
+
+ if (!response.ok) {
+ throw new Error(`Browse failed: ${response.status}`);
+ }
+
+ const result = await response.json();
+ console.log(`🔍 Found ${result.data.totalRecords} templates/folders`);
+
+ return result.data;
+ }
+
+ async getTemplateDetails(templateId) {
+ const response = await fetch(`${this.baseUrl}/template/${templateId}`, {
+ method: 'GET',
+ headers: this.headers
+ });
+
+ if (!response.ok) {
+ throw new Error(`Template details failed: ${response.status}`);
+ }
+
+ const result = await response.json();
+ const template = result.data.results;
+
+ console.log(`📊 Variables: ${template.variables.length}`);
+ console.log(`🔤 Default font: ${template.defaultFont || 'N/A'}`);
+
+ return template;
+ }
+
+ async getTemplatePDFPreview(templateId) {
+ const response = await fetch(`${this.baseUrl}/template/${templateId}/previewpdflink`, {
+ method: 'GET',
+ headers: this.headers
+ });
+
+ if (!response.ok) {
+ throw new Error(`PDF preview failed: ${response.status}`);
+ }
+
+ const result = await response.json();
+ console.log(`🖼️ PDF Preview available: ${result.results}`);
+
+ return result.results;
+ }
+
+ // ===============================
+ // COMMON: Generate Deliverable
+ // ===============================
+
+ async generateDeliverable(templateId, deliverableData) {
+ const payload = {
+ templateId: templateId,
+ name: deliverableData.name,
+ description: deliverableData.description || '',
+ variables: deliverableData.variables,
+ tags: deliverableData.tags || ['api-generated'],
+ fonts: deliverableData.fonts || '[]',
+ defaultFont: deliverableData.defaultFont || 'Arial',
+ replaceFonts: deliverableData.replaceFonts !== undefined ? deliverableData.replaceFonts : true,
+ metadata: deliverableData.metadata || {
+ sessions: [{
+ id: this.generateSessionId(),
+ starttime: new Date().toISOString(),
+ endtime: new Date().toISOString()
+ }],
+ workflow: 'API Complete Workflow',
+ generated: new Date().toISOString()
+ }
+ };
+
+ const response = await fetch(`${this.baseUrl}/deliverable`, {
+ method: 'POST',
+ headers: {
+ ...this.headers,
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(payload)
+ });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+ throw new Error(`Deliverable generation failed: ${response.status} - ${errorText}`);
+ }
+
+ const result = await response.json();
+ const deliverable = result.data.results.deliverable;
+
+ console.log(`✅ Generated: ${deliverable.name}`);
+ console.log(`📄 Created by: ${deliverable.createdBy}`);
+ console.log(`📅 Created on: ${deliverable.createdOn}`);
+
+ return deliverable;
+ }
+
+ // ===============================
+ // UTILITY FUNCTIONS
+ // ===============================
+
+ createVariablesFromTemplate(templateVariables) {
+ return templateVariables.map((variable, index) => ({
+ mimeType: variable.mimeType || "text",
+ name: variable.name,
+ placeholder: variable.placeholder,
+ text: this.generateSampleText(variable.name),
+ allowRichTextInjection: variable.allowRichTextInjection || 0,
+ autogenerated: false,
+ count: 1,
+ order: index + 1,
+ subvariables: this.createSampleSubvariables(variable.placeholder),
+ metadata: {
+ generatedBy: "API Workflow",
+ variableType: variable.mimeType || "text"
+ },
+ aiPrompt: `Generate appropriate content for ${variable.name}`
+ }));
+ }
+
+ generateSampleText(variableName) {
+ const sampleData = {
+ 'Company': 'TechCorp Solutions Inc.',
+ 'Employee': 'John Smith',
+ 'Date': new Date().toLocaleDateString(),
+ 'Title': 'Senior Software Engineer',
+ 'Department': 'Engineering',
+ 'Salary': '$95,000',
+ 'Address': '123 Main Street, Tech City, TC 12345',
+ 'Phone': '(555) 123-4567',
+ 'Email': 'john.smith@techcorp.com'
+ };
+
+ // Find matching sample data or generate generic text
+ for (const [key, value] of Object.entries(sampleData)) {
+ if (variableName.toLowerCase().includes(key.toLowerCase())) {
+ return value;
+ }
+ }
+
+ return `Sample ${variableName} Content`;
+ }
+
+ createSampleSubvariables(placeholder) {
+ // Create relevant subvariables based on placeholder name
+ if (placeholder.toLowerCase().includes('employee')) {
+ return [
+ { placeholder: "{Employee.Title}", text: "Senior Software Engineer" },
+ { placeholder: "{Employee.StartDate}", text: new Date().toLocaleDateString() }
+ ];
+ } else if (placeholder.toLowerCase().includes('company')) {
+ return [
+ { placeholder: "{Company.Address}", text: "123 Main Street, Tech City, TC 12345" },
+ { placeholder: "{Company.Phone}", text: "(555) 123-4567" }
+ ];
+ }
+
+ return [];
+ }
+
+ generateSessionId() {
+ return Math.random().toString(36).substr(2, 9) + '-' +
+ Math.random().toString(36).substr(2, 9) + '-' +
+ Math.random().toString(36).substr(2, 9);
+ }
+
+ async downloadDeliverable(deliverableId, filename) {
+ console.log(`\n📥 Downloading file: ${filename}`);
+
+ const response = await fetch(`${this.baseUrl}/deliverable/file/${deliverableId}`, {
+ method: 'GET',
+ headers: this.headers
+ });
+
+ if (!response.ok) {
+ throw new Error(`Download failed: ${response.status}`);
+ }
+
+ console.log(`✅ File ready for download: ${filename}`);
+ console.log(`📁 Content-Type: ${response.headers.get('content-type')}`);
+ console.log(`📊 Content-Length: ${response.headers.get('content-length')} bytes`);
+
+ // In a real application, you would save the file or return the buffer
+ // const buffer = await response.buffer();
+ // fs.writeFileSync(filename, buffer);
+
+ return {
+ filename,
+ contentType: response.headers.get('content-type'),
+ contentLength: response.headers.get('content-length')
+ };
+ }
+
+ // ===============================
+ // DEMO FUNCTIONS
+ // ===============================
+
+ async demoPathA(templateFilePath) {
+ console.log('🚀 DEMO: Path A - Upload New Template Workflow');
+ console.log('===============================================\n');
+
+ return await this.pathA_UploadAndGenerate(
+ templateFilePath,
+ 'Contract Generated via Path A - API Upload'
+ );
+ }
+
+ async demoPathB() {
+ console.log('🚀 DEMO: Path B - Browse Existing Template Workflow');
+ console.log('=================================================\n');
+
+ return await this.pathB_BrowseAndGenerate(
+ 'contract',
+ 'Contract Generated via Path B - Browse & Select'
+ );
+ }
+
+ async demoComparison() {
+ console.log('🚀 DEMO: Complete Workflow Comparison');
+ console.log('====================================\n');
+
+ try {
+ console.log('Testing both paths with the same template type...\n');
+
+ // Run Path B first (browse existing)
+ const pathBResult = await this.demoPathB();
+
+ console.log('\n' + '='.repeat(60) + '\n');
+
+ // For Path A, we'd need a template file
+ console.log('📝 Path A requires a template file to upload.');
+ console.log(' Example: await workflow.demoPathA("./contract-template.docx")');
+
+ return { pathB: pathBResult };
+
+ } catch (error) {
+ console.error('Demo comparison failed:', error.message);
+ }
+ }
+}
+
+// ===============================
+// EXAMPLE USAGE
+// ===============================
+
+async function runExamples() {
+ const workflow = new TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL);
+
+ try {
+ // Demo Path B (Browse existing templates)
+ await workflow.demoPathB();
+
+ // Uncomment to demo Path A (requires template file):
+ // await workflow.demoPathA('./path/to/your/template.docx');
+
+ // Uncomment to run full comparison:
+ // await workflow.demoComparison();
+
+ } catch (error) {
+ console.error('Workflow demo failed:', error.message);
+ }
+}
+
+// Export for use in other modules
+module.exports = {
+ TemplateWorkflowManager
+};
+
+// Run examples if script is executed directly
+if (require.main === module) {
+ runExamples();
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/powershell.ps1 b/static/scripts/templates/api/complete-workflows/powershell.ps1
new file mode 100644
index 0000000..e05d504
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/powershell.ps1
@@ -0,0 +1,425 @@
+# Configuration - Update these values
+$API_TOKEN = "YOUR_API_TOKEN"
+$ORG_ID = "YOUR_ORGANIZATION_ID"
+$BASE_URL = "https://api.turbodocx.com"
+
+##
+# Complete Template Workflow Manager
+# Demonstrates both upload and browse/select paths
+##
+
+class TemplateWorkflowManager {
+ [string]$ApiToken
+ [string]$OrgId
+ [string]$BaseUrl
+
+ TemplateWorkflowManager([string]$apiToken, [string]$orgId, [string]$baseUrl) {
+ $this.ApiToken = $apiToken
+ $this.OrgId = $orgId
+ $this.BaseUrl = $baseUrl
+ Write-Host "=== TurboDocx Template Generation Workflow Manager ===" -ForegroundColor Cyan
+ }
+
+ [void] DemonstrateCompleteWorkflow() {
+ Write-Host "`nSelect workflow path:" -ForegroundColor Yellow
+ Write-Host "A) Upload new template"
+ Write-Host "B) Browse and select existing template"
+
+ # For this example, we'll demonstrate both paths
+ Write-Host "`n=== Demonstrating Path A: Upload Template ===" -ForegroundColor Magenta
+ $templateIdA = $this.DemonstrateUploadWorkflow()
+
+ Write-Host "`n=== Demonstrating Path B: Browse Templates ===" -ForegroundColor Magenta
+ $templateIdB = $this.DemonstrateBrowseWorkflow()
+
+ # Generate deliverables for both templates if successful
+ if ($templateIdA) {
+ Write-Host "`n=== Generating Deliverable from Uploaded Template ===" -ForegroundColor Green
+ $this.GenerateAndDownloadDeliverable($templateIdA, "A")
+ }
+
+ if ($templateIdB) {
+ Write-Host "`n=== Generating Deliverable from Selected Template ===" -ForegroundColor Green
+ $this.GenerateAndDownloadDeliverable($templateIdB, "B")
+ }
+ }
+
+ [string] DemonstrateUploadWorkflow() {
+ try {
+ Write-Host "`n--- Path A: Upload and Create Template ---" -ForegroundColor Yellow
+
+ # Check for template file
+ $templateFile = ".\contract-template.docx"
+ if (-not (Test-Path $templateFile)) {
+ Write-Host "⚠️ Template file not found: $templateFile" -ForegroundColor Yellow
+ Write-Host "Creating a placeholder message for demonstration"
+ return $null
+ }
+
+ $result = $this.UploadTemplate($templateFile)
+ $template = $result.data.results.template
+
+ Write-Host "✅ Upload workflow completed" -ForegroundColor Green
+ Write-Host "Template ID: $($template.id)"
+ Write-Host "Ready for deliverable generation"
+
+ return $template.id
+ }
+ catch {
+ Write-Host "❌ Upload workflow failed: $($_.Exception.Message)" -ForegroundColor Red
+ return $null
+ }
+ }
+
+ [string] DemonstrateBrowseWorkflow() {
+ try {
+ Write-Host "`n--- Path B: Browse and Select Template ---" -ForegroundColor Yellow
+
+ # Browse templates
+ $browseResult = $this.BrowseTemplates(10, 0, 'contract', $true)
+
+ # Find first template (not folder)
+ $selectedTemplate = $browseResult.results | Where-Object { $_.type -eq 'template' } | Select-Object -First 1
+
+ if ($null -eq $selectedTemplate) {
+ Write-Host "⚠️ No templates found in browse results" -ForegroundColor Yellow
+ return $null
+ }
+
+ Write-Host "Selected: $($selectedTemplate.name)"
+
+ # Get detailed information
+ $templateDetails = $this.GetTemplateDetails($selectedTemplate.id)
+
+ # Optionally get PDF preview
+ $pdfPreview = $this.GetTemplatePdfPreview($selectedTemplate.id)
+
+ Write-Host "✅ Browse workflow completed" -ForegroundColor Green
+ Write-Host "Template ID: $($templateDetails.id)"
+ Write-Host "PDF Preview: $pdfPreview"
+ Write-Host "Ready for deliverable generation"
+
+ return $templateDetails.id
+ }
+ catch {
+ Write-Host "❌ Browse workflow failed: $($_.Exception.Message)" -ForegroundColor Red
+ return $null
+ }
+ }
+
+ [void] GenerateAndDownloadDeliverable([string]$templateId, [string]$pathLabel) {
+ try {
+ Write-Host "`n--- Generating Deliverable (Path $pathLabel) ---" -ForegroundColor Yellow
+
+ $deliverableData = $this.CreateDeliverableData($templateId, $pathLabel)
+ $deliverable = $this.GenerateDeliverable($templateId, $deliverableData)
+
+ # Download the file
+ $downloadResult = $this.DownloadDeliverable(
+ $deliverable.id,
+ "$($deliverable.name)_path_$pathLabel.docx"
+ )
+
+ Write-Host "✅ Complete workflow finished successfully for Path $pathLabel" -ForegroundColor Green
+ Write-Host "Deliverable ID: $($deliverable.id)"
+ Write-Host "Download info: $($downloadResult | ConvertTo-Json -Compress)"
+ }
+ catch {
+ Write-Host "❌ Deliverable generation failed for Path $pathLabel : $($_.Exception.Message)" -ForegroundColor Red
+ }
+ }
+
+ [hashtable] UploadTemplate([string]$templateFilePath) {
+ $uri = "$($this.BaseUrl)/template/upload-and-create"
+ $boundary = "----PowerShellBoundary$((Get-Random -Maximum 1000000))"
+
+ # Read file content
+ $fileContent = [System.IO.File]::ReadAllBytes($templateFilePath)
+ $fileName = [System.IO.Path]::GetFileName($templateFilePath)
+
+ # Build multipart form data
+ $bodyLines = @()
+
+ # Template file field
+ $bodyLines += "--$boundary"
+ $bodyLines += "Content-Disposition: form-data; name=`"templateFile`"; filename=`"$fileName`""
+ $bodyLines += "Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document"
+ $bodyLines += ""
+
+ # Convert file content to string for inclusion
+ $encoding = [System.Text.Encoding]::GetEncoding("ISO-8859-1")
+ $bodyLines += $encoding.GetString($fileContent)
+
+ # Name field
+ $bodyLines += "--$boundary"
+ $bodyLines += "Content-Disposition: form-data; name=`"name`""
+ $bodyLines += ""
+ $bodyLines += "Employee Contract Template"
+
+ # Description field
+ $bodyLines += "--$boundary"
+ $bodyLines += "Content-Disposition: form-data; name=`"description`""
+ $bodyLines += ""
+ $bodyLines += "Standard employee contract with variable placeholders"
+
+ # Variables field
+ $bodyLines += "--$boundary"
+ $bodyLines += "Content-Disposition: form-data; name=`"variables`""
+ $bodyLines += ""
+ $bodyLines += "[]"
+
+ # Tags field
+ $bodyLines += "--$boundary"
+ $bodyLines += "Content-Disposition: form-data; name=`"tags`""
+ $bodyLines += ""
+ $bodyLines += '["hr", "contract", "template"]'
+
+ $bodyLines += "--$boundary--"
+
+ # Join with CRLF
+ $body = ($bodyLines -join "`r`n")
+ $bodyBytes = $encoding.GetBytes($body)
+
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $($this.ApiToken)"
+ 'x-rapiddocx-org-id' = $this.OrgId
+ 'User-Agent' = 'TurboDocx API Client'
+ 'Content-Type' = "multipart/form-data; boundary=$boundary"
+ }
+
+ # Make request
+ $response = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body $bodyBytes
+ return $response
+ }
+
+ [hashtable] BrowseTemplates([int]$limit, [int]$offset, [string]$query, [bool]$showTags) {
+ # Build query parameters
+ $params = @{
+ 'limit' = $limit
+ 'offset' = $offset
+ 'showTags' = $showTags.ToString().ToLower()
+ }
+
+ if ($query -ne '') {
+ $params['query'] = $query
+ }
+
+ # Build query string
+ $queryString = ($params.GetEnumerator() | ForEach-Object {
+ "$([System.Web.HttpUtility]::UrlEncode($_.Key))=$([System.Web.HttpUtility]::UrlEncode($_.Value))"
+ }) -join '&'
+
+ $uri = "$($this.BaseUrl)/template-item?$queryString"
+
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $($this.ApiToken)"
+ 'x-rapiddocx-org-id' = $this.OrgId
+ 'User-Agent' = 'TurboDocx API Client'
+ }
+
+ # Make request
+ $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
+ return $response.data
+ }
+
+ [hashtable] GetTemplateDetails([string]$templateId) {
+ $uri = "$($this.BaseUrl)/template/$templateId"
+
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $($this.ApiToken)"
+ 'x-rapiddocx-org-id' = $this.OrgId
+ 'User-Agent' = 'TurboDocx API Client'
+ }
+
+ # Make request
+ $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
+ return $response.data.results
+ }
+
+ [string] GetTemplatePdfPreview([string]$templateId) {
+ $uri = "$($this.BaseUrl)/template/$templateId/previewpdflink"
+
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $($this.ApiToken)"
+ 'x-rapiddocx-org-id' = $this.OrgId
+ 'User-Agent' = 'TurboDocx API Client'
+ }
+
+ # Make request
+ $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
+ return $response.results
+ }
+
+ [hashtable] GenerateDeliverable([string]$templateId, [hashtable]$deliverableData) {
+ $uri = "$($this.BaseUrl)/deliverable"
+
+ Write-Host "Generating deliverable..."
+ Write-Host "Template ID: $templateId"
+ Write-Host "Deliverable Name: $($deliverableData.name)"
+ Write-Host "Variables: $($deliverableData.variables.Count)"
+
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $($this.ApiToken)"
+ 'x-rapiddocx-org-id' = $this.OrgId
+ 'User-Agent' = 'TurboDocx API Client'
+ 'Content-Type' = 'application/json'
+ }
+
+ # Convert to JSON
+ $jsonBody = $deliverableData | ConvertTo-Json -Depth 10
+
+ # Make request
+ $response = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body $jsonBody
+
+ # Parse JSON response
+ $deliverable = $response.data.results.deliverable
+
+ Write-Host "✅ Deliverable generated successfully!" -ForegroundColor Green
+ Write-Host "Deliverable ID: $($deliverable.id)"
+ Write-Host "Created by: $($deliverable.createdBy)"
+ Write-Host "Created on: $($deliverable.createdOn)"
+ Write-Host "Template ID: $($deliverable.templateId)"
+
+ return $deliverable
+ }
+
+ [hashtable] DownloadDeliverable([string]$deliverableId, [string]$filename) {
+ Write-Host "Downloading file: $filename"
+
+ $uri = "$($this.BaseUrl)/deliverable/file/$deliverableId"
+
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $($this.ApiToken)"
+ 'x-rapiddocx-org-id' = $this.OrgId
+ 'User-Agent' = 'TurboDocx API Client'
+ }
+
+ # Make request
+ $response = Invoke-WebRequest -Uri $uri -Method Get -Headers $headers
+
+ if ($response.StatusCode -ne 200) {
+ throw "Download failed: $($response.StatusCode)"
+ }
+
+ Write-Host "✅ File ready for download: $filename" -ForegroundColor Green
+
+ $contentType = if ($response.Headers['Content-Type']) { $response.Headers['Content-Type'] } else { 'N/A' }
+ $contentLength = if ($response.Headers['Content-Length']) { $response.Headers['Content-Length'] } else { 'N/A' }
+
+ Write-Host "📁 Content-Type: $contentType"
+ Write-Host "📊 Content-Length: $contentLength bytes"
+
+ # In a real application, you would save the file
+ # [System.IO.File]::WriteAllBytes($filename, $response.Content)
+
+ return @{
+ 'filename' = $filename
+ 'content_type' = $contentType
+ 'content_length' = $contentLength
+ }
+ }
+
+ [hashtable] CreateDeliverableData([string]$templateId, [string]$pathLabel) {
+ $now = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
+
+ return @{
+ 'templateId' = $templateId
+ 'name' = "Contract Document - Path $pathLabel"
+ 'description' = "Employment contract generated via workflow path $pathLabel"
+ 'variables' = $this.CreateComplexVariables()
+ 'tags' = @('hr', 'contract', 'employee', 'engineering')
+ 'fonts' = '[{"name":"Arial","usage":269}]'
+ 'defaultFont' = 'Arial'
+ 'replaceFonts' = $true
+ 'metadata' = @{
+ 'sessions' = @(
+ @{
+ 'id' = [System.Guid]::NewGuid().ToString()
+ 'starttime' = $now
+ 'endtime' = $now
+ }
+ )
+ 'createdBy' = 'PowerShell Workflow Manager'
+ 'documentType' = 'Employment Contract'
+ 'version' = 'v1.0'
+ 'workflowPath' = $pathLabel
+ }
+ }
+ }
+
+ [array] CreateComplexVariables() {
+ return @(
+ @{
+ 'mimeType' = 'text'
+ 'name' = 'Employee Name'
+ 'placeholder' = '{EmployeeName}'
+ 'text' = 'John Smith'
+ 'allowRichTextInjection' = 0
+ 'autogenerated' = $false
+ 'count' = 1
+ 'order' = 1
+ 'subvariables' = @(
+ @{
+ 'placeholder' = '{EmployeeName.Title}'
+ 'text' = 'Senior Software Engineer'
+ },
+ @{
+ 'placeholder' = '{EmployeeName.StartDate}'
+ 'text' = 'January 15, 2024'
+ }
+ )
+ 'metadata' = @{
+ 'department' = 'Engineering'
+ 'level' = 'Senior'
+ }
+ 'aiPrompt' = 'Generate a professional job description for a senior software engineer role'
+ },
+ @{
+ 'mimeType' = 'text'
+ 'name' = 'Company Information'
+ 'placeholder' = '{CompanyInfo}'
+ 'text' = 'TechCorp Solutions Inc.'
+ 'allowRichTextInjection' = 1
+ 'autogenerated' = $false
+ 'count' = 1
+ 'order' = 2
+ 'subvariables' = @(
+ @{
+ 'placeholder' = '{CompanyInfo.Address}'
+ 'text' = '123 Innovation Drive, Tech City, TC 12345'
+ },
+ @{
+ 'placeholder' = '{CompanyInfo.Phone}'
+ 'text' = '(555) 123-4567'
+ }
+ )
+ 'metadata' = @{}
+ 'aiPrompt' = ''
+ }
+ )
+ }
+}
+
+# Example usage
+try {
+ Add-Type -AssemblyName System.Web
+
+ $workflowManager = [TemplateWorkflowManager]::new($API_TOKEN, $ORG_ID, $BASE_URL)
+ $workflowManager.DemonstrateCompleteWorkflow()
+
+ Write-Host "`n=== Workflow Demonstration Complete ===" -ForegroundColor Green
+ Write-Host "Both upload and browse/select paths have been demonstrated."
+ Write-Host "Choose the appropriate path for your use case:"
+ Write-Host "- Upload path: When you have new templates to create"
+ Write-Host "- Browse path: When you want to use existing templates"
+}
+catch {
+ Write-Error "Workflow demonstration failed: $($_.Exception.Message)"
+ exit 1
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/python/fastapi.py b/static/scripts/templates/api/complete-workflows/python/fastapi.py
new file mode 100644
index 0000000..634dff5
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/python/fastapi.py
@@ -0,0 +1,418 @@
+import requests
+import json
+import uuid
+import os
+from datetime import datetime
+from urllib.parse import urlencode
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+class TemplateWorkflowManager:
+ """
+ Complete Template Generation Workflows
+ Demonstrates both Path A (Upload) and Path B (Browse/Select) followed by generation
+ """
+
+ def __init__(self, api_token, org_id, base_url):
+ self.api_token = api_token
+ self.org_id = org_id
+ self.base_url = base_url
+ self.headers = {
+ 'Authorization': f'Bearer {api_token}',
+ 'x-rapiddocx-org-id': org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ # ===============================
+ # PATH A: Upload New Template
+ # ===============================
+
+ def path_a_upload_and_generate(self, template_file_path, deliverable_name):
+ """Complete Path A workflow: Upload → Generate"""
+ print("🔄 PATH A: Upload New Template → Generate Deliverable")
+ print("=" * 48)
+
+ try:
+ # Step 1: Upload and create template
+ print("\n📤 Step 1: Uploading template...")
+ template = self.upload_template(template_file_path)
+
+ # Step 2: Generate deliverable using uploaded template
+ print("\n📝 Step 2: Generating deliverable...")
+ deliverable = self.generate_deliverable(template['id'], {
+ 'name': deliverable_name,
+ 'description': f"Generated from uploaded template: {template['name']}",
+ 'variables': self.create_variables_from_template(template['variables'])
+ })
+
+ print("\n✅ PATH A COMPLETE!")
+ print(f"Template ID: {template['id']}")
+ print(f"Deliverable ID: {deliverable['id']}")
+
+ # Download the generated file
+ self.download_deliverable(deliverable['id'], f"{deliverable['name']}.docx")
+
+ return {'template': template, 'deliverable': deliverable}
+
+ except Exception as error:
+ print(f"❌ Path A failed: {error}")
+ raise
+
+ def upload_template(self, template_file_path):
+ """Upload a template file and create template record"""
+ if not os.path.exists(template_file_path):
+ raise FileNotFoundError(f"Template file not found: {template_file_path}")
+
+ url = f"{self.base_url}/template/upload-and-create"
+
+ files = {
+ 'templateFile': (
+ os.path.basename(template_file_path),
+ open(template_file_path, 'rb'),
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+ )
+ }
+
+ data = {
+ 'name': 'API Upload Template',
+ 'description': 'Template uploaded via API for testing',
+ 'variables': '[]',
+ 'tags': '["api", "test", "upload"]'
+ }
+
+ try:
+ response = requests.post(url, headers=self.headers, files=files, data=data)
+ response.raise_for_status()
+
+ result = response.json()
+ template = result['data']['results']['template']
+
+ print(f"✅ Template uploaded: {template['name']} ({template['id']})")
+ print(f"📊 Variables extracted: {len(template['variables']) if template['variables'] else 0}")
+ print(f"🔤 Default font: {template['defaultFont']}")
+ print(f"📝 Fonts used: {len(template['fonts']) if template['fonts'] else 0}")
+
+ return template
+
+ finally:
+ files['templateFile'][1].close()
+
+ # ===============================
+ # PATH B: Browse and Select
+ # ===============================
+
+ def path_b_browse_and_generate(self, search_query, deliverable_name):
+ """Complete Path B workflow: Browse → Select → Generate"""
+ print("🔍 PATH B: Browse Existing Templates → Generate Deliverable")
+ print("=" * 56)
+
+ try:
+ # Step 1: Browse templates
+ print("\n🔍 Step 1: Browsing templates...")
+ browse_result = self.browse_templates({'query': search_query})
+
+ # Step 2: Select first available template
+ selected_template = None
+ for item in browse_result['results']:
+ if item['type'] == 'template':
+ selected_template = item
+ break
+
+ if not selected_template:
+ raise Exception('No templates found in browse results')
+
+ print(f"📋 Selected: {selected_template['name']} ({selected_template['id']})")
+
+ # Step 3: Get template details
+ print("\n📖 Step 2: Getting template details...")
+ template_details = self.get_template_details(selected_template['id'])
+
+ # Step 4: Get PDF preview (optional)
+ print("\n🖼️ Step 3: Getting PDF preview...")
+ pdf_preview = self.get_template_pdf_preview(selected_template['id'])
+
+ # Step 5: Generate deliverable
+ print("\n📝 Step 4: Generating deliverable...")
+ deliverable = self.generate_deliverable(template_details['id'], {
+ 'name': deliverable_name,
+ 'description': f"Generated from existing template: {template_details['name']}",
+ 'variables': self.create_variables_from_template(template_details['variables'])
+ })
+
+ print("\n✅ PATH B COMPLETE!")
+ print(f"Template ID: {template_details['id']}")
+ print(f"Deliverable ID: {deliverable['id']}")
+
+ # Download the generated file
+ self.download_deliverable(deliverable['id'], f"{deliverable['name']}.docx")
+
+ return {
+ 'template': template_details,
+ 'deliverable': deliverable,
+ 'pdf_preview': pdf_preview
+ }
+
+ except Exception as error:
+ print(f"❌ Path B failed: {error}")
+ raise
+
+ def browse_templates(self, options=None):
+ """Browse available templates and folders"""
+ if options is None:
+ options = {}
+
+ params = {
+ 'limit': options.get('limit', 25),
+ 'offset': options.get('offset', 0),
+ 'showTags': str(options.get('show_tags', True)).lower()
+ }
+
+ query = options.get('query', '')
+ if query:
+ params['query'] = query
+
+ url = f"{self.base_url}/template-item?{urlencode(params)}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ data = result['data']
+
+ print(f"🔍 Found {data['totalRecords']} templates/folders")
+
+ return data
+
+ def get_template_details(self, template_id):
+ """Get detailed template information"""
+ url = f"{self.base_url}/template/{template_id}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ template = result['data']['results']
+
+ print(f"📊 Variables: {len(template['variables'])}")
+ print(f"🔤 Default font: {template.get('defaultFont', 'N/A')}")
+
+ return template
+
+ def get_template_pdf_preview(self, template_id):
+ """Get PDF preview URL for template"""
+ url = f"{self.base_url}/template/{template_id}/previewpdflink"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ pdf_url = result['results']
+
+ print(f"🖼️ PDF Preview available: {pdf_url}")
+
+ return pdf_url
+
+ # ===============================
+ # COMMON: Generate Deliverable
+ # ===============================
+
+ def generate_deliverable(self, template_id, deliverable_data):
+ """Generate a deliverable document from template"""
+ payload = {
+ "templateId": template_id,
+ "name": deliverable_data['name'],
+ "description": deliverable_data.get('description', ''),
+ "variables": deliverable_data['variables'],
+ "tags": deliverable_data.get('tags', ['api-generated']),
+ "fonts": deliverable_data.get('fonts', '[]'),
+ "defaultFont": deliverable_data.get('defaultFont', 'Arial'),
+ "replaceFonts": deliverable_data.get('replaceFonts', True),
+ "metadata": deliverable_data.get('metadata', {
+ "sessions": [{
+ "id": self.generate_session_id(),
+ "starttime": datetime.utcnow().isoformat() + "Z",
+ "endtime": datetime.utcnow().isoformat() + "Z"
+ }],
+ "workflow": "API Complete Workflow",
+ "generated": datetime.utcnow().isoformat() + "Z"
+ })
+ }
+
+ url = f"{self.base_url}/deliverable"
+ headers = {**self.headers, 'Content-Type': 'application/json'}
+
+ response = requests.post(url, headers=headers, json=payload)
+ response.raise_for_status()
+
+ result = response.json()
+ deliverable = result['data']['results']['deliverable']
+
+ print(f"✅ Generated: {deliverable['name']}")
+ print(f"📄 Created by: {deliverable['createdBy']}")
+ print(f"📅 Created on: {deliverable['createdOn']}")
+
+ return deliverable
+
+ # ===============================
+ # UTILITY FUNCTIONS
+ # ===============================
+
+ def create_variables_from_template(self, template_variables):
+ """Create variable payload from template variable definitions"""
+ return [
+ {
+ "mimeType": variable.get('mimeType', 'text'),
+ "name": variable['name'],
+ "placeholder": variable['placeholder'],
+ "text": self.generate_sample_text(variable['name']),
+ "allowRichTextInjection": variable.get('allowRichTextInjection', 0),
+ "autogenerated": False,
+ "count": 1,
+ "order": index + 1,
+ "subvariables": self.create_sample_subvariables(variable['placeholder']),
+ "metadata": {
+ "generatedBy": "API Workflow",
+ "variableType": variable.get('mimeType', 'text')
+ },
+ "aiPrompt": f"Generate appropriate content for {variable['name']}"
+ }
+ for index, variable in enumerate(template_variables)
+ ]
+
+ def generate_sample_text(self, variable_name):
+ """Generate sample text based on variable name"""
+ sample_data = {
+ 'company': 'TechCorp Solutions Inc.',
+ 'employee': 'John Smith',
+ 'date': datetime.now().strftime('%B %d, %Y'),
+ 'title': 'Senior Software Engineer',
+ 'department': 'Engineering',
+ 'salary': '$95,000',
+ 'address': '123 Main Street, Tech City, TC 12345',
+ 'phone': '(555) 123-4567',
+ 'email': 'john.smith@techcorp.com'
+ }
+
+ # Find matching sample data or generate generic text
+ for key, value in sample_data.items():
+ if key.lower() in variable_name.lower():
+ return value
+
+ return f"Sample {variable_name} Content"
+
+ def create_sample_subvariables(self, placeholder):
+ """Create relevant subvariables based on placeholder name"""
+ placeholder_lower = placeholder.lower()
+
+ if 'employee' in placeholder_lower:
+ return [
+ {"placeholder": "{Employee.Title}", "text": "Senior Software Engineer"},
+ {"placeholder": "{Employee.StartDate}", "text": datetime.now().strftime('%B %d, %Y')}
+ ]
+ elif 'company' in placeholder_lower:
+ return [
+ {"placeholder": "{Company.Address}", "text": "123 Main Street, Tech City, TC 12345"},
+ {"placeholder": "{Company.Phone}", "text": "(555) 123-4567"}
+ ]
+
+ return []
+
+ def generate_session_id(self):
+ """Generate a unique session ID"""
+ return str(uuid.uuid4())
+
+ def download_deliverable(self, deliverable_id, filename):
+ """Download the generated deliverable file"""
+ print(f"\n📥 Downloading file: {filename}")
+
+ url = f"{self.base_url}/deliverable/file/{deliverable_id}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ print(f"✅ File ready for download: {filename}")
+ print(f"📁 Content-Type: {response.headers.get('content-type')}")
+ print(f"📊 Content-Length: {response.headers.get('content-length')} bytes")
+
+ # In a real application, you would save the file
+ # with open(filename, 'wb') as f:
+ # f.write(response.content)
+
+ return {
+ 'filename': filename,
+ 'content_type': response.headers.get('content-type'),
+ 'content_length': response.headers.get('content-length')
+ }
+
+ # ===============================
+ # DEMO FUNCTIONS
+ # ===============================
+
+ def demo_path_a(self, template_file_path):
+ """Demo Path A workflow"""
+ print("🚀 DEMO: Path A - Upload New Template Workflow")
+ print("=" * 45)
+ print()
+
+ return self.path_a_upload_and_generate(
+ template_file_path,
+ 'Contract Generated via Path A - API Upload'
+ )
+
+ def demo_path_b(self):
+ """Demo Path B workflow"""
+ print("🚀 DEMO: Path B - Browse Existing Template Workflow")
+ print("=" * 51)
+ print()
+
+ return self.path_b_browse_and_generate(
+ 'contract',
+ 'Contract Generated via Path B - Browse & Select'
+ )
+
+ def demo_comparison(self):
+ """Demo comparison of both workflows"""
+ print("🚀 DEMO: Complete Workflow Comparison")
+ print("=" * 36)
+ print()
+
+ try:
+ print("Testing both paths with the same template type...\n")
+
+ # Run Path B first (browse existing)
+ path_b_result = self.demo_path_b()
+
+ print("\n" + "=" * 60 + "\n")
+
+ # For Path A, we'd need a template file
+ print("📝 Path A requires a template file to upload.")
+ print(" Example: workflow.demo_path_a('./contract-template.docx')")
+
+ return {'path_b': path_b_result}
+
+ except Exception as error:
+ print(f"Demo comparison failed: {error}")
+
+def run_examples():
+ """Run example workflows"""
+ workflow = TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL)
+
+ try:
+ # Demo Path B (Browse existing templates)
+ workflow.demo_path_b()
+
+ # Uncomment to demo Path A (requires template file):
+ # workflow.demo_path_a('./path/to/your/template.docx')
+
+ # Uncomment to run full comparison:
+ # workflow.demo_comparison()
+
+ except Exception as error:
+ print(f"Workflow demo failed: {error}")
+
+# Example usage
+if __name__ == "__main__":
+ run_examples()
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/python/flask.py b/static/scripts/templates/api/complete-workflows/python/flask.py
new file mode 100644
index 0000000..634dff5
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/python/flask.py
@@ -0,0 +1,418 @@
+import requests
+import json
+import uuid
+import os
+from datetime import datetime
+from urllib.parse import urlencode
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+class TemplateWorkflowManager:
+ """
+ Complete Template Generation Workflows
+ Demonstrates both Path A (Upload) and Path B (Browse/Select) followed by generation
+ """
+
+ def __init__(self, api_token, org_id, base_url):
+ self.api_token = api_token
+ self.org_id = org_id
+ self.base_url = base_url
+ self.headers = {
+ 'Authorization': f'Bearer {api_token}',
+ 'x-rapiddocx-org-id': org_id,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ # ===============================
+ # PATH A: Upload New Template
+ # ===============================
+
+ def path_a_upload_and_generate(self, template_file_path, deliverable_name):
+ """Complete Path A workflow: Upload → Generate"""
+ print("🔄 PATH A: Upload New Template → Generate Deliverable")
+ print("=" * 48)
+
+ try:
+ # Step 1: Upload and create template
+ print("\n📤 Step 1: Uploading template...")
+ template = self.upload_template(template_file_path)
+
+ # Step 2: Generate deliverable using uploaded template
+ print("\n📝 Step 2: Generating deliverable...")
+ deliverable = self.generate_deliverable(template['id'], {
+ 'name': deliverable_name,
+ 'description': f"Generated from uploaded template: {template['name']}",
+ 'variables': self.create_variables_from_template(template['variables'])
+ })
+
+ print("\n✅ PATH A COMPLETE!")
+ print(f"Template ID: {template['id']}")
+ print(f"Deliverable ID: {deliverable['id']}")
+
+ # Download the generated file
+ self.download_deliverable(deliverable['id'], f"{deliverable['name']}.docx")
+
+ return {'template': template, 'deliverable': deliverable}
+
+ except Exception as error:
+ print(f"❌ Path A failed: {error}")
+ raise
+
+ def upload_template(self, template_file_path):
+ """Upload a template file and create template record"""
+ if not os.path.exists(template_file_path):
+ raise FileNotFoundError(f"Template file not found: {template_file_path}")
+
+ url = f"{self.base_url}/template/upload-and-create"
+
+ files = {
+ 'templateFile': (
+ os.path.basename(template_file_path),
+ open(template_file_path, 'rb'),
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+ )
+ }
+
+ data = {
+ 'name': 'API Upload Template',
+ 'description': 'Template uploaded via API for testing',
+ 'variables': '[]',
+ 'tags': '["api", "test", "upload"]'
+ }
+
+ try:
+ response = requests.post(url, headers=self.headers, files=files, data=data)
+ response.raise_for_status()
+
+ result = response.json()
+ template = result['data']['results']['template']
+
+ print(f"✅ Template uploaded: {template['name']} ({template['id']})")
+ print(f"📊 Variables extracted: {len(template['variables']) if template['variables'] else 0}")
+ print(f"🔤 Default font: {template['defaultFont']}")
+ print(f"📝 Fonts used: {len(template['fonts']) if template['fonts'] else 0}")
+
+ return template
+
+ finally:
+ files['templateFile'][1].close()
+
+ # ===============================
+ # PATH B: Browse and Select
+ # ===============================
+
+ def path_b_browse_and_generate(self, search_query, deliverable_name):
+ """Complete Path B workflow: Browse → Select → Generate"""
+ print("🔍 PATH B: Browse Existing Templates → Generate Deliverable")
+ print("=" * 56)
+
+ try:
+ # Step 1: Browse templates
+ print("\n🔍 Step 1: Browsing templates...")
+ browse_result = self.browse_templates({'query': search_query})
+
+ # Step 2: Select first available template
+ selected_template = None
+ for item in browse_result['results']:
+ if item['type'] == 'template':
+ selected_template = item
+ break
+
+ if not selected_template:
+ raise Exception('No templates found in browse results')
+
+ print(f"📋 Selected: {selected_template['name']} ({selected_template['id']})")
+
+ # Step 3: Get template details
+ print("\n📖 Step 2: Getting template details...")
+ template_details = self.get_template_details(selected_template['id'])
+
+ # Step 4: Get PDF preview (optional)
+ print("\n🖼️ Step 3: Getting PDF preview...")
+ pdf_preview = self.get_template_pdf_preview(selected_template['id'])
+
+ # Step 5: Generate deliverable
+ print("\n📝 Step 4: Generating deliverable...")
+ deliverable = self.generate_deliverable(template_details['id'], {
+ 'name': deliverable_name,
+ 'description': f"Generated from existing template: {template_details['name']}",
+ 'variables': self.create_variables_from_template(template_details['variables'])
+ })
+
+ print("\n✅ PATH B COMPLETE!")
+ print(f"Template ID: {template_details['id']}")
+ print(f"Deliverable ID: {deliverable['id']}")
+
+ # Download the generated file
+ self.download_deliverable(deliverable['id'], f"{deliverable['name']}.docx")
+
+ return {
+ 'template': template_details,
+ 'deliverable': deliverable,
+ 'pdf_preview': pdf_preview
+ }
+
+ except Exception as error:
+ print(f"❌ Path B failed: {error}")
+ raise
+
+ def browse_templates(self, options=None):
+ """Browse available templates and folders"""
+ if options is None:
+ options = {}
+
+ params = {
+ 'limit': options.get('limit', 25),
+ 'offset': options.get('offset', 0),
+ 'showTags': str(options.get('show_tags', True)).lower()
+ }
+
+ query = options.get('query', '')
+ if query:
+ params['query'] = query
+
+ url = f"{self.base_url}/template-item?{urlencode(params)}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ data = result['data']
+
+ print(f"🔍 Found {data['totalRecords']} templates/folders")
+
+ return data
+
+ def get_template_details(self, template_id):
+ """Get detailed template information"""
+ url = f"{self.base_url}/template/{template_id}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ template = result['data']['results']
+
+ print(f"📊 Variables: {len(template['variables'])}")
+ print(f"🔤 Default font: {template.get('defaultFont', 'N/A')}")
+
+ return template
+
+ def get_template_pdf_preview(self, template_id):
+ """Get PDF preview URL for template"""
+ url = f"{self.base_url}/template/{template_id}/previewpdflink"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ result = response.json()
+ pdf_url = result['results']
+
+ print(f"🖼️ PDF Preview available: {pdf_url}")
+
+ return pdf_url
+
+ # ===============================
+ # COMMON: Generate Deliverable
+ # ===============================
+
+ def generate_deliverable(self, template_id, deliverable_data):
+ """Generate a deliverable document from template"""
+ payload = {
+ "templateId": template_id,
+ "name": deliverable_data['name'],
+ "description": deliverable_data.get('description', ''),
+ "variables": deliverable_data['variables'],
+ "tags": deliverable_data.get('tags', ['api-generated']),
+ "fonts": deliverable_data.get('fonts', '[]'),
+ "defaultFont": deliverable_data.get('defaultFont', 'Arial'),
+ "replaceFonts": deliverable_data.get('replaceFonts', True),
+ "metadata": deliverable_data.get('metadata', {
+ "sessions": [{
+ "id": self.generate_session_id(),
+ "starttime": datetime.utcnow().isoformat() + "Z",
+ "endtime": datetime.utcnow().isoformat() + "Z"
+ }],
+ "workflow": "API Complete Workflow",
+ "generated": datetime.utcnow().isoformat() + "Z"
+ })
+ }
+
+ url = f"{self.base_url}/deliverable"
+ headers = {**self.headers, 'Content-Type': 'application/json'}
+
+ response = requests.post(url, headers=headers, json=payload)
+ response.raise_for_status()
+
+ result = response.json()
+ deliverable = result['data']['results']['deliverable']
+
+ print(f"✅ Generated: {deliverable['name']}")
+ print(f"📄 Created by: {deliverable['createdBy']}")
+ print(f"📅 Created on: {deliverable['createdOn']}")
+
+ return deliverable
+
+ # ===============================
+ # UTILITY FUNCTIONS
+ # ===============================
+
+ def create_variables_from_template(self, template_variables):
+ """Create variable payload from template variable definitions"""
+ return [
+ {
+ "mimeType": variable.get('mimeType', 'text'),
+ "name": variable['name'],
+ "placeholder": variable['placeholder'],
+ "text": self.generate_sample_text(variable['name']),
+ "allowRichTextInjection": variable.get('allowRichTextInjection', 0),
+ "autogenerated": False,
+ "count": 1,
+ "order": index + 1,
+ "subvariables": self.create_sample_subvariables(variable['placeholder']),
+ "metadata": {
+ "generatedBy": "API Workflow",
+ "variableType": variable.get('mimeType', 'text')
+ },
+ "aiPrompt": f"Generate appropriate content for {variable['name']}"
+ }
+ for index, variable in enumerate(template_variables)
+ ]
+
+ def generate_sample_text(self, variable_name):
+ """Generate sample text based on variable name"""
+ sample_data = {
+ 'company': 'TechCorp Solutions Inc.',
+ 'employee': 'John Smith',
+ 'date': datetime.now().strftime('%B %d, %Y'),
+ 'title': 'Senior Software Engineer',
+ 'department': 'Engineering',
+ 'salary': '$95,000',
+ 'address': '123 Main Street, Tech City, TC 12345',
+ 'phone': '(555) 123-4567',
+ 'email': 'john.smith@techcorp.com'
+ }
+
+ # Find matching sample data or generate generic text
+ for key, value in sample_data.items():
+ if key.lower() in variable_name.lower():
+ return value
+
+ return f"Sample {variable_name} Content"
+
+ def create_sample_subvariables(self, placeholder):
+ """Create relevant subvariables based on placeholder name"""
+ placeholder_lower = placeholder.lower()
+
+ if 'employee' in placeholder_lower:
+ return [
+ {"placeholder": "{Employee.Title}", "text": "Senior Software Engineer"},
+ {"placeholder": "{Employee.StartDate}", "text": datetime.now().strftime('%B %d, %Y')}
+ ]
+ elif 'company' in placeholder_lower:
+ return [
+ {"placeholder": "{Company.Address}", "text": "123 Main Street, Tech City, TC 12345"},
+ {"placeholder": "{Company.Phone}", "text": "(555) 123-4567"}
+ ]
+
+ return []
+
+ def generate_session_id(self):
+ """Generate a unique session ID"""
+ return str(uuid.uuid4())
+
+ def download_deliverable(self, deliverable_id, filename):
+ """Download the generated deliverable file"""
+ print(f"\n📥 Downloading file: {filename}")
+
+ url = f"{self.base_url}/deliverable/file/{deliverable_id}"
+
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ print(f"✅ File ready for download: {filename}")
+ print(f"📁 Content-Type: {response.headers.get('content-type')}")
+ print(f"📊 Content-Length: {response.headers.get('content-length')} bytes")
+
+ # In a real application, you would save the file
+ # with open(filename, 'wb') as f:
+ # f.write(response.content)
+
+ return {
+ 'filename': filename,
+ 'content_type': response.headers.get('content-type'),
+ 'content_length': response.headers.get('content-length')
+ }
+
+ # ===============================
+ # DEMO FUNCTIONS
+ # ===============================
+
+ def demo_path_a(self, template_file_path):
+ """Demo Path A workflow"""
+ print("🚀 DEMO: Path A - Upload New Template Workflow")
+ print("=" * 45)
+ print()
+
+ return self.path_a_upload_and_generate(
+ template_file_path,
+ 'Contract Generated via Path A - API Upload'
+ )
+
+ def demo_path_b(self):
+ """Demo Path B workflow"""
+ print("🚀 DEMO: Path B - Browse Existing Template Workflow")
+ print("=" * 51)
+ print()
+
+ return self.path_b_browse_and_generate(
+ 'contract',
+ 'Contract Generated via Path B - Browse & Select'
+ )
+
+ def demo_comparison(self):
+ """Demo comparison of both workflows"""
+ print("🚀 DEMO: Complete Workflow Comparison")
+ print("=" * 36)
+ print()
+
+ try:
+ print("Testing both paths with the same template type...\n")
+
+ # Run Path B first (browse existing)
+ path_b_result = self.demo_path_b()
+
+ print("\n" + "=" * 60 + "\n")
+
+ # For Path A, we'd need a template file
+ print("📝 Path A requires a template file to upload.")
+ print(" Example: workflow.demo_path_a('./contract-template.docx')")
+
+ return {'path_b': path_b_result}
+
+ except Exception as error:
+ print(f"Demo comparison failed: {error}")
+
+def run_examples():
+ """Run example workflows"""
+ workflow = TemplateWorkflowManager(API_TOKEN, ORG_ID, BASE_URL)
+
+ try:
+ # Demo Path B (Browse existing templates)
+ workflow.demo_path_b()
+
+ # Uncomment to demo Path A (requires template file):
+ # workflow.demo_path_a('./path/to/your/template.docx')
+
+ # Uncomment to run full comparison:
+ # workflow.demo_comparison()
+
+ except Exception as error:
+ print(f"Workflow demo failed: {error}")
+
+# Example usage
+if __name__ == "__main__":
+ run_examples()
\ No newline at end of file
diff --git a/static/scripts/templates/api/complete-workflows/ruby.rb b/static/scripts/templates/api/complete-workflows/ruby.rb
new file mode 100644
index 0000000..fa14b81
--- /dev/null
+++ b/static/scripts/templates/api/complete-workflows/ruby.rb
@@ -0,0 +1,443 @@
+require 'net/http'
+require 'uri'
+require 'json'
+require 'cgi'
+require 'securerandom'
+require 'time'
+require 'mime/types'
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+##
+# Complete Template Workflow Manager
+# Demonstrates both upload and browse/select paths
+##
+
+class TemplateWorkflowManager
+ def initialize
+ puts "=== TurboDocx Template Generation Workflow Manager ==="
+ end
+
+ def demonstrate_complete_workflow
+ puts "\nSelect workflow path:"
+ puts "A) Upload new template"
+ puts "B) Browse and select existing template"
+
+ # For this example, we'll demonstrate both paths
+ puts "\n=== Demonstrating Path A: Upload Template ==="
+ template_id_a = demonstrate_upload_workflow
+
+ puts "\n=== Demonstrating Path B: Browse Templates ==="
+ template_id_b = demonstrate_browse_workflow
+
+ # Generate deliverables for both templates if successful
+ if template_id_a
+ puts "\n=== Generating Deliverable from Uploaded Template ==="
+ generate_and_download_deliverable(template_id_a, "A")
+ end
+
+ if template_id_b
+ puts "\n=== Generating Deliverable from Selected Template ==="
+ generate_and_download_deliverable(template_id_b, "B")
+ end
+ end
+
+ private
+
+ def demonstrate_upload_workflow
+ begin
+ puts "\n--- Path A: Upload and Create Template ---"
+
+ # Check for template file
+ template_file = "./contract-template.docx"
+ unless File.exist?(template_file)
+ puts "⚠️ Template file not found: #{template_file}"
+ puts "Creating a placeholder message for demonstration"
+ return nil
+ end
+
+ result = upload_template(template_file)
+ template = result['data']['results']['template']
+
+ puts "✅ Upload workflow completed"
+ puts "Template ID: #{template['id']}"
+ puts "Ready for deliverable generation"
+
+ template['id']
+ rescue => e
+ puts "❌ Upload workflow failed: #{e.message}"
+ nil
+ end
+ end
+
+ def demonstrate_browse_workflow
+ begin
+ puts "\n--- Path B: Browse and Select Template ---"
+
+ # Browse templates
+ browse_result = browse_templates(10, 0, 'contract', true)
+
+ # Find first template (not folder)
+ selected_template = browse_result['results'].find { |item| item['type'] == 'template' }
+
+ if selected_template.nil?
+ puts "⚠️ No templates found in browse results"
+ return nil
+ end
+
+ puts "Selected: #{selected_template['name']}"
+
+ # Get detailed information
+ template_details = get_template_details(selected_template['id'])
+
+ # Optionally get PDF preview
+ pdf_preview = get_template_pdf_preview(selected_template['id'])
+
+ puts "✅ Browse workflow completed"
+ puts "Template ID: #{template_details['id']}"
+ puts "PDF Preview: #{pdf_preview}"
+ puts "Ready for deliverable generation"
+
+ template_details['id']
+ rescue => e
+ puts "❌ Browse workflow failed: #{e.message}"
+ nil
+ end
+ end
+
+ def generate_and_download_deliverable(template_id, path_label)
+ begin
+ puts "\n--- Generating Deliverable (Path #{path_label}) ---"
+
+ deliverable_data = create_deliverable_data(template_id, path_label)
+ deliverable = generate_deliverable(template_id, deliverable_data)
+
+ # Download the file
+ download_result = download_deliverable(
+ deliverable['id'],
+ "#{deliverable['name']}_path_#{path_label}.docx"
+ )
+
+ puts "✅ Complete workflow finished successfully for Path #{path_label}"
+ puts "Deliverable ID: #{deliverable['id']}"
+ puts "Download info: #{download_result}"
+
+ rescue => e
+ puts "❌ Deliverable generation failed for Path #{path_label}: #{e.message}"
+ end
+ end
+
+ def upload_template(template_file_path)
+ uri = URI("#{BASE_URL}/template/upload-and-create")
+ boundary = "----RubyBoundary#{rand(1000000)}"
+
+ # Build multipart form data
+ form_data = ""
+
+ # Template file field
+ form_data << "--#{boundary}\r\n"
+ form_data << "Content-Disposition: form-data; name=\"templateFile\"; filename=\"#{File.basename(template_file_path)}\"\r\n"
+ form_data << "Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document\r\n\r\n"
+ form_data << File.read(template_file_path)
+
+ # Name field
+ form_data << "\r\n--#{boundary}\r\n"
+ form_data << "Content-Disposition: form-data; name=\"name\"\r\n\r\n"
+ form_data << "Employee Contract Template"
+
+ # Description field
+ form_data << "\r\n--#{boundary}\r\n"
+ form_data << "Content-Disposition: form-data; name=\"description\"\r\n\r\n"
+ form_data << "Standard employee contract with variable placeholders"
+
+ # Variables field
+ form_data << "\r\n--#{boundary}\r\n"
+ form_data << "Content-Disposition: form-data; name=\"variables\"\r\n\r\n"
+ form_data << "[]"
+
+ # Tags field
+ form_data << "\r\n--#{boundary}\r\n"
+ form_data << "Content-Disposition: form-data; name=\"tags\"\r\n\r\n"
+ form_data << '["hr", "contract", "template"]'
+
+ form_data << "\r\n--#{boundary}--\r\n"
+
+ # Create HTTP connection
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ # Create request
+ request = Net::HTTP::Post.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+ request['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
+ request.body = form_data
+
+ # Make request
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "HTTP error #{response.code}: #{response.body}"
+ end
+
+ JSON.parse(response.body)
+ end
+
+ def browse_templates(limit = 25, offset = 0, query = '', show_tags = true, selected_tags = nil)
+ # Build query parameters
+ params = {
+ 'limit' => limit.to_s,
+ 'offset' => offset.to_s,
+ 'showTags' => show_tags.to_s
+ }
+
+ params['query'] = query unless query.empty?
+
+ if selected_tags
+ selected_tags.each do |tag|
+ params["selectedTags[]"] = tag
+ end
+ end
+
+ query_string = params.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v)}" }.join('&')
+ uri = URI("#{BASE_URL}/template-item?#{query_string}")
+
+ # Create HTTP connection
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ # Create request
+ request = Net::HTTP::Get.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+
+ # Make request
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "HTTP error #{response.code}: #{response.body}"
+ end
+
+ JSON.parse(response.body)['data']
+ end
+
+ def get_template_details(template_id)
+ uri = URI("#{BASE_URL}/template/#{template_id}")
+
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ request = Net::HTTP::Get.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "HTTP error #{response.code}: #{response.body}"
+ end
+
+ JSON.parse(response.body)['data']['results']
+ end
+
+ def get_template_pdf_preview(template_id)
+ uri = URI("#{BASE_URL}/template/#{template_id}/previewpdflink")
+
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ request = Net::HTTP::Get.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "HTTP error #{response.code}: #{response.body}"
+ end
+
+ JSON.parse(response.body)['results']
+ end
+
+ def generate_deliverable(template_id, deliverable_data)
+ uri = URI("#{BASE_URL}/deliverable")
+
+ puts "Generating deliverable..."
+ puts "Template ID: #{template_id}"
+ puts "Deliverable Name: #{deliverable_data['name']}"
+ puts "Variables: #{deliverable_data['variables'].length}"
+
+ # Create HTTP connection
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ # Create request
+ request = Net::HTTP::Post.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+ request['Content-Type'] = 'application/json'
+
+ # Set request body
+ request.body = deliverable_data.to_json
+
+ # Make request
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "HTTP error #{response.code}: #{response.body}"
+ end
+
+ # Parse JSON response
+ result = JSON.parse(response.body)
+ deliverable = result['data']['results']['deliverable']
+
+ puts "✅ Deliverable generated successfully!"
+ puts "Deliverable ID: #{deliverable['id']}"
+ puts "Created by: #{deliverable['createdBy']}"
+ puts "Created on: #{deliverable['createdOn']}"
+ puts "Template ID: #{deliverable['templateId']}"
+
+ deliverable
+ end
+
+ def download_deliverable(deliverable_id, filename)
+ puts "Downloading file: #{filename}"
+
+ uri = URI("#{BASE_URL}/deliverable/file/#{deliverable_id}")
+
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ request = Net::HTTP::Get.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "Download failed: #{response.code}"
+ end
+
+ puts "✅ File ready for download: #{filename}"
+
+ content_type = response['Content-Type'] || 'N/A'
+ content_length = response['Content-Length'] || 'N/A'
+
+ puts "📁 Content-Type: #{content_type}"
+ puts "📊 Content-Length: #{content_length} bytes"
+
+ # In a real application, you would save the file
+ # File.write(filename, response.body)
+
+ {
+ 'filename' => filename,
+ 'content_type' => content_type,
+ 'content_length' => content_length
+ }
+ end
+
+ def create_deliverable_data(template_id, path_label)
+ now = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%S.%3NZ')
+
+ {
+ 'templateId' => template_id,
+ 'name' => "Contract Document - Path #{path_label}",
+ 'description' => "Employment contract generated via workflow path #{path_label}",
+ 'variables' => create_complex_variables,
+ 'tags' => ['hr', 'contract', 'employee', 'engineering'],
+ 'fonts' => '[{"name":"Arial","usage":269}]',
+ 'defaultFont' => 'Arial',
+ 'replaceFonts' => true,
+ 'metadata' => {
+ 'sessions' => [
+ {
+ 'id' => SecureRandom.uuid,
+ 'starttime' => now,
+ 'endtime' => now
+ }
+ ],
+ 'createdBy' => 'Ruby Workflow Manager',
+ 'documentType' => 'Employment Contract',
+ 'version' => 'v1.0',
+ 'workflowPath' => path_label
+ }
+ }
+ end
+
+ def create_complex_variables
+ [
+ {
+ 'mimeType' => 'text',
+ 'name' => 'Employee Name',
+ 'placeholder' => '{EmployeeName}',
+ 'text' => 'John Smith',
+ 'allowRichTextInjection' => 0,
+ 'autogenerated' => false,
+ 'count' => 1,
+ 'order' => 1,
+ 'subvariables' => [
+ {
+ 'placeholder' => '{EmployeeName.Title}',
+ 'text' => 'Senior Software Engineer'
+ },
+ {
+ 'placeholder' => '{EmployeeName.StartDate}',
+ 'text' => 'January 15, 2024'
+ }
+ ],
+ 'metadata' => {
+ 'department' => 'Engineering',
+ 'level' => 'Senior'
+ },
+ 'aiPrompt' => 'Generate a professional job description for a senior software engineer role'
+ },
+ {
+ 'mimeType' => 'text',
+ 'name' => 'Company Information',
+ 'placeholder' => '{CompanyInfo}',
+ 'text' => 'TechCorp Solutions Inc.',
+ 'allowRichTextInjection' => 1,
+ 'autogenerated' => false,
+ 'count' => 1,
+ 'order' => 2,
+ 'subvariables' => [
+ {
+ 'placeholder' => '{CompanyInfo.Address}',
+ 'text' => '123 Innovation Drive, Tech City, TC 12345'
+ },
+ {
+ 'placeholder' => '{CompanyInfo.Phone}',
+ 'text' => '(555) 123-4567'
+ }
+ ],
+ 'metadata' => {},
+ 'aiPrompt' => ''
+ }
+ ]
+ end
+end
+
+# Example usage
+begin
+ workflow_manager = TemplateWorkflowManager.new
+ workflow_manager.demonstrate_complete_workflow
+
+ puts "\n=== Workflow Demonstration Complete ==="
+ puts "Both upload and browse/select paths have been demonstrated."
+ puts "Choose the appropriate path for your use case:"
+ puts "- Upload path: When you have new templates to create"
+ puts "- Browse path: When you want to use existing templates"
+
+rescue => e
+ puts "Workflow demonstration failed: #{e.message}"
+ exit 1
+end
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/csharp/controller.cs b/static/scripts/templates/api/generate-deliverable/csharp/controller.cs
new file mode 100644
index 0000000..d0c328e
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/csharp/controller.cs
@@ -0,0 +1,202 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+using System.Text.Json;
+using System.Text;
+
+/**
+ * Final Step: Generate Deliverable (Both Paths Converge Here)
+ */
+class DeliverableGenerator
+{
+ // Configuration - Update these values
+ private const string API_TOKEN = "YOUR_API_TOKEN";
+ private const string ORG_ID = "YOUR_ORGANIZATION_ID";
+ private const string BASE_URL = "https://api.turbodocx.com";
+
+ static async Task Main(string[] args)
+ {
+ try
+ {
+ Console.WriteLine("=== Final Step: Generate Deliverable ===");
+
+ // This would come from either Path A (upload) or Path B (browse/select)
+ var templateId = "0b1099cf-d7b9-41a4-822b-51b68fd4885a";
+
+ var deliverableData = CreateDeliverableData();
+ var deliverable = await GenerateDeliverable(templateId, deliverableData);
+
+ // Download the generated file
+ Console.WriteLine("\n=== Download Generated File ===");
+ using var document = JsonDocument.Parse(deliverable);
+ var deliverableInfo = document.RootElement.GetProperty("data").GetProperty("results").GetProperty("deliverable");
+
+ var deliverableId = deliverableInfo.GetProperty("id").GetString();
+ var deliverableName = deliverableInfo.GetProperty("name").GetString();
+ await DownloadDeliverable(deliverableId, $"{deliverableName}.docx");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Deliverable generation failed: {ex.Message}");
+ }
+ }
+
+ /**
+ * Generate a deliverable document from template with variable substitution
+ */
+ private static async Task GenerateDeliverable(string templateId, string deliverableDataJson)
+ {
+ using var client = new HttpClient();
+
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ Console.WriteLine("Generating deliverable...");
+ Console.WriteLine($"Template ID: {templateId}");
+
+ using var document = JsonDocument.Parse(deliverableDataJson);
+ var deliverableName = document.RootElement.GetProperty("name").GetString();
+ var variableCount = document.RootElement.GetProperty("variables").GetArrayLength();
+
+ Console.WriteLine($"Deliverable Name: {deliverableName}");
+ Console.WriteLine($"Variables: {variableCount}");
+
+ var content = new StringContent(deliverableDataJson, Encoding.UTF8, "application/json");
+ var response = await client.PostAsync($"{BASE_URL}/deliverable", content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"HTTP error {response.StatusCode}: {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var resultDoc = JsonDocument.Parse(result);
+ var deliverable = resultDoc.RootElement.GetProperty("data").GetProperty("results").GetProperty("deliverable");
+
+ Console.WriteLine("✅ Deliverable generated successfully!");
+ Console.WriteLine($"Deliverable ID: {deliverable.GetProperty("id").GetString()}");
+ Console.WriteLine($"Created by: {deliverable.GetProperty("createdBy").GetString()}");
+ Console.WriteLine($"Created on: {deliverable.GetProperty("createdOn").GetString()}");
+ Console.WriteLine($"Template ID: {deliverable.GetProperty("templateId").GetString()}");
+
+ return result;
+ }
+
+ /**
+ * Download the generated deliverable file
+ */
+ private static async Task DownloadDeliverable(string deliverableId, string filename)
+ {
+ using var client = new HttpClient();
+
+ Console.WriteLine($"Downloading file: {filename}");
+
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ var response = await client.GetAsync($"{BASE_URL}/deliverable/file/{deliverableId}");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ throw new HttpRequestException($"Download failed: {response.StatusCode}");
+ }
+
+ Console.WriteLine($"✅ File ready for download: {filename}");
+
+ var contentType = response.Content.Headers.ContentType?.ToString() ?? "N/A";
+ var contentLength = response.Content.Headers.ContentLength?.ToString() ?? "N/A";
+
+ Console.WriteLine($"📁 Content-Type: {contentType}");
+ Console.WriteLine($"📊 Content-Length: {contentLength} bytes");
+
+ // In a real application, you would save the file
+ // var fileBytes = await response.Content.ReadAsByteArrayAsync();
+ // await File.WriteAllBytesAsync(filename, fileBytes);
+ }
+
+ /**
+ * Create example deliverable data with complex variables
+ */
+ private static string CreateDeliverableData()
+ {
+ var templateId = "0b1099cf-d7b9-41a4-822b-51b68fd4885a";
+
+ return $$"""
+ {
+ "templateId": "{{templateId}}",
+ "name": "Employee Contract - John Smith",
+ "description": "Employment contract for new senior software engineer",
+ "variables": [
+ {
+ "mimeType": "text",
+ "name": "Employee Name",
+ "placeholder": "{EmployeeName}",
+ "text": "John Smith",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 1,
+ "order": 1,
+ "subvariables": [
+ {
+ "placeholder": "{EmployeeName.Title}",
+ "text": "Senior Software Engineer"
+ },
+ {
+ "placeholder": "{EmployeeName.StartDate}",
+ "text": "January 15, 2024"
+ }
+ ],
+ "metadata": {
+ "department": "Engineering",
+ "level": "Senior"
+ },
+ "aiPrompt": "Generate a professional job description for a senior software engineer role"
+ },
+ {
+ "mimeType": "text",
+ "name": "Company Information",
+ "placeholder": "{CompanyInfo}",
+ "text": "TechCorp Solutions Inc.",
+ "allowRichTextInjection": 1,
+ "autogenerated": false,
+ "count": 1,
+ "order": 2,
+ "subvariables": [
+ {
+ "placeholder": "{CompanyInfo.Address}",
+ "text": "123 Innovation Drive, Tech City, TC 12345"
+ },
+ {
+ "placeholder": "{CompanyInfo.Phone}",
+ "text": "(555) 123-4567"
+ }
+ ],
+ "metadata": {},
+ "aiPrompt": ""
+ }
+ ],
+ "tags": ["hr", "contract", "employee", "engineering"],
+ "fonts": "[{\"name\":\"Arial\",\"usage\":269}]",
+ "defaultFont": "Arial",
+ "replaceFonts": true,
+ "metadata": {
+ "sessions": [
+ {
+ "id": "{{Guid.NewGuid()}}",
+ "starttime": "{{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}}",
+ "endtime": "{{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}}"
+ }
+ ],
+ "createdBy": "HR Department",
+ "documentType": "Employment Contract",
+ "version": "v1.0"
+ }
+ }
+ """;
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/csharp/minimal.cs b/static/scripts/templates/api/generate-deliverable/csharp/minimal.cs
new file mode 100644
index 0000000..d0c328e
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/csharp/minimal.cs
@@ -0,0 +1,202 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+using System.Text.Json;
+using System.Text;
+
+/**
+ * Final Step: Generate Deliverable (Both Paths Converge Here)
+ */
+class DeliverableGenerator
+{
+ // Configuration - Update these values
+ private const string API_TOKEN = "YOUR_API_TOKEN";
+ private const string ORG_ID = "YOUR_ORGANIZATION_ID";
+ private const string BASE_URL = "https://api.turbodocx.com";
+
+ static async Task Main(string[] args)
+ {
+ try
+ {
+ Console.WriteLine("=== Final Step: Generate Deliverable ===");
+
+ // This would come from either Path A (upload) or Path B (browse/select)
+ var templateId = "0b1099cf-d7b9-41a4-822b-51b68fd4885a";
+
+ var deliverableData = CreateDeliverableData();
+ var deliverable = await GenerateDeliverable(templateId, deliverableData);
+
+ // Download the generated file
+ Console.WriteLine("\n=== Download Generated File ===");
+ using var document = JsonDocument.Parse(deliverable);
+ var deliverableInfo = document.RootElement.GetProperty("data").GetProperty("results").GetProperty("deliverable");
+
+ var deliverableId = deliverableInfo.GetProperty("id").GetString();
+ var deliverableName = deliverableInfo.GetProperty("name").GetString();
+ await DownloadDeliverable(deliverableId, $"{deliverableName}.docx");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Deliverable generation failed: {ex.Message}");
+ }
+ }
+
+ /**
+ * Generate a deliverable document from template with variable substitution
+ */
+ private static async Task GenerateDeliverable(string templateId, string deliverableDataJson)
+ {
+ using var client = new HttpClient();
+
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ Console.WriteLine("Generating deliverable...");
+ Console.WriteLine($"Template ID: {templateId}");
+
+ using var document = JsonDocument.Parse(deliverableDataJson);
+ var deliverableName = document.RootElement.GetProperty("name").GetString();
+ var variableCount = document.RootElement.GetProperty("variables").GetArrayLength();
+
+ Console.WriteLine($"Deliverable Name: {deliverableName}");
+ Console.WriteLine($"Variables: {variableCount}");
+
+ var content = new StringContent(deliverableDataJson, Encoding.UTF8, "application/json");
+ var response = await client.PostAsync($"{BASE_URL}/deliverable", content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"HTTP error {response.StatusCode}: {errorContent}");
+ }
+
+ var result = await response.Content.ReadAsStringAsync();
+
+ using var resultDoc = JsonDocument.Parse(result);
+ var deliverable = resultDoc.RootElement.GetProperty("data").GetProperty("results").GetProperty("deliverable");
+
+ Console.WriteLine("✅ Deliverable generated successfully!");
+ Console.WriteLine($"Deliverable ID: {deliverable.GetProperty("id").GetString()}");
+ Console.WriteLine($"Created by: {deliverable.GetProperty("createdBy").GetString()}");
+ Console.WriteLine($"Created on: {deliverable.GetProperty("createdOn").GetString()}");
+ Console.WriteLine($"Template ID: {deliverable.GetProperty("templateId").GetString()}");
+
+ return result;
+ }
+
+ /**
+ * Download the generated deliverable file
+ */
+ private static async Task DownloadDeliverable(string deliverableId, string filename)
+ {
+ using var client = new HttpClient();
+
+ Console.WriteLine($"Downloading file: {filename}");
+
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ var response = await client.GetAsync($"{BASE_URL}/deliverable/file/{deliverableId}");
+
+ if (!response.IsSuccessStatusCode)
+ {
+ throw new HttpRequestException($"Download failed: {response.StatusCode}");
+ }
+
+ Console.WriteLine($"✅ File ready for download: {filename}");
+
+ var contentType = response.Content.Headers.ContentType?.ToString() ?? "N/A";
+ var contentLength = response.Content.Headers.ContentLength?.ToString() ?? "N/A";
+
+ Console.WriteLine($"📁 Content-Type: {contentType}");
+ Console.WriteLine($"📊 Content-Length: {contentLength} bytes");
+
+ // In a real application, you would save the file
+ // var fileBytes = await response.Content.ReadAsByteArrayAsync();
+ // await File.WriteAllBytesAsync(filename, fileBytes);
+ }
+
+ /**
+ * Create example deliverable data with complex variables
+ */
+ private static string CreateDeliverableData()
+ {
+ var templateId = "0b1099cf-d7b9-41a4-822b-51b68fd4885a";
+
+ return $$"""
+ {
+ "templateId": "{{templateId}}",
+ "name": "Employee Contract - John Smith",
+ "description": "Employment contract for new senior software engineer",
+ "variables": [
+ {
+ "mimeType": "text",
+ "name": "Employee Name",
+ "placeholder": "{EmployeeName}",
+ "text": "John Smith",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 1,
+ "order": 1,
+ "subvariables": [
+ {
+ "placeholder": "{EmployeeName.Title}",
+ "text": "Senior Software Engineer"
+ },
+ {
+ "placeholder": "{EmployeeName.StartDate}",
+ "text": "January 15, 2024"
+ }
+ ],
+ "metadata": {
+ "department": "Engineering",
+ "level": "Senior"
+ },
+ "aiPrompt": "Generate a professional job description for a senior software engineer role"
+ },
+ {
+ "mimeType": "text",
+ "name": "Company Information",
+ "placeholder": "{CompanyInfo}",
+ "text": "TechCorp Solutions Inc.",
+ "allowRichTextInjection": 1,
+ "autogenerated": false,
+ "count": 1,
+ "order": 2,
+ "subvariables": [
+ {
+ "placeholder": "{CompanyInfo.Address}",
+ "text": "123 Innovation Drive, Tech City, TC 12345"
+ },
+ {
+ "placeholder": "{CompanyInfo.Phone}",
+ "text": "(555) 123-4567"
+ }
+ ],
+ "metadata": {},
+ "aiPrompt": ""
+ }
+ ],
+ "tags": ["hr", "contract", "employee", "engineering"],
+ "fonts": "[{\"name\":\"Arial\",\"usage\":269}]",
+ "defaultFont": "Arial",
+ "replaceFonts": true,
+ "metadata": {
+ "sessions": [
+ {
+ "id": "{{Guid.NewGuid()}}",
+ "starttime": "{{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}}",
+ "endtime": "{{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}}"
+ }
+ ],
+ "createdBy": "HR Department",
+ "documentType": "Employment Contract",
+ "version": "v1.0"
+ }
+ }
+ """;
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/curl.sh b/static/scripts/templates/api/generate-deliverable/curl.sh
new file mode 100644
index 0000000..fe3f755
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/curl.sh
@@ -0,0 +1,257 @@
+#!/bin/bash
+
+# Configuration - Update these values
+API_TOKEN="YOUR_API_TOKEN"
+ORG_ID="YOUR_ORGANIZATION_ID"
+BASE_URL="https://api.turbodocx.com"
+
+# Final Step: Generate Deliverable (Both Paths Converge Here)
+
+echo "=== Final Step: Generate Deliverable ==="
+
+# Template ID - This would come from either Path A (upload) or Path B (browse/select)
+TEMPLATE_ID="0b1099cf-d7b9-41a4-822b-51b68fd4885a"
+
+echo "Template ID: $TEMPLATE_ID"
+echo "Generating deliverable with complex variable structure..."
+
+# Generate deliverable with complex variable payload
+curl -X POST "$BASE_URL/deliverable" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "templateId": "'$TEMPLATE_ID'",
+ "name": "Employee Contract - John Smith",
+ "description": "Employment contract for new senior software engineer",
+ "variables": [
+ {
+ "mimeType": "text",
+ "name": "Employee Name",
+ "placeholder": "{EmployeeName}",
+ "text": "John Smith",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 1,
+ "order": 1,
+ "subvariables": [
+ {
+ "placeholder": "{EmployeeName.Title}",
+ "text": "Senior Software Engineer"
+ },
+ {
+ "placeholder": "{EmployeeName.StartDate}",
+ "text": "January 15, 2024"
+ }
+ ],
+ "metadata": {
+ "department": "Engineering",
+ "level": "Senior"
+ },
+ "aiPrompt": "Generate a professional job description for a senior software engineer role"
+ },
+ {
+ "mimeType": "text",
+ "name": "Company Information",
+ "placeholder": "{CompanyInfo}",
+ "text": "TechCorp Solutions Inc.",
+ "allowRichTextInjection": 1,
+ "autogenerated": false,
+ "count": 1,
+ "order": 2,
+ "subvariables": [
+ {
+ "placeholder": "{CompanyInfo.Address}",
+ "text": "123 Innovation Drive, Tech City, TC 12345"
+ },
+ {
+ "placeholder": "{CompanyInfo.Phone}",
+ "text": "(555) 123-4567"
+ }
+ ],
+ "metadata": {},
+ "aiPrompt": ""
+ },
+ {
+ "mimeType": "text",
+ "name": "Project Assignments",
+ "placeholder": "{ProjectAssignments}",
+ "text": "Multiple ongoing projects",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 3,
+ "order": 3,
+ "subvariables": [],
+ "variableStack": {
+ "0": {
+ "text": "Project Alpha - Backend Development",
+ "subvariables": [
+ {
+ "placeholder": "{ProjectAssignments.Duration}",
+ "text": "6 months"
+ },
+ {
+ "placeholder": "{ProjectAssignments.Priority}",
+ "text": "High"
+ }
+ ]
+ },
+ "1": {
+ "text": "Project Beta - API Integration",
+ "subvariables": [
+ {
+ "placeholder": "{ProjectAssignments.Duration}",
+ "text": "3 months"
+ },
+ {
+ "placeholder": "{ProjectAssignments.Priority}",
+ "text": "Medium"
+ }
+ ]
+ },
+ "2": {
+ "text": "Project Gamma - Code Review",
+ "subvariables": [
+ {
+ "placeholder": "{ProjectAssignments.Duration}",
+ "text": "Ongoing"
+ },
+ {
+ "placeholder": "{ProjectAssignments.Priority}",
+ "text": "Low"
+ }
+ ]
+ }
+ },
+ "metadata": {
+ "totalProjects": 3,
+ "estimatedHours": 1200
+ },
+ "aiPrompt": "Create detailed project descriptions for software development initiatives"
+ },
+ {
+ "mimeType": "text",
+ "name": "Benefits Package",
+ "placeholder": "{BenefitsPackage}",
+ "text": "Comprehensive benefits including health, dental, vision, and 401k",
+ "allowRichTextInjection": 1,
+ "autogenerated": false,
+ "count": 1,
+ "order": 4,
+ "subvariables": [
+ {
+ "placeholder": "{BenefitsPackage.HealthInsurance}",
+ "text": "Full coverage health insurance with $500 deductible"
+ },
+ {
+ "placeholder": "{BenefitsPackage.PTO}",
+ "text": "25 days paid time off annually"
+ },
+ {
+ "placeholder": "{BenefitsPackage.Retirement}",
+ "text": "401k with 6% company match"
+ }
+ ],
+ "metadata": {
+ "packageValue": "$15,000 annually",
+ "effective": "First day of employment"
+ },
+ "aiPrompt": "Outline a competitive benefits package for a senior software engineer"
+ }
+ ],
+ "tags": ["hr", "contract", "employee", "engineering"],
+ "fonts": "[{\"name\":\"Arial\",\"usage\":269}]",
+ "defaultFont": "Arial",
+ "replaceFonts": true,
+ "metadata": {
+ "sessions": [
+ {
+ "id": "cf1cd4b9-6fdc-47e3-b59d-594cd6564501",
+ "starttime": "2024-01-15T14:12:10.721Z",
+ "endtime": "2024-01-15T14:13:45.724Z"
+ }
+ ],
+ "createdBy": "HR Department",
+ "documentType": "Employment Contract",
+ "version": "v1.0"
+ }
+ }' | jq '.'
+
+echo -e "\n=== Deliverable Generation Complete ==="
+
+# Extract deliverable ID for download
+DELIVERABLE_ID=$(echo "$GENERATE_RESPONSE" | jq -r '.data.results.deliverable.id')
+DELIVERABLE_NAME=$(echo "$GENERATE_RESPONSE" | jq -r '.data.results.deliverable.name')
+
+if [ "$DELIVERABLE_ID" != "null" ] && [ -n "$DELIVERABLE_ID" ]; then
+ echo "\n=== Download Generated File ==="
+ echo "Downloading deliverable: $DELIVERABLE_NAME"
+
+ curl -X GET "$BASE_URL/deliverable/file/$DELIVERABLE_ID" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client" \
+ --output "$DELIVERABLE_NAME.docx" \
+ --write-out "Downloaded: %{filename_effective} (%{size_download} bytes)\n"
+else
+ echo "❌ Could not extract deliverable ID from response"
+fi
+
+# Example: Simple variable structure (minimal example)
+echo -e "\n--- Alternative: Simple Variable Structure ---"
+echo "For a simpler example with basic variables:"
+
+cat << 'EOF'
+curl -X POST "$BASE_URL/deliverable" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "templateId": "TEMPLATE_ID",
+ "name": "Simple Document",
+ "description": "Basic document generation",
+ "variables": [
+ {
+ "mimeType": "text",
+ "name": "Company Name",
+ "placeholder": "{CompanyName}",
+ "text": "Acme Corporation",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 1,
+ "order": 1,
+ "subvariables": [],
+ "metadata": {},
+ "aiPrompt": ""
+ },
+ {
+ "mimeType": "text",
+ "name": "Date",
+ "placeholder": "{Date}",
+ "text": "January 15, 2024",
+ "allowRichTextInjection": 0,
+ "autogenerated": false,
+ "count": 1,
+ "order": 2,
+ "subvariables": [],
+ "metadata": {},
+ "aiPrompt": ""
+ }
+ ],
+ "tags": ["simple", "test"],
+ "fonts": "[]",
+ "defaultFont": "Arial",
+ "replaceFonts": true,
+ "metadata": {
+ "sessions": [
+ {
+ "id": "simple-session-123",
+ "starttime": "'$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)'",
+ "endtime": "'$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)'"
+ }
+ ]
+ }
+ }'
+EOF
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/fastapi.py b/static/scripts/templates/api/generate-deliverable/fastapi.py
new file mode 100644
index 0000000..0c5341d
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/fastapi.py
@@ -0,0 +1,513 @@
+#!/usr/bin/env python3
+
+import requests
+import json
+import uuid
+from datetime import datetime
+from typing import Optional, List, Dict, Any
+from fastapi import FastAPI, HTTPException
+from fastapi.responses import StreamingResponse
+from pydantic import BaseModel
+import uvicorn
+import io
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+app = FastAPI(
+ title="TurboDocx Deliverable Generator Service",
+ description="FastAPI service for generating deliverables from templates using TurboDocx API",
+ version="1.0.0"
+)
+
+class Variable(BaseModel):
+ mimeType: str
+ name: str
+ placeholder: str
+ text: str
+ allowRichTextInjection: int
+ autogenerated: bool
+ count: int
+ order: int
+ subvariables: Optional[List[Dict[str, str]]] = []
+ variableStack: Optional[Dict[str, Any]] = {}
+ metadata: Optional[Dict[str, Any]] = {}
+ aiPrompt: Optional[str] = ""
+
+class Session(BaseModel):
+ id: str
+ starttime: str
+ endtime: str
+
+class Metadata(BaseModel):
+ sessions: List[Session]
+ createdBy: str
+ documentType: str
+ version: str
+
+class DeliverableData(BaseModel):
+ templateId: str
+ name: str
+ description: str
+ variables: List[Variable]
+ tags: List[str]
+ fonts: str
+ defaultFont: str
+ replaceFonts: bool
+ metadata: Metadata
+
+class GenerateRequest(BaseModel):
+ templateId: str
+ deliverableData: Optional[DeliverableData] = None
+
+class WorkflowRequest(BaseModel):
+ templateId: str
+ customVariables: Optional[List[Variable]] = None
+
+class GenerateResponse(BaseModel):
+ success: bool
+ message: str
+ data: dict
+
+class WorkflowResponse(BaseModel):
+ success: bool
+ message: str
+ data: dict
+
+class ConfigurationInfo(BaseModel):
+ baseUrl: str
+ hasToken: bool
+ hasOrgId: bool
+
+class ServiceInfo(BaseModel):
+ service: str
+ endpoints: dict
+ configuration: ConfigurationInfo
+
+def generate_deliverable(template_id: str, deliverable_data: dict) -> dict:
+ """
+ Final Step: Generate Deliverable (Both Paths Converge Here)
+ Generate a deliverable document from template with variable substitution
+ """
+ url = f"{BASE_URL}/deliverable"
+
+ print('Generating deliverable...')
+ print(f'Template ID: {template_id}')
+ print(f'Deliverable Name: {deliverable_data["name"]}')
+ print(f'Variables: {len(deliverable_data["variables"])}')
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client',
+ 'Content-Type': 'application/json'
+ }
+
+ try:
+ response = requests.post(url, json=deliverable_data, headers=headers)
+ response.raise_for_status()
+
+ # Parse JSON response
+ result = response.json()
+ deliverable = result['data']['results']['deliverable']
+
+ print('✅ Deliverable generated successfully!')
+ print(f'Deliverable ID: {deliverable["id"]}')
+ print(f'Created by: {deliverable["createdBy"]}')
+ print(f'Created on: {deliverable["createdOn"]}')
+ print(f'Template ID: {deliverable["templateId"]}')
+
+ return deliverable
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Deliverable generation failed: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+def download_deliverable(deliverable_id: str, filename: str) -> dict:
+ """Download the generated deliverable file"""
+ print(f'Downloading file: {filename}')
+
+ url = f"{BASE_URL}/deliverable/file/{deliverable_id}"
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ try:
+ response = requests.get(url, headers=headers, stream=True)
+ response.raise_for_status()
+
+ print(f'✅ File ready for download: {filename}')
+
+ content_type = response.headers.get('Content-Type', 'N/A')
+ content_length = response.headers.get('Content-Length', 'N/A')
+
+ print(f'📁 Content-Type: {content_type}')
+ print(f'📊 Content-Length: {content_length} bytes')
+
+ # Return response object for streaming
+ return {
+ 'filename': filename,
+ 'contentType': content_type,
+ 'contentLength': content_length,
+ 'response': response
+ }
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Download failed: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+def create_complex_variables() -> List[dict]:
+ """Create complex variable structures for testing"""
+ return [
+ {
+ 'mimeType': 'text',
+ 'name': 'Employee Name',
+ 'placeholder': '{EmployeeName}',
+ 'text': 'John Smith',
+ 'allowRichTextInjection': 0,
+ 'autogenerated': False,
+ 'count': 1,
+ 'order': 1,
+ 'subvariables': [
+ {
+ 'placeholder': '{EmployeeName.Title}',
+ 'text': 'Senior Software Engineer'
+ },
+ {
+ 'placeholder': '{EmployeeName.StartDate}',
+ 'text': 'January 15, 2024'
+ }
+ ],
+ 'metadata': {
+ 'department': 'Engineering',
+ 'level': 'Senior'
+ },
+ 'aiPrompt': 'Generate a professional job description for a senior software engineer role'
+ },
+ {
+ 'mimeType': 'text',
+ 'name': 'Company Information',
+ 'placeholder': '{CompanyInfo}',
+ 'text': 'TechCorp Solutions Inc.',
+ 'allowRichTextInjection': 1,
+ 'autogenerated': False,
+ 'count': 1,
+ 'order': 2,
+ 'subvariables': [
+ {
+ 'placeholder': '{CompanyInfo.Address}',
+ 'text': '123 Innovation Drive, Tech City, TC 12345'
+ },
+ {
+ 'placeholder': '{CompanyInfo.Phone}',
+ 'text': '(555) 123-4567'
+ }
+ ],
+ 'metadata': {},
+ 'aiPrompt': ''
+ },
+ {
+ 'mimeType': 'text',
+ 'name': 'Project Assignments',
+ 'placeholder': '{ProjectAssignments}',
+ 'text': 'Multiple ongoing projects',
+ 'allowRichTextInjection': 0,
+ 'autogenerated': False,
+ 'count': 3,
+ 'order': 3,
+ 'subvariables': [],
+ 'variableStack': {
+ '0': {
+ 'text': 'Project Alpha - Backend Development',
+ 'subvariables': [
+ {
+ 'placeholder': '{ProjectAssignments.Duration}',
+ 'text': '6 months'
+ },
+ {
+ 'placeholder': '{ProjectAssignments.Priority}',
+ 'text': 'High'
+ }
+ ]
+ },
+ '1': {
+ 'text': 'Project Beta - API Integration',
+ 'subvariables': [
+ {
+ 'placeholder': '{ProjectAssignments.Duration}',
+ 'text': '3 months'
+ },
+ {
+ 'placeholder': '{ProjectAssignments.Priority}',
+ 'text': 'Medium'
+ }
+ ]
+ },
+ '2': {
+ 'text': 'Project Gamma - Code Review',
+ 'subvariables': [
+ {
+ 'placeholder': '{ProjectAssignments.Duration}',
+ 'text': 'Ongoing'
+ },
+ {
+ 'placeholder': '{ProjectAssignments.Priority}',
+ 'text': 'Low'
+ }
+ ]
+ }
+ },
+ 'metadata': {
+ 'totalProjects': 3,
+ 'estimatedHours': 1200
+ },
+ 'aiPrompt': 'Create detailed project descriptions for software development initiatives'
+ },
+ {
+ 'mimeType': 'text',
+ 'name': 'Benefits Package',
+ 'placeholder': '{BenefitsPackage}',
+ 'text': 'Comprehensive benefits including health, dental, vision, and 401k',
+ 'allowRichTextInjection': 1,
+ 'autogenerated': False,
+ 'count': 1,
+ 'order': 4,
+ 'subvariables': [
+ {
+ 'placeholder': '{BenefitsPackage.HealthInsurance}',
+ 'text': 'Full coverage health insurance with $500 deductible'
+ },
+ {
+ 'placeholder': '{BenefitsPackage.PTO}',
+ 'text': '25 days paid time off annually'
+ },
+ {
+ 'placeholder': '{BenefitsPackage.Retirement}',
+ 'text': '401k with 6% company match'
+ }
+ ],
+ 'metadata': {
+ 'packageValue': '$15,000 annually',
+ 'effective': 'First day of employment'
+ },
+ 'aiPrompt': 'Outline a competitive benefits package for a senior software engineer'
+ }
+ ]
+
+def create_deliverable_data(template_id: str) -> dict:
+ """Create example deliverable data with complex variables"""
+ now = datetime.utcnow().isoformat() + 'Z'
+
+ return {
+ 'templateId': template_id,
+ 'name': 'Employee Contract - John Smith',
+ 'description': 'Employment contract for new senior software engineer',
+ 'variables': create_complex_variables(),
+ 'tags': ['hr', 'contract', 'employee', 'engineering'],
+ 'fonts': '[{"name":"Arial","usage":269}]',
+ 'defaultFont': 'Arial',
+ 'replaceFonts': True,
+ 'metadata': {
+ 'sessions': [
+ {
+ 'id': str(uuid.uuid4()),
+ 'starttime': now,
+ 'endtime': now
+ }
+ ],
+ 'createdBy': 'HR Department',
+ 'documentType': 'Employment Contract',
+ 'version': 'v1.0'
+ }
+ }
+
+# FastAPI route handlers
+@app.post("/generate-deliverable", response_model=GenerateResponse)
+async def generate_deliverable_endpoint(request: GenerateRequest):
+ """Generate deliverable from template"""
+ try:
+ # Use provided data or create default data
+ if request.deliverableData:
+ deliverable_data = request.deliverableData.dict()
+ else:
+ deliverable_data = create_deliverable_data(request.templateId)
+
+ deliverable = generate_deliverable(request.templateId, deliverable_data)
+
+ return GenerateResponse(
+ success=True,
+ message="Deliverable generated successfully",
+ data=deliverable
+ )
+
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Deliverable generation failed: {str(e)}")
+
+@app.get("/download-deliverable/{deliverable_id}")
+async def download_deliverable_endpoint(deliverable_id: str, filename: Optional[str] = None):
+ """Download generated deliverable file"""
+ try:
+ if not filename:
+ filename = f'deliverable-{deliverable_id}.docx'
+
+ download_info = download_deliverable(deliverable_id, filename)
+
+ # Create streaming response
+ def generate_file_stream():
+ for chunk in download_info['response'].iter_content(chunk_size=8192):
+ yield chunk
+
+ headers = {
+ 'Content-Disposition': f'attachment; filename="{filename}"'
+ }
+
+ if download_info['contentLength'] and download_info['contentLength'] != 'N/A':
+ headers['Content-Length'] = download_info['contentLength']
+
+ return StreamingResponse(
+ generate_file_stream(),
+ media_type=download_info['contentType'],
+ headers=headers
+ )
+
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Download failed: {str(e)}")
+
+@app.post("/complete-workflow", response_model=WorkflowResponse)
+async def complete_workflow_endpoint(request: WorkflowRequest):
+ """Complete generation and download workflow"""
+ try:
+ # Create deliverable data
+ deliverable_data = create_deliverable_data(request.templateId)
+
+ # Override variables if custom ones provided
+ if request.customVariables:
+ # Convert Pydantic models to dict
+ deliverable_data['variables'] = [var.dict() if hasattr(var, 'dict') else var for var in request.customVariables]
+
+ # Generate deliverable
+ print('=== Generating Deliverable ===')
+ deliverable = generate_deliverable(request.templateId, deliverable_data)
+
+ # Get download info (but don't actually download in this example)
+ print('\n=== Getting Download Info ===')
+ download_url = f"{BASE_URL}/deliverable/file/{deliverable['id']}"
+
+ return WorkflowResponse(
+ success=True,
+ message="Complete workflow executed successfully",
+ data={
+ 'deliverable': deliverable,
+ 'downloadUrl': download_url,
+ 'downloadEndpoint': f"/download-deliverable/{deliverable['id']}",
+ 'summary': {
+ 'deliverableId': deliverable['id'],
+ 'templateId': deliverable['templateId'],
+ 'createdBy': deliverable['createdBy'],
+ 'createdOn': deliverable['createdOn']
+ }
+ }
+ )
+
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Complete workflow failed: {str(e)}")
+
+@app.get("/health")
+async def health_check():
+ """Health check endpoint"""
+ return {
+ "status": "healthy",
+ "service": "deliverable-generator"
+ }
+
+@app.get("/generator-info", response_model=ServiceInfo)
+async def generator_info():
+ """Service information endpoint"""
+ return ServiceInfo(
+ service="TurboDocx Deliverable Generator Service",
+ endpoints={
+ "POST /generate-deliverable": "Generate a deliverable from template",
+ "GET /download-deliverable/{deliverable_id}": "Download generated deliverable file",
+ "POST /complete-workflow": "Complete generation and download workflow",
+ "GET /health": "Service health check",
+ "GET /generator-info": "Service information",
+ "GET /docs": "Interactive API documentation",
+ "GET /redoc": "Alternative API documentation"
+ },
+ configuration=ConfigurationInfo(
+ baseUrl=BASE_URL,
+ hasToken=bool(API_TOKEN and API_TOKEN != 'YOUR_API_TOKEN'),
+ hasOrgId=bool(ORG_ID and ORG_ID != 'YOUR_ORGANIZATION_ID')
+ )
+ )
+
+def demonstrate_generation():
+ """Example usage function"""
+ try:
+ print('=== Final Step: Generate Deliverable ===')
+
+ # This would come from either Path A (upload) or Path B (browse/select)
+ template_id = "0b1099cf-d7b9-41a4-822b-51b68fd4885a"
+
+ deliverable_data = create_deliverable_data(template_id)
+ deliverable = generate_deliverable(template_id, deliverable_data)
+
+ # Get download info (but don't actually download in demo)
+ print('\n=== Download Info ===')
+ print(f'Download URL: {BASE_URL}/deliverable/file/{deliverable["id"]}')
+
+ print('\n=== Generation Complete ===')
+ print('Deliverable generated successfully')
+
+ return {
+ 'deliverable': deliverable,
+ 'downloadUrl': f'{BASE_URL}/deliverable/file/{deliverable["id"]}'
+ }
+
+ except Exception as e:
+ print(f'Generation demonstration failed: {str(e)}')
+ exit(1)
+
+if __name__ == '__main__':
+ import sys
+ import os
+
+ if '--demo' in sys.argv:
+ # Run demonstration
+ demonstrate_generation()
+ else:
+ # Start FastAPI server
+ port = int(os.environ.get('PORT', 8003))
+ host = os.environ.get('HOST', '0.0.0.0')
+
+ print('🚀 TurboDocx Deliverable Generator Service started')
+ print(f'📡 Server listening on http://{host}:{port}')
+ print('\nAvailable endpoints:')
+ print(f' POST http://{host}:{port}/generate-deliverable')
+ print(f' GET http://{host}:{port}/download-deliverable/{{deliverable_id}}')
+ print(f' POST http://{host}:{port}/complete-workflow')
+ print(f' GET http://{host}:{port}/health')
+ print(f' GET http://{host}:{port}/generator-info')
+ print(f' GET http://{host}:{port}/docs (Interactive API docs)')
+ print(f' GET http://{host}:{port}/redoc (Alternative API docs)')
+
+ uvicorn.run(app, host=host, port=port)
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/fastify.js b/static/scripts/templates/api/generate-deliverable/fastify.js
new file mode 100644
index 0000000..ed273a2
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/fastify.js
@@ -0,0 +1,478 @@
+const fastify = require('fastify')({ logger: true });
+const axios = require('axios');
+const { v4: uuidv4 } = require('uuid');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+/**
+ * Final Step: Generate Deliverable (Both Paths Converge Here)
+ */
+
+/**
+ * Generate a deliverable document from template with variable substitution
+ */
+async function generateDeliverable(templateId, deliverableData) {
+ const url = `${BASE_URL}/deliverable`;
+
+ console.log('Generating deliverable...');
+ console.log(`Template ID: ${templateId}`);
+ console.log(`Deliverable Name: ${deliverableData.name}`);
+ console.log(`Variables: ${deliverableData.variables.length}`);
+
+ try {
+ const response = await axios.post(url, deliverableData, {
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client',
+ 'Content-Type': 'application/json'
+ }
+ });
+
+ // Parse JSON response
+ const deliverable = response.data.data.results.deliverable;
+
+ console.log('✅ Deliverable generated successfully!');
+ console.log(`Deliverable ID: ${deliverable.id}`);
+ console.log(`Created by: ${deliverable.createdBy}`);
+ console.log(`Created on: ${deliverable.createdOn}`);
+ console.log(`Template ID: ${deliverable.templateId}`);
+
+ return deliverable;
+ } catch (error) {
+ console.error('Deliverable generation failed:', error.response?.data || error.message);
+ throw error;
+ }
+}
+
+/**
+ * Download the generated deliverable file
+ */
+async function downloadDeliverable(deliverableId, filename) {
+ console.log(`Downloading file: ${filename}`);
+
+ const url = `${BASE_URL}/deliverable/file/${deliverableId}`;
+
+ try {
+ const response = await axios.get(url, {
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ },
+ responseType: 'stream'
+ });
+
+ console.log(`✅ File ready for download: ${filename}`);
+
+ const contentType = response.headers['content-type'] || 'N/A';
+ const contentLength = response.headers['content-length'] || 'N/A';
+
+ console.log(`📁 Content-Type: ${contentType}`);
+ console.log(`📊 Content-Length: ${contentLength} bytes`);
+
+ // In a real application, you would save the file
+ // const fs = require('fs');
+ // const writer = fs.createWriteStream(filename);
+ // response.data.pipe(writer);
+ //
+ // return new Promise((resolve, reject) => {
+ // writer.on('finish', resolve);
+ // writer.on('error', reject);
+ // });
+
+ return {
+ filename,
+ contentType,
+ contentLength,
+ downloadStream: response.data
+ };
+ } catch (error) {
+ console.error('Download failed:', error.response?.data || error.message);
+ throw error;
+ }
+}
+
+/**
+ * Create example deliverable data with complex variables
+ */
+function createDeliverableData(templateId) {
+ const now = new Date().toISOString();
+
+ return {
+ templateId,
+ name: 'Employee Contract - John Smith',
+ description: 'Employment contract for new senior software engineer',
+ variables: createComplexVariables(),
+ tags: ['hr', 'contract', 'employee', 'engineering'],
+ fonts: '[{"name":"Arial","usage":269}]',
+ defaultFont: 'Arial',
+ replaceFonts: true,
+ metadata: {
+ sessions: [
+ {
+ id: uuidv4(),
+ starttime: now,
+ endtime: now
+ }
+ ],
+ createdBy: 'HR Department',
+ documentType: 'Employment Contract',
+ version: 'v1.0'
+ }
+ };
+}
+
+/**
+ * Create complex variable structures for testing
+ */
+function createComplexVariables() {
+ return [
+ {
+ mimeType: 'text',
+ name: 'Employee Name',
+ placeholder: '{EmployeeName}',
+ text: 'John Smith',
+ allowRichTextInjection: 0,
+ autogenerated: false,
+ count: 1,
+ order: 1,
+ subvariables: [
+ {
+ placeholder: '{EmployeeName.Title}',
+ text: 'Senior Software Engineer'
+ },
+ {
+ placeholder: '{EmployeeName.StartDate}',
+ text: 'January 15, 2024'
+ }
+ ],
+ metadata: {
+ department: 'Engineering',
+ level: 'Senior'
+ },
+ aiPrompt: 'Generate a professional job description for a senior software engineer role'
+ },
+ {
+ mimeType: 'text',
+ name: 'Company Information',
+ placeholder: '{CompanyInfo}',
+ text: 'TechCorp Solutions Inc.',
+ allowRichTextInjection: 1,
+ autogenerated: false,
+ count: 1,
+ order: 2,
+ subvariables: [
+ {
+ placeholder: '{CompanyInfo.Address}',
+ text: '123 Innovation Drive, Tech City, TC 12345'
+ },
+ {
+ placeholder: '{CompanyInfo.Phone}',
+ text: '(555) 123-4567'
+ }
+ ],
+ metadata: {},
+ aiPrompt: ''
+ },
+ {
+ mimeType: 'text',
+ name: 'Project Assignments',
+ placeholder: '{ProjectAssignments}',
+ text: 'Multiple ongoing projects',
+ allowRichTextInjection: 0,
+ autogenerated: false,
+ count: 3,
+ order: 3,
+ subvariables: [],
+ variableStack: {
+ '0': {
+ text: 'Project Alpha - Backend Development',
+ subvariables: [
+ {
+ placeholder: '{ProjectAssignments.Duration}',
+ text: '6 months'
+ },
+ {
+ placeholder: '{ProjectAssignments.Priority}',
+ text: 'High'
+ }
+ ]
+ },
+ '1': {
+ text: 'Project Beta - API Integration',
+ subvariables: [
+ {
+ placeholder: '{ProjectAssignments.Duration}',
+ text: '3 months'
+ },
+ {
+ placeholder: '{ProjectAssignments.Priority}',
+ text: 'Medium'
+ }
+ ]
+ },
+ '2': {
+ text: 'Project Gamma - Code Review',
+ subvariables: [
+ {
+ placeholder: '{ProjectAssignments.Duration}',
+ text: 'Ongoing'
+ },
+ {
+ placeholder: '{ProjectAssignments.Priority}',
+ text: 'Low'
+ }
+ ]
+ }
+ },
+ metadata: {
+ totalProjects: 3,
+ estimatedHours: 1200
+ },
+ aiPrompt: 'Create detailed project descriptions for software development initiatives'
+ },
+ {
+ mimeType: 'text',
+ name: 'Benefits Package',
+ placeholder: '{BenefitsPackage}',
+ text: 'Comprehensive benefits including health, dental, vision, and 401k',
+ allowRichTextInjection: 1,
+ autogenerated: false,
+ count: 1,
+ order: 4,
+ subvariables: [
+ {
+ placeholder: '{BenefitsPackage.HealthInsurance}',
+ text: 'Full coverage health insurance with $500 deductible'
+ },
+ {
+ placeholder: '{BenefitsPackage.PTO}',
+ text: '25 days paid time off annually'
+ },
+ {
+ placeholder: '{BenefitsPackage.Retirement}',
+ text: '401k with 6% company match'
+ }
+ ],
+ metadata: {
+ packageValue: '$15,000 annually',
+ effective: 'First day of employment'
+ },
+ aiPrompt: 'Outline a competitive benefits package for a senior software engineer'
+ }
+ ];
+}
+
+// Fastify route handlers
+async function registerRoutes() {
+ // Generate deliverable route
+ fastify.post('/generate-deliverable', async (request, reply) => {
+ try {
+ const { templateId, deliverableData } = request.body;
+
+ if (!templateId) {
+ return reply.code(400).send({
+ error: 'templateId is required'
+ });
+ }
+
+ // Use provided data or create default data
+ const dataToUse = deliverableData || createDeliverableData(templateId);
+
+ const deliverable = await generateDeliverable(templateId, dataToUse);
+
+ reply.send({
+ success: true,
+ message: 'Deliverable generated successfully',
+ data: deliverable
+ });
+ } catch (error) {
+ console.error('Error generating deliverable:', error);
+ reply.code(500).send({
+ error: 'Deliverable generation failed',
+ message: error.message
+ });
+ }
+ });
+
+ // Download deliverable route
+ fastify.get('/download-deliverable/:deliverableId', async (request, reply) => {
+ try {
+ const { deliverableId } = request.params;
+ const { filename = `deliverable-${deliverableId}.docx` } = request.query;
+
+ const downloadInfo = await downloadDeliverable(deliverableId, filename);
+
+ // Set appropriate headers for file download
+ reply.header('Content-Type', downloadInfo.contentType);
+ reply.header('Content-Disposition', `attachment; filename="${filename}"`);
+ if (downloadInfo.contentLength && downloadInfo.contentLength !== 'N/A') {
+ reply.header('Content-Length', downloadInfo.contentLength);
+ }
+
+ // Stream the file data
+ reply.send(downloadInfo.downloadStream);
+ } catch (error) {
+ console.error('Error downloading deliverable:', error);
+ reply.code(500).send({
+ error: 'Download failed',
+ message: error.message
+ });
+ }
+ });
+
+ // Complete generation workflow route
+ fastify.post('/complete-workflow', async (request, reply) => {
+ try {
+ const { templateId, customVariables } = request.body;
+
+ if (!templateId) {
+ return reply.code(400).send({
+ error: 'templateId is required'
+ });
+ }
+
+ // Create deliverable data
+ let deliverableData = createDeliverableData(templateId);
+
+ // Override variables if custom ones provided
+ if (customVariables && Array.isArray(customVariables)) {
+ deliverableData.variables = customVariables;
+ }
+
+ // Generate deliverable
+ console.log('=== Generating Deliverable ===');
+ const deliverable = await generateDeliverable(templateId, deliverableData);
+
+ // Get download info (but don't actually download in this example)
+ console.log('\n=== Getting Download Info ===');
+ const downloadUrl = `${BASE_URL}/deliverable/file/${deliverable.id}`;
+
+ reply.send({
+ success: true,
+ message: 'Complete workflow executed successfully',
+ data: {
+ deliverable,
+ downloadUrl,
+ downloadEndpoint: `/download-deliverable/${deliverable.id}`,
+ summary: {
+ deliverableId: deliverable.id,
+ templateId: deliverable.templateId,
+ createdBy: deliverable.createdBy,
+ createdOn: deliverable.createdOn
+ }
+ }
+ });
+ } catch (error) {
+ console.error('Error in complete workflow:', error);
+ reply.code(500).send({
+ error: 'Complete workflow failed',
+ message: error.message
+ });
+ }
+ });
+
+ // Health check route
+ fastify.get('/health', async (request, reply) => {
+ reply.send({ status: 'healthy', service: 'deliverable-generator' });
+ });
+
+ // Service info route
+ fastify.get('/generator-info', async (request, reply) => {
+ reply.send({
+ service: 'TurboDocx Deliverable Generator Service',
+ endpoints: {
+ 'POST /generate-deliverable': 'Generate a deliverable from template',
+ 'GET /download-deliverable/:deliverableId': 'Download generated deliverable file',
+ 'POST /complete-workflow': 'Complete generation and download workflow',
+ 'GET /health': 'Service health check',
+ 'GET /generator-info': 'Service information'
+ },
+ configuration: {
+ baseUrl: BASE_URL,
+ hasToken: !!API_TOKEN && API_TOKEN !== 'YOUR_API_TOKEN',
+ hasOrgId: !!ORG_ID && ORG_ID !== 'YOUR_ORGANIZATION_ID'
+ }
+ });
+ });
+}
+
+// Example usage function
+async function demonstrateGeneration() {
+ try {
+ console.log('=== Final Step: Generate Deliverable ===');
+
+ // This would come from either Path A (upload) or Path B (browse/select)
+ const templateId = "0b1099cf-d7b9-41a4-822b-51b68fd4885a";
+
+ const deliverableData = createDeliverableData(templateId);
+ const deliverable = await generateDeliverable(templateId, deliverableData);
+
+ // Download the generated file
+ console.log('\n=== Download Generated File ===');
+ const downloadInfo = await downloadDeliverable(deliverable.id, `${deliverable.name}.docx`);
+
+ console.log('\n=== Generation Complete ===');
+ console.log('Deliverable generated and download info retrieved successfully');
+
+ return {
+ deliverable,
+ downloadInfo
+ };
+ } catch (error) {
+ console.error('Generation demonstration failed:', error.message);
+ process.exit(1);
+ }
+}
+
+// Server startup
+async function startServer() {
+ try {
+ await registerRoutes();
+
+ const port = process.env.PORT || 3003;
+ const host = process.env.HOST || '0.0.0.0';
+
+ await fastify.listen({ port, host });
+
+ console.log('🚀 TurboDocx Deliverable Generator Service started');
+ console.log(`📡 Server listening on http://${host}:${port}`);
+ console.log('\nAvailable endpoints:');
+ console.log(` POST http://${host}:${port}/generate-deliverable`);
+ console.log(` GET http://${host}:${port}/download-deliverable/:deliverableId`);
+ console.log(` POST http://${host}:${port}/complete-workflow`);
+ console.log(` GET http://${host}:${port}/health`);
+ console.log(` GET http://${host}:${port}/generator-info`);
+
+ } catch (error) {
+ fastify.log.error(error);
+ process.exit(1);
+ }
+}
+
+// Check if this file is being run directly
+if (require.main === module) {
+ const args = process.argv.slice(2);
+
+ if (args.includes('--demo')) {
+ // Run demonstration
+ demonstrateGeneration();
+ } else {
+ // Start server
+ startServer();
+ }
+}
+
+module.exports = {
+ generateDeliverable,
+ downloadDeliverable,
+ createDeliverableData,
+ createComplexVariables,
+ demonstrateGeneration,
+ startServer,
+ fastify
+};
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/flask.py b/static/scripts/templates/api/generate-deliverable/flask.py
new file mode 100644
index 0000000..b927b15
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/flask.py
@@ -0,0 +1,463 @@
+#!/usr/bin/env python3
+
+import requests
+import json
+import uuid
+from datetime import datetime
+from flask import Flask, request, jsonify, Response
+import io
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+app = Flask(__name__)
+
+def generate_deliverable(template_id, deliverable_data):
+ """
+ Final Step: Generate Deliverable (Both Paths Converge Here)
+ Generate a deliverable document from template with variable substitution
+ """
+ url = f"{BASE_URL}/deliverable"
+
+ print('Generating deliverable...')
+ print(f'Template ID: {template_id}')
+ print(f'Deliverable Name: {deliverable_data["name"]}')
+ print(f'Variables: {len(deliverable_data["variables"])}')
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client',
+ 'Content-Type': 'application/json'
+ }
+
+ try:
+ response = requests.post(url, json=deliverable_data, headers=headers)
+ response.raise_for_status()
+
+ # Parse JSON response
+ result = response.json()
+ deliverable = result['data']['results']['deliverable']
+
+ print('✅ Deliverable generated successfully!')
+ print(f'Deliverable ID: {deliverable["id"]}')
+ print(f'Created by: {deliverable["createdBy"]}')
+ print(f'Created on: {deliverable["createdOn"]}')
+ print(f'Template ID: {deliverable["templateId"]}')
+
+ return deliverable
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Deliverable generation failed: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+def download_deliverable(deliverable_id, filename):
+ """Download the generated deliverable file"""
+ print(f'Downloading file: {filename}')
+
+ url = f"{BASE_URL}/deliverable/file/{deliverable_id}"
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ try:
+ response = requests.get(url, headers=headers, stream=True)
+ response.raise_for_status()
+
+ print(f'✅ File ready for download: {filename}')
+
+ content_type = response.headers.get('Content-Type', 'N/A')
+ content_length = response.headers.get('Content-Length', 'N/A')
+
+ print(f'📁 Content-Type: {content_type}')
+ print(f'📊 Content-Length: {content_length} bytes')
+
+ # In a real application, you would save the file
+ # with open(filename, 'wb') as f:
+ # for chunk in response.iter_content(chunk_size=8192):
+ # f.write(chunk)
+
+ return {
+ 'filename': filename,
+ 'contentType': content_type,
+ 'contentLength': content_length,
+ 'downloadStream': response.content
+ }
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Download failed: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+def create_complex_variables():
+ """Create complex variable structures for testing"""
+ return [
+ {
+ 'mimeType': 'text',
+ 'name': 'Employee Name',
+ 'placeholder': '{EmployeeName}',
+ 'text': 'John Smith',
+ 'allowRichTextInjection': 0,
+ 'autogenerated': False,
+ 'count': 1,
+ 'order': 1,
+ 'subvariables': [
+ {
+ 'placeholder': '{EmployeeName.Title}',
+ 'text': 'Senior Software Engineer'
+ },
+ {
+ 'placeholder': '{EmployeeName.StartDate}',
+ 'text': 'January 15, 2024'
+ }
+ ],
+ 'metadata': {
+ 'department': 'Engineering',
+ 'level': 'Senior'
+ },
+ 'aiPrompt': 'Generate a professional job description for a senior software engineer role'
+ },
+ {
+ 'mimeType': 'text',
+ 'name': 'Company Information',
+ 'placeholder': '{CompanyInfo}',
+ 'text': 'TechCorp Solutions Inc.',
+ 'allowRichTextInjection': 1,
+ 'autogenerated': False,
+ 'count': 1,
+ 'order': 2,
+ 'subvariables': [
+ {
+ 'placeholder': '{CompanyInfo.Address}',
+ 'text': '123 Innovation Drive, Tech City, TC 12345'
+ },
+ {
+ 'placeholder': '{CompanyInfo.Phone}',
+ 'text': '(555) 123-4567'
+ }
+ ],
+ 'metadata': {},
+ 'aiPrompt': ''
+ },
+ {
+ 'mimeType': 'text',
+ 'name': 'Project Assignments',
+ 'placeholder': '{ProjectAssignments}',
+ 'text': 'Multiple ongoing projects',
+ 'allowRichTextInjection': 0,
+ 'autogenerated': False,
+ 'count': 3,
+ 'order': 3,
+ 'subvariables': [],
+ 'variableStack': {
+ '0': {
+ 'text': 'Project Alpha - Backend Development',
+ 'subvariables': [
+ {
+ 'placeholder': '{ProjectAssignments.Duration}',
+ 'text': '6 months'
+ },
+ {
+ 'placeholder': '{ProjectAssignments.Priority}',
+ 'text': 'High'
+ }
+ ]
+ },
+ '1': {
+ 'text': 'Project Beta - API Integration',
+ 'subvariables': [
+ {
+ 'placeholder': '{ProjectAssignments.Duration}',
+ 'text': '3 months'
+ },
+ {
+ 'placeholder': '{ProjectAssignments.Priority}',
+ 'text': 'Medium'
+ }
+ ]
+ },
+ '2': {
+ 'text': 'Project Gamma - Code Review',
+ 'subvariables': [
+ {
+ 'placeholder': '{ProjectAssignments.Duration}',
+ 'text': 'Ongoing'
+ },
+ {
+ 'placeholder': '{ProjectAssignments.Priority}',
+ 'text': 'Low'
+ }
+ ]
+ }
+ },
+ 'metadata': {
+ 'totalProjects': 3,
+ 'estimatedHours': 1200
+ },
+ 'aiPrompt': 'Create detailed project descriptions for software development initiatives'
+ },
+ {
+ 'mimeType': 'text',
+ 'name': 'Benefits Package',
+ 'placeholder': '{BenefitsPackage}',
+ 'text': 'Comprehensive benefits including health, dental, vision, and 401k',
+ 'allowRichTextInjection': 1,
+ 'autogenerated': False,
+ 'count': 1,
+ 'order': 4,
+ 'subvariables': [
+ {
+ 'placeholder': '{BenefitsPackage.HealthInsurance}',
+ 'text': 'Full coverage health insurance with $500 deductible'
+ },
+ {
+ 'placeholder': '{BenefitsPackage.PTO}',
+ 'text': '25 days paid time off annually'
+ },
+ {
+ 'placeholder': '{BenefitsPackage.Retirement}',
+ 'text': '401k with 6% company match'
+ }
+ ],
+ 'metadata': {
+ 'packageValue': '$15,000 annually',
+ 'effective': 'First day of employment'
+ },
+ 'aiPrompt': 'Outline a competitive benefits package for a senior software engineer'
+ }
+ ]
+
+def create_deliverable_data(template_id):
+ """Create example deliverable data with complex variables"""
+ now = datetime.utcnow().isoformat() + 'Z'
+
+ return {
+ 'templateId': template_id,
+ 'name': 'Employee Contract - John Smith',
+ 'description': 'Employment contract for new senior software engineer',
+ 'variables': create_complex_variables(),
+ 'tags': ['hr', 'contract', 'employee', 'engineering'],
+ 'fonts': '[{"name":"Arial","usage":269}]',
+ 'defaultFont': 'Arial',
+ 'replaceFonts': True,
+ 'metadata': {
+ 'sessions': [
+ {
+ 'id': str(uuid.uuid4()),
+ 'starttime': now,
+ 'endtime': now
+ }
+ ],
+ 'createdBy': 'HR Department',
+ 'documentType': 'Employment Contract',
+ 'version': 'v1.0'
+ }
+ }
+
+# Flask route handlers
+@app.route('/generate-deliverable', methods=['POST'])
+def generate_deliverable_endpoint():
+ """Generate deliverable endpoint"""
+ try:
+ data = request.get_json()
+
+ if not data or 'templateId' not in data:
+ return jsonify({
+ 'error': 'templateId is required'
+ }), 400
+
+ template_id = data['templateId']
+
+ # Use provided data or create default data
+ deliverable_data = data.get('deliverableData')
+ if not deliverable_data:
+ deliverable_data = create_deliverable_data(template_id)
+
+ deliverable = generate_deliverable(template_id, deliverable_data)
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Deliverable generated successfully',
+ 'data': deliverable
+ })
+
+ except Exception as e:
+ app.logger.error(f'Error generating deliverable: {str(e)}')
+ return jsonify({
+ 'error': 'Deliverable generation failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/download-deliverable/', methods=['GET'])
+def download_deliverable_endpoint(deliverable_id):
+ """Download deliverable endpoint"""
+ try:
+ filename = request.args.get('filename', f'deliverable-{deliverable_id}.docx')
+
+ download_info = download_deliverable(deliverable_id, filename)
+
+ # Create response with file stream
+ response = Response(
+ download_info['downloadStream'],
+ mimetype=download_info['contentType']
+ )
+ response.headers['Content-Disposition'] = f'attachment; filename="{filename}"'
+
+ if download_info['contentLength'] and download_info['contentLength'] != 'N/A':
+ response.headers['Content-Length'] = download_info['contentLength']
+
+ return response
+
+ except Exception as e:
+ app.logger.error(f'Error downloading deliverable: {str(e)}')
+ return jsonify({
+ 'error': 'Download failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/complete-workflow', methods=['POST'])
+def complete_workflow_endpoint():
+ """Complete generation workflow endpoint"""
+ try:
+ data = request.get_json()
+
+ if not data or 'templateId' not in data:
+ return jsonify({
+ 'error': 'templateId is required'
+ }), 400
+
+ template_id = data['templateId']
+ custom_variables = data.get('customVariables')
+
+ # Create deliverable data
+ deliverable_data = create_deliverable_data(template_id)
+
+ # Override variables if custom ones provided
+ if custom_variables and isinstance(custom_variables, list):
+ deliverable_data['variables'] = custom_variables
+
+ # Generate deliverable
+ print('=== Generating Deliverable ===')
+ deliverable = generate_deliverable(template_id, deliverable_data)
+
+ # Get download info (but don't actually download in this example)
+ print('\n=== Getting Download Info ===')
+ download_url = f"{BASE_URL}/deliverable/file/{deliverable['id']}"
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Complete workflow executed successfully',
+ 'data': {
+ 'deliverable': deliverable,
+ 'downloadUrl': download_url,
+ 'downloadEndpoint': f"/download-deliverable/{deliverable['id']}",
+ 'summary': {
+ 'deliverableId': deliverable['id'],
+ 'templateId': deliverable['templateId'],
+ 'createdBy': deliverable['createdBy'],
+ 'createdOn': deliverable['createdOn']
+ }
+ }
+ })
+
+ except Exception as e:
+ app.logger.error(f'Error in complete workflow: {str(e)}')
+ return jsonify({
+ 'error': 'Complete workflow failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/health', methods=['GET'])
+def health_check():
+ """Health check endpoint"""
+ return jsonify({
+ 'status': 'healthy',
+ 'service': 'deliverable-generator'
+ })
+
+@app.route('/generator-info', methods=['GET'])
+def generator_info():
+ """Service information endpoint"""
+ return jsonify({
+ 'service': 'TurboDocx Deliverable Generator Service',
+ 'endpoints': {
+ 'POST /generate-deliverable': 'Generate a deliverable from template',
+ 'GET /download-deliverable/': 'Download generated deliverable file',
+ 'POST /complete-workflow': 'Complete generation and download workflow',
+ 'GET /health': 'Service health check',
+ 'GET /generator-info': 'Service information'
+ },
+ 'configuration': {
+ 'baseUrl': BASE_URL,
+ 'hasToken': bool(API_TOKEN and API_TOKEN != 'YOUR_API_TOKEN'),
+ 'hasOrgId': bool(ORG_ID and ORG_ID != 'YOUR_ORGANIZATION_ID')
+ }
+ })
+
+def demonstrate_generation():
+ """Example usage function"""
+ try:
+ print('=== Final Step: Generate Deliverable ===')
+
+ # This would come from either Path A (upload) or Path B (browse/select)
+ template_id = "0b1099cf-d7b9-41a4-822b-51b68fd4885a"
+
+ deliverable_data = create_deliverable_data(template_id)
+ deliverable = generate_deliverable(template_id, deliverable_data)
+
+ # Download the generated file
+ print('\n=== Download Generated File ===')
+ download_info = download_deliverable(deliverable['id'], f"{deliverable['name']}.docx")
+
+ print('\n=== Generation Complete ===')
+ print('Deliverable generated and download info retrieved successfully')
+
+ return {
+ 'deliverable': deliverable,
+ 'downloadInfo': download_info
+ }
+
+ except Exception as e:
+ print(f'Generation demonstration failed: {str(e)}')
+ exit(1)
+
+if __name__ == '__main__':
+ import sys
+ import os
+
+ if '--demo' in sys.argv:
+ # Run demonstration
+ demonstrate_generation()
+ else:
+ # Start Flask server
+ port = int(os.environ.get('PORT', 5003))
+ host = os.environ.get('HOST', '0.0.0.0')
+
+ print('🚀 TurboDocx Deliverable Generator Service started')
+ print(f'📡 Server listening on http://{host}:{port}')
+ print('\nAvailable endpoints:')
+ print(f' POST http://{host}:{port}/generate-deliverable')
+ print(f' GET http://{host}:{port}/download-deliverable/')
+ print(f' POST http://{host}:{port}/complete-workflow')
+ print(f' GET http://{host}:{port}/health')
+ print(f' GET http://{host}:{port}/generator-info')
+
+ app.run(host=host, port=port, debug=False)
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/go.go b/static/scripts/templates/api/generate-deliverable/go.go
new file mode 100644
index 0000000..aec2435
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/go.go
@@ -0,0 +1,304 @@
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "time"
+)
+
+// Configuration - Update these values
+const (
+ API_TOKEN = "YOUR_API_TOKEN"
+ ORG_ID = "YOUR_ORGANIZATION_ID"
+ BASE_URL = "https://api.turbodocx.com"
+)
+
+// DeliverableRequest represents the request structure for deliverable generation
+type DeliverableRequest struct {
+ TemplateID string `json:"templateId"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Variables []Variable `json:"variables"`
+ Tags []string `json:"tags"`
+ Fonts string `json:"fonts"`
+ DefaultFont string `json:"defaultFont"`
+ ReplaceFonts bool `json:"replaceFonts"`
+ Metadata Metadata `json:"metadata"`
+}
+
+type Variable struct {
+ MimeType string `json:"mimeType"`
+ Name string `json:"name"`
+ Placeholder string `json:"placeholder"`
+ Text string `json:"text"`
+ AllowRichTextInjection int `json:"allowRichTextInjection"`
+ Autogenerated bool `json:"autogenerated"`
+ Count int `json:"count"`
+ Order int `json:"order"`
+ Subvariables []Subvariable `json:"subvariables"`
+ VariableMetadata VariableMetadata `json:"metadata"`
+ AIPrompt string `json:"aiPrompt"`
+}
+
+type Subvariable struct {
+ Placeholder string `json:"placeholder"`
+ Text string `json:"text"`
+}
+
+type VariableMetadata struct {
+ Department string `json:"department"`
+ Level string `json:"level"`
+}
+
+type Metadata struct {
+ Sessions []Session `json:"sessions"`
+ CreatedBy string `json:"createdBy"`
+ DocumentType string `json:"documentType"`
+ Version string `json:"version"`
+}
+
+type Session struct {
+ ID string `json:"id"`
+ StartTime string `json:"starttime"`
+ EndTime string `json:"endtime"`
+}
+
+// DeliverableResponse represents the API response structure
+type DeliverableResponse struct {
+ Data struct {
+ Results struct {
+ Deliverable struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ CreatedBy string `json:"createdBy"`
+ CreatedOn string `json:"createdOn"`
+ TemplateID string `json:"templateId"`
+ } `json:"deliverable"`
+ } `json:"results"`
+ } `json:"data"`
+}
+
+/**
+ * Final Step: Generate Deliverable (Both Paths Converge Here)
+ */
+func main() {
+ fmt.Println("=== Final Step: Generate Deliverable ===")
+
+ // This would come from either Path A (upload) or Path B (browse/select)
+ templateID := "0b1099cf-d7b9-41a4-822b-51b68fd4885a"
+
+ deliverableData := createDeliverableData(templateID)
+ deliverable, err := generateDeliverable(deliverableData)
+ if err != nil {
+ fmt.Printf("Deliverable generation failed: %v\n", err)
+ return
+ }
+
+ // Download the generated file
+ fmt.Println("\n=== Download Generated File ===")
+ err = downloadDeliverable(deliverable.Data.Results.Deliverable.ID,
+ deliverable.Data.Results.Deliverable.Name+".docx")
+ if err != nil {
+ fmt.Printf("Download failed: %v\n", err)
+ return
+ }
+}
+
+/**
+ * Generate a deliverable document from template with variable substitution
+ */
+func generateDeliverable(deliverableData DeliverableRequest) (*DeliverableResponse, error) {
+ fmt.Println("Generating deliverable...")
+ fmt.Printf("Template ID: %s\n", deliverableData.TemplateID)
+ fmt.Printf("Deliverable Name: %s\n", deliverableData.Name)
+ fmt.Printf("Variables: %d\n", len(deliverableData.Variables))
+
+ // Convert to JSON
+ jsonData, err := json.Marshal(deliverableData)
+ if err != nil {
+ return nil, fmt.Errorf("failed to marshal JSON: %v", err)
+ }
+
+ // Create request
+ req, err := http.NewRequest("POST", BASE_URL+"/deliverable", bytes.NewBuffer(jsonData))
+ if err != nil {
+ return nil, fmt.Errorf("failed to create request: %v", err)
+ }
+
+ // Set headers
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+ req.Header.Set("Content-Type", "application/json")
+
+ // Make request
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, fmt.Errorf("HTTP error %d: %s", resp.StatusCode, string(body))
+ }
+
+ // Parse response
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %v", err)
+ }
+
+ var result DeliverableResponse
+ err = json.Unmarshal(body, &result)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse JSON: %v", err)
+ }
+
+ deliverable := result.Data.Results.Deliverable
+ fmt.Println("✅ Deliverable generated successfully!")
+ fmt.Printf("Deliverable ID: %s\n", deliverable.ID)
+ fmt.Printf("Created by: %s\n", deliverable.CreatedBy)
+ fmt.Printf("Created on: %s\n", deliverable.CreatedOn)
+ fmt.Printf("Template ID: %s\n", deliverable.TemplateID)
+
+ return &result, nil
+}
+
+/**
+ * Download the generated deliverable file
+ */
+func downloadDeliverable(deliverableID, filename string) error {
+ fmt.Printf("Downloading file: %s\n", filename)
+
+ requestURL := fmt.Sprintf("%s/deliverable/file/%s", BASE_URL, deliverableID)
+
+ req, err := http.NewRequest("GET", requestURL, nil)
+ if err != nil {
+ return fmt.Errorf("failed to create request: %v", err)
+ }
+
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("download failed: %d", resp.StatusCode)
+ }
+
+ fmt.Printf("✅ File ready for download: %s\n", filename)
+
+ contentType := resp.Header.Get("Content-Type")
+ if contentType == "" {
+ contentType = "N/A"
+ }
+
+ contentLength := resp.Header.Get("Content-Length")
+ if contentLength == "" {
+ contentLength = "N/A"
+ }
+
+ fmt.Printf("📁 Content-Type: %s\n", contentType)
+ fmt.Printf("📊 Content-Length: %s bytes\n", contentLength)
+
+ // In a real application, you would save the file
+ // body, err := io.ReadAll(resp.Body)
+ // if err != nil {
+ // return fmt.Errorf("failed to read file content: %v", err)
+ // }
+ // err = os.WriteFile(filename, body, 0644)
+ // if err != nil {
+ // return fmt.Errorf("failed to save file: %v", err)
+ // }
+
+ return nil
+}
+
+/**
+ * Create example deliverable data with complex variables
+ */
+func createDeliverableData(templateID string) DeliverableRequest {
+ now := time.Now().UTC().Format(time.RFC3339)
+
+ return DeliverableRequest{
+ TemplateID: templateID,
+ Name: "Employee Contract - John Smith",
+ Description: "Employment contract for new senior software engineer",
+ Variables: []Variable{
+ {
+ MimeType: "text",
+ Name: "Employee Name",
+ Placeholder: "{EmployeeName}",
+ Text: "John Smith",
+ AllowRichTextInjection: 0,
+ Autogenerated: false,
+ Count: 1,
+ Order: 1,
+ Subvariables: []Subvariable{
+ {
+ Placeholder: "{EmployeeName.Title}",
+ Text: "Senior Software Engineer",
+ },
+ {
+ Placeholder: "{EmployeeName.StartDate}",
+ Text: "January 15, 2024",
+ },
+ },
+ VariableMetadata: VariableMetadata{
+ Department: "Engineering",
+ Level: "Senior",
+ },
+ AIPrompt: "Generate a professional job description for a senior software engineer role",
+ },
+ {
+ MimeType: "text",
+ Name: "Company Information",
+ Placeholder: "{CompanyInfo}",
+ Text: "TechCorp Solutions Inc.",
+ AllowRichTextInjection: 1,
+ Autogenerated: false,
+ Count: 1,
+ Order: 2,
+ Subvariables: []Subvariable{
+ {
+ Placeholder: "{CompanyInfo.Address}",
+ Text: "123 Innovation Drive, Tech City, TC 12345",
+ },
+ {
+ Placeholder: "{CompanyInfo.Phone}",
+ Text: "(555) 123-4567",
+ },
+ },
+ VariableMetadata: VariableMetadata{},
+ AIPrompt: "",
+ },
+ },
+ Tags: []string{"hr", "contract", "employee", "engineering"},
+ Fonts: `[{"name":"Arial","usage":269}]`,
+ DefaultFont: "Arial",
+ ReplaceFonts: true,
+ Metadata: Metadata{
+ Sessions: []Session{
+ {
+ ID: fmt.Sprintf("go-session-%d", time.Now().Unix()),
+ StartTime: now,
+ EndTime: now,
+ },
+ },
+ CreatedBy: "HR Department",
+ DocumentType: "Employment Contract",
+ Version: "v1.0",
+ },
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/java.java b/static/scripts/templates/api/generate-deliverable/java.java
new file mode 100644
index 0000000..9d3ebb6
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/java.java
@@ -0,0 +1,228 @@
+import java.io.*;
+import java.net.URI;
+import java.net.http.*;
+import java.time.Instant;
+import java.util.UUID;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+/**
+ * Final Step: Generate Deliverable (Both Paths Converge Here)
+ */
+public class DeliverableGenerator {
+ // Configuration - Update these values
+ private static final String API_TOKEN = "YOUR_API_TOKEN";
+ private static final String ORG_ID = "YOUR_ORGANIZATION_ID";
+ private static final String BASE_URL = "https://api.turbodocx.com";
+
+ public static void main(String[] args) throws Exception {
+ try {
+ System.out.println("=== Final Step: Generate Deliverable ===");
+
+ // This would come from either Path A (upload) or Path B (browse/select)
+ String templateId = "0b1099cf-d7b9-41a4-822b-51b68fd4885a";
+
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode deliverableData = mapper.createObjectNode();
+ deliverableData.put("name", "Employee Contract - John Smith");
+ deliverableData.put("description", "Employment contract for new senior software engineer");
+ deliverableData.set("variables", createComplexVariables(mapper));
+
+ ArrayNode tags = mapper.createArrayNode();
+ tags.add("hr").add("contract").add("employee").add("engineering");
+ deliverableData.set("tags", tags);
+
+ deliverableData.put("fonts", "[{\"name\":\"Arial\",\"usage\":269}]");
+ deliverableData.put("defaultFont", "Arial");
+ deliverableData.put("replaceFonts", true);
+ deliverableData.set("metadata", createMetadata(mapper));
+
+ JsonNode deliverable = generateDeliverable(templateId, deliverableData);
+
+ // Download the generated file
+ System.out.println("\n=== Download Generated File ===");
+ downloadDeliverable(deliverable.get("id").asText(), deliverable.get("name").asText() + ".docx");
+
+ } catch (Exception e) {
+ System.err.println("Deliverable generation failed: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Generate a deliverable document from template with variable substitution
+ */
+ private static JsonNode generateDeliverable(String templateId, ObjectNode deliverableData) throws Exception {
+ HttpClient client = HttpClient.newHttpClient();
+ ObjectMapper mapper = new ObjectMapper();
+
+ ObjectNode payload = mapper.createObjectNode();
+ payload.put("templateId", templateId);
+ payload.put("name", deliverableData.get("name").asText());
+ payload.put("description", deliverableData.get("description").asText());
+ payload.set("variables", deliverableData.get("variables"));
+ payload.set("tags", deliverableData.get("tags"));
+ payload.put("fonts", deliverableData.get("fonts").asText());
+ payload.put("defaultFont", deliverableData.get("defaultFont").asText());
+ payload.put("replaceFonts", deliverableData.get("replaceFonts").asBoolean());
+ payload.set("metadata", deliverableData.get("metadata"));
+
+ System.out.println("Generating deliverable...");
+ System.out.println("Template ID: " + templateId);
+ System.out.println("Deliverable Name: " + payload.get("name").asText());
+ System.out.println("Variables: " + payload.get("variables").size());
+
+ String jsonBody = mapper.writeValueAsString(payload);
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(BASE_URL + "/deliverable"))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .header("Content-Type", "application/json")
+ .POST(HttpRequest.BodyPublishers.ofString(jsonBody))
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("HTTP error " + response.statusCode() + ": " + response.body());
+ }
+
+ JsonNode result = mapper.readTree(response.body());
+ JsonNode deliverable = result.get("data").get("results").get("deliverable");
+
+ System.out.println("✅ Deliverable generated successfully!");
+ System.out.println("Deliverable ID: " + deliverable.get("id").asText());
+ System.out.println("Created by: " + deliverable.get("createdBy").asText());
+ System.out.println("Created on: " + deliverable.get("createdOn").asText());
+ System.out.println("Template ID: " + deliverable.get("templateId").asText());
+
+ return deliverable;
+ }
+
+ /**
+ * Download the generated deliverable file
+ */
+ private static void downloadDeliverable(String deliverableId, String filename) throws Exception {
+ HttpClient client = HttpClient.newHttpClient();
+
+ System.out.println("Downloading file: " + filename);
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(BASE_URL + "/deliverable/file/" + deliverableId))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .GET()
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("Download failed: " + response.statusCode());
+ }
+
+ System.out.println("✅ File ready for download: " + filename);
+ String contentType = response.headers().firstValue("content-type").orElse("N/A");
+ String contentLength = response.headers().firstValue("content-length").orElse("N/A");
+ System.out.println("📁 Content-Type: " + contentType);
+ System.out.println("📊 Content-Length: " + contentLength + " bytes");
+
+ // In a real application, you would save the file
+ // Files.write(Paths.get(filename), response.body().getBytes());
+ }
+
+ /**
+ * Example: Complex variable structure with all features
+ */
+ private static ArrayNode createComplexVariables(ObjectMapper mapper) {
+ ArrayNode variables = mapper.createArrayNode();
+
+ // Employee variable with subvariables
+ ObjectNode employeeVar = mapper.createObjectNode();
+ employeeVar.put("mimeType", "text");
+ employeeVar.put("name", "Employee Name");
+ employeeVar.put("placeholder", "{EmployeeName}");
+ employeeVar.put("text", "John Smith");
+ employeeVar.put("allowRichTextInjection", 0);
+ employeeVar.put("autogenerated", false);
+ employeeVar.put("count", 1);
+ employeeVar.put("order", 1);
+
+ ArrayNode empSubVars = mapper.createArrayNode();
+ ObjectNode titleSub = mapper.createObjectNode();
+ titleSub.put("placeholder", "{EmployeeName.Title}");
+ titleSub.put("text", "Senior Software Engineer");
+ empSubVars.add(titleSub);
+
+ ObjectNode dateSub = mapper.createObjectNode();
+ dateSub.put("placeholder", "{EmployeeName.StartDate}");
+ dateSub.put("text", "January 15, 2024");
+ empSubVars.add(dateSub);
+
+ employeeVar.set("subvariables", empSubVars);
+
+ ObjectNode empMetadata = mapper.createObjectNode();
+ empMetadata.put("department", "Engineering");
+ empMetadata.put("level", "Senior");
+ employeeVar.set("metadata", empMetadata);
+
+ employeeVar.put("aiPrompt", "Generate a professional job description for a senior software engineer role");
+
+ variables.add(employeeVar);
+
+ // Company Information variable
+ ObjectNode companyVar = mapper.createObjectNode();
+ companyVar.put("mimeType", "text");
+ companyVar.put("name", "Company Information");
+ companyVar.put("placeholder", "{CompanyInfo}");
+ companyVar.put("text", "TechCorp Solutions Inc.");
+ companyVar.put("allowRichTextInjection", 1);
+ companyVar.put("autogenerated", false);
+ companyVar.put("count", 1);
+ companyVar.put("order", 2);
+
+ ArrayNode compSubVars = mapper.createArrayNode();
+ ObjectNode addressSub = mapper.createObjectNode();
+ addressSub.put("placeholder", "{CompanyInfo.Address}");
+ addressSub.put("text", "123 Innovation Drive, Tech City, TC 12345");
+ compSubVars.add(addressSub);
+
+ ObjectNode phoneSub = mapper.createObjectNode();
+ phoneSub.put("placeholder", "{CompanyInfo.Phone}");
+ phoneSub.put("text", "(555) 123-4567");
+ compSubVars.add(phoneSub);
+
+ companyVar.set("subvariables", compSubVars);
+ companyVar.set("metadata", mapper.createObjectNode());
+ companyVar.put("aiPrompt", "");
+
+ variables.add(companyVar);
+
+ return variables;
+ }
+
+ /**
+ * Create metadata for the deliverable
+ */
+ private static ObjectNode createMetadata(ObjectMapper mapper) {
+ ObjectNode metadata = mapper.createObjectNode();
+
+ ArrayNode sessions = mapper.createArrayNode();
+ ObjectNode session = mapper.createObjectNode();
+ session.put("id", UUID.randomUUID().toString());
+ session.put("starttime", Instant.now().toString());
+ session.put("endtime", Instant.now().toString());
+ sessions.add(session);
+
+ metadata.set("sessions", sessions);
+ metadata.put("createdBy", "HR Department");
+ metadata.put("documentType", "Employment Contract");
+ metadata.put("version", "v1.0");
+
+ return metadata;
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/nodejs/express.js b/static/scripts/templates/api/generate-deliverable/nodejs/express.js
new file mode 100644
index 0000000..f61d91d
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/nodejs/express.js
@@ -0,0 +1,320 @@
+const fetch = require('node-fetch');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+// Final Step: Generate Deliverable (Both Paths Converge Here)
+
+/**
+ * Generate a deliverable document from template with variable substitution
+ */
+async function generateDeliverable(templateId, deliverableData) {
+ try {
+ const url = `${BASE_URL}/deliverable`;
+
+ const payload = {
+ templateId: templateId,
+ name: deliverableData.name,
+ description: deliverableData.description || '',
+ variables: deliverableData.variables,
+ tags: deliverableData.tags || [],
+ fonts: deliverableData.fonts || '[]',
+ defaultFont: deliverableData.defaultFont || 'Arial',
+ replaceFonts: deliverableData.replaceFonts !== undefined ? deliverableData.replaceFonts : true,
+ metadata: deliverableData.metadata || {
+ sessions: [{
+ id: generateSessionId(),
+ starttime: new Date().toISOString(),
+ endtime: new Date().toISOString()
+ }]
+ }
+ };
+
+ console.log('Generating deliverable...');
+ console.log(`Template ID: ${templateId}`);
+ console.log(`Deliverable Name: ${payload.name}`);
+ console.log(`Variables: ${payload.variables.length}`);
+
+ const response = await fetch(url, {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client',
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(payload)
+ });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+ throw new Error(`HTTP error! status: ${response.status}, body: ${errorText}`);
+ }
+
+ const result = await response.json();
+ const deliverable = result.data.results.deliverable;
+
+ console.log('✅ Deliverable generated successfully!');
+ console.log(`Deliverable ID: ${deliverable.id}`);
+ console.log(`Created by: ${deliverable.createdBy}`);
+ console.log(`Created on: ${deliverable.createdOn}`);
+ console.log(`Template ID: ${deliverable.templateId}`);
+
+ return deliverable;
+
+ } catch (error) {
+ console.error('Error generating deliverable:', error);
+ throw error;
+ }
+}
+
+/**
+ * Example: Complex variable structure with all features
+ */
+function createComplexVariables() {
+ return [
+ {
+ mimeType: "text",
+ name: "Employee Name",
+ placeholder: "{EmployeeName}",
+ text: "John Smith",
+ allowRichTextInjection: 0,
+ autogenerated: false,
+ count: 1,
+ order: 1,
+ subvariables: [
+ {
+ placeholder: "{EmployeeName.Title}",
+ text: "Senior Software Engineer"
+ },
+ {
+ placeholder: "{EmployeeName.StartDate}",
+ text: "January 15, 2024"
+ }
+ ],
+ metadata: {
+ department: "Engineering",
+ level: "Senior"
+ },
+ aiPrompt: "Generate a professional job description for a senior software engineer role"
+ },
+ {
+ mimeType: "text",
+ name: "Company Information",
+ placeholder: "{CompanyInfo}",
+ text: "TechCorp Solutions Inc.",
+ allowRichTextInjection: 1,
+ autogenerated: false,
+ count: 1,
+ order: 2,
+ subvariables: [
+ {
+ placeholder: "{CompanyInfo.Address}",
+ text: "123 Innovation Drive, Tech City, TC 12345"
+ },
+ {
+ placeholder: "{CompanyInfo.Phone}",
+ text: "(555) 123-4567"
+ }
+ ],
+ metadata: {},
+ aiPrompt: ""
+ },
+ {
+ mimeType: "text",
+ name: "Project Assignments",
+ placeholder: "{ProjectAssignments}",
+ text: "Multiple ongoing projects",
+ allowRichTextInjection: 0,
+ autogenerated: false,
+ count: 3,
+ order: 3,
+ subvariables: [],
+ variableStack: {
+ "0": {
+ text: "Project Alpha - Backend Development",
+ subvariables: [
+ {
+ placeholder: "{ProjectAssignments.Duration}",
+ text: "6 months"
+ },
+ {
+ placeholder: "{ProjectAssignments.Priority}",
+ text: "High"
+ }
+ ]
+ },
+ "1": {
+ text: "Project Beta - API Integration",
+ subvariables: [
+ {
+ placeholder: "{ProjectAssignments.Duration}",
+ text: "3 months"
+ },
+ {
+ placeholder: "{ProjectAssignments.Priority}",
+ text: "Medium"
+ }
+ ]
+ },
+ "2": {
+ text: "Project Gamma - Code Review",
+ subvariables: [
+ {
+ placeholder: "{ProjectAssignments.Duration}",
+ text: "Ongoing"
+ },
+ {
+ placeholder: "{ProjectAssignments.Priority}",
+ text: "Low"
+ }
+ ]
+ }
+ },
+ metadata: {
+ totalProjects: 3,
+ estimatedHours: 1200
+ },
+ aiPrompt: "Create detailed project descriptions for software development initiatives"
+ },
+ {
+ mimeType: "text",
+ name: "Benefits Package",
+ placeholder: "{BenefitsPackage}",
+ text: "Comprehensive benefits including health, dental, vision, and 401k",
+ allowRichTextInjection: 1,
+ autogenerated: false,
+ count: 1,
+ order: 4,
+ subvariables: [
+ {
+ placeholder: "{BenefitsPackage.HealthInsurance}",
+ text: "Full coverage health insurance with $500 deductible"
+ },
+ {
+ placeholder: "{BenefitsPackage.PTO}",
+ text: "25 days paid time off annually"
+ },
+ {
+ placeholder: "{BenefitsPackage.Retirement}",
+ text: "401k with 6% company match"
+ }
+ ],
+ metadata: {
+ packageValue: "$15,000 annually",
+ effective: "First day of employment"
+ },
+ aiPrompt: "Outline a competitive benefits package for a senior software engineer"
+ }
+ ];
+}
+
+/**
+ * Generate a session ID for metadata tracking
+ */
+function generateSessionId() {
+ return Math.random().toString(36).substr(2, 9) + '-' +
+ Math.random().toString(36).substr(2, 9) + '-' +
+ Math.random().toString(36).substr(2, 9);
+}
+
+/**
+ * Download the generated deliverable file
+ */
+async function downloadDeliverable(deliverableId, filename) {
+ try {
+ const url = `${BASE_URL}/deliverable/file/${deliverableId}`;
+
+ console.log(`Downloading file: ${filename}`);
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`Download failed: ${response.status}`);
+ }
+
+ console.log(`✅ File ready for download: ${filename}`);
+ console.log(`📁 Content-Type: ${response.headers.get('content-type')}`);
+ console.log(`📊 Content-Length: ${response.headers.get('content-length')} bytes`);
+
+ // In a real application, you would save the file
+ // const buffer = await response.buffer();
+ // fs.writeFileSync(filename, buffer);
+
+ return {
+ filename,
+ contentType: response.headers.get('content-type'),
+ contentLength: response.headers.get('content-length')
+ };
+
+ } catch (error) {
+ console.error('Error downloading file:', error);
+ throw error;
+ }
+}
+
+/**
+ * Example usage with realistic data
+ */
+async function exampleGenerateDeliverable() {
+ try {
+ // This would come from either Path A (upload) or Path B (browse/select)
+ const templateId = "0b1099cf-d7b9-41a4-822b-51b68fd4885a";
+
+ const deliverableData = {
+ name: "Employee Contract - John Smith",
+ description: "Employment contract for new senior software engineer",
+ variables: createComplexVariables(),
+ tags: ["hr", "contract", "employee", "engineering"],
+ fonts: '[{"name":"Arial","usage":269}]',
+ defaultFont: "Arial",
+ replaceFonts: true,
+ metadata: {
+ sessions: [
+ {
+ id: "cf1cd4b9-6fdc-47e3-b59d-594cd6564501",
+ starttime: "2024-01-15T14:12:10.721Z",
+ endtime: "2024-01-15T14:13:45.724Z"
+ }
+ ],
+ createdBy: "HR Department",
+ documentType: "Employment Contract",
+ version: "v1.0"
+ }
+ };
+
+ console.log('=== Final Step: Generate Deliverable ===');
+ const deliverable = await generateDeliverable(templateId, deliverableData);
+
+ // Download the generated file
+ console.log('\n=== Download Generated File ===');
+ await downloadDeliverable(deliverable.id, `${deliverable.name}.docx`);
+
+ return deliverable;
+
+ } catch (error) {
+ console.error('Deliverable generation failed:', error.message);
+ }
+}
+
+// Export functions for use in other modules
+module.exports = {
+ generateDeliverable,
+ downloadDeliverable,
+ createComplexVariables,
+ exampleGenerateDeliverable
+};
+
+// Run example if script is executed directly
+if (require.main === module) {
+ exampleGenerateDeliverable();
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/nodejs/fastify.js b/static/scripts/templates/api/generate-deliverable/nodejs/fastify.js
new file mode 100644
index 0000000..f61d91d
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/nodejs/fastify.js
@@ -0,0 +1,320 @@
+const fetch = require('node-fetch');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+
+// Final Step: Generate Deliverable (Both Paths Converge Here)
+
+/**
+ * Generate a deliverable document from template with variable substitution
+ */
+async function generateDeliverable(templateId, deliverableData) {
+ try {
+ const url = `${BASE_URL}/deliverable`;
+
+ const payload = {
+ templateId: templateId,
+ name: deliverableData.name,
+ description: deliverableData.description || '',
+ variables: deliverableData.variables,
+ tags: deliverableData.tags || [],
+ fonts: deliverableData.fonts || '[]',
+ defaultFont: deliverableData.defaultFont || 'Arial',
+ replaceFonts: deliverableData.replaceFonts !== undefined ? deliverableData.replaceFonts : true,
+ metadata: deliverableData.metadata || {
+ sessions: [{
+ id: generateSessionId(),
+ starttime: new Date().toISOString(),
+ endtime: new Date().toISOString()
+ }]
+ }
+ };
+
+ console.log('Generating deliverable...');
+ console.log(`Template ID: ${templateId}`);
+ console.log(`Deliverable Name: ${payload.name}`);
+ console.log(`Variables: ${payload.variables.length}`);
+
+ const response = await fetch(url, {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client',
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(payload)
+ });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+ throw new Error(`HTTP error! status: ${response.status}, body: ${errorText}`);
+ }
+
+ const result = await response.json();
+ const deliverable = result.data.results.deliverable;
+
+ console.log('✅ Deliverable generated successfully!');
+ console.log(`Deliverable ID: ${deliverable.id}`);
+ console.log(`Created by: ${deliverable.createdBy}`);
+ console.log(`Created on: ${deliverable.createdOn}`);
+ console.log(`Template ID: ${deliverable.templateId}`);
+
+ return deliverable;
+
+ } catch (error) {
+ console.error('Error generating deliverable:', error);
+ throw error;
+ }
+}
+
+/**
+ * Example: Complex variable structure with all features
+ */
+function createComplexVariables() {
+ return [
+ {
+ mimeType: "text",
+ name: "Employee Name",
+ placeholder: "{EmployeeName}",
+ text: "John Smith",
+ allowRichTextInjection: 0,
+ autogenerated: false,
+ count: 1,
+ order: 1,
+ subvariables: [
+ {
+ placeholder: "{EmployeeName.Title}",
+ text: "Senior Software Engineer"
+ },
+ {
+ placeholder: "{EmployeeName.StartDate}",
+ text: "January 15, 2024"
+ }
+ ],
+ metadata: {
+ department: "Engineering",
+ level: "Senior"
+ },
+ aiPrompt: "Generate a professional job description for a senior software engineer role"
+ },
+ {
+ mimeType: "text",
+ name: "Company Information",
+ placeholder: "{CompanyInfo}",
+ text: "TechCorp Solutions Inc.",
+ allowRichTextInjection: 1,
+ autogenerated: false,
+ count: 1,
+ order: 2,
+ subvariables: [
+ {
+ placeholder: "{CompanyInfo.Address}",
+ text: "123 Innovation Drive, Tech City, TC 12345"
+ },
+ {
+ placeholder: "{CompanyInfo.Phone}",
+ text: "(555) 123-4567"
+ }
+ ],
+ metadata: {},
+ aiPrompt: ""
+ },
+ {
+ mimeType: "text",
+ name: "Project Assignments",
+ placeholder: "{ProjectAssignments}",
+ text: "Multiple ongoing projects",
+ allowRichTextInjection: 0,
+ autogenerated: false,
+ count: 3,
+ order: 3,
+ subvariables: [],
+ variableStack: {
+ "0": {
+ text: "Project Alpha - Backend Development",
+ subvariables: [
+ {
+ placeholder: "{ProjectAssignments.Duration}",
+ text: "6 months"
+ },
+ {
+ placeholder: "{ProjectAssignments.Priority}",
+ text: "High"
+ }
+ ]
+ },
+ "1": {
+ text: "Project Beta - API Integration",
+ subvariables: [
+ {
+ placeholder: "{ProjectAssignments.Duration}",
+ text: "3 months"
+ },
+ {
+ placeholder: "{ProjectAssignments.Priority}",
+ text: "Medium"
+ }
+ ]
+ },
+ "2": {
+ text: "Project Gamma - Code Review",
+ subvariables: [
+ {
+ placeholder: "{ProjectAssignments.Duration}",
+ text: "Ongoing"
+ },
+ {
+ placeholder: "{ProjectAssignments.Priority}",
+ text: "Low"
+ }
+ ]
+ }
+ },
+ metadata: {
+ totalProjects: 3,
+ estimatedHours: 1200
+ },
+ aiPrompt: "Create detailed project descriptions for software development initiatives"
+ },
+ {
+ mimeType: "text",
+ name: "Benefits Package",
+ placeholder: "{BenefitsPackage}",
+ text: "Comprehensive benefits including health, dental, vision, and 401k",
+ allowRichTextInjection: 1,
+ autogenerated: false,
+ count: 1,
+ order: 4,
+ subvariables: [
+ {
+ placeholder: "{BenefitsPackage.HealthInsurance}",
+ text: "Full coverage health insurance with $500 deductible"
+ },
+ {
+ placeholder: "{BenefitsPackage.PTO}",
+ text: "25 days paid time off annually"
+ },
+ {
+ placeholder: "{BenefitsPackage.Retirement}",
+ text: "401k with 6% company match"
+ }
+ ],
+ metadata: {
+ packageValue: "$15,000 annually",
+ effective: "First day of employment"
+ },
+ aiPrompt: "Outline a competitive benefits package for a senior software engineer"
+ }
+ ];
+}
+
+/**
+ * Generate a session ID for metadata tracking
+ */
+function generateSessionId() {
+ return Math.random().toString(36).substr(2, 9) + '-' +
+ Math.random().toString(36).substr(2, 9) + '-' +
+ Math.random().toString(36).substr(2, 9);
+}
+
+/**
+ * Download the generated deliverable file
+ */
+async function downloadDeliverable(deliverableId, filename) {
+ try {
+ const url = `${BASE_URL}/deliverable/file/${deliverableId}`;
+
+ console.log(`Downloading file: ${filename}`);
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`Download failed: ${response.status}`);
+ }
+
+ console.log(`✅ File ready for download: ${filename}`);
+ console.log(`📁 Content-Type: ${response.headers.get('content-type')}`);
+ console.log(`📊 Content-Length: ${response.headers.get('content-length')} bytes`);
+
+ // In a real application, you would save the file
+ // const buffer = await response.buffer();
+ // fs.writeFileSync(filename, buffer);
+
+ return {
+ filename,
+ contentType: response.headers.get('content-type'),
+ contentLength: response.headers.get('content-length')
+ };
+
+ } catch (error) {
+ console.error('Error downloading file:', error);
+ throw error;
+ }
+}
+
+/**
+ * Example usage with realistic data
+ */
+async function exampleGenerateDeliverable() {
+ try {
+ // This would come from either Path A (upload) or Path B (browse/select)
+ const templateId = "0b1099cf-d7b9-41a4-822b-51b68fd4885a";
+
+ const deliverableData = {
+ name: "Employee Contract - John Smith",
+ description: "Employment contract for new senior software engineer",
+ variables: createComplexVariables(),
+ tags: ["hr", "contract", "employee", "engineering"],
+ fonts: '[{"name":"Arial","usage":269}]',
+ defaultFont: "Arial",
+ replaceFonts: true,
+ metadata: {
+ sessions: [
+ {
+ id: "cf1cd4b9-6fdc-47e3-b59d-594cd6564501",
+ starttime: "2024-01-15T14:12:10.721Z",
+ endtime: "2024-01-15T14:13:45.724Z"
+ }
+ ],
+ createdBy: "HR Department",
+ documentType: "Employment Contract",
+ version: "v1.0"
+ }
+ };
+
+ console.log('=== Final Step: Generate Deliverable ===');
+ const deliverable = await generateDeliverable(templateId, deliverableData);
+
+ // Download the generated file
+ console.log('\n=== Download Generated File ===');
+ await downloadDeliverable(deliverable.id, `${deliverable.name}.docx`);
+
+ return deliverable;
+
+ } catch (error) {
+ console.error('Deliverable generation failed:', error.message);
+ }
+}
+
+// Export functions for use in other modules
+module.exports = {
+ generateDeliverable,
+ downloadDeliverable,
+ createComplexVariables,
+ exampleGenerateDeliverable
+};
+
+// Run example if script is executed directly
+if (require.main === module) {
+ exampleGenerateDeliverable();
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/powershell.ps1 b/static/scripts/templates/api/generate-deliverable/powershell.ps1
new file mode 100644
index 0000000..cc439d8
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/powershell.ps1
@@ -0,0 +1,296 @@
+# Configuration - Update these values
+$API_TOKEN = "YOUR_API_TOKEN"
+$ORG_ID = "YOUR_ORGANIZATION_ID"
+$BASE_URL = "https://api.turbodocx.com"
+
+##
+# Final Step: Generate Deliverable (Both Paths Converge Here)
+##
+
+function Generate-Deliverable {
+ param(
+ [Parameter(Mandatory=$true)]
+ [string]$TemplateId,
+ [Parameter(Mandatory=$true)]
+ [hashtable]$DeliverableData
+ )
+
+ $uri = "$BASE_URL/deliverable"
+
+ Write-Host "Generating deliverable..."
+ Write-Host "Template ID: $TemplateId"
+ Write-Host "Deliverable Name: $($DeliverableData.name)"
+ Write-Host "Variables: $($DeliverableData.variables.Count)"
+
+ try {
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $API_TOKEN"
+ 'x-rapiddocx-org-id' = $ORG_ID
+ 'User-Agent' = 'TurboDocx API Client'
+ 'Content-Type' = 'application/json'
+ }
+
+ # Convert to JSON
+ $jsonBody = $DeliverableData | ConvertTo-Json -Depth 10
+
+ # Make request
+ $response = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body $jsonBody
+
+ # Parse JSON response
+ $deliverable = $response.data.results.deliverable
+
+ Write-Host "✅ Deliverable generated successfully!" -ForegroundColor Green
+ Write-Host "Deliverable ID: $($deliverable.id)"
+ Write-Host "Created by: $($deliverable.createdBy)"
+ Write-Host "Created on: $($deliverable.createdOn)"
+ Write-Host "Template ID: $($deliverable.templateId)"
+
+ return $deliverable
+ }
+ catch {
+ Write-Error "Deliverable generation failed: $($_.Exception.Message)"
+ throw
+ }
+}
+
+function Download-Deliverable {
+ param(
+ [Parameter(Mandatory=$true)]
+ [string]$DeliverableId,
+ [Parameter(Mandatory=$true)]
+ [string]$Filename
+ )
+
+ Write-Host "Downloading file: $Filename"
+
+ $uri = "$BASE_URL/deliverable/file/$DeliverableId"
+
+ try {
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $API_TOKEN"
+ 'x-rapiddocx-org-id' = $ORG_ID
+ 'User-Agent' = 'TurboDocx API Client'
+ }
+
+ # Make request
+ $response = Invoke-WebRequest -Uri $uri -Method Get -Headers $headers
+
+ if ($response.StatusCode -ne 200) {
+ throw "Download failed: $($response.StatusCode)"
+ }
+
+ Write-Host "✅ File ready for download: $Filename" -ForegroundColor Green
+
+ $contentType = if ($response.Headers['Content-Type']) { $response.Headers['Content-Type'] } else { 'N/A' }
+ $contentLength = if ($response.Headers['Content-Length']) { $response.Headers['Content-Length'] } else { 'N/A' }
+
+ Write-Host "📁 Content-Type: $contentType"
+ Write-Host "📊 Content-Length: $contentLength bytes"
+
+ # In a real application, you would save the file
+ # [System.IO.File]::WriteAllBytes($Filename, $response.Content)
+
+ return @{
+ 'filename' = $Filename
+ 'content_type' = $contentType
+ 'content_length' = $contentLength
+ }
+ }
+ catch {
+ Write-Error "Download failed: $($_.Exception.Message)"
+ throw
+ }
+}
+
+function New-ComplexVariables {
+ return @(
+ @{
+ 'mimeType' = 'text'
+ 'name' = 'Employee Name'
+ 'placeholder' = '{EmployeeName}'
+ 'text' = 'John Smith'
+ 'allowRichTextInjection' = 0
+ 'autogenerated' = $false
+ 'count' = 1
+ 'order' = 1
+ 'subvariables' = @(
+ @{
+ 'placeholder' = '{EmployeeName.Title}'
+ 'text' = 'Senior Software Engineer'
+ },
+ @{
+ 'placeholder' = '{EmployeeName.StartDate}'
+ 'text' = 'January 15, 2024'
+ }
+ )
+ 'metadata' = @{
+ 'department' = 'Engineering'
+ 'level' = 'Senior'
+ }
+ 'aiPrompt' = 'Generate a professional job description for a senior software engineer role'
+ },
+ @{
+ 'mimeType' = 'text'
+ 'name' = 'Company Information'
+ 'placeholder' = '{CompanyInfo}'
+ 'text' = 'TechCorp Solutions Inc.'
+ 'allowRichTextInjection' = 1
+ 'autogenerated' = $false
+ 'count' = 1
+ 'order' = 2
+ 'subvariables' = @(
+ @{
+ 'placeholder' = '{CompanyInfo.Address}'
+ 'text' = '123 Innovation Drive, Tech City, TC 12345'
+ },
+ @{
+ 'placeholder' = '{CompanyInfo.Phone}'
+ 'text' = '(555) 123-4567'
+ }
+ )
+ 'metadata' = @{}
+ 'aiPrompt' = ''
+ },
+ @{
+ 'mimeType' = 'text'
+ 'name' = 'Project Assignments'
+ 'placeholder' = '{ProjectAssignments}'
+ 'text' = 'Multiple ongoing projects'
+ 'allowRichTextInjection' = 0
+ 'autogenerated' = $false
+ 'count' = 3
+ 'order' = 3
+ 'subvariables' = @()
+ 'variableStack' = @{
+ '0' = @{
+ 'text' = 'Project Alpha - Backend Development'
+ 'subvariables' = @(
+ @{
+ 'placeholder' = '{ProjectAssignments.Duration}'
+ 'text' = '6 months'
+ },
+ @{
+ 'placeholder' = '{ProjectAssignments.Priority}'
+ 'text' = 'High'
+ }
+ )
+ }
+ '1' = @{
+ 'text' = 'Project Beta - API Integration'
+ 'subvariables' = @(
+ @{
+ 'placeholder' = '{ProjectAssignments.Duration}'
+ 'text' = '3 months'
+ },
+ @{
+ 'placeholder' = '{ProjectAssignments.Priority}'
+ 'text' = 'Medium'
+ }
+ )
+ }
+ '2' = @{
+ 'text' = 'Project Gamma - Code Review'
+ 'subvariables' = @(
+ @{
+ 'placeholder' = '{ProjectAssignments.Duration}'
+ 'text' = 'Ongoing'
+ },
+ @{
+ 'placeholder' = '{ProjectAssignments.Priority}'
+ 'text' = 'Low'
+ }
+ )
+ }
+ }
+ 'metadata' = @{
+ 'totalProjects' = 3
+ 'estimatedHours' = 1200
+ }
+ 'aiPrompt' = 'Create detailed project descriptions for software development initiatives'
+ },
+ @{
+ 'mimeType' = 'text'
+ 'name' = 'Benefits Package'
+ 'placeholder' = '{BenefitsPackage}'
+ 'text' = 'Comprehensive benefits including health, dental, vision, and 401k'
+ 'allowRichTextInjection' = 1
+ 'autogenerated' = $false
+ 'count' = 1
+ 'order' = 4
+ 'subvariables' = @(
+ @{
+ 'placeholder' = '{BenefitsPackage.HealthInsurance}'
+ 'text' = 'Full coverage health insurance with $500 deductible'
+ },
+ @{
+ 'placeholder' = '{BenefitsPackage.PTO}'
+ 'text' = '25 days paid time off annually'
+ },
+ @{
+ 'placeholder' = '{BenefitsPackage.Retirement}'
+ 'text' = '401k with 6% company match'
+ }
+ )
+ 'metadata' = @{
+ 'packageValue' = '$15,000 annually'
+ 'effective' = 'First day of employment'
+ }
+ 'aiPrompt' = 'Outline a competitive benefits package for a senior software engineer'
+ }
+ )
+}
+
+function New-DeliverableData {
+ param(
+ [Parameter(Mandatory=$true)]
+ [string]$TemplateId
+ )
+
+ $now = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
+
+ return @{
+ 'templateId' = $TemplateId
+ 'name' = 'Employee Contract - John Smith'
+ 'description' = 'Employment contract for new senior software engineer'
+ 'variables' = New-ComplexVariables
+ 'tags' = @('hr', 'contract', 'employee', 'engineering')
+ 'fonts' = '[{"name":"Arial","usage":269}]'
+ 'defaultFont' = 'Arial'
+ 'replaceFonts' = $true
+ 'metadata' = @{
+ 'sessions' = @(
+ @{
+ 'id' = [System.Guid]::NewGuid().ToString()
+ 'starttime' = $now
+ 'endtime' = $now
+ }
+ )
+ 'createdBy' = 'HR Department'
+ 'documentType' = 'Employment Contract'
+ 'version' = 'v1.0'
+ }
+ }
+}
+
+# Example usage
+try {
+ Write-Host "=== Final Step: Generate Deliverable ===" -ForegroundColor Cyan
+
+ # This would come from either Path A (upload) or Path B (browse/select)
+ $templateId = "0b1099cf-d7b9-41a4-822b-51b68fd4885a"
+
+ $deliverableData = New-DeliverableData -TemplateId $templateId
+ $deliverable = Generate-Deliverable -TemplateId $templateId -DeliverableData $deliverableData
+
+ # Download the generated file
+ Write-Host "`n=== Download Generated File ===" -ForegroundColor Cyan
+ $downloadResult = Download-Deliverable -DeliverableId $deliverable.id -Filename "$($deliverable.name).docx"
+
+ Write-Host "`nGeneration and download completed successfully!" -ForegroundColor Green
+}
+catch {
+ Write-Error "Deliverable generation failed: $($_.Exception.Message)"
+ exit 1
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/python/fastapi.py b/static/scripts/templates/api/generate-deliverable/python/fastapi.py
new file mode 100644
index 0000000..f58eda3
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/python/fastapi.py
@@ -0,0 +1,286 @@
+import requests
+import json
+import uuid
+from datetime import datetime
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+class DeliverableGenerator:
+ """Final Step: Generate Deliverable (Both Paths Converge Here)"""
+
+ def __init__(self, api_token, org_id, base_url):
+ self.api_token = api_token
+ self.org_id = org_id
+ self.base_url = base_url
+ self.headers = {
+ 'Authorization': f'Bearer {api_token}',
+ 'x-rapiddocx-org-id': org_id,
+ 'User-Agent': 'TurboDocx API Client',
+ 'Content-Type': 'application/json'
+ }
+
+ def generate_deliverable(self, template_id, deliverable_data):
+ """Generate a deliverable document from template with variable substitution"""
+ try:
+ url = f"{self.base_url}/deliverable"
+
+ payload = {
+ "templateId": template_id,
+ "name": deliverable_data["name"],
+ "description": deliverable_data.get("description", ""),
+ "variables": deliverable_data["variables"],
+ "tags": deliverable_data.get("tags", []),
+ "fonts": deliverable_data.get("fonts", "[]"),
+ "defaultFont": deliverable_data.get("defaultFont", "Arial"),
+ "replaceFonts": deliverable_data.get("replaceFonts", True),
+ "metadata": deliverable_data.get("metadata", {
+ "sessions": [{
+ "id": self.generate_session_id(),
+ "starttime": datetime.utcnow().isoformat() + "Z",
+ "endtime": datetime.utcnow().isoformat() + "Z"
+ }]
+ })
+ }
+
+ print(f"Generating deliverable...")
+ print(f"Template ID: {template_id}")
+ print(f"Deliverable Name: {payload['name']}")
+ print(f"Variables: {len(payload['variables'])}")
+
+ response = requests.post(url, headers=self.headers, json=payload)
+ response.raise_for_status()
+
+ result = response.json()
+ deliverable = result['data']['results']['deliverable']
+
+ print("✅ Deliverable generated successfully!")
+ print(f"Deliverable ID: {deliverable['id']}")
+ print(f"Created by: {deliverable['createdBy']}")
+ print(f"Created on: {deliverable['createdOn']}")
+ print(f"Template ID: {deliverable['templateId']}")
+
+ return deliverable
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error generating deliverable: {e}")
+ if hasattr(e, 'response') and e.response is not None:
+ print(f"Response body: {e.response.text}")
+ raise
+
+ def create_complex_variables(self):
+ """Example: Complex variable structure with all features"""
+ return [
+ {
+ "mimeType": "text",
+ "name": "Employee Name",
+ "placeholder": "{EmployeeName}",
+ "text": "John Smith",
+ "allowRichTextInjection": 0,
+ "autogenerated": False,
+ "count": 1,
+ "order": 1,
+ "subvariables": [
+ {
+ "placeholder": "{EmployeeName.Title}",
+ "text": "Senior Software Engineer"
+ },
+ {
+ "placeholder": "{EmployeeName.StartDate}",
+ "text": "January 15, 2024"
+ }
+ ],
+ "metadata": {
+ "department": "Engineering",
+ "level": "Senior"
+ },
+ "aiPrompt": "Generate a professional job description for a senior software engineer role"
+ },
+ {
+ "mimeType": "text",
+ "name": "Company Information",
+ "placeholder": "{CompanyInfo}",
+ "text": "TechCorp Solutions Inc.",
+ "allowRichTextInjection": 1,
+ "autogenerated": False,
+ "count": 1,
+ "order": 2,
+ "subvariables": [
+ {
+ "placeholder": "{CompanyInfo.Address}",
+ "text": "123 Innovation Drive, Tech City, TC 12345"
+ },
+ {
+ "placeholder": "{CompanyInfo.Phone}",
+ "text": "(555) 123-4567"
+ }
+ ],
+ "metadata": {},
+ "aiPrompt": ""
+ },
+ {
+ "mimeType": "text",
+ "name": "Project Assignments",
+ "placeholder": "{ProjectAssignments}",
+ "text": "Multiple ongoing projects",
+ "allowRichTextInjection": 0,
+ "autogenerated": False,
+ "count": 3,
+ "order": 3,
+ "subvariables": [],
+ "variableStack": {
+ "0": {
+ "text": "Project Alpha - Backend Development",
+ "subvariables": [
+ {
+ "placeholder": "{ProjectAssignments.Duration}",
+ "text": "6 months"
+ },
+ {
+ "placeholder": "{ProjectAssignments.Priority}",
+ "text": "High"
+ }
+ ]
+ },
+ "1": {
+ "text": "Project Beta - API Integration",
+ "subvariables": [
+ {
+ "placeholder": "{ProjectAssignments.Duration}",
+ "text": "3 months"
+ },
+ {
+ "placeholder": "{ProjectAssignments.Priority}",
+ "text": "Medium"
+ }
+ ]
+ },
+ "2": {
+ "text": "Project Gamma - Code Review",
+ "subvariables": [
+ {
+ "placeholder": "{ProjectAssignments.Duration}",
+ "text": "Ongoing"
+ },
+ {
+ "placeholder": "{ProjectAssignments.Priority}",
+ "text": "Low"
+ }
+ ]
+ }
+ },
+ "metadata": {
+ "totalProjects": 3,
+ "estimatedHours": 1200
+ },
+ "aiPrompt": "Create detailed project descriptions for software development initiatives"
+ },
+ {
+ "mimeType": "text",
+ "name": "Benefits Package",
+ "placeholder": "{BenefitsPackage}",
+ "text": "Comprehensive benefits including health, dental, vision, and 401k",
+ "allowRichTextInjection": 1,
+ "autogenerated": False,
+ "count": 1,
+ "order": 4,
+ "subvariables": [
+ {
+ "placeholder": "{BenefitsPackage.HealthInsurance}",
+ "text": "Full coverage health insurance with $500 deductible"
+ },
+ {
+ "placeholder": "{BenefitsPackage.PTO}",
+ "text": "25 days paid time off annually"
+ },
+ {
+ "placeholder": "{BenefitsPackage.Retirement}",
+ "text": "401k with 6% company match"
+ }
+ ],
+ "metadata": {
+ "packageValue": "$15,000 annually",
+ "effective": "First day of employment"
+ },
+ "aiPrompt": "Outline a competitive benefits package for a senior software engineer"
+ }
+ ]
+
+ def generate_session_id(self):
+ """Generate a session ID for metadata tracking"""
+ return str(uuid.uuid4())
+
+ def download_deliverable(self, deliverable_id, filename):
+ """Download the generated deliverable file"""
+ try:
+ url = f"{self.base_url}/deliverable/file/{deliverable_id}"
+
+ print(f"Downloading file: {filename}")
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ print(f"✅ File ready for download: {filename}")
+ print(f"📁 Content-Type: {response.headers.get('content-type')}")
+ print(f"📊 Content-Length: {response.headers.get('content-length')} bytes")
+
+ # In a real application, you would save the file
+ # with open(filename, 'wb') as f:
+ # f.write(response.content)
+
+ return {
+ 'filename': filename,
+ 'content_type': response.headers.get('content-type'),
+ 'content_length': response.headers.get('content-length')
+ }
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error downloading file: {e}")
+ raise
+
+def example_generate_deliverable():
+ """Example usage with realistic data"""
+ try:
+ generator = DeliverableGenerator(API_TOKEN, ORG_ID, BASE_URL)
+
+ # This would come from either Path A (upload) or Path B (browse/select)
+ template_id = "0b1099cf-d7b9-41a4-822b-51b68fd4885a"
+
+ deliverable_data = {
+ "name": "Employee Contract - John Smith",
+ "description": "Employment contract for new senior software engineer",
+ "variables": generator.create_complex_variables(),
+ "tags": ["hr", "contract", "employee", "engineering"],
+ "fonts": '[{"name":"Arial","usage":269}]',
+ "defaultFont": "Arial",
+ "replaceFonts": True,
+ "metadata": {
+ "sessions": [
+ {
+ "id": "cf1cd4b9-6fdc-47e3-b59d-594cd6564501",
+ "starttime": "2024-01-15T14:12:10.721Z",
+ "endtime": "2024-01-15T14:13:45.724Z"
+ }
+ ],
+ "createdBy": "HR Department",
+ "documentType": "Employment Contract",
+ "version": "v1.0"
+ }
+ }
+
+ print("=== Final Step: Generate Deliverable ===")
+ deliverable = generator.generate_deliverable(template_id, deliverable_data)
+
+ # Download the generated file
+ print("\n=== Download Generated File ===")
+ generator.download_deliverable(deliverable['id'], f"{deliverable['name']}.docx")
+
+ return deliverable
+
+ except Exception as error:
+ print(f"Deliverable generation failed: {error}")
+
+# Example usage
+if __name__ == "__main__":
+ example_generate_deliverable()
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/python/flask.py b/static/scripts/templates/api/generate-deliverable/python/flask.py
new file mode 100644
index 0000000..f58eda3
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/python/flask.py
@@ -0,0 +1,286 @@
+import requests
+import json
+import uuid
+from datetime import datetime
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+class DeliverableGenerator:
+ """Final Step: Generate Deliverable (Both Paths Converge Here)"""
+
+ def __init__(self, api_token, org_id, base_url):
+ self.api_token = api_token
+ self.org_id = org_id
+ self.base_url = base_url
+ self.headers = {
+ 'Authorization': f'Bearer {api_token}',
+ 'x-rapiddocx-org-id': org_id,
+ 'User-Agent': 'TurboDocx API Client',
+ 'Content-Type': 'application/json'
+ }
+
+ def generate_deliverable(self, template_id, deliverable_data):
+ """Generate a deliverable document from template with variable substitution"""
+ try:
+ url = f"{self.base_url}/deliverable"
+
+ payload = {
+ "templateId": template_id,
+ "name": deliverable_data["name"],
+ "description": deliverable_data.get("description", ""),
+ "variables": deliverable_data["variables"],
+ "tags": deliverable_data.get("tags", []),
+ "fonts": deliverable_data.get("fonts", "[]"),
+ "defaultFont": deliverable_data.get("defaultFont", "Arial"),
+ "replaceFonts": deliverable_data.get("replaceFonts", True),
+ "metadata": deliverable_data.get("metadata", {
+ "sessions": [{
+ "id": self.generate_session_id(),
+ "starttime": datetime.utcnow().isoformat() + "Z",
+ "endtime": datetime.utcnow().isoformat() + "Z"
+ }]
+ })
+ }
+
+ print(f"Generating deliverable...")
+ print(f"Template ID: {template_id}")
+ print(f"Deliverable Name: {payload['name']}")
+ print(f"Variables: {len(payload['variables'])}")
+
+ response = requests.post(url, headers=self.headers, json=payload)
+ response.raise_for_status()
+
+ result = response.json()
+ deliverable = result['data']['results']['deliverable']
+
+ print("✅ Deliverable generated successfully!")
+ print(f"Deliverable ID: {deliverable['id']}")
+ print(f"Created by: {deliverable['createdBy']}")
+ print(f"Created on: {deliverable['createdOn']}")
+ print(f"Template ID: {deliverable['templateId']}")
+
+ return deliverable
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error generating deliverable: {e}")
+ if hasattr(e, 'response') and e.response is not None:
+ print(f"Response body: {e.response.text}")
+ raise
+
+ def create_complex_variables(self):
+ """Example: Complex variable structure with all features"""
+ return [
+ {
+ "mimeType": "text",
+ "name": "Employee Name",
+ "placeholder": "{EmployeeName}",
+ "text": "John Smith",
+ "allowRichTextInjection": 0,
+ "autogenerated": False,
+ "count": 1,
+ "order": 1,
+ "subvariables": [
+ {
+ "placeholder": "{EmployeeName.Title}",
+ "text": "Senior Software Engineer"
+ },
+ {
+ "placeholder": "{EmployeeName.StartDate}",
+ "text": "January 15, 2024"
+ }
+ ],
+ "metadata": {
+ "department": "Engineering",
+ "level": "Senior"
+ },
+ "aiPrompt": "Generate a professional job description for a senior software engineer role"
+ },
+ {
+ "mimeType": "text",
+ "name": "Company Information",
+ "placeholder": "{CompanyInfo}",
+ "text": "TechCorp Solutions Inc.",
+ "allowRichTextInjection": 1,
+ "autogenerated": False,
+ "count": 1,
+ "order": 2,
+ "subvariables": [
+ {
+ "placeholder": "{CompanyInfo.Address}",
+ "text": "123 Innovation Drive, Tech City, TC 12345"
+ },
+ {
+ "placeholder": "{CompanyInfo.Phone}",
+ "text": "(555) 123-4567"
+ }
+ ],
+ "metadata": {},
+ "aiPrompt": ""
+ },
+ {
+ "mimeType": "text",
+ "name": "Project Assignments",
+ "placeholder": "{ProjectAssignments}",
+ "text": "Multiple ongoing projects",
+ "allowRichTextInjection": 0,
+ "autogenerated": False,
+ "count": 3,
+ "order": 3,
+ "subvariables": [],
+ "variableStack": {
+ "0": {
+ "text": "Project Alpha - Backend Development",
+ "subvariables": [
+ {
+ "placeholder": "{ProjectAssignments.Duration}",
+ "text": "6 months"
+ },
+ {
+ "placeholder": "{ProjectAssignments.Priority}",
+ "text": "High"
+ }
+ ]
+ },
+ "1": {
+ "text": "Project Beta - API Integration",
+ "subvariables": [
+ {
+ "placeholder": "{ProjectAssignments.Duration}",
+ "text": "3 months"
+ },
+ {
+ "placeholder": "{ProjectAssignments.Priority}",
+ "text": "Medium"
+ }
+ ]
+ },
+ "2": {
+ "text": "Project Gamma - Code Review",
+ "subvariables": [
+ {
+ "placeholder": "{ProjectAssignments.Duration}",
+ "text": "Ongoing"
+ },
+ {
+ "placeholder": "{ProjectAssignments.Priority}",
+ "text": "Low"
+ }
+ ]
+ }
+ },
+ "metadata": {
+ "totalProjects": 3,
+ "estimatedHours": 1200
+ },
+ "aiPrompt": "Create detailed project descriptions for software development initiatives"
+ },
+ {
+ "mimeType": "text",
+ "name": "Benefits Package",
+ "placeholder": "{BenefitsPackage}",
+ "text": "Comprehensive benefits including health, dental, vision, and 401k",
+ "allowRichTextInjection": 1,
+ "autogenerated": False,
+ "count": 1,
+ "order": 4,
+ "subvariables": [
+ {
+ "placeholder": "{BenefitsPackage.HealthInsurance}",
+ "text": "Full coverage health insurance with $500 deductible"
+ },
+ {
+ "placeholder": "{BenefitsPackage.PTO}",
+ "text": "25 days paid time off annually"
+ },
+ {
+ "placeholder": "{BenefitsPackage.Retirement}",
+ "text": "401k with 6% company match"
+ }
+ ],
+ "metadata": {
+ "packageValue": "$15,000 annually",
+ "effective": "First day of employment"
+ },
+ "aiPrompt": "Outline a competitive benefits package for a senior software engineer"
+ }
+ ]
+
+ def generate_session_id(self):
+ """Generate a session ID for metadata tracking"""
+ return str(uuid.uuid4())
+
+ def download_deliverable(self, deliverable_id, filename):
+ """Download the generated deliverable file"""
+ try:
+ url = f"{self.base_url}/deliverable/file/{deliverable_id}"
+
+ print(f"Downloading file: {filename}")
+ response = requests.get(url, headers=self.headers)
+ response.raise_for_status()
+
+ print(f"✅ File ready for download: {filename}")
+ print(f"📁 Content-Type: {response.headers.get('content-type')}")
+ print(f"📊 Content-Length: {response.headers.get('content-length')} bytes")
+
+ # In a real application, you would save the file
+ # with open(filename, 'wb') as f:
+ # f.write(response.content)
+
+ return {
+ 'filename': filename,
+ 'content_type': response.headers.get('content-type'),
+ 'content_length': response.headers.get('content-length')
+ }
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error downloading file: {e}")
+ raise
+
+def example_generate_deliverable():
+ """Example usage with realistic data"""
+ try:
+ generator = DeliverableGenerator(API_TOKEN, ORG_ID, BASE_URL)
+
+ # This would come from either Path A (upload) or Path B (browse/select)
+ template_id = "0b1099cf-d7b9-41a4-822b-51b68fd4885a"
+
+ deliverable_data = {
+ "name": "Employee Contract - John Smith",
+ "description": "Employment contract for new senior software engineer",
+ "variables": generator.create_complex_variables(),
+ "tags": ["hr", "contract", "employee", "engineering"],
+ "fonts": '[{"name":"Arial","usage":269}]',
+ "defaultFont": "Arial",
+ "replaceFonts": True,
+ "metadata": {
+ "sessions": [
+ {
+ "id": "cf1cd4b9-6fdc-47e3-b59d-594cd6564501",
+ "starttime": "2024-01-15T14:12:10.721Z",
+ "endtime": "2024-01-15T14:13:45.724Z"
+ }
+ ],
+ "createdBy": "HR Department",
+ "documentType": "Employment Contract",
+ "version": "v1.0"
+ }
+ }
+
+ print("=== Final Step: Generate Deliverable ===")
+ deliverable = generator.generate_deliverable(template_id, deliverable_data)
+
+ # Download the generated file
+ print("\n=== Download Generated File ===")
+ generator.download_deliverable(deliverable['id'], f"{deliverable['name']}.docx")
+
+ return deliverable
+
+ except Exception as error:
+ print(f"Deliverable generation failed: {error}")
+
+# Example usage
+if __name__ == "__main__":
+ example_generate_deliverable()
\ No newline at end of file
diff --git a/static/scripts/templates/api/generate-deliverable/ruby.rb b/static/scripts/templates/api/generate-deliverable/ruby.rb
new file mode 100644
index 0000000..19566a6
--- /dev/null
+++ b/static/scripts/templates/api/generate-deliverable/ruby.rb
@@ -0,0 +1,285 @@
+require 'net/http'
+require 'uri'
+require 'json'
+require 'securerandom'
+require 'time'
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+
+##
+# Final Step: Generate Deliverable (Both Paths Converge Here)
+##
+
+def generate_deliverable(template_id, deliverable_data)
+ uri = URI("#{BASE_URL}/deliverable")
+
+ puts "Generating deliverable..."
+ puts "Template ID: #{template_id}"
+ puts "Deliverable Name: #{deliverable_data['name']}"
+ puts "Variables: #{deliverable_data['variables'].length}"
+
+ # Create HTTP connection
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ # Create request
+ request = Net::HTTP::Post.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+ request['Content-Type'] = 'application/json'
+
+ # Set request body
+ request.body = deliverable_data.to_json
+
+ # Make request
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "HTTP error #{response.code}: #{response.body}"
+ end
+
+ # Parse JSON response
+ result = JSON.parse(response.body)
+ deliverable = result['data']['results']['deliverable']
+
+ puts "✅ Deliverable generated successfully!"
+ puts "Deliverable ID: #{deliverable['id']}"
+ puts "Created by: #{deliverable['createdBy']}"
+ puts "Created on: #{deliverable['createdOn']}"
+ puts "Template ID: #{deliverable['templateId']}"
+
+ deliverable
+rescue JSON::ParserError => e
+ raise "Failed to parse JSON response: #{e.message}"
+rescue => e
+ puts "Deliverable generation failed: #{e.message}"
+ raise
+end
+
+def download_deliverable(deliverable_id, filename)
+ puts "Downloading file: #{filename}"
+
+ uri = URI("#{BASE_URL}/deliverable/file/#{deliverable_id}")
+
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ request = Net::HTTP::Get.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "Download failed: #{response.code}"
+ end
+
+ puts "✅ File ready for download: #{filename}"
+
+ content_type = response['Content-Type'] || 'N/A'
+ content_length = response['Content-Length'] || 'N/A'
+
+ puts "📁 Content-Type: #{content_type}"
+ puts "📊 Content-Length: #{content_length} bytes"
+
+ # In a real application, you would save the file
+ # File.write(filename, response.body)
+
+ {
+ 'filename' => filename,
+ 'content_type' => content_type,
+ 'content_length' => content_length
+ }
+rescue => e
+ puts "Download failed: #{e.message}"
+ raise
+end
+
+def create_complex_variables
+ [
+ {
+ 'mimeType' => 'text',
+ 'name' => 'Employee Name',
+ 'placeholder' => '{EmployeeName}',
+ 'text' => 'John Smith',
+ 'allowRichTextInjection' => 0,
+ 'autogenerated' => false,
+ 'count' => 1,
+ 'order' => 1,
+ 'subvariables' => [
+ {
+ 'placeholder' => '{EmployeeName.Title}',
+ 'text' => 'Senior Software Engineer'
+ },
+ {
+ 'placeholder' => '{EmployeeName.StartDate}',
+ 'text' => 'January 15, 2024'
+ }
+ ],
+ 'metadata' => {
+ 'department' => 'Engineering',
+ 'level' => 'Senior'
+ },
+ 'aiPrompt' => 'Generate a professional job description for a senior software engineer role'
+ },
+ {
+ 'mimeType' => 'text',
+ 'name' => 'Company Information',
+ 'placeholder' => '{CompanyInfo}',
+ 'text' => 'TechCorp Solutions Inc.',
+ 'allowRichTextInjection' => 1,
+ 'autogenerated' => false,
+ 'count' => 1,
+ 'order' => 2,
+ 'subvariables' => [
+ {
+ 'placeholder' => '{CompanyInfo.Address}',
+ 'text' => '123 Innovation Drive, Tech City, TC 12345'
+ },
+ {
+ 'placeholder' => '{CompanyInfo.Phone}',
+ 'text' => '(555) 123-4567'
+ }
+ ],
+ 'metadata' => {},
+ 'aiPrompt' => ''
+ },
+ {
+ 'mimeType' => 'text',
+ 'name' => 'Project Assignments',
+ 'placeholder' => '{ProjectAssignments}',
+ 'text' => 'Multiple ongoing projects',
+ 'allowRichTextInjection' => 0,
+ 'autogenerated' => false,
+ 'count' => 3,
+ 'order' => 3,
+ 'subvariables' => [],
+ 'variableStack' => {
+ '0' => {
+ 'text' => 'Project Alpha - Backend Development',
+ 'subvariables' => [
+ {
+ 'placeholder' => '{ProjectAssignments.Duration}',
+ 'text' => '6 months'
+ },
+ {
+ 'placeholder' => '{ProjectAssignments.Priority}',
+ 'text' => 'High'
+ }
+ ]
+ },
+ '1' => {
+ 'text' => 'Project Beta - API Integration',
+ 'subvariables' => [
+ {
+ 'placeholder' => '{ProjectAssignments.Duration}',
+ 'text' => '3 months'
+ },
+ {
+ 'placeholder' => '{ProjectAssignments.Priority}',
+ 'text' => 'Medium'
+ }
+ ]
+ },
+ '2' => {
+ 'text' => 'Project Gamma - Code Review',
+ 'subvariables' => [
+ {
+ 'placeholder' => '{ProjectAssignments.Duration}',
+ 'text' => 'Ongoing'
+ },
+ {
+ 'placeholder' => '{ProjectAssignments.Priority}',
+ 'text' => 'Low'
+ }
+ ]
+ }
+ },
+ 'metadata' => {
+ 'totalProjects' => 3,
+ 'estimatedHours' => 1200
+ },
+ 'aiPrompt' => 'Create detailed project descriptions for software development initiatives'
+ },
+ {
+ 'mimeType' => 'text',
+ 'name' => 'Benefits Package',
+ 'placeholder' => '{BenefitsPackage}',
+ 'text' => 'Comprehensive benefits including health, dental, vision, and 401k',
+ 'allowRichTextInjection' => 1,
+ 'autogenerated' => false,
+ 'count' => 1,
+ 'order' => 4,
+ 'subvariables' => [
+ {
+ 'placeholder' => '{BenefitsPackage.HealthInsurance}',
+ 'text' => 'Full coverage health insurance with $500 deductible'
+ },
+ {
+ 'placeholder' => '{BenefitsPackage.PTO}',
+ 'text' => '25 days paid time off annually'
+ },
+ {
+ 'placeholder' => '{BenefitsPackage.Retirement}',
+ 'text' => '401k with 6% company match'
+ }
+ ],
+ 'metadata' => {
+ 'packageValue' => '$15,000 annually',
+ 'effective' => 'First day of employment'
+ },
+ 'aiPrompt' => 'Outline a competitive benefits package for a senior software engineer'
+ }
+ ]
+end
+
+def create_deliverable_data(template_id)
+ now = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%S.%3NZ')
+
+ {
+ 'templateId' => template_id,
+ 'name' => 'Employee Contract - John Smith',
+ 'description' => 'Employment contract for new senior software engineer',
+ 'variables' => create_complex_variables,
+ 'tags' => ['hr', 'contract', 'employee', 'engineering'],
+ 'fonts' => '[{"name":"Arial","usage":269}]',
+ 'defaultFont' => 'Arial',
+ 'replaceFonts' => true,
+ 'metadata' => {
+ 'sessions' => [
+ {
+ 'id' => SecureRandom.uuid,
+ 'starttime' => now,
+ 'endtime' => now
+ }
+ ],
+ 'createdBy' => 'HR Department',
+ 'documentType' => 'Employment Contract',
+ 'version' => 'v1.0'
+ }
+ }
+end
+
+# Example usage
+begin
+ puts "=== Final Step: Generate Deliverable ==="
+
+ # This would come from either Path A (upload) or Path B (browse/select)
+ template_id = "0b1099cf-d7b9-41a4-822b-51b68fd4885a"
+
+ deliverable_data = create_deliverable_data(template_id)
+ deliverable = generate_deliverable(template_id, deliverable_data)
+
+ # Download the generated file
+ puts "\n=== Download Generated File ==="
+ download_deliverable(deliverable['id'], "#{deliverable['name']}.docx")
+
+rescue => e
+ puts "Deliverable generation failed: #{e.message}"
+ exit 1
+end
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/csharp/controller copy.cs b/static/scripts/templates/api/upload-template/csharp/controller copy.cs
new file mode 100644
index 0000000..7b5190b
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/csharp/controller copy.cs
@@ -0,0 +1,109 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+using System.Text.Json;
+
+/**
+ * Path A: Upload and Create Template
+ * Uploads a .docx/.pptx template and extracts variables automatically
+ */
+class TemplateUpload
+{
+ // Configuration - Update these values
+ private const string API_TOKEN = "YOUR_API_TOKEN";
+ private const string ORG_ID = "YOUR_ORGANIZATION_ID";
+ private const string BASE_URL = "https://api.turbodocx.com";
+ private const string TEMPLATE_NAME = "Employee Contract Template";
+
+ static async Task Main(string[] args)
+ {
+ try
+ {
+ var result = await UploadTemplate("./contract-template.docx");
+
+ using var document = JsonDocument.Parse(result);
+ var template = document.RootElement
+ .GetProperty("data")
+ .GetProperty("results")
+ .GetProperty("template");
+
+ Console.WriteLine($"Template uploaded successfully: {template.GetProperty("id").GetString()}");
+ Console.WriteLine($"Template name: {template.GetProperty("name").GetString()}");
+
+ // Handle nullable variables field
+ var variableCount = 0;
+ if (template.TryGetProperty("variables", out var variables) &&
+ variables.ValueKind != JsonValueKind.Null)
+ {
+ variableCount = variables.GetArrayLength();
+ }
+ Console.WriteLine($"Variables extracted: {variableCount}");
+
+ Console.WriteLine($"Default font: {template.GetProperty("defaultFont").GetString()}");
+
+ // Handle nullable fonts field
+ var fontCount = 0;
+ if (template.TryGetProperty("fonts", out var fonts) &&
+ fonts.ValueKind != JsonValueKind.Null)
+ {
+ fontCount = fonts.GetArrayLength();
+ }
+ Console.WriteLine($"Fonts used: {fontCount}");
+
+ var redirectUrl = document.RootElement
+ .GetProperty("data")
+ .GetProperty("results")
+ .GetProperty("redirectUrl");
+ Console.WriteLine($"Redirect to: {redirectUrl.GetString()}");
+
+ Console.WriteLine($"Ready to generate documents with template: {template.GetProperty("id").GetString()}");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Upload failed: {ex.Message}");
+ }
+ }
+
+ private static async Task UploadTemplate(string templateFilePath)
+ {
+ // Check if file exists
+ if (!File.Exists(templateFilePath))
+ {
+ throw new FileNotFoundException($"Template file not found: {templateFilePath}");
+ }
+
+ using var client = new HttpClient();
+
+ // Set headers
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ // Create multipart form data
+ using var content = new MultipartFormDataContent();
+
+ // Add template file
+ var fileContent = new ByteArrayContent(File.ReadAllBytes(templateFilePath));
+ fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+ content.Add(fileContent, "templateFile", Path.GetFileName(templateFilePath));
+
+ // Add form fields
+ content.Add(new StringContent(TEMPLATE_NAME), "name");
+ content.Add(new StringContent("Standard employee contract with variable placeholders"), "description");
+ content.Add(new StringContent("[]"), "variables");
+ content.Add(new StringContent("[\"hr\", \"contract\", \"template\"]"), "tags");
+
+ // Make request
+ var response = await client.PostAsync(BASE_URL + "/template/upload-and-create", content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"HTTP error {response.StatusCode}: {errorContent}");
+ }
+
+ return await response.Content.ReadAsStringAsync();
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/csharp/controller.cs b/static/scripts/templates/api/upload-template/csharp/controller.cs
new file mode 100644
index 0000000..7b5190b
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/csharp/controller.cs
@@ -0,0 +1,109 @@
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+using System.Text.Json;
+
+/**
+ * Path A: Upload and Create Template
+ * Uploads a .docx/.pptx template and extracts variables automatically
+ */
+class TemplateUpload
+{
+ // Configuration - Update these values
+ private const string API_TOKEN = "YOUR_API_TOKEN";
+ private const string ORG_ID = "YOUR_ORGANIZATION_ID";
+ private const string BASE_URL = "https://api.turbodocx.com";
+ private const string TEMPLATE_NAME = "Employee Contract Template";
+
+ static async Task Main(string[] args)
+ {
+ try
+ {
+ var result = await UploadTemplate("./contract-template.docx");
+
+ using var document = JsonDocument.Parse(result);
+ var template = document.RootElement
+ .GetProperty("data")
+ .GetProperty("results")
+ .GetProperty("template");
+
+ Console.WriteLine($"Template uploaded successfully: {template.GetProperty("id").GetString()}");
+ Console.WriteLine($"Template name: {template.GetProperty("name").GetString()}");
+
+ // Handle nullable variables field
+ var variableCount = 0;
+ if (template.TryGetProperty("variables", out var variables) &&
+ variables.ValueKind != JsonValueKind.Null)
+ {
+ variableCount = variables.GetArrayLength();
+ }
+ Console.WriteLine($"Variables extracted: {variableCount}");
+
+ Console.WriteLine($"Default font: {template.GetProperty("defaultFont").GetString()}");
+
+ // Handle nullable fonts field
+ var fontCount = 0;
+ if (template.TryGetProperty("fonts", out var fonts) &&
+ fonts.ValueKind != JsonValueKind.Null)
+ {
+ fontCount = fonts.GetArrayLength();
+ }
+ Console.WriteLine($"Fonts used: {fontCount}");
+
+ var redirectUrl = document.RootElement
+ .GetProperty("data")
+ .GetProperty("results")
+ .GetProperty("redirectUrl");
+ Console.WriteLine($"Redirect to: {redirectUrl.GetString()}");
+
+ Console.WriteLine($"Ready to generate documents with template: {template.GetProperty("id").GetString()}");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Upload failed: {ex.Message}");
+ }
+ }
+
+ private static async Task UploadTemplate(string templateFilePath)
+ {
+ // Check if file exists
+ if (!File.Exists(templateFilePath))
+ {
+ throw new FileNotFoundException($"Template file not found: {templateFilePath}");
+ }
+
+ using var client = new HttpClient();
+
+ // Set headers
+ client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_TOKEN);
+ client.DefaultRequestHeaders.Add("x-rapiddocx-org-id", ORG_ID);
+ client.DefaultRequestHeaders.Add("User-Agent", "TurboDocx API Client");
+
+ // Create multipart form data
+ using var content = new MultipartFormDataContent();
+
+ // Add template file
+ var fileContent = new ByteArrayContent(File.ReadAllBytes(templateFilePath));
+ fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+ content.Add(fileContent, "templateFile", Path.GetFileName(templateFilePath));
+
+ // Add form fields
+ content.Add(new StringContent(TEMPLATE_NAME), "name");
+ content.Add(new StringContent("Standard employee contract with variable placeholders"), "description");
+ content.Add(new StringContent("[]"), "variables");
+ content.Add(new StringContent("[\"hr\", \"contract\", \"template\"]"), "tags");
+
+ // Make request
+ var response = await client.PostAsync(BASE_URL + "/template/upload-and-create", content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ throw new HttpRequestException($"HTTP error {response.StatusCode}: {errorContent}");
+ }
+
+ return await response.Content.ReadAsStringAsync();
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/curl.sh b/static/scripts/templates/api/upload-template/curl.sh
new file mode 100644
index 0000000..8db04bd
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/curl.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+# Configuration - Update these values
+API_TOKEN="YOUR_API_TOKEN"
+ORG_ID="YOUR_ORGANIZATION_ID"
+BASE_URL="https://api.turbodocx.com"
+TEMPLATE_NAME="Employee Contract Template"
+TEMPLATE_FILE="./contract-template.docx"
+
+# Path A: Upload and Create Template
+echo "Uploading template: $TEMPLATE_NAME"
+
+UPLOAD_RESPONSE=$(curl -s -X POST "$BASE_URL/template/upload-and-create" \
+ -H "Authorization: Bearer $API_TOKEN" \
+ -H "x-rapiddocx-org-id: $ORG_ID" \
+ -H "User-Agent: TurboDocx API Client" \
+ -F "templateFile=@$TEMPLATE_FILE" \
+ -F "name=$TEMPLATE_NAME" \
+ -F "description=Standard employee contract with variable placeholders" \
+ -F 'variables=[]' \
+ -F 'tags=["hr", "contract", "template"]')
+
+echo "Upload Response:"
+echo "$UPLOAD_RESPONSE" | jq '.'
+
+# Extract template ID and details
+TEMPLATE_ID=$(echo "$UPLOAD_RESPONSE" | jq -r '.data.results.template.id')
+TEMPLATE_NAME_RETURNED=$(echo "$UPLOAD_RESPONSE" | jq -r '.data.results.template.name')
+VARIABLE_COUNT=$(echo "$UPLOAD_RESPONSE" | jq '.data.results.template.variables | length // 0')
+DEFAULT_FONT=$(echo "$UPLOAD_RESPONSE" | jq -r '.data.results.template.defaultFont')
+FONT_COUNT=$(echo "$UPLOAD_RESPONSE" | jq '.data.results.template.fonts | length // 0')
+REDIRECT_URL=$(echo "$UPLOAD_RESPONSE" | jq -r '.data.results.redirectUrl')
+
+if [ "$TEMPLATE_ID" = "null" ] || [ -z "$TEMPLATE_ID" ]; then
+ echo "❌ Failed to extract template ID from upload response"
+ exit 1
+fi
+
+echo "✅ Template uploaded: $TEMPLATE_NAME_RETURNED ($TEMPLATE_ID)"
+echo "📊 Variables extracted: $VARIABLE_COUNT"
+echo "🔤 Default font: $DEFAULT_FONT"
+echo "📝 Fonts used: $FONT_COUNT"
+echo "🔗 Redirect to: $REDIRECT_URL"
+
+echo "Template upload complete!"
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/fastapi.py b/static/scripts/templates/api/upload-template/fastapi.py
new file mode 100644
index 0000000..a1fff52
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/fastapi.py
@@ -0,0 +1,233 @@
+#!/usr/bin/env python3
+
+import os
+import requests
+import json
+import tempfile
+from typing import Optional
+from fastapi import FastAPI, HTTPException, UploadFile, File
+from pydantic import BaseModel
+import uvicorn
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+TEMPLATE_NAME = "Employee Contract Template"
+
+app = FastAPI(
+ title="TurboDocx Template Upload Service",
+ description="FastAPI service for uploading templates to TurboDocx API",
+ version="1.0.0"
+)
+
+class UploadRequest(BaseModel):
+ templateFilePath: str
+
+class UploadResponse(BaseModel):
+ success: bool
+ message: str
+ data: dict
+
+class ConfigurationInfo(BaseModel):
+ baseUrl: str
+ hasToken: bool
+ hasOrgId: bool
+
+class ServiceInfo(BaseModel):
+ service: str
+ endpoints: dict
+ configuration: ConfigurationInfo
+
+def upload_template(template_file_path: str) -> dict:
+ """
+ Path A: Upload and Create Template
+ Uploads a .docx/.pptx template and extracts variables automatically
+ """
+ # Check if file exists
+ if not os.path.exists(template_file_path):
+ raise FileNotFoundError(f"Template file not found: {template_file_path}")
+
+ url = f"{BASE_URL}/template/upload-and-create"
+
+ # Prepare files and data
+ with open(template_file_path, 'rb') as file:
+ files = {
+ 'templateFile': (os.path.basename(template_file_path), file,
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')
+ }
+
+ data = {
+ 'name': TEMPLATE_NAME,
+ 'description': 'Standard employee contract with variable placeholders',
+ 'variables': '[]',
+ 'tags': '["hr", "contract", "template"]'
+ }
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ print(f"Uploading template: {os.path.basename(template_file_path)}")
+ print(f"Template name: {TEMPLATE_NAME}")
+
+ try:
+ response = requests.post(url, files=files, data=data, headers=headers)
+ response.raise_for_status()
+
+ # Parse response
+ result = response.json()
+ template = result['data']['results']['template']
+
+ print(f"✅ Template uploaded successfully: {template['id']}")
+ print(f"Template name: {template['name']}")
+
+ # Handle nullable variables field
+ variable_count = len(template['variables']) if template.get('variables') else 0
+ print(f"Variables extracted: {variable_count}")
+
+ print(f"Default font: {template.get('defaultFont', 'N/A')}")
+
+ # Handle nullable fonts field
+ font_count = len(template['fonts']) if template.get('fonts') else 0
+ print(f"Fonts used: {font_count}")
+
+ print(f"Redirect to: {result['data']['results']['redirectUrl']}")
+ print(f"Ready to generate documents with template: {template['id']}")
+
+ return result
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Upload failed: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+# FastAPI route handlers
+@app.post("/upload-template", response_model=UploadResponse)
+async def upload_template_endpoint(request: UploadRequest):
+ """Upload template from file path"""
+ try:
+ result = upload_template(request.templateFilePath)
+
+ return UploadResponse(
+ success=True,
+ message="Template uploaded successfully",
+ data=result
+ )
+
+ except FileNotFoundError as e:
+ raise HTTPException(status_code=404, detail=str(e))
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Template upload failed: {str(e)}")
+
+@app.post("/upload-file", response_model=UploadResponse)
+async def upload_file_endpoint(templateFile: UploadFile = File(...)):
+ """Upload template file directly"""
+ try:
+ # Validate file type
+ if not templateFile.filename.endswith(('.docx', '.pptx')):
+ raise HTTPException(
+ status_code=400,
+ detail="Invalid file type. Only .docx and .pptx files are supported."
+ )
+
+ # Save uploaded file temporarily
+ with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(templateFile.filename)[1]) as temp_file:
+ content = await templateFile.read()
+ temp_file.write(content)
+ temp_path = temp_file.name
+
+ try:
+ result = upload_template(temp_path)
+
+ return UploadResponse(
+ success=True,
+ message="Template uploaded successfully",
+ data=result
+ )
+
+ finally:
+ # Clean up temporary file
+ if os.path.exists(temp_path):
+ os.remove(temp_path)
+
+ except HTTPException:
+ raise
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"File upload failed: {str(e)}")
+
+@app.get("/health")
+async def health_check():
+ """Health check endpoint"""
+ return {
+ "status": "healthy",
+ "service": "template-upload"
+ }
+
+@app.get("/upload-info", response_model=ServiceInfo)
+async def upload_info():
+ """Service information endpoint"""
+ return ServiceInfo(
+ service="TurboDocx Template Upload Service",
+ endpoints={
+ "POST /upload-template": "Upload a template file (JSON with templateFilePath)",
+ "POST /upload-file": "Upload a template file (multipart form data)",
+ "GET /health": "Service health check",
+ "GET /upload-info": "Service information",
+ "GET /docs": "Interactive API documentation",
+ "GET /redoc": "Alternative API documentation"
+ },
+ configuration=ConfigurationInfo(
+ baseUrl=BASE_URL,
+ hasToken=bool(API_TOKEN and API_TOKEN != 'YOUR_API_TOKEN'),
+ hasOrgId=bool(ORG_ID and ORG_ID != 'YOUR_ORGANIZATION_ID')
+ )
+ )
+
+def demonstrate_upload():
+ """Example usage function"""
+ try:
+ print('=== Template Upload Demonstration ===')
+
+ template_file = './contract-template.docx'
+ result = upload_template(template_file)
+
+ print('\n=== Upload Complete ===')
+ print('Template ready for deliverable generation')
+
+ return result
+
+ except Exception as e:
+ print(f'Demonstration failed: {str(e)}')
+ exit(1)
+
+if __name__ == '__main__':
+ import sys
+
+ if '--demo' in sys.argv:
+ # Run demonstration
+ demonstrate_upload()
+ else:
+ # Start FastAPI server
+ port = int(os.environ.get('PORT', 8001))
+ host = os.environ.get('HOST', '0.0.0.0')
+
+ print('🚀 TurboDocx Template Upload Service started')
+ print(f'📡 Server listening on http://{host}:{port}')
+ print('\nAvailable endpoints:')
+ print(f' POST http://{host}:{port}/upload-template')
+ print(f' POST http://{host}:{port}/upload-file')
+ print(f' GET http://{host}:{port}/health')
+ print(f' GET http://{host}:{port}/upload-info')
+ print(f' GET http://{host}:{port}/docs (Interactive API docs)')
+ print(f' GET http://{host}:{port}/redoc (Alternative API docs)')
+
+ uvicorn.run(app, host=host, port=port)
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/fastify.js b/static/scripts/templates/api/upload-template/fastify.js
new file mode 100644
index 0000000..30ad4e7
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/fastify.js
@@ -0,0 +1,194 @@
+const fastify = require('fastify')({ logger: true });
+const fs = require('fs');
+const path = require('path');
+const FormData = require('form-data');
+const axios = require('axios');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+const TEMPLATE_NAME = "Employee Contract Template";
+
+/**
+ * Path A: Upload and Create Template
+ * Uploads a .docx/.pptx template and extracts variables automatically
+ */
+
+/**
+ * Upload template endpoint handler
+ */
+async function uploadTemplate(templateFilePath) {
+ // Check if file exists
+ if (!fs.existsSync(templateFilePath)) {
+ throw new Error(`Template file not found: ${templateFilePath}`);
+ }
+
+ const url = `${BASE_URL}/template/upload-and-create`;
+
+ // Create form data
+ const form = new FormData();
+
+ // Add template file
+ form.append('templateFile', fs.createReadStream(templateFilePath), {
+ filename: path.basename(templateFilePath),
+ contentType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+ });
+
+ // Add metadata fields
+ form.append('name', TEMPLATE_NAME);
+ form.append('description', 'Standard employee contract with variable placeholders');
+ form.append('variables', '[]');
+ form.append('tags', '["hr", "contract", "template"]');
+
+ try {
+ console.log(`Uploading template: ${path.basename(templateFilePath)}`);
+ console.log(`Template name: ${TEMPLATE_NAME}`);
+
+ const response = await axios.post(url, form, {
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client',
+ ...form.getHeaders()
+ }
+ });
+
+ // Parse response
+ const template = response.data.data.results.template;
+
+ console.log(`✅ Template uploaded successfully: ${template.id}`);
+ console.log(`Template name: ${template.name}`);
+
+ // Handle nullable variables field
+ const variableCount = template.variables ? template.variables.length : 0;
+ console.log(`Variables extracted: ${variableCount}`);
+
+ console.log(`Default font: ${template.defaultFont}`);
+
+ // Handle nullable fonts field
+ const fontCount = template.fonts ? template.fonts.length : 0;
+ console.log(`Fonts used: ${fontCount}`);
+
+ console.log(`Redirect to: ${response.data.data.results.redirectUrl}`);
+ console.log(`Ready to generate documents with template: ${template.id}`);
+
+ return response.data;
+ } catch (error) {
+ console.error('Upload failed:', error.response?.data || error.message);
+ throw error;
+ }
+}
+
+// Fastify route handlers
+async function registerRoutes() {
+ // Upload template route
+ fastify.post('/upload-template', async (request, reply) => {
+ try {
+ const { templateFilePath } = request.body;
+
+ if (!templateFilePath) {
+ return reply.code(400).send({
+ error: 'templateFilePath is required'
+ });
+ }
+
+ const result = await uploadTemplate(templateFilePath);
+
+ reply.send({
+ success: true,
+ message: 'Template uploaded successfully',
+ data: result
+ });
+ } catch (error) {
+ console.error('Error uploading template:', error);
+ reply.code(500).send({
+ error: 'Template upload failed',
+ message: error.message
+ });
+ }
+ });
+
+ // Health check route
+ fastify.get('/health', async (request, reply) => {
+ reply.send({ status: 'healthy', service: 'template-upload' });
+ });
+
+ // Get upload status route
+ fastify.get('/upload-info', async (request, reply) => {
+ reply.send({
+ service: 'TurboDocx Template Upload Service',
+ endpoints: {
+ 'POST /upload-template': 'Upload a new template file',
+ 'GET /health': 'Service health check',
+ 'GET /upload-info': 'Service information'
+ },
+ configuration: {
+ baseUrl: BASE_URL,
+ hasToken: !!API_TOKEN && API_TOKEN !== 'YOUR_API_TOKEN',
+ hasOrgId: !!ORG_ID && ORG_ID !== 'YOUR_ORGANIZATION_ID'
+ }
+ });
+ });
+}
+
+// Example usage function
+async function demonstrateUpload() {
+ try {
+ console.log('=== Template Upload Demonstration ===');
+
+ const templateFile = './contract-template.docx';
+ const result = await uploadTemplate(templateFile);
+
+ console.log('\n=== Upload Complete ===');
+ console.log('Template ready for deliverable generation');
+
+ return result;
+ } catch (error) {
+ console.error('Demonstration failed:', error.message);
+ process.exit(1);
+ }
+}
+
+// Server startup
+async function startServer() {
+ try {
+ await registerRoutes();
+
+ const port = process.env.PORT || 3001;
+ const host = process.env.HOST || '0.0.0.0';
+
+ await fastify.listen({ port, host });
+
+ console.log('🚀 TurboDocx Template Upload Service started');
+ console.log(`📡 Server listening on http://${host}:${port}`);
+ console.log('\nAvailable endpoints:');
+ console.log(` POST http://${host}:${port}/upload-template`);
+ console.log(` GET http://${host}:${port}/health`);
+ console.log(` GET http://${host}:${port}/upload-info`);
+
+ } catch (error) {
+ fastify.log.error(error);
+ process.exit(1);
+ }
+}
+
+// Check if this file is being run directly
+if (require.main === module) {
+ const args = process.argv.slice(2);
+
+ if (args.includes('--demo')) {
+ // Run demonstration
+ demonstrateUpload();
+ } else {
+ // Start server
+ startServer();
+ }
+}
+
+module.exports = {
+ uploadTemplate,
+ startServer,
+ demonstrateUpload,
+ fastify
+};
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/flask.py b/static/scripts/templates/api/upload-template/flask.py
new file mode 100644
index 0000000..44e7247
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/flask.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python3
+
+import os
+import requests
+import json
+from flask import Flask, request, jsonify
+from werkzeug.utils import secure_filename
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+TEMPLATE_NAME = "Employee Contract Template"
+
+app = Flask(__name__)
+
+def upload_template(template_file_path):
+ """
+ Path A: Upload and Create Template
+ Uploads a .docx/.pptx template and extracts variables automatically
+ """
+ # Check if file exists
+ if not os.path.exists(template_file_path):
+ raise FileNotFoundError(f"Template file not found: {template_file_path}")
+
+ url = f"{BASE_URL}/template/upload-and-create"
+
+ # Prepare files and data
+ with open(template_file_path, 'rb') as file:
+ files = {
+ 'templateFile': (os.path.basename(template_file_path), file,
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')
+ }
+
+ data = {
+ 'name': TEMPLATE_NAME,
+ 'description': 'Standard employee contract with variable placeholders',
+ 'variables': '[]',
+ 'tags': '["hr", "contract", "template"]'
+ }
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ print(f"Uploading template: {os.path.basename(template_file_path)}")
+ print(f"Template name: {TEMPLATE_NAME}")
+
+ try:
+ response = requests.post(url, files=files, data=data, headers=headers)
+ response.raise_for_status()
+
+ # Parse response
+ result = response.json()
+ template = result['data']['results']['template']
+
+ print(f"✅ Template uploaded successfully: {template['id']}")
+ print(f"Template name: {template['name']}")
+
+ # Handle nullable variables field
+ variable_count = len(template['variables']) if template.get('variables') else 0
+ print(f"Variables extracted: {variable_count}")
+
+ print(f"Default font: {template.get('defaultFont', 'N/A')}")
+
+ # Handle nullable fonts field
+ font_count = len(template['fonts']) if template.get('fonts') else 0
+ print(f"Fonts used: {font_count}")
+
+ print(f"Redirect to: {result['data']['results']['redirectUrl']}")
+ print(f"Ready to generate documents with template: {template['id']}")
+
+ return result
+
+ except requests.exceptions.RequestException as e:
+ error_msg = f"Upload failed: {str(e)}"
+ if hasattr(e, 'response') and e.response is not None:
+ try:
+ error_data = e.response.json()
+ error_msg += f" - {error_data}"
+ except:
+ error_msg += f" - {e.response.text}"
+ print(error_msg)
+ raise
+
+# Flask route handlers
+@app.route('/upload-template', methods=['POST'])
+def upload_template_endpoint():
+ """Upload template endpoint"""
+ try:
+ data = request.get_json()
+
+ if not data or 'templateFilePath' not in data:
+ return jsonify({
+ 'error': 'templateFilePath is required'
+ }), 400
+
+ template_file_path = data['templateFilePath']
+ result = upload_template(template_file_path)
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Template uploaded successfully',
+ 'data': result
+ })
+
+ except FileNotFoundError as e:
+ return jsonify({
+ 'error': 'File not found',
+ 'message': str(e)
+ }), 404
+
+ except Exception as e:
+ app.logger.error(f'Error uploading template: {str(e)}')
+ return jsonify({
+ 'error': 'Template upload failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/upload-file', methods=['POST'])
+def upload_file_endpoint():
+ """Upload template file directly via form data"""
+ try:
+ if 'templateFile' not in request.files:
+ return jsonify({
+ 'error': 'No template file provided'
+ }), 400
+
+ file = request.files['templateFile']
+ if file.filename == '':
+ return jsonify({
+ 'error': 'No file selected'
+ }), 400
+
+ # Save the uploaded file temporarily
+ if file:
+ filename = secure_filename(file.filename)
+ temp_path = os.path.join('/tmp', filename)
+ file.save(temp_path)
+
+ try:
+ result = upload_template(temp_path)
+
+ return jsonify({
+ 'success': True,
+ 'message': 'Template uploaded successfully',
+ 'data': result
+ })
+
+ finally:
+ # Clean up temporary file
+ if os.path.exists(temp_path):
+ os.remove(temp_path)
+
+ except Exception as e:
+ app.logger.error(f'Error uploading file: {str(e)}')
+ return jsonify({
+ 'error': 'File upload failed',
+ 'message': str(e)
+ }), 500
+
+@app.route('/health', methods=['GET'])
+def health_check():
+ """Health check endpoint"""
+ return jsonify({
+ 'status': 'healthy',
+ 'service': 'template-upload'
+ })
+
+@app.route('/upload-info', methods=['GET'])
+def upload_info():
+ """Service information endpoint"""
+ return jsonify({
+ 'service': 'TurboDocx Template Upload Service',
+ 'endpoints': {
+ 'POST /upload-template': 'Upload a template file (JSON with templateFilePath)',
+ 'POST /upload-file': 'Upload a template file (multipart form data)',
+ 'GET /health': 'Service health check',
+ 'GET /upload-info': 'Service information'
+ },
+ 'configuration': {
+ 'baseUrl': BASE_URL,
+ 'hasToken': bool(API_TOKEN and API_TOKEN != 'YOUR_API_TOKEN'),
+ 'hasOrgId': bool(ORG_ID and ORG_ID != 'YOUR_ORGANIZATION_ID')
+ }
+ })
+
+def demonstrate_upload():
+ """Example usage function"""
+ try:
+ print('=== Template Upload Demonstration ===')
+
+ template_file = './contract-template.docx'
+ result = upload_template(template_file)
+
+ print('\n=== Upload Complete ===')
+ print('Template ready for deliverable generation')
+
+ return result
+
+ except Exception as e:
+ print(f'Demonstration failed: {str(e)}')
+ exit(1)
+
+if __name__ == '__main__':
+ import sys
+
+ if '--demo' in sys.argv:
+ # Run demonstration
+ demonstrate_upload()
+ else:
+ # Start Flask server
+ port = int(os.environ.get('PORT', 5001))
+ host = os.environ.get('HOST', '0.0.0.0')
+
+ print('🚀 TurboDocx Template Upload Service started')
+ print(f'📡 Server listening on http://{host}:{port}')
+ print('\nAvailable endpoints:')
+ print(f' POST http://{host}:{port}/upload-template')
+ print(f' POST http://{host}:{port}/upload-file')
+ print(f' GET http://{host}:{port}/health')
+ print(f' GET http://{host}:{port}/upload-info')
+
+ app.run(host=host, port=port, debug=False)
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/go.go b/static/scripts/templates/api/upload-template/go.go
new file mode 100644
index 0000000..1d8c28f
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/go.go
@@ -0,0 +1,153 @@
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "mime/multipart"
+ "net/http"
+ "os"
+)
+
+// Configuration - Update these values
+const (
+ API_TOKEN = "YOUR_API_TOKEN"
+ ORG_ID = "YOUR_ORGANIZATION_ID"
+ BASE_URL = "https://api.turbodocx.com"
+ TEMPLATE_NAME = "Employee Contract Template"
+)
+
+// UploadResponse represents the API response structure
+type UploadResponse struct {
+ Data struct {
+ Results struct {
+ Template struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ DefaultFont string `json:"defaultFont"`
+ Variables []struct {
+ Name string `json:"name"`
+ Placeholder string `json:"placeholder"`
+ } `json:"variables"`
+ Fonts []struct {
+ Name string `json:"name"`
+ Usage int `json:"usage"`
+ } `json:"fonts"`
+ } `json:"template"`
+ RedirectURL string `json:"redirectUrl"`
+ } `json:"results"`
+ } `json:"data"`
+}
+
+/**
+ * Path A: Upload and Create Template
+ * Uploads a .docx/.pptx template and extracts variables automatically
+ */
+func main() {
+ templateFile := "./contract-template.docx"
+
+ result, err := uploadTemplate(templateFile)
+ if err != nil {
+ fmt.Printf("Upload failed: %v\n", err)
+ return
+ }
+
+ template := result.Data.Results.Template
+
+ fmt.Printf("Template uploaded successfully: %s\n", template.ID)
+ fmt.Printf("Template name: %s\n", template.Name)
+
+ variableCount := 0
+ if template.Variables != nil {
+ variableCount = len(template.Variables)
+ }
+ fmt.Printf("Variables extracted: %d\n", variableCount)
+
+ fmt.Printf("Default font: %s\n", template.DefaultFont)
+
+ fontCount := 0
+ if template.Fonts != nil {
+ fontCount = len(template.Fonts)
+ }
+ fmt.Printf("Fonts used: %d\n", fontCount)
+
+ fmt.Printf("Redirect to: %s\n", result.Data.Results.RedirectURL)
+ fmt.Printf("Ready to generate documents with template: %s\n", template.ID)
+}
+
+func uploadTemplate(templateFilePath string) (*UploadResponse, error) {
+ // Check if file exists
+ if _, err := os.Stat(templateFilePath); os.IsNotExist(err) {
+ return nil, fmt.Errorf("template file not found: %s", templateFilePath)
+ }
+
+ // Create multipart form data
+ var buf bytes.Buffer
+ writer := multipart.NewWriter(&buf)
+
+ // Add template file
+ file, err := os.Open(templateFilePath)
+ if err != nil {
+ return nil, fmt.Errorf("failed to open file: %v", err)
+ }
+ defer file.Close()
+
+ part, err := writer.CreateFormFile("templateFile", templateFilePath)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create form file: %v", err)
+ }
+
+ _, err = io.Copy(part, file)
+ if err != nil {
+ return nil, fmt.Errorf("failed to copy file: %v", err)
+ }
+
+ // Add form fields
+ writer.WriteField("name", TEMPLATE_NAME)
+ writer.WriteField("description", "Standard employee contract with variable placeholders")
+ writer.WriteField("variables", "[]")
+ writer.WriteField("tags", `["hr", "contract", "template"]`)
+
+ writer.Close()
+
+ // Create HTTP request
+ req, err := http.NewRequest("POST", BASE_URL+"/template/upload-and-create", &buf)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create request: %v", err)
+ }
+
+ // Set headers
+ req.Header.Set("Authorization", "Bearer "+API_TOKEN)
+ req.Header.Set("x-rapiddocx-org-id", ORG_ID)
+ req.Header.Set("User-Agent", "TurboDocx API Client")
+ req.Header.Set("Content-Type", writer.FormDataContentType())
+
+ // Make request
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("failed to make request: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, fmt.Errorf("HTTP error %d: %s", resp.StatusCode, string(body))
+ }
+
+ // Parse response
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read response: %v", err)
+ }
+
+ var result UploadResponse
+ err = json.Unmarshal(body, &result)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse JSON: %v", err)
+ }
+
+ return &result, nil
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/java.java b/static/scripts/templates/api/upload-template/java.java
new file mode 100644
index 0000000..a24dcbf
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/java.java
@@ -0,0 +1,120 @@
+import java.io.*;
+import java.net.URI;
+import java.net.http.*;
+import java.nio.file.*;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Path A: Upload and Create Template
+ * Uploads a .docx/.pptx template and extracts variables automatically
+ */
+public class TemplateUpload {
+ // Configuration - Update these values
+ private static final String API_TOKEN = "YOUR_API_TOKEN";
+ private static final String ORG_ID = "YOUR_ORGANIZATION_ID";
+ private static final String BASE_URL = "https://api.turbodocx.com";
+ private static final String TEMPLATE_NAME = "Employee Contract Template";
+
+ public static void main(String[] args) throws Exception {
+ try {
+ JsonNode result = uploadTemplate("./contract-template.docx");
+ JsonNode template = result.get("data").get("results").get("template");
+
+ System.out.println("Template uploaded successfully: " + template.get("id").asText());
+ System.out.println("Template name: " + template.get("name").asText());
+
+ // Handle nullable variables field
+ JsonNode variables = template.get("variables");
+ int variableCount = (variables != null && !variables.isNull()) ? variables.size() : 0;
+ System.out.println("Variables extracted: " + variableCount);
+
+ System.out.println("Default font: " + template.get("defaultFont").asText());
+
+ // Handle nullable fonts field
+ JsonNode fonts = template.get("fonts");
+ int fontCount = (fonts != null && !fonts.isNull()) ? fonts.size() : 0;
+ System.out.println("Fonts used: " + fontCount);
+
+ System.out.println("Redirect to: " + result.get("data").get("results").get("redirectUrl").asText());
+ System.out.println("Ready to generate documents with template: " + template.get("id").asText());
+
+ } catch (Exception e) {
+ System.err.println("Upload failed: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ private static JsonNode uploadTemplate(String templateFilePath) throws Exception {
+ // Check if file exists
+ Path filePath = Paths.get(templateFilePath);
+ if (!Files.exists(filePath)) {
+ throw new FileNotFoundException("Template file not found: " + templateFilePath);
+ }
+
+ HttpClient client = HttpClient.newHttpClient();
+ String boundary = "----JavaBoundary" + System.currentTimeMillis();
+ byte[] fileBytes = Files.readAllBytes(filePath);
+
+ // Build multipart form data
+ StringBuilder formData = new StringBuilder();
+
+ // Template file field
+ formData.append("--").append(boundary).append("\r\n");
+ formData.append("Content-Disposition: form-data; name=\"templateFile\"; filename=\"")
+ .append(filePath.getFileName().toString()).append("\"\r\n");
+ formData.append("Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document\r\n\r\n");
+
+ // Name field
+ String nameField = "\r\n--" + boundary + "\r\n" +
+ "Content-Disposition: form-data; name=\"name\"\r\n\r\n" +
+ TEMPLATE_NAME;
+
+ // Description field
+ String descField = "\r\n--" + boundary + "\r\n" +
+ "Content-Disposition: form-data; name=\"description\"\r\n\r\n" +
+ "Standard employee contract with variable placeholders";
+
+ // Variables field
+ String varsField = "\r\n--" + boundary + "\r\n" +
+ "Content-Disposition: form-data; name=\"variables\"\r\n\r\n" +
+ "[]";
+
+ // Tags field
+ String tagsField = "\r\n--" + boundary + "\r\n" +
+ "Content-Disposition: form-data; name=\"tags\"\r\n\r\n" +
+ "[\"hr\", \"contract\", \"template\"]";
+
+ String endBoundary = "\r\n--" + boundary + "--\r\n";
+
+ // Combine all parts
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(formData.toString().getBytes());
+ baos.write(fileBytes);
+ baos.write(nameField.getBytes());
+ baos.write(descField.getBytes());
+ baos.write(varsField.getBytes());
+ baos.write(tagsField.getBytes());
+ baos.write(endBoundary.getBytes());
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(BASE_URL + "/template/upload-and-create"))
+ .header("Authorization", "Bearer " + API_TOKEN)
+ .header("x-rapiddocx-org-id", ORG_ID)
+ .header("User-Agent", "TurboDocx API Client")
+ .header("Content-Type", "multipart/form-data; boundary=" + boundary)
+ .POST(HttpRequest.BodyPublishers.ofByteArray(baos.toByteArray()))
+ .timeout(java.time.Duration.ofMinutes(2))
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() != 200) {
+ throw new RuntimeException("HTTP error " + response.statusCode() + ": " + response.body());
+ }
+
+ // Parse JSON response
+ ObjectMapper mapper = new ObjectMapper();
+ return mapper.readTree(response.body());
+ }
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/nodejs/express.js b/static/scripts/templates/api/upload-template/nodejs/express.js
new file mode 100644
index 0000000..0cc29f8
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/nodejs/express.js
@@ -0,0 +1,60 @@
+const FormData = require('form-data');
+const fs = require('fs');
+const fetch = require('node-fetch');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+const TEMPLATE_NAME = "Employee Contract Template";
+
+// Path A: Upload and Create Template
+async function uploadTemplate() {
+ try {
+ const formData = new FormData();
+ formData.append('templateFile', fs.createReadStream('./contract-template.docx'));
+ formData.append('name', TEMPLATE_NAME);
+ formData.append('description', 'Standard employee contract with variable placeholders');
+ formData.append('variables', '[]'); // Optional: pre-defined variables
+ formData.append('tags', '["hr", "contract", "template"]');
+
+ const response = await fetch(`${BASE_URL}/template/upload-and-create`, {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client',
+ ...formData.getHeaders()
+ },
+ body: formData
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const result = await response.json();
+ const template = result.data.results.template;
+
+ console.log('Template uploaded successfully:', template.id);
+ console.log('Template name:', template.name);
+ console.log('Variables extracted:', template.variables ? template.variables.length : 0);
+ console.log('Default font:', template.defaultFont);
+ console.log('Fonts used:', template.fonts ? template.fonts.length : 0);
+ console.log('Redirect to:', result.data.results.redirectUrl);
+
+ return template;
+ } catch (error) {
+ console.error('Error uploading template:', error);
+ throw error;
+ }
+}
+
+// Example usage
+uploadTemplate()
+ .then(template => {
+ console.log('Ready to generate documents with template:', template.id);
+ })
+ .catch(error => {
+ console.error('Upload failed:', error.message);
+ });
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/nodejs/fastify.js b/static/scripts/templates/api/upload-template/nodejs/fastify.js
new file mode 100644
index 0000000..0cc29f8
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/nodejs/fastify.js
@@ -0,0 +1,60 @@
+const FormData = require('form-data');
+const fs = require('fs');
+const fetch = require('node-fetch');
+
+// Configuration - Update these values
+const API_TOKEN = "YOUR_API_TOKEN";
+const ORG_ID = "YOUR_ORGANIZATION_ID";
+const BASE_URL = "https://api.turbodocx.com";
+const TEMPLATE_NAME = "Employee Contract Template";
+
+// Path A: Upload and Create Template
+async function uploadTemplate() {
+ try {
+ const formData = new FormData();
+ formData.append('templateFile', fs.createReadStream('./contract-template.docx'));
+ formData.append('name', TEMPLATE_NAME);
+ formData.append('description', 'Standard employee contract with variable placeholders');
+ formData.append('variables', '[]'); // Optional: pre-defined variables
+ formData.append('tags', '["hr", "contract", "template"]');
+
+ const response = await fetch(`${BASE_URL}/template/upload-and-create`, {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${API_TOKEN}`,
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client',
+ ...formData.getHeaders()
+ },
+ body: formData
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const result = await response.json();
+ const template = result.data.results.template;
+
+ console.log('Template uploaded successfully:', template.id);
+ console.log('Template name:', template.name);
+ console.log('Variables extracted:', template.variables ? template.variables.length : 0);
+ console.log('Default font:', template.defaultFont);
+ console.log('Fonts used:', template.fonts ? template.fonts.length : 0);
+ console.log('Redirect to:', result.data.results.redirectUrl);
+
+ return template;
+ } catch (error) {
+ console.error('Error uploading template:', error);
+ throw error;
+ }
+}
+
+// Example usage
+uploadTemplate()
+ .then(template => {
+ console.log('Ready to generate documents with template:', template.id);
+ })
+ .catch(error => {
+ console.error('Upload failed:', error.message);
+ });
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/php.php b/static/scripts/templates/api/upload-template/php.php
new file mode 100644
index 0000000..d19d511
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/php.php
@@ -0,0 +1,88 @@
+ new CURLFile($templateFile, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', basename($templateFile)),
+ 'name' => $templateName,
+ 'description' => 'Standard employee contract with variable placeholders',
+ 'variables' => '[]',
+ 'tags' => '["hr", "contract", "template"]'
+ ];
+
+ // Initialize cURL
+ $ch = curl_init();
+ curl_setopt_array($ch, [
+ CURLOPT_URL => $url,
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => $postData,
+ CURLOPT_HTTPHEADER => $headers,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_SSL_VERIFYPEER => true,
+ CURLOPT_TIMEOUT => 60
+ ]);
+
+ $response = curl_exec($ch);
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ $error = curl_error($ch);
+ curl_close($ch);
+
+ if ($error) {
+ throw new Exception("cURL error: " . $error);
+ }
+
+ if ($httpCode !== 200) {
+ throw new Exception("HTTP error: " . $httpCode . " - " . $response);
+ }
+
+ $result = json_decode($response, true);
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ throw new Exception("JSON decode error: " . json_last_error_msg());
+ }
+
+ return $result;
+}
+
+// Example usage
+try {
+ $result = uploadTemplate($apiToken, $orgId, $baseUrl, $templateName, $templateFile);
+ $template = $result['data']['results']['template'];
+
+ echo "Template uploaded successfully: " . $template['id'] . "\n";
+ echo "Template name: " . $template['name'] . "\n";
+ echo "Variables extracted: " . (isset($template['variables']) && $template['variables'] ? count($template['variables']) : 0) . "\n";
+ echo "Default font: " . ($template['defaultFont'] ?? 'N/A') . "\n";
+ echo "Fonts used: " . (isset($template['fonts']) && $template['fonts'] ? count($template['fonts']) : 0) . "\n";
+ echo "Redirect to: " . $result['data']['results']['redirectUrl'] . "\n";
+
+ echo "Ready to generate documents with template: " . $template['id'] . "\n";
+
+} catch (Exception $e) {
+ echo "Upload failed: " . $e->getMessage() . "\n";
+}
+?>
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/powershell.ps1 b/static/scripts/templates/api/upload-template/powershell.ps1
new file mode 100644
index 0000000..06b0406
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/powershell.ps1
@@ -0,0 +1,123 @@
+# Configuration - Update these values
+$API_TOKEN = "YOUR_API_TOKEN"
+$ORG_ID = "YOUR_ORGANIZATION_ID"
+$BASE_URL = "https://api.turbodocx.com"
+$TEMPLATE_NAME = "Employee Contract Template"
+
+##
+# Path A: Upload and Create Template
+# Uploads a .docx/.pptx template and extracts variables automatically
+##
+
+function Upload-Template {
+ param(
+ [Parameter(Mandatory=$true)]
+ [string]$TemplateFilePath
+ )
+
+ # Check if file exists
+ if (-not (Test-Path $TemplateFilePath)) {
+ throw "Template file not found: $TemplateFilePath"
+ }
+
+ $uri = "$BASE_URL/template/upload-and-create"
+ $boundary = "----PowerShellBoundary$((Get-Random -Maximum 1000000))"
+
+ # Read file content
+ $fileContent = [System.IO.File]::ReadAllBytes($TemplateFilePath)
+ $fileName = [System.IO.Path]::GetFileName($TemplateFilePath)
+
+ # Build multipart form data
+ $bodyLines = @()
+
+ # Template file field
+ $bodyLines += "--$boundary"
+ $bodyLines += "Content-Disposition: form-data; name=`"templateFile`"; filename=`"$fileName`""
+ $bodyLines += "Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document"
+ $bodyLines += ""
+
+ # Convert file content to string for inclusion
+ $encoding = [System.Text.Encoding]::GetEncoding("ISO-8859-1")
+ $bodyLines += $encoding.GetString($fileContent)
+
+ # Name field
+ $bodyLines += "--$boundary"
+ $bodyLines += "Content-Disposition: form-data; name=`"name`""
+ $bodyLines += ""
+ $bodyLines += $TEMPLATE_NAME
+
+ # Description field
+ $bodyLines += "--$boundary"
+ $bodyLines += "Content-Disposition: form-data; name=`"description`""
+ $bodyLines += ""
+ $bodyLines += "Standard employee contract with variable placeholders"
+
+ # Variables field
+ $bodyLines += "--$boundary"
+ $bodyLines += "Content-Disposition: form-data; name=`"variables`""
+ $bodyLines += ""
+ $bodyLines += "[]"
+
+ # Tags field
+ $bodyLines += "--$boundary"
+ $bodyLines += "Content-Disposition: form-data; name=`"tags`""
+ $bodyLines += ""
+ $bodyLines += '["hr", "contract", "template"]'
+
+ $bodyLines += "--$boundary--"
+
+ # Join with CRLF
+ $body = ($bodyLines -join "`r`n")
+ $bodyBytes = $encoding.GetBytes($body)
+
+ try {
+ # Create headers
+ $headers = @{
+ 'Authorization' = "Bearer $API_TOKEN"
+ 'x-rapiddocx-org-id' = $ORG_ID
+ 'User-Agent' = 'TurboDocx API Client'
+ 'Content-Type' = "multipart/form-data; boundary=$boundary"
+ }
+
+ Write-Host "Uploading template: $fileName"
+ Write-Host "Template name: $TEMPLATE_NAME"
+
+ # Make request
+ $response = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body $bodyBytes
+
+ # Parse response
+ $template = $response.data.results.template
+
+ Write-Host "✅ Template uploaded successfully: $($template.id)" -ForegroundColor Green
+ Write-Host "Template name: $($template.name)"
+
+ # Handle nullable variables field
+ $variableCount = if ($template.variables) { $template.variables.Count } else { 0 }
+ Write-Host "Variables extracted: $variableCount"
+
+ Write-Host "Default font: $($template.defaultFont)"
+
+ # Handle nullable fonts field
+ $fontCount = if ($template.fonts) { $template.fonts.Count } else { 0 }
+ Write-Host "Fonts used: $fontCount"
+
+ Write-Host "Redirect to: $($response.data.results.redirectUrl)"
+ Write-Host "Ready to generate documents with template: $($template.id)"
+
+ return $response
+ }
+ catch {
+ Write-Error "Upload failed: $($_.Exception.Message)"
+ throw
+ }
+}
+
+# Example usage
+try {
+ $templateFile = ".\contract-template.docx"
+ $result = Upload-Template -TemplateFilePath $templateFile
+}
+catch {
+ Write-Error "Error: $($_.Exception.Message)"
+ exit 1
+}
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/python/fastapi.py b/static/scripts/templates/api/upload-template/python/fastapi.py
new file mode 100644
index 0000000..2371244
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/python/fastapi.py
@@ -0,0 +1,71 @@
+import requests
+import json
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+TEMPLATE_NAME = "Employee Contract Template"
+
+def upload_template():
+ """
+ Path A: Upload and Create Template
+ Uploads a .docx/.pptx template and extracts variables automatically
+ """
+ try:
+ url = f"{BASE_URL}/template/upload-and-create"
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ # Prepare form data
+ files = {
+ 'templateFile': ('contract-template.docx', open('./contract-template.docx', 'rb'),
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')
+ }
+
+ data = {
+ 'name': TEMPLATE_NAME,
+ 'description': 'Standard employee contract with variable placeholders',
+ 'variables': '[]', # Optional: pre-defined variables
+ 'tags': '["hr", "contract", "template"]'
+ }
+
+ response = requests.post(url, headers=headers, files=files, data=data)
+ response.raise_for_status()
+
+ result = response.json()
+ template = result['data']['results']['template']
+
+ print(f"Template uploaded successfully: {template['id']}")
+ print(f"Template name: {template['name']}")
+ print(f"Variables extracted: {len(template['variables']) if template['variables'] else 0}")
+ print(f"Default font: {template['defaultFont']}")
+ print(f"Fonts used: {len(template['fonts']) if template['fonts'] else 0}")
+ print(f"Redirect to: {result['data']['results']['redirectUrl']}")
+
+ # Clean up file handle
+ files['templateFile'][1].close()
+
+ return template
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error uploading template: {e}")
+ raise
+ except FileNotFoundError:
+ print("Error: Template file './contract-template.docx' not found")
+ raise
+ except json.JSONDecodeError as e:
+ print(f"Error parsing response: {e}")
+ raise
+
+# Example usage
+if __name__ == "__main__":
+ try:
+ template = upload_template()
+ print(f"Ready to generate documents with template: {template['id']}")
+ except Exception as error:
+ print(f"Upload failed: {error}")
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/python/flask.py b/static/scripts/templates/api/upload-template/python/flask.py
new file mode 100644
index 0000000..2371244
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/python/flask.py
@@ -0,0 +1,71 @@
+import requests
+import json
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+TEMPLATE_NAME = "Employee Contract Template"
+
+def upload_template():
+ """
+ Path A: Upload and Create Template
+ Uploads a .docx/.pptx template and extracts variables automatically
+ """
+ try:
+ url = f"{BASE_URL}/template/upload-and-create"
+
+ headers = {
+ 'Authorization': f'Bearer {API_TOKEN}',
+ 'x-rapiddocx-org-id': ORG_ID,
+ 'User-Agent': 'TurboDocx API Client'
+ }
+
+ # Prepare form data
+ files = {
+ 'templateFile': ('contract-template.docx', open('./contract-template.docx', 'rb'),
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')
+ }
+
+ data = {
+ 'name': TEMPLATE_NAME,
+ 'description': 'Standard employee contract with variable placeholders',
+ 'variables': '[]', # Optional: pre-defined variables
+ 'tags': '["hr", "contract", "template"]'
+ }
+
+ response = requests.post(url, headers=headers, files=files, data=data)
+ response.raise_for_status()
+
+ result = response.json()
+ template = result['data']['results']['template']
+
+ print(f"Template uploaded successfully: {template['id']}")
+ print(f"Template name: {template['name']}")
+ print(f"Variables extracted: {len(template['variables']) if template['variables'] else 0}")
+ print(f"Default font: {template['defaultFont']}")
+ print(f"Fonts used: {len(template['fonts']) if template['fonts'] else 0}")
+ print(f"Redirect to: {result['data']['results']['redirectUrl']}")
+
+ # Clean up file handle
+ files['templateFile'][1].close()
+
+ return template
+
+ except requests.exceptions.RequestException as e:
+ print(f"Error uploading template: {e}")
+ raise
+ except FileNotFoundError:
+ print("Error: Template file './contract-template.docx' not found")
+ raise
+ except json.JSONDecodeError as e:
+ print(f"Error parsing response: {e}")
+ raise
+
+# Example usage
+if __name__ == "__main__":
+ try:
+ template = upload_template()
+ print(f"Ready to generate documents with template: {template['id']}")
+ except Exception as error:
+ print(f"Upload failed: {error}")
\ No newline at end of file
diff --git a/static/scripts/templates/api/upload-template/ruby.rb b/static/scripts/templates/api/upload-template/ruby.rb
new file mode 100644
index 0000000..0782dd9
--- /dev/null
+++ b/static/scripts/templates/api/upload-template/ruby.rb
@@ -0,0 +1,111 @@
+require 'net/http'
+require 'uri'
+require 'json'
+require 'mime/types'
+
+# Configuration - Update these values
+API_TOKEN = "YOUR_API_TOKEN"
+ORG_ID = "YOUR_ORGANIZATION_ID"
+BASE_URL = "https://api.turbodocx.com"
+TEMPLATE_NAME = "Employee Contract Template"
+
+##
+# Path A: Upload and Create Template
+# Uploads a .docx/.pptx template and extracts variables automatically
+##
+
+def upload_template(template_file_path)
+ # Check if file exists
+ unless File.exist?(template_file_path)
+ raise "Template file not found: #{template_file_path}"
+ end
+
+ uri = URI("#{BASE_URL}/template/upload-and-create")
+ boundary = "----RubyBoundary#{rand(1000000)}"
+
+ # Build multipart form data
+ form_data = ""
+
+ # Template file field
+ form_data << "--#{boundary}\r\n"
+ form_data << "Content-Disposition: form-data; name=\"templateFile\"; filename=\"#{File.basename(template_file_path)}\"\r\n"
+ form_data << "Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document\r\n\r\n"
+ form_data << File.read(template_file_path)
+
+ # Name field
+ form_data << "\r\n--#{boundary}\r\n"
+ form_data << "Content-Disposition: form-data; name=\"name\"\r\n\r\n"
+ form_data << TEMPLATE_NAME
+
+ # Description field
+ form_data << "\r\n--#{boundary}\r\n"
+ form_data << "Content-Disposition: form-data; name=\"description\"\r\n\r\n"
+ form_data << "Standard employee contract with variable placeholders"
+
+ # Variables field
+ form_data << "\r\n--#{boundary}\r\n"
+ form_data << "Content-Disposition: form-data; name=\"variables\"\r\n\r\n"
+ form_data << "[]"
+
+ # Tags field
+ form_data << "\r\n--#{boundary}\r\n"
+ form_data << "Content-Disposition: form-data; name=\"tags\"\r\n\r\n"
+ form_data << '["hr", "contract", "template"]'
+
+ form_data << "\r\n--#{boundary}--\r\n"
+
+ # Create HTTP connection
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+
+ # Create request
+ request = Net::HTTP::Post.new(uri)
+ request['Authorization'] = "Bearer #{API_TOKEN}"
+ request['x-rapiddocx-org-id'] = ORG_ID
+ request['User-Agent'] = 'TurboDocx API Client'
+ request['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
+ request.body = form_data
+
+ # Make request
+ response = http.request(request)
+
+ unless response.code == '200'
+ raise "HTTP error #{response.code}: #{response.body}"
+ end
+
+ # Parse JSON response
+ result = JSON.parse(response.body)
+ template = result['data']['results']['template']
+
+ puts "Template uploaded successfully: #{template['id']}"
+ puts "Template name: #{template['name']}"
+
+ # Handle nullable variables field
+ variable_count = template['variables'] ? template['variables'].length : 0
+ puts "Variables extracted: #{variable_count}"
+
+ puts "Default font: #{template['defaultFont']}"
+
+ # Handle nullable fonts field
+ font_count = template['fonts'] ? template['fonts'].length : 0
+ puts "Fonts used: #{font_count}"
+
+ puts "Redirect to: #{result['data']['results']['redirectUrl']}"
+ puts "Ready to generate documents with template: #{template['id']}"
+
+ result
+rescue JSON::ParserError => e
+ raise "Failed to parse JSON response: #{e.message}"
+rescue => e
+ puts "Upload failed: #{e.message}"
+ raise
+end
+
+# Example usage
+begin
+ template_file = "./contract-template.docx"
+ result = upload_template(template_file)
+rescue => e
+ puts "Error: #{e.message}"
+ exit 1
+end
\ No newline at end of file